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: get all services #2367

Merged
merged 5 commits into from
Apr 15, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,11 @@ func (itvs *InterpretationTimeValueStore) GetService(name service.ServiceName) (
}
return serviceStarlark, nil
}

func (itvs *InterpretationTimeValueStore) GetServices() ([]*kurtosis_types.Service, error) {
servicesStarlark, err := itvs.serviceValues.GetServices()
if err != nil {
tedim52 marked this conversation as resolved.
Show resolved Hide resolved
return nil, stacktrace.Propagate(err, "An error occurred fetching interpretation time service objects from db")
}
return servicesStarlark, nil
}
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,34 @@ func (repository *serviceInterpretationValueRepository) GetService(name service.
}
logrus.Debugf("Successfully got value for '%v'", name)
return value, nil
}

func (repository *serviceInterpretationValueRepository) GetServices() ([]*kurtosis_types.Service, error) {
logrus.Debug("Getting all known interpretation time service values.")
var services []*kurtosis_types.Service

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

return bucket.ForEach(func(serviceName, serializedValue []byte) error {
deserializedValue, interpretationErr := repository.starlarkValueSerde.Deserialize(string(serializedValue))
if interpretationErr != nil {
return stacktrace.Propagate(interpretationErr, "an error occurred while deserializing object associated with service '%v' in repository", serviceName)
}

kurtosisServiceValue, ok := deserializedValue.(*kurtosis_types.Service)
if !ok {
return stacktrace.NewError("an error occurred casting repository service value to kurtosis service value for service: %v", serviceName)
}

services = append(services, kurtosisServiceValue)
return nil
})
}); err != nil {
return nil, stacktrace.Propagate(err, "An error occurred while getting services values from repository.")
}
logrus.Debugf("Successfully retrieved interpretation time service values.")
return services, nil
}

