-
Notifications
You must be signed in to change notification settings - Fork 58
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Persist enclave plan in the Starlark executor memory (#757)
## Description: The Starlark executor now keeps track of all instructions that were executed within this enclave. It doesn't take into account the manual modification that might have been made, such as manual file uploads via the CLI. ## Is this change user facing? NO <!-- If yes, please add the "user facing" label to the PR --> <!-- If yes, don't forget to include docs changes where relevant --> ## References (if applicable): <!-- Add relevant Github Issues, Discord threads, or other helpful information. -->
- Loading branch information
Guillaume Bouvignies
authored
Jun 23, 2023
1 parent
8c2b697
commit 2c3d74e
Showing
13 changed files
with
476 additions
and
190 deletions.
There are no files selected for viewing
69 changes: 69 additions & 0 deletions
69
core/server/api_container/server/startosis_engine/instructions_plan/instructions_plan.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
package instructions_plan | ||
|
||
import ( | ||
"github.com/kurtosis-tech/kurtosis/container-engine-lib/lib/uuid_generator" | ||
"github.com/kurtosis-tech/kurtosis/core/server/api_container/server/startosis_engine/kurtosis_instruction" | ||
"github.com/kurtosis-tech/kurtosis/core/server/api_container/server/startosis_engine/startosis_errors" | ||
"github.com/kurtosis-tech/stacktrace" | ||
"go.starlark.net/starlark" | ||
) | ||
|
||
// InstructionsPlan is the object to store a sequence of instructions which forms a "plan" for the enclave. | ||
// Right now, the object is fairly simple in the sense of it just stores literally the sequence of instructions, and | ||
// a bit of metadata about each instruction (i.e. whether it has been executed of not, for example) | ||
// The plan is "append-only", i.e. when an instruction is added, it cannot be removed. | ||
// The only read method is GeneratePlan unwraps the plan into an actual list of instructions that can be submitted to | ||
// the executor. | ||
type InstructionsPlan struct { | ||
scheduledInstructionsIndex map[ScheduledInstructionUuid]*ScheduledInstruction | ||
|
||
instructionsSequence []ScheduledInstructionUuid | ||
} | ||
|
||
func NewInstructionsPlan() *InstructionsPlan { | ||
return &InstructionsPlan{ | ||
scheduledInstructionsIndex: map[ScheduledInstructionUuid]*ScheduledInstruction{}, | ||
instructionsSequence: []ScheduledInstructionUuid{}, | ||
} | ||
} | ||
|
||
func (plan *InstructionsPlan) AddInstruction(instruction kurtosis_instruction.KurtosisInstruction, returnedValue starlark.Value) error { | ||
generatedUuid, err := uuid_generator.GenerateUUIDString() | ||
if err != nil { | ||
return stacktrace.Propagate(err, "Unable to generate a random UUID for instruction '%s' to add it to the plan", instruction.String()) | ||
} | ||
|
||
scheduledInstructionUuid := ScheduledInstructionUuid(generatedUuid) | ||
scheduledInstruction := NewScheduledInstruction(scheduledInstructionUuid, instruction, returnedValue) | ||
|
||
plan.scheduledInstructionsIndex[scheduledInstructionUuid] = scheduledInstruction | ||
plan.instructionsSequence = append(plan.instructionsSequence, scheduledInstructionUuid) | ||
return nil | ||
} | ||
|
||
func (plan *InstructionsPlan) AddScheduledInstruction(scheduledInstruction *ScheduledInstruction) *ScheduledInstruction { | ||
newScheduledInstructionUuid := scheduledInstruction.uuid | ||
newScheduledInstruction := NewScheduledInstruction(newScheduledInstructionUuid, scheduledInstruction.kurtosisInstruction, scheduledInstruction.returnedValue) | ||
newScheduledInstruction.Executed(scheduledInstruction.IsExecuted()) | ||
|
||
plan.scheduledInstructionsIndex[newScheduledInstructionUuid] = newScheduledInstruction | ||
plan.instructionsSequence = append(plan.instructionsSequence, newScheduledInstructionUuid) | ||
return newScheduledInstruction | ||
} | ||
|
||
// GeneratePlan unwraps the plan into a list of instructions | ||
func (plan *InstructionsPlan) GeneratePlan() ([]*ScheduledInstruction, *startosis_errors.InterpretationError) { | ||
var generatedPlan []*ScheduledInstruction | ||
for _, instructionUuid := range plan.instructionsSequence { | ||
instruction, found := plan.scheduledInstructionsIndex[instructionUuid] | ||
if !found { | ||
return nil, startosis_errors.NewInterpretationError("Unexpected error generating the Kurtosis Instructions plan. Instruction with UUID '%s' was scheduled but could not be found in Kurtosis instruction index", instructionUuid) | ||
} | ||
generatedPlan = append(generatedPlan, instruction) | ||
} | ||
return generatedPlan, nil | ||
} | ||
|
||
func (plan *InstructionsPlan) Size() int { | ||
return len(plan.instructionsSequence) | ||
} |
86 changes: 86 additions & 0 deletions
86
.../server/api_container/server/startosis_engine/instructions_plan/instructions_plan_test.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
package instructions_plan | ||
|
||
import ( | ||
"github.com/kurtosis-tech/kurtosis/core/server/api_container/server/startosis_engine/kurtosis_instruction/mock_instruction" | ||
"github.com/stretchr/testify/require" | ||
"go.starlark.net/starlark" | ||
"testing" | ||
) | ||
|
||
func TestAddInstruction(t *testing.T) { | ||
plan := NewInstructionsPlan() | ||
|
||
instruction1 := mock_instruction.NewMockKurtosisInstruction(t) | ||
instruction1ReturnedValue := starlark.None | ||
require.NoError(t, plan.AddInstruction(instruction1, instruction1ReturnedValue)) | ||
|
||
require.Len(t, plan.instructionsSequence, 1) | ||
scheduledInstructionUuid := plan.instructionsSequence[0] | ||
require.Contains(t, plan.scheduledInstructionsIndex, scheduledInstructionUuid) | ||
scheduledInstruction, found := plan.scheduledInstructionsIndex[scheduledInstructionUuid] | ||
require.True(t, found) | ||
require.Equal(t, scheduledInstruction.GetInstruction(), instruction1) | ||
require.False(t, scheduledInstruction.IsExecuted()) | ||
require.Equal(t, scheduledInstruction.GetReturnedValue(), instruction1ReturnedValue) | ||
} | ||
|
||
func TestAddScheduledInstruction(t *testing.T) { | ||
plan := NewInstructionsPlan() | ||
|
||
instruction1Uuid := ScheduledInstructionUuid("instruction1") | ||
instruction1 := mock_instruction.NewMockKurtosisInstruction(t) | ||
instruction1ReturnedValue := starlark.MakeInt(1) | ||
scheduleInstruction := NewScheduledInstruction(instruction1Uuid, instruction1, instruction1ReturnedValue) | ||
scheduleInstruction.executed = true | ||
|
||
plan.AddScheduledInstruction(scheduleInstruction) | ||
|
||
require.Len(t, plan.instructionsSequence, 1) | ||
scheduledInstructionUuid := plan.instructionsSequence[0] | ||
require.Equal(t, instruction1Uuid, scheduledInstructionUuid) | ||
require.Contains(t, plan.scheduledInstructionsIndex, scheduledInstructionUuid) | ||
addedScheduledInstruction, found := plan.scheduledInstructionsIndex[scheduledInstructionUuid] | ||
require.True(t, found) | ||
require.NotSame(t, scheduleInstruction, addedScheduledInstruction) // validate the instruction was cloned | ||
require.Equal(t, addedScheduledInstruction.GetInstruction(), instruction1) | ||
require.True(t, addedScheduledInstruction.IsExecuted()) | ||
require.Equal(t, addedScheduledInstruction.GetReturnedValue(), instruction1ReturnedValue) | ||
} | ||
|
||
func TestGeneratePlan(t *testing.T) { | ||
plan := NewInstructionsPlan() | ||
|
||
// add instruction1 which is marked as executed | ||
instruction1Uuid := ScheduledInstructionUuid("instruction1") | ||
instruction1 := mock_instruction.NewMockKurtosisInstruction(t) | ||
instruction1ReturnedValue := starlark.None | ||
scheduleInstruction1 := NewScheduledInstruction(instruction1Uuid, instruction1, instruction1ReturnedValue) | ||
scheduleInstruction1.Executed(true) | ||
|
||
plan.scheduledInstructionsIndex[instruction1Uuid] = scheduleInstruction1 | ||
plan.instructionsSequence = append(plan.instructionsSequence, instruction1Uuid) | ||
|
||
// add instruction2 which by default is not executed | ||
instruction2Uuid := ScheduledInstructionUuid("instruction2") | ||
instruction2 := mock_instruction.NewMockKurtosisInstruction(t) | ||
instruction2ReturnedValue := starlark.MakeInt(1) | ||
scheduleInstruction2 := NewScheduledInstruction(instruction2Uuid, instruction2, instruction2ReturnedValue) | ||
|
||
plan.scheduledInstructionsIndex[instruction2Uuid] = scheduleInstruction2 | ||
plan.instructionsSequence = append(plan.instructionsSequence, instruction2Uuid) | ||
|
||
// generate plan and validate it | ||
instructionsSequence, err := plan.GeneratePlan() | ||
require.Nil(t, err) | ||
|
||
require.Len(t, instructionsSequence, 2) | ||
scheduledInstruction1 := instructionsSequence[0] | ||
require.Equal(t, scheduledInstruction1.GetInstruction(), instruction1) | ||
require.True(t, scheduledInstruction1.IsExecuted()) | ||
require.Equal(t, scheduledInstruction1.GetReturnedValue(), instruction1ReturnedValue) | ||
|
||
scheduledInstruction2 := instructionsSequence[1] | ||
require.Equal(t, scheduledInstruction2.GetInstruction(), instruction2) | ||
require.False(t, scheduledInstruction2.IsExecuted()) | ||
require.Equal(t, scheduledInstruction2.GetReturnedValue(), instruction2ReturnedValue) | ||
} |
49 changes: 49 additions & 0 deletions
49
core/server/api_container/server/startosis_engine/instructions_plan/scheduled_instruction.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
package instructions_plan | ||
|
||
import ( | ||
"github.com/kurtosis-tech/kurtosis/core/server/api_container/server/startosis_engine/kurtosis_instruction" | ||
"go.starlark.net/starlark" | ||
) | ||
|
||
type ScheduledInstructionUuid string | ||
|
||
// ScheduledInstruction is a wrapper around a KurtosisInstruction to specify that the instruction is part of an | ||
// InstructionPlan. The instruction plan can either be the current enclave plan (which has been executed) or a newly | ||
// generated plan from the latest interpretation. | ||
// In any case, the ScheduledInstructionUuid stores the result object from the interpretation of the instruction, | ||
// as well as a flag to track whether this instruction was already executed or not. | ||
type ScheduledInstruction struct { | ||
uuid ScheduledInstructionUuid | ||
|
||
kurtosisInstruction kurtosis_instruction.KurtosisInstruction | ||
|
||
returnedValue starlark.Value | ||
|
||
executed bool | ||
} | ||
|
||
func NewScheduledInstruction(uuid ScheduledInstructionUuid, kurtosisInstruction kurtosis_instruction.KurtosisInstruction, returnedValue starlark.Value) *ScheduledInstruction { | ||
return &ScheduledInstruction{ | ||
uuid: uuid, | ||
kurtosisInstruction: kurtosisInstruction, | ||
returnedValue: returnedValue, | ||
executed: false, | ||
} | ||
} | ||
|
||
func (instruction *ScheduledInstruction) GetInstruction() kurtosis_instruction.KurtosisInstruction { | ||
return instruction.kurtosisInstruction | ||
} | ||
|
||
func (instruction *ScheduledInstruction) GetReturnedValue() starlark.Value { | ||
return instruction.returnedValue | ||
} | ||
|
||
func (instruction *ScheduledInstruction) Executed(isExecuted bool) *ScheduledInstruction { | ||
instruction.executed = isExecuted | ||
return instruction | ||
} | ||
|
||
func (instruction *ScheduledInstruction) IsExecuted() bool { | ||
return instruction.executed | ||
} |
19 changes: 19 additions & 0 deletions
19
...ver/api_container/server/startosis_engine/instructions_plan/scheduled_instruction_test.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package instructions_plan | ||
|
||
import ( | ||
"github.com/kurtosis-tech/kurtosis/core/server/api_container/server/startosis_engine/kurtosis_instruction/mock_instruction" | ||
"github.com/stretchr/testify/require" | ||
"go.starlark.net/starlark" | ||
"testing" | ||
) | ||
|
||
func TestExecutedDefaultAndUpdate(t *testing.T) { | ||
instruction1Uuid := ScheduledInstructionUuid("instruction1") | ||
instruction1 := mock_instruction.NewMockKurtosisInstruction(t) | ||
instruction1ReturnedValue := starlark.MakeInt(1) | ||
scheduleInstruction := NewScheduledInstruction(instruction1Uuid, instruction1, instruction1ReturnedValue) | ||
|
||
require.False(t, scheduleInstruction.executed) | ||
scheduleInstruction.Executed(true) | ||
require.True(t, scheduleInstruction.executed) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.