Skip to content

Commit

Permalink
feat: Persist runtime value store (#1170)
Browse files Browse the repository at this point in the history
## Description:
Persist runtime value store

## Is this change user-facing?
NO

## References (if applicable):
This is part of the APIC restart project
  • Loading branch information
leoporoli committed Sep 1, 2023
1 parent 10c461f commit cfec9b3
Show file tree
Hide file tree
Showing 36 changed files with 802 additions and 67 deletions.
6 changes: 5 additions & 1 deletion core/server/api_container/main.go
Expand Up @@ -162,7 +162,11 @@ func runMain() error {
return stacktrace.Propagate(err, "An error occurred creating the service network")
}

runtimeValueStore := runtime_value_store.NewRuntimeValueStore()
runtimeValueStore, err := runtime_value_store.CreateRuntimeValueStore(enclaveDb)
if err != nil {
return stacktrace.Propagate(err, "An error occurred creating the runtime value store")
}

// TODO: Consolidate Interpreter, Validator and Executor into a single interface
startosisRunner := startosis_engine.NewStartosisRunner(
startosis_engine.NewStartosisInterpreter(serviceNetwork, gitPackageContentProvider, runtimeValueStore, serverArgs.EnclaveEnvVars),
Expand Down
Expand Up @@ -152,7 +152,9 @@ func (builtin *AddServiceCapabilities) Execute(ctx context.Context, _ *builtin_a
return "", stacktrace.Propagate(err, "An error occurred while checking if service '%v' is ready", replacedServiceName)
}

fillAddServiceReturnValueWithRuntimeValues(startedService, builtin.resultUuid, builtin.runtimeValueStore)
if err := fillAddServiceReturnValueWithRuntimeValues(startedService, builtin.resultUuid, builtin.runtimeValueStore); err != nil {
return "", stacktrace.Propagate(err, "An error occurred while adding service return values with result key UUID '%s'", builtin.resultUuid)
}
instructionResult := fmt.Sprintf("Service '%s' added with service UUID '%s'", replacedServiceName, startedService.GetRegistration().GetUUID())
return instructionResult, nil
}
Expand Down
Expand Up @@ -24,11 +24,14 @@ const (
hostnameRuntimeValue = "hostname"
)

func fillAddServiceReturnValueWithRuntimeValues(service *service.Service, resultUuid string, runtimeValueStore *runtime_value_store.RuntimeValueStore) {
runtimeValueStore.SetValue(resultUuid, map[string]starlark.Comparable{
func fillAddServiceReturnValueWithRuntimeValues(service *service.Service, resultUuid string, runtimeValueStore *runtime_value_store.RuntimeValueStore) error {
if err := runtimeValueStore.SetValue(resultUuid, map[string]starlark.Comparable{
ipAddressRuntimeValue: starlark.String(service.GetRegistration().GetPrivateIP().String()),
hostnameRuntimeValue: starlark.String(service.GetRegistration().GetHostname()),
})
}); err != nil {
return stacktrace.Propagate(err, "An error occurred setting value with key '%s' in the runtime value store", resultUuid)
}
return nil
}

func makeAddServiceInterpretationReturnValue(serviceName starlark.String, serviceConfig *service.ServiceConfig, resultUuid string) (*kurtosis_types.Service, *startosis_errors.InterpretationError) {
Expand Down
Expand Up @@ -3,10 +3,13 @@ package add_service
import (
"fmt"
"github.com/kurtosis-tech/kurtosis/container-engine-lib/lib/backend_interface/objects/service"
"github.com/kurtosis-tech/kurtosis/container-engine-lib/lib/database_accessors/enclave_db"
"github.com/kurtosis-tech/kurtosis/core/server/api_container/server/startosis_engine/kurtosis_instruction/shared_helpers/magic_string_helper"
"github.com/kurtosis-tech/kurtosis/core/server/api_container/server/startosis_engine/runtime_value_store"
"github.com/stretchr/testify/require"
bolt "go.etcd.io/bbolt"
"go.starlark.net/starlark"
"os"
"testing"
)

Expand All @@ -15,13 +18,17 @@ const (
)

func TestAddServiceShared_EntryPointArgsRuntimeValueAreReplaced(t *testing.T) {
runtimeValueStore := runtime_value_store.NewRuntimeValueStore()
enclaveDb := getEnclaveDBForTest(t)
runtimeValueStore, err := runtime_value_store.CreateRuntimeValueStore(enclaveDb)
require.NoError(t, err)

stringValueUuid, err := runtimeValueStore.CreateValue()
require.Nil(t, err, "error creating a runtime value UUID")
runtimeValueName := "value"
runtimeValueStore.SetValue(stringValueUuid, map[string]starlark.Comparable{
err = runtimeValueStore.SetValue(stringValueUuid, map[string]starlark.Comparable{
runtimeValueName: starlark.MakeInt(8765),
})
require.NoError(t, err)
runtimeValue := fmt.Sprintf(magic_string_helper.RuntimeValueReplacementPlaceholderFormat, stringValueUuid, runtimeValueName)

serviceName := service.ServiceName("example-datastore-server-2")
Expand All @@ -48,13 +55,16 @@ func TestAddServiceShared_EntryPointArgsRuntimeValueAreReplaced(t *testing.T) {
}

func TestAddServiceShared_CmdArgsRuntimeValueAreReplaced(t *testing.T) {
runtimeValueStore := runtime_value_store.NewRuntimeValueStore()
enclaveDb := getEnclaveDBForTest(t)
runtimeValueStore, err := runtime_value_store.CreateRuntimeValueStore(enclaveDb)
require.NoError(t, err)
stringValueUuid, err := runtimeValueStore.CreateValue()
require.Nil(t, err, "error creating a runtime value UUID")
runtimeValueName := "value"
runtimeValueStore.SetValue(stringValueUuid, map[string]starlark.Comparable{
err = runtimeValueStore.SetValue(stringValueUuid, map[string]starlark.Comparable{
runtimeValueName: starlark.MakeInt(999999),
})
require.NoError(t, err)
runtimeValue := fmt.Sprintf(magic_string_helper.RuntimeValueReplacementPlaceholderFormat, stringValueUuid, runtimeValueName)

serviceName := service.ServiceName("example-datastore-server-2")
Expand All @@ -81,13 +91,16 @@ func TestAddServiceShared_CmdArgsRuntimeValueAreReplaced(t *testing.T) {
}

func TestAddServiceShared_EnvVarsWithRuntimeValueAreReplaced(t *testing.T) {
runtimeValueStore := runtime_value_store.NewRuntimeValueStore()
enclaveDb := getEnclaveDBForTest(t)
runtimeValueStore, err := runtime_value_store.CreateRuntimeValueStore(enclaveDb)
require.NoError(t, err)
stringValueUuid, err := runtimeValueStore.CreateValue()
require.Nil(t, err, "error creating a runtime value UUID")
runtimeValueName := "value"
runtimeValueStore.SetValue(stringValueUuid, map[string]starlark.Comparable{
err = runtimeValueStore.SetValue(stringValueUuid, map[string]starlark.Comparable{
runtimeValueName: starlark.MakeInt(8765),
})
require.NoError(t, err)
runtimeValue := fmt.Sprintf(magic_string_helper.RuntimeValueReplacementPlaceholderFormat, stringValueUuid, runtimeValueName)

serviceName := service.ServiceName("example-datastore-server-2")
Expand Down Expand Up @@ -119,13 +132,16 @@ func TestAddServiceShared_EnvVarsWithRuntimeValueAreReplaced(t *testing.T) {
}

func TestAddServiceShared_ServiceNameWithRuntimeValuesAreReplaced(t *testing.T) {
runtimeValueStore := runtime_value_store.NewRuntimeValueStore()
enclaveDb := getEnclaveDBForTest(t)
runtimeValueStore, err := runtime_value_store.CreateRuntimeValueStore(enclaveDb)
require.NoError(t, err)
stringValueUuid, err := runtimeValueStore.CreateValue()
require.Nil(t, err, "error creating a runtime value UUID")
valueName := "value"
runtimeValueStore.SetValue(stringValueUuid, map[string]starlark.Comparable{
err = runtimeValueStore.SetValue(stringValueUuid, map[string]starlark.Comparable{
"value": starlark.String("database-1"),
})
require.NoError(t, err)
stringRuntimeValue := fmt.Sprintf(magic_string_helper.RuntimeValueReplacementPlaceholderFormat, stringValueUuid, valueName)

serviceName := service.ServiceName(stringRuntimeValue)
Expand All @@ -149,3 +165,20 @@ func TestAddServiceShared_ServiceNameWithRuntimeValuesAreReplaced(t *testing.T)
require.Nil(t, err)
require.Equal(t, service.ServiceName("database-1"), replacedServiceName)
}

func getEnclaveDBForTest(t *testing.T) *enclave_db.EnclaveDB {
file, err := os.CreateTemp("/tmp", "*.db")
defer func() {
err = os.Remove(file.Name())
require.NoError(t, err)
}()

require.NoError(t, err)
db, err := bolt.Open(file.Name(), 0666, nil)
require.NoError(t, err)
enclaveDb := &enclave_db.EnclaveDB{
DB: db,
}

return enclaveDb
}
Expand Up @@ -194,7 +194,9 @@ func (builtin *AddServicesCapabilities) Execute(ctx context.Context, _ *builtin_
instructionResult := strings.Builder{}
instructionResult.WriteString(fmt.Sprintf("Successfully added the following '%d' services:", len(startedServices)))
for serviceName, serviceObj := range startedAndUpdatedService {
fillAddServiceReturnValueWithRuntimeValues(serviceObj, builtin.resultUuids[serviceName], builtin.runtimeValueStore)
if err := fillAddServiceReturnValueWithRuntimeValues(serviceObj, builtin.resultUuids[serviceName], builtin.runtimeValueStore); err != nil {
return "", stacktrace.Propagate(err, "An error occurred while adding service return values with result key UUID '%s'", builtin.resultUuids[serviceName])
}
instructionResult.WriteString(fmt.Sprintf("\n Service '%s' added with UUID '%s'", serviceName, serviceObj.GetRegistration().GetUUID()))
}
shouldDeleteAllStartedServices = false
Expand Down
Expand Up @@ -168,7 +168,9 @@ func (builtin *ExecCapabilities) Execute(ctx context.Context, _ *builtin_argumen
return "", stacktrace.NewError(formatErrorMessage(errorMessage, result["output"].String()))
}

builtin.runtimeValueStore.SetValue(builtin.resultUuid, result)
if err := builtin.runtimeValueStore.SetValue(builtin.resultUuid, result); err != nil {
return "", stacktrace.Propagate(err, "An error occurred setting value '%+v' using key UUID '%s' in the runtime value store", result, builtin.resultUuid)
}
instructionResult := builtin.execRecipe.ResultMapToString(result)
return instructionResult, err
}
Expand Down
Expand Up @@ -179,7 +179,10 @@ func (builtin *RequestCapabilities) Execute(ctx context.Context, _ *builtin_argu
if !builtin.skipCodeCheck && !builtin.isAcceptableCode(result) {
return "", stacktrace.NewError("Request returned status code '%v' that is not part of the acceptable status codes '%v'", result["code"], builtin.acceptableCodes)
}
builtin.runtimeValueStore.SetValue(builtin.resultUuid, result)
if err := builtin.runtimeValueStore.SetValue(builtin.resultUuid, result); err != nil {
return "", stacktrace.Propagate(err, "An error occurred setting value '%+v' using key UUID '%s' in the runtime value store", result, builtin.resultUuid)
}

instructionResult := builtin.httpRequestRecipe.ResultMapToString(result)
return instructionResult, err
}
Expand Down
Expand Up @@ -2,9 +2,12 @@ package magic_string_helper

import (
"fmt"
"github.com/kurtosis-tech/kurtosis/container-engine-lib/lib/database_accessors/enclave_db"
"github.com/kurtosis-tech/kurtosis/core/server/api_container/server/startosis_engine/runtime_value_store"
"github.com/stretchr/testify/require"
bolt "go.etcd.io/bbolt"
"go.starlark.net/starlark"
"os"
"testing"
)

Expand All @@ -17,13 +20,17 @@ const (
var testIntRuntimeValue = starlark.MakeInt(0)

func TestGetOrReplaceRuntimeValueFromString_BasicFetch(t *testing.T) {
runtimeValueStore := runtime_value_store.NewRuntimeValueStore()
enclaveDb := getEnclaveDBForTest(t)
runtimeValueStore, err := runtime_value_store.CreateRuntimeValueStore(enclaveDb)
require.NoError(t, err)
stringValueUuid, err := runtimeValueStore.CreateValue()
require.Nil(t, err)
runtimeValueStore.SetValue(stringValueUuid, map[string]starlark.Comparable{testRuntimeValueField: testStringRuntimeValue})
err = runtimeValueStore.SetValue(stringValueUuid, map[string]starlark.Comparable{testRuntimeValueField: testStringRuntimeValue})
require.NoError(t, err)
intValueUuid, err := runtimeValueStore.CreateValue()
require.Nil(t, err)
runtimeValueStore.SetValue(intValueUuid, map[string]starlark.Comparable{testRuntimeValueField: testIntRuntimeValue})
err = runtimeValueStore.SetValue(intValueUuid, map[string]starlark.Comparable{testRuntimeValueField: testIntRuntimeValue})
require.NoError(t, err)
fetchedStringValue, err := GetOrReplaceRuntimeValueFromString(fmt.Sprintf(RuntimeValueReplacementPlaceholderFormat, stringValueUuid, testRuntimeValueField), runtimeValueStore)
require.Nil(t, err)
require.Equal(t, fetchedStringValue, testStringRuntimeValue)
Expand All @@ -33,13 +40,17 @@ func TestGetOrReplaceRuntimeValueFromString_BasicFetch(t *testing.T) {
}

func TestGetOrReplaceRuntimeValueFromString_Interpolated(t *testing.T) {
runtimeValueStore := runtime_value_store.NewRuntimeValueStore()
enclaveDb := getEnclaveDBForTest(t)
runtimeValueStore, err := runtime_value_store.CreateRuntimeValueStore(enclaveDb)
require.NoError(t, err)
stringValueUuid, err := runtimeValueStore.CreateValue()
require.Nil(t, err)
runtimeValueStore.SetValue(stringValueUuid, map[string]starlark.Comparable{testRuntimeValueField: testStringRuntimeValue})
err = runtimeValueStore.SetValue(stringValueUuid, map[string]starlark.Comparable{testRuntimeValueField: testStringRuntimeValue})
require.NoError(t, err)
intValueUuid, err := runtimeValueStore.CreateValue()
require.Nil(t, err)
runtimeValueStore.SetValue(intValueUuid, map[string]starlark.Comparable{testRuntimeValueField: testIntRuntimeValue})
err = runtimeValueStore.SetValue(intValueUuid, map[string]starlark.Comparable{testRuntimeValueField: testIntRuntimeValue})
require.NoError(t, err)
stringRuntimeValue := fmt.Sprintf(RuntimeValueReplacementPlaceholderFormat, stringValueUuid, testRuntimeValueField)
intRuntimeValue := fmt.Sprintf(RuntimeValueReplacementPlaceholderFormat, intValueUuid, testRuntimeValueField)
interpolatedString := fmt.Sprintf("%v is not %v", stringRuntimeValue, intRuntimeValue)
Expand All @@ -49,17 +60,38 @@ func TestGetOrReplaceRuntimeValueFromString_Interpolated(t *testing.T) {
}

func TestReplaceRuntimeValueFromString(t *testing.T) {
runtimeValueStore := runtime_value_store.NewRuntimeValueStore()
enclaveDb := getEnclaveDBForTest(t)
runtimeValueStore, err := runtime_value_store.CreateRuntimeValueStore(enclaveDb)
require.NoError(t, err)
stringValueUuid, err := runtimeValueStore.CreateValue()
require.Nil(t, err)
runtimeValueStore.SetValue(stringValueUuid, map[string]starlark.Comparable{testRuntimeValueField: testStringRuntimeValue})
err = runtimeValueStore.SetValue(stringValueUuid, map[string]starlark.Comparable{testRuntimeValueField: testStringRuntimeValue})
require.NoError(t, err)
intValueUuid, err := runtimeValueStore.CreateValue()
require.Nil(t, err)
runtimeValueStore.SetValue(intValueUuid, map[string]starlark.Comparable{testRuntimeValueField: testIntRuntimeValue})
err = runtimeValueStore.SetValue(intValueUuid, map[string]starlark.Comparable{testRuntimeValueField: testIntRuntimeValue})
require.NoError(t, err)
stringRuntimeValue := fmt.Sprintf(RuntimeValueReplacementPlaceholderFormat, stringValueUuid, testRuntimeValueField)
intRuntimeValue := fmt.Sprintf(RuntimeValueReplacementPlaceholderFormat, intValueUuid, testRuntimeValueField)
interpolatedString := fmt.Sprintf("%v is not %v", stringRuntimeValue, intRuntimeValue)
resolvedInterpolatedString, err := ReplaceRuntimeValueInString(interpolatedString, runtimeValueStore)
require.Nil(t, err)
require.Equal(t, resolvedInterpolatedString, testExpectedInterpolatedString.GoString())
}

func getEnclaveDBForTest(t *testing.T) *enclave_db.EnclaveDB {
file, err := os.CreateTemp("/tmp", "*.db")
defer func() {
err = os.Remove(file.Name())
require.NoError(t, err)
}()

require.NoError(t, err)
db, err := bolt.Open(file.Name(), 0666, nil)
require.NoError(t, err)
enclaveDb := &enclave_db.EnclaveDB{
DB: db,
}

return enclaveDb
}
Expand Up @@ -310,7 +310,9 @@ func (builtin *RunPythonCapabilities) Execute(ctx context.Context, _ *builtin_ar
runResultCodeKey: starlark.MakeInt(int(runPythonExecutionResult.GetExitCode())),
}

builtin.runtimeValueStore.SetValue(builtin.resultUuid, result)
if err := builtin.runtimeValueStore.SetValue(builtin.resultUuid, result); err != nil {
return "", stacktrace.Propagate(err, "An error occurred setting value '%+v' using key UUID '%s' in the runtime value store", result, builtin.resultUuid)
}
instructionResult := resultMapToString(result, RunPythonBuiltinName)

// throw an error as execution of the command failed
Expand Down
Expand Up @@ -214,7 +214,9 @@ func (builtin *RunShCapabilities) Execute(ctx context.Context, _ *builtin_argume
runResultCodeKey: starlark.MakeInt(int(createDefaultDirectoryResult.GetExitCode())),
}

builtin.runtimeValueStore.SetValue(builtin.resultUuid, result)
if err := builtin.runtimeValueStore.SetValue(builtin.resultUuid, result); err != nil {
return "", stacktrace.Propagate(err, "An error occurred setting value '%+v' using key UUID '%s' in the runtime value store", result, builtin.resultUuid)
}
instructionResult := resultMapToString(result, RunShBuiltinName)

// throw an error as execution of the command failed
Expand Down
Expand Up @@ -261,7 +261,9 @@ func (builtin *WaitCapabilities) Execute(ctx context.Context, _ *builtin_argumen
)
}

builtin.runtimeValueStore.SetValue(builtin.resultUuid, lastResult)
if err := builtin.runtimeValueStore.SetValue(builtin.resultUuid, lastResult); err != nil {
return "", stacktrace.Propagate(err, "An error occurred setting value '%+v' using key UUID '%s' in the runtime value store", lastResult, builtin.resultUuid)
}

instructionResult := fmt.Sprintf(
"Wait took %d tries (%v in total). Assertion passed with following:\n%s",
Expand Down
Expand Up @@ -5,6 +5,7 @@ import (
"github.com/kurtosis-tech/kurtosis/container-engine-lib/lib/backend_interface/objects/container_status"
"github.com/kurtosis-tech/kurtosis/container-engine-lib/lib/backend_interface/objects/port_spec"
"github.com/kurtosis-tech/kurtosis/container-engine-lib/lib/backend_interface/objects/service"
"github.com/kurtosis-tech/kurtosis/container-engine-lib/lib/database_accessors/enclave_db"
"github.com/kurtosis-tech/kurtosis/core/server/api_container/server/service_network"
"github.com/kurtosis-tech/kurtosis/core/server/api_container/server/startosis_engine/kurtosis_instruction/add_service"
"github.com/kurtosis-tech/kurtosis/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/kurtosis_plan_instruction"
Expand All @@ -14,7 +15,9 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
bolt "go.etcd.io/bbolt"
"go.starlark.net/starlark"
"os"
"testing"
)

Expand All @@ -34,7 +37,9 @@ func (t *addServiceTestCase) GetId() string {

func (t *addServiceTestCase) GetInstruction() *kurtosis_plan_instruction.KurtosisPlanInstruction {
serviceNetwork := service_network.NewMockServiceNetwork(t)
runtimeValueStore := runtime_value_store.NewRuntimeValueStore()
enclaveDb := getEnclaveDBForTest(t.T)
runtimeValueStore, err := runtime_value_store.CreateRuntimeValueStore(enclaveDb)
require.NoError(t, err)

serviceNetwork.EXPECT().ExistServiceRegistration(TestServiceName).Times(1).Return(false, nil)
serviceNetwork.EXPECT().AddService(
Expand Down Expand Up @@ -88,3 +93,20 @@ func (t *addServiceTestCase) Assert(interpretationResult starlark.Value, executi
expectedExecutionResult := fmt.Sprintf("Service '%s' added with service UUID '%s'", TestServiceName, TestServiceUuid)
require.Equal(t, expectedExecutionResult, *executionResult)
}

func getEnclaveDBForTest(t *testing.T) *enclave_db.EnclaveDB {
file, err := os.CreateTemp("/tmp", "*.db")
defer func() {
err = os.Remove(file.Name())
require.NoError(t, err)
}()

require.NoError(t, err)
db, err := bolt.Open(file.Name(), 0666, nil)
require.NoError(t, err)
enclaveDb := &enclave_db.EnclaveDB{
DB: db,
}

return enclaveDb
}
Expand Up @@ -37,7 +37,9 @@ func (t *addServicesTestCase) GetId() string {

func (t *addServicesTestCase) GetInstruction() *kurtosis_plan_instruction.KurtosisPlanInstruction {
serviceNetwork := service_network.NewMockServiceNetwork(t)
runtimeValueStore := runtime_value_store.NewRuntimeValueStore()
enclaveDb := getEnclaveDBForTest(t.T)
runtimeValueStore, err := runtime_value_store.CreateRuntimeValueStore(enclaveDb)
require.NoError(t, err)

serviceNetwork.EXPECT().ExistServiceRegistration(TestServiceName).Times(1).Return(false, nil)
serviceNetwork.EXPECT().ExistServiceRegistration(TestServiceName2).Times(1).Return(false, nil)
Expand Down
Expand Up @@ -35,10 +35,13 @@ func (t assertTestCase) GetId() string {
}

func (t assertTestCase) GetInstruction() *kurtosis_plan_instruction.KurtosisPlanInstruction {
runtimeValueStore := runtime_value_store.NewRuntimeValueStore()
runtimeValueStore.SetValue(t.runtimeValueUuid, map[string]starlark.Comparable{
enclaveDb := getEnclaveDBForTest(t.T)
runtimeValueStore, err := runtime_value_store.CreateRuntimeValueStore(enclaveDb)
require.NoError(t, err)
err = runtimeValueStore.SetValue(t.runtimeValueUuid, map[string]starlark.Comparable{
"value": starlark.String(runtimeValueValue),
})
require.NoError(t, err)
return assert.NewAssert(runtimeValueStore)
}

Expand Down

0 comments on commit cfec9b3

Please sign in to comment.