Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: added the get_service instruction #2233

Merged
merged 13 commits into from
Feb 28, 2024
8 changes: 7 additions & 1 deletion core/server/api_container/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ package main
import (
"context"
"fmt"
"github.com/kurtosis-tech/kurtosis/core/server/api_container/server/startosis_engine/interpretation_time_value_store"
"net"
"os"
"path"
Expand Down Expand Up @@ -203,6 +204,11 @@ func runMain() error {
return stacktrace.Propagate(err, "An error occurred creating the runtime value store")
}

interpretationTimeValueStore, err := interpretation_time_value_store.CreateInterpretationTimeValueStore(enclaveDb, starlarkValueSerde)
if err != nil {
return stacktrace.Propagate(err, "an error occurred while creating the interpretation time value store")
}

// Load the current enclave plan, in case the enclave is being restarted
enclavePlan, err := enclave_plan_persistence.Load(enclaveDb)
if err != nil {
Expand All @@ -211,7 +217,7 @@ func runMain() error {

// TODO: Consolidate Interpreter, Validator and Executor into a single interface
startosisRunner := startosis_engine.NewStartosisRunner(
startosis_engine.NewStartosisInterpreter(serviceNetwork, gitPackageContentProvider, runtimeValueStore, starlarkValueSerde, serverArgs.EnclaveEnvVars),
startosis_engine.NewStartosisInterpreter(serviceNetwork, gitPackageContentProvider, runtimeValueStore, starlarkValueSerde, serverArgs.EnclaveEnvVars, interpretationTimeValueStore),
startosis_engine.NewStartosisValidator(&kurtosisBackend, serviceNetwork, filesArtifactStore),
startosis_engine.NewStartosisExecutor(starlarkValueSerde, runtimeValueStore, enclavePlan, enclaveDb))

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package interpretation_time_value_store

import (
"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_types"
"github.com/kurtosis-tech/stacktrace"
)

type InterpretationTimeValueStore struct {
serviceValues *serviceInterpretationValueRepository
serde *kurtosis_types.StarlarkValueSerde
}

func CreateInterpretationTimeValueStore(enclaveDb *enclave_db.EnclaveDB, serde *kurtosis_types.StarlarkValueSerde) (*InterpretationTimeValueStore, error) {
serviceValuesRepository, err := getOrCreateNewServiceInterpretationTimeValueRepository(enclaveDb, serde)
if err != nil {
return nil, stacktrace.Propagate(err, "An error occurred creating interpretation time value store")
}
return &InterpretationTimeValueStore{serviceValues: serviceValuesRepository, serde: serde}, nil
}

func (itvs *InterpretationTimeValueStore) AddService(name service.ServiceName, service *kurtosis_types.Service) error {
if err := itvs.serviceValues.AddService(name, service); err != nil {
return stacktrace.Propagate(err, "An error occurred while adding value '%v' for service '%v' to db", service, name)
}
return nil
}

func (itvs *InterpretationTimeValueStore) GetService(name service.ServiceName) (*kurtosis_types.Service, error) {
serviceStarlark, err := itvs.serviceValues.GetService(name)
if err != nil {
return nil, stacktrace.Propagate(err, "An error occurred fetching interpretation time value for '%v' from db", name)
}
return serviceStarlark, nil
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package interpretation_time_value_store

import (
"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_types"
"github.com/kurtosis-tech/stacktrace"
"github.com/sirupsen/logrus"
bolt "go.etcd.io/bbolt"
)

var (
serviceInterpretationValueBucketName = []byte("service-interpretation-value")
emptyValue = []byte{}
)

type serviceInterpretationValueRepository struct {
enclaveDb *enclave_db.EnclaveDB
starlarkValueSerde *kurtosis_types.StarlarkValueSerde
}

func getOrCreateNewServiceInterpretationTimeValueRepository(
enclaveDb *enclave_db.EnclaveDB,
starlarkValueSerde *kurtosis_types.StarlarkValueSerde,
) (*serviceInterpretationValueRepository, error) {
if err := enclaveDb.Update(func(tx *bolt.Tx) error {
bucket, err := tx.CreateBucketIfNotExists(serviceInterpretationValueBucketName)
if err != nil {
return stacktrace.Propagate(err, "An error occurred while creating the bucket for the service interpretation time value repository")
}
logrus.Debugf("Recipe result bucket: '%+v'", bucket)

return nil
}); err != nil {
return nil, stacktrace.Propagate(err, "An error occurred while building service interpretation time value repository")
}

repository := &serviceInterpretationValueRepository{
enclaveDb: enclaveDb,
starlarkValueSerde: starlarkValueSerde,
}

return repository, nil
}

func (repository *serviceInterpretationValueRepository) AddService(name service.ServiceName, service *kurtosis_types.Service) error {
h4ck3rk3y marked this conversation as resolved.
Show resolved Hide resolved
logrus.Debugf("Saving service interpretation value '%v' for service with name '%v' to", service, name)
if err := repository.enclaveDb.Update(func(tx *bolt.Tx) error {
bucket := tx.Bucket(serviceInterpretationValueBucketName)

serviceNameKey := getKey(name)
serializedValue := repository.starlarkValueSerde.Serialize(service)

// save it to disk
if err := bucket.Put(serviceNameKey, []byte(serializedValue)); err != nil {
return stacktrace.Propagate(err, "An error occurred while saving service interpretation time value '%v' for service '%v'", serializedValue, serviceNameKey)
}
return nil
}); err != nil {
return stacktrace.Propagate(err, "An error occurred while saving service interpretation time value '%v' for service '%v'", service, name)
}
logrus.Debugf("Succesfully saved service '%v'", name)
return nil
}

func (repository *serviceInterpretationValueRepository) GetService(name service.ServiceName) (*kurtosis_types.Service, error) {
logrus.Debugf("Getting service interpretation time value for service '%v'", name)
var value *kurtosis_types.Service

if err := repository.enclaveDb.View(func(tx *bolt.Tx) error {
bucket := tx.Bucket(serviceInterpretationValueBucketName)

serviceNameKey := getKey(name)

serviceSerializedValue := bucket.Get(serviceNameKey)

// check for existence
if serviceSerializedValue == nil {
return stacktrace.NewError("Service '%v' doesn't exist in the repository", name)
}

isEmptyValue := len(serviceSerializedValue) == len(emptyValue)

serviceSerializedValueStr := string(serviceSerializedValue)

// this will the case if the key was saved with an empty value
h4ck3rk3y marked this conversation as resolved.
Show resolved Hide resolved
if isEmptyValue {
return nil
}

deserializedValue, interpretationErr := repository.starlarkValueSerde.Deserialize(serviceSerializedValueStr)
if interpretationErr != nil {
return stacktrace.Propagate(interpretationErr, "an error occurred while deserializing object associated with service '%v' in repository", name)
}

var ok bool
value, ok = deserializedValue.(*kurtosis_types.Service)
if !ok {
return stacktrace.NewError("An error occurred converting the deserialized value '%v' into required internal type", deserializedValue)
}

return nil
}); err != nil {
return nil, stacktrace.Propagate(err, "An error occurred while getting service '%v' from db", name)
}
logrus.Debugf("Successfully got value for '%v'", name)
return value, nil

}

func getKey(name service.ServiceName) []byte {
return []byte(name)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package interpretation_time_value_store

import (
port_spec_core "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/startosis_engine/kurtosis_types"
"github.com/kurtosis-tech/kurtosis/core/server/api_container/server/startosis_engine/kurtosis_types/port_spec"
"github.com/stretchr/testify/require"
bolt "go.etcd.io/bbolt"
"go.starlark.net/starlark"
"go.starlark.net/starlarkstruct"
"os"
"testing"
)

const (
starlarkThreadName = "thread-for-db-test"
serviceName = service.ServiceName("datastore-1")
serviceNameStarlarkStr = starlark.String(serviceName)
hostName = serviceNameStarlarkStr
ipAddress = starlark.String("172.23.34.44")
)

func TestAddAndGetTest(t *testing.T) {
h4ck3rk3y marked this conversation as resolved.
Show resolved Hide resolved
repository := getRecipeResultRepositoryForTest(t)
require.NotNil(t, repository)

applicationProtocol := ""
maybeUrl := ""

port, interpretationErr := port_spec.CreatePortSpecUsingGoValues(
string(serviceName),
uint16(443),
port_spec_core.TransportProtocol_TCP,
&applicationProtocol,
"10s",
&maybeUrl,
)
require.Nil(t, interpretationErr)
ports := starlark.NewDict(1)
require.NoError(t, ports.SetKey(starlark.String("http"), port))

expectedService, interpretationErr := kurtosis_types.CreateService(serviceNameStarlarkStr, hostName, ipAddress, ports)
require.Nil(t, interpretationErr)

err := repository.AddService(serviceName, expectedService)
require.Nil(t, err)

actualService, err := repository.GetService(serviceName)
require.Nil(t, err)
require.Equal(t, expectedService.AttrNames(), actualService.AttrNames())
require.Equal(t, expectedService.String(), actualService.String())
}

func getRecipeResultRepositoryForTest(t *testing.T) *serviceInterpretationValueRepository {
h4ck3rk3y marked this conversation as resolved.
Show resolved Hide resolved
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,
}

dummySerde := newDummyStarlarkValueSerDeForTest()

repository, err := getOrCreateNewServiceInterpretationTimeValueRepository(enclaveDb, dummySerde)
require.NoError(t, err)

return repository
}

func newDummyStarlarkValueSerDeForTest() *kurtosis_types.StarlarkValueSerde {
thread := &starlark.Thread{
Name: starlarkThreadName,
Print: nil,
Load: nil,
OnMaxSteps: nil,
Steps: 0,
}
starlarkEnv := starlark.StringDict{
starlarkstruct.Default.GoString(): starlark.NewBuiltin(starlarkstruct.Default.GoString(), starlarkstruct.Make),

kurtosis_types.ServiceTypeName: starlark.NewBuiltin(kurtosis_types.ServiceTypeName, kurtosis_types.NewServiceType().CreateBuiltin()),
port_spec.PortSpecTypeName: starlark.NewBuiltin(port_spec.PortSpecTypeName, port_spec.NewPortSpecType().CreateBuiltin()),
}
return kurtosis_types.NewStarlarkValueSerde(thread, starlarkEnv)
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ import (
"github.com/kurtosis-tech/kurtosis/core/server/api_container/server/startosis_engine/builtins/import_module"
"github.com/kurtosis-tech/kurtosis/core/server/api_container/server/startosis_engine/builtins/print_builtin"
"github.com/kurtosis-tech/kurtosis/core/server/api_container/server/startosis_engine/builtins/read_file"
"github.com/kurtosis-tech/kurtosis/core/server/api_container/server/startosis_engine/interpretation_time_value_store"
"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_instruction/exec"
"github.com/kurtosis-tech/kurtosis/core/server/api_container/server/startosis_engine/kurtosis_instruction/get_service"
"github.com/kurtosis-tech/kurtosis/core/server/api_container/server/startosis_engine/kurtosis_instruction/kurtosis_print"
"github.com/kurtosis-tech/kurtosis/core/server/api_container/server/startosis_engine/kurtosis_instruction/remove_service"
"github.com/kurtosis-tech/kurtosis/core/server/api_container/server/startosis_engine/kurtosis_instruction/render_templates"
Expand Down Expand Up @@ -60,10 +62,12 @@ func KurtosisPlanInstructions(
packageContentProvider startosis_packages.PackageContentProvider,
packageReplaceOptions map[string]string,
nonBlockingMode bool,
interpretationTimeValueStore *interpretation_time_value_store.InterpretationTimeValueStore,
) []*kurtosis_plan_instruction.KurtosisPlanInstruction {
return []*kurtosis_plan_instruction.KurtosisPlanInstruction{
add_service.NewAddService(serviceNetwork, runtimeValueStore, packageId, packageContentProvider, packageReplaceOptions),
add_service.NewAddServices(serviceNetwork, runtimeValueStore, packageId, packageContentProvider, packageReplaceOptions),
add_service.NewAddService(serviceNetwork, runtimeValueStore, packageId, packageContentProvider, packageReplaceOptions, interpretationTimeValueStore),
add_service.NewAddServices(serviceNetwork, runtimeValueStore, packageId, packageContentProvider, packageReplaceOptions, interpretationTimeValueStore),
get_service.NewGetService(interpretationTimeValueStore),
verify.NewVerify(runtimeValueStore),
exec.NewExec(serviceNetwork, runtimeValueStore),
kurtosis_print.NewPrint(serviceNetwork, runtimeValueStore),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/kurtosis-tech/kurtosis/core/server/api_container/server/service_network"
"github.com/kurtosis-tech/kurtosis/core/server/api_container/server/startosis_engine/enclave_plan_persistence"
"github.com/kurtosis-tech/kurtosis/core/server/api_container/server/startosis_engine/enclave_structure"
"github.com/kurtosis-tech/kurtosis/core/server/api_container/server/startosis_engine/interpretation_time_value_store"
"github.com/kurtosis-tech/kurtosis/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework"
"github.com/kurtosis-tech/kurtosis/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/builtin_argument"
"github.com/kurtosis-tech/kurtosis/core/server/api_container/server/startosis_engine/kurtosis_starlark_framework/kurtosis_plan_instruction"
Expand All @@ -32,7 +33,8 @@ func NewAddService(
runtimeValueStore *runtime_value_store.RuntimeValueStore,
packageId string,
packageContentProvider startosis_packages.PackageContentProvider,
packageReplaceOptions map[string]string) *kurtosis_plan_instruction.KurtosisPlanInstruction {
packageReplaceOptions map[string]string,
interpretationTimeValueStore *interpretation_time_value_store.InterpretationTimeValueStore) *kurtosis_plan_instruction.KurtosisPlanInstruction {
return &kurtosis_plan_instruction.KurtosisPlanInstruction{
KurtosisBaseBuiltin: &kurtosis_starlark_framework.KurtosisBaseBuiltin{
Name: AddServiceBuiltinName,
Expand Down Expand Up @@ -74,6 +76,8 @@ func NewAddService(

resultUuid: "", // populated at interpretation time
readyCondition: nil, // populated at interpretation time

interpretationTimeValueStore: interpretationTimeValueStore,
}
},

Expand All @@ -97,6 +101,8 @@ type AddServiceCapabilities struct {
packageContentProvider startosis_packages.PackageContentProvider
packageReplaceOptions map[string]string

interpretationTimeValueStore *interpretation_time_value_store.InterpretationTimeValueStore

resultUuid string
}

Expand Down Expand Up @@ -134,6 +140,11 @@ func (builtin *AddServiceCapabilities) Interpret(locatorOfModuleInWhichThisBuilt
if interpretationErr != nil {
return nil, interpretationErr
}

err = builtin.interpretationTimeValueStore.AddService(builtin.serviceName, returnValue)
if err != nil {
return nil, startosis_errors.WrapWithInterpretationError(err, "An error occurred while persisting return value for service '%v'", serviceName)
}
return returnValue, nil
}

Expand Down
Loading
Loading