func getKey(name service.ServiceName) []byte {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package interpretation_time_value_store

import (
"fmt"
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"
Expand All @@ -16,7 +17,7 @@ import (

const (
starlarkThreadName = "thread-for-db-test"
serviceName = service.ServiceName("datastore-1")
serviceName = service.ServiceName("datastore")
serviceNameStarlarkStr = starlark.String(serviceName)
hostName = serviceNameStarlarkStr
ipAddress = starlark.String("172.23.34.44")
Expand Down Expand Up @@ -62,6 +63,44 @@ func TestPutGetFail_ForMissingServiceName(t *testing.T) {
require.Nil(t, actualService)
}

func TestGetServices(t *testing.T) {
repository := getServiceInterpretationTimeValueRepository(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))

serviceOneName := fmt.Sprintf("%v-%v", serviceNameStarlarkStr, "1")
serviceOne, interpretationErr := kurtosis_types.CreateService(starlark.String(serviceOneName), hostName, ipAddress, ports)
require.Nil(t, interpretationErr)

serviceTwoName := fmt.Sprintf("%v-%v", serviceNameStarlarkStr, "2")
serviceTwo, interpretationErr := kurtosis_types.CreateService(starlark.String(serviceTwoName), hostName, ipAddress, ports)
require.Nil(t, interpretationErr)

err := repository.PutService(service.ServiceName(serviceOneName), serviceOne)
require.Nil(t, err)
err = repository.PutService(service.ServiceName(serviceTwoName), serviceTwo)
require.Nil(t, err)

actualServices, err := repository.GetServices()
require.NoError(t, err)
require.Len(t, actualServices, 2)
// TODO: check the contents of each objects
}
tedim52 marked this conversation as resolved.
Show resolved Hide resolved

func getServiceInterpretationTimeValueRepository(t *testing.T) *serviceInterpretationValueRepository {
file, err := os.CreateTemp("/tmp", "*.db")
defer func() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"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_files_artifact"
"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/get_services"
"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 @@ -71,6 +72,7 @@ func KurtosisPlanInstructions(
add_service.NewAddService(serviceNetwork, runtimeValueStore, packageId, packageContentProvider, packageReplaceOptions, interpretationTimeValueStore, imageDownloadMode),
add_service.NewAddServices(serviceNetwork, runtimeValueStore, packageId, packageContentProvider, packageReplaceOptions, interpretationTimeValueStore, imageDownloadMode),
get_service.NewGetService(interpretationTimeValueStore),
get_services.NewGetServices(interpretationTimeValueStore),
get_files_artifact.NewGetFilesArtifact(),
verify.NewVerify(runtimeValueStore),
exec.NewExec(serviceNetwork, runtimeValueStore),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package get_services

import (
"context"
"github.com/kurtosis-tech/kurtosis/container-engine-lib/lib/backend_interface/objects/service"
"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"
"github.com/kurtosis-tech/kurtosis/core/server/api_container/server/startosis_engine/plan_yaml"
"github.com/kurtosis-tech/kurtosis/core/server/api_container/server/startosis_engine/startosis_errors"
"github.com/kurtosis-tech/kurtosis/core/server/api_container/server/startosis_engine/startosis_validator"
"go.starlark.net/starlark"
)

const (
GetServicesBuiltinName = "get_services"
descriptionStr = "Fetching services"
)

func NewGetServices(interpretationTimeStore *interpretation_time_value_store.InterpretationTimeValueStore) *kurtosis_plan_instruction.KurtosisPlanInstruction {
return &kurtosis_plan_instruction.KurtosisPlanInstruction{
KurtosisBaseBuiltin: &kurtosis_starlark_framework.KurtosisBaseBuiltin{
Name: GetServicesBuiltinName,
Arguments: []*builtin_argument.BuiltinArgument{},
Deprecation: nil,
},
Capabilities: func() kurtosis_plan_instruction.KurtosisPlanInstructionCapabilities {
return &GetServicesCapabilities{
interpretationTimeStore: interpretationTimeStore,
serviceNames: []service.ServiceName{}, // populated at interpretation time
description: "", // populated at interpretation time
}
},
DefaultDisplayArguments: map[string]bool{},
}
}

type GetServicesCapabilities struct {
interpretationTimeStore *interpretation_time_value_store.InterpretationTimeValueStore
serviceNames []service.ServiceName
description string
}

func (builtin *GetServicesCapabilities) Interpret(_ string, arguments *builtin_argument.ArgumentValuesSet) (starlark.Value, *startosis_errors.InterpretationError) {
builtin.description = builtin_argument.GetDescriptionOrFallBack(arguments, descriptionStr)

// Right now, due to semantics of interpretationTimeStore this will return all services that have been added during interpretation, not accounting for services removed
// TODO: Remove service from interpretationTimeStore during plan.remove_service()
tedim52 marked this conversation as resolved.
Show resolved Hide resolved
services, err := builtin.interpretationTimeStore.GetServices()
if err != nil {
return nil, startosis_errors.WrapWithInterpretationError(err, "An error occurred while fetching service.")
}
servicesList := &starlark.List{}
for _, serviceVal := range services {
name, err := serviceVal.GetName()
if err != nil {
return nil, startosis_errors.WrapWithInterpretationError(err, "An error occurred getting name of service: %v", serviceVal)
}
builtin.serviceNames = append(builtin.serviceNames, name)

_ = servicesList.Append(serviceVal)
}

return servicesList, nil
}

func (builtin *GetServicesCapabilities) Validate(_ *builtin_argument.ArgumentValuesSet, validatorEnvironment *startosis_validator.ValidatorEnvironment) *startosis_errors.ValidationError {
// validate if all services exist in the validation environment
for _, serviceName := range builtin.serviceNames {
if exists := validatorEnvironment.DoesServiceNameExist(serviceName); exists == startosis_validator.ComponentNotFound {
return startosis_errors.NewValidationError("Service '%v' required by '%v' instruction doesn't exist", serviceName, GetServicesBuiltinName)
}
}
return nil
}

func (builtin *GetServicesCapabilities) Execute(_ context.Context, _ *builtin_argument.ArgumentValuesSet) (string, error) {
// note: this is a no op
return descriptionStr, nil
}

func (builtin *GetServicesCapabilities) TryResolveWith(instructionsAreEqual bool, _ *enclave_plan_persistence.EnclavePlanInstruction, enclaveComponents *enclave_structure.EnclaveComponents) enclave_structure.InstructionResolutionStatus {
if instructionsAreEqual {
return enclave_structure.InstructionIsEqual
}
return enclave_structure.InstructionIsUnknown
}

func (builtin *GetServicesCapabilities) FillPersistableAttributes(builder *enclave_plan_persistence.EnclavePlanInstructionBuilder) {
builder.SetType(GetServicesBuiltinName)
}

func (builtin *GetServicesCapabilities) UpdatePlan(planYaml *plan_yaml.PlanYaml) error {
// get services does not affect the plan
return nil
}

func (builtin *GetServicesCapabilities) Description() string {
return builtin.description
}
Loading