diff --git a/apps/workspace-engine/pkg/engine/variable/deployment_variable_repository.go b/apps/workspace-engine/pkg/engine/variable/deployment_variable_repository.go new file mode 100644 index 000000000..12cc70a35 --- /dev/null +++ b/apps/workspace-engine/pkg/engine/variable/deployment_variable_repository.go @@ -0,0 +1,82 @@ +package variable + +import ( + "context" + "sync" + "workspace-engine/pkg/model" + "workspace-engine/pkg/model/resource" +) + +type DeploymentVariable interface { + GetID() string + GetDeploymentID() string + GetKey() string + Resolve(ctx context.Context, resource *resource.Resource) (string, error) +} + +var _ model.Repository[DeploymentVariable] = (*DeploymentVariableRepository)(nil) + +type DeploymentVariableRepository struct { + variables map[string]*DeploymentVariable + mu sync.RWMutex +} + +func NewDeploymentVariableRepository() *DeploymentVariableRepository { + return &DeploymentVariableRepository{variables: make(map[string]*DeploymentVariable)} +} + +func (r *DeploymentVariableRepository) GetAll(ctx context.Context) []*DeploymentVariable { + r.mu.RLock() + defer r.mu.RUnlock() + + return nil +} + +func (r *DeploymentVariableRepository) GetAllByDeploymentID(ctx context.Context, deploymentID string) []*DeploymentVariable { + r.mu.RLock() + defer r.mu.RUnlock() + + return nil +} + +func (r *DeploymentVariableRepository) GetByDeploymentIDAndKey(ctx context.Context, deploymentID, key string) *DeploymentVariable { + r.mu.RLock() + defer r.mu.RUnlock() + + return nil +} + +func (r *DeploymentVariableRepository) Get(ctx context.Context, id string) *DeploymentVariable { + r.mu.RLock() + defer r.mu.RUnlock() + + return nil +} + +func (r *DeploymentVariableRepository) Create(ctx context.Context, variable *DeploymentVariable) error { + r.mu.Lock() + defer r.mu.Unlock() + + return nil +} + +func (r *DeploymentVariableRepository) Update(ctx context.Context, variable *DeploymentVariable) error { + r.mu.Lock() + defer r.mu.Unlock() + + return nil +} + +func (r *DeploymentVariableRepository) Delete(ctx context.Context, id string) error { + r.mu.Lock() + defer r.mu.Unlock() + + return nil +} + +func (r *DeploymentVariableRepository) Exists(ctx context.Context, id string) bool { + r.mu.RLock() + defer r.mu.RUnlock() + + return false +} diff --git a/apps/workspace-engine/pkg/engine/variable/manager_deployment_variable.go b/apps/workspace-engine/pkg/engine/variable/manager_deployment_variable.go new file mode 100644 index 000000000..129c45a54 --- /dev/null +++ b/apps/workspace-engine/pkg/engine/variable/manager_deployment_variable.go @@ -0,0 +1,35 @@ +package variable + +import ( + "context" + "fmt" + "workspace-engine/pkg/model/resource" +) + +var _ VariableManager = (*DeploymentVariableManager)(nil) + +type DeploymentVariableManager struct { + deploymentVariables *DeploymentVariableRepository +} + +func NewDeploymentVariableManager(deploymentVariables *DeploymentVariableRepository) *DeploymentVariableManager { + return &DeploymentVariableManager{ + deploymentVariables: deploymentVariables, + } +} + +func (m *DeploymentVariableManager) Resolve(ctx context.Context, resource *resource.Resource, deploymentID string, key string) (*string, error) { + deploymentVariablePtr := m.deploymentVariables.GetByDeploymentIDAndKey(ctx, deploymentID, key) + if deploymentVariablePtr == nil || *deploymentVariablePtr == nil { + return nil, nil + } + + deploymentVariable := *deploymentVariablePtr + + resolved, err := deploymentVariable.Resolve(ctx, resource) + if err != nil { + return nil, fmt.Errorf("failed to resolve deployment variable for key: %s, deploymentID: %s, err: %w", key, deploymentID, err) + } + + return &resolved, nil +} diff --git a/apps/workspace-engine/pkg/engine/variable/manager_resource_variable.go b/apps/workspace-engine/pkg/engine/variable/manager_resource_variable.go new file mode 100644 index 000000000..983321f63 --- /dev/null +++ b/apps/workspace-engine/pkg/engine/variable/manager_resource_variable.go @@ -0,0 +1,35 @@ +package variable + +import ( + "context" + "fmt" + "workspace-engine/pkg/model/resource" +) + +var _ VariableManager = (*ResourceVariableManager)(nil) + +type ResourceVariableManager struct { + resourceVariables *ResourceVariableRepository +} + +func NewResourceVariableManager(resourceVariables *ResourceVariableRepository) *ResourceVariableManager { + return &ResourceVariableManager{ + resourceVariables: resourceVariables, + } +} + +func (m *ResourceVariableManager) Resolve(ctx context.Context, resource *resource.Resource, deploymentID string, key string) (*string, error) { + resourceVariablePtr := m.resourceVariables.GetByResourceIDAndKey(ctx, resource.GetID(), key) + if resourceVariablePtr == nil || *resourceVariablePtr == nil { + return nil, nil + } + + resourceVariable := *resourceVariablePtr + + resolved, err := resourceVariable.Resolve(ctx) + if err != nil { + return nil, fmt.Errorf("failed to resolve resource variable for key: %s, resource: %s, err: %w", key, resource.GetID(), err) + } + + return &resolved, nil +} diff --git a/apps/workspace-engine/pkg/engine/variable/manager_variable.go b/apps/workspace-engine/pkg/engine/variable/manager_variable.go new file mode 100644 index 000000000..7e488c734 --- /dev/null +++ b/apps/workspace-engine/pkg/engine/variable/manager_variable.go @@ -0,0 +1,47 @@ +package variable + +import ( + "context" + "fmt" + "workspace-engine/pkg/model/resource" +) + +type VariableManager interface { + Resolve(ctx context.Context, resource *resource.Resource, deploymentID string, key string) (*string, error) +} + +type WorkspaceVariableManager struct { + getKeys func(ctx context.Context, deploymentID string) []string + managers []VariableManager +} + +func NewWorkspaceVariableManager( + getKeys func(ctx context.Context, deploymentID string) []string, + managers []VariableManager, +) *WorkspaceVariableManager { + return &WorkspaceVariableManager{ + getKeys: getKeys, + managers: managers, + } +} + +func (v *WorkspaceVariableManager) ResolveDeploymentVariables(ctx context.Context, resource *resource.Resource, deploymentID string) (map[string]string, error) { + resolvedVariables := make(map[string]string) + + keys := v.getKeys(ctx, deploymentID) + for _, key := range keys { + for _, manager := range v.managers { + resolvedValue, err := manager.Resolve(ctx, resource, deploymentID, key) + if err != nil { + return nil, fmt.Errorf("failed to resolve for key: %s, resource: %s, err: %w", key, resource.GetID(), err) + } + + if resolvedValue != nil { + resolvedVariables[key] = *resolvedValue + break + } + } + } + + return resolvedVariables, nil +} diff --git a/apps/workspace-engine/pkg/engine/variable/resource_variable_repository.go b/apps/workspace-engine/pkg/engine/variable/resource_variable_repository.go index 0bb7ef66e..63e937633 100644 --- a/apps/workspace-engine/pkg/engine/variable/resource_variable_repository.go +++ b/apps/workspace-engine/pkg/engine/variable/resource_variable_repository.go @@ -2,174 +2,67 @@ package variable import ( "context" - "errors" - "fmt" "sync" "workspace-engine/pkg/model" - modelvariable "workspace-engine/pkg/model/variable" ) -var _ model.Repository[modelvariable.ResourceVariable] = (*ResourceVariableRepository)(nil) +type ResourceVariable interface { + GetID() string + GetResourceID() string + GetKey() string + Resolve(ctx context.Context) (string, error) +} + +var _ model.Repository[ResourceVariable] = (*ResourceVariableRepository)(nil) type ResourceVariableRepository struct { - variables map[string]map[string]*modelvariable.ResourceVariable // resourceID -> key -> variable + variables map[string]*ResourceVariable mu sync.RWMutex } func NewResourceVariableRepository() *ResourceVariableRepository { - return &ResourceVariableRepository{variables: make(map[string]map[string]*modelvariable.ResourceVariable)} + return &ResourceVariableRepository{variables: make(map[string]*ResourceVariable)} } -func (r *ResourceVariableRepository) GetAll(ctx context.Context) []*modelvariable.ResourceVariable { +func (r *ResourceVariableRepository) GetAll(ctx context.Context) []*ResourceVariable { r.mu.RLock() defer r.mu.RUnlock() - var variables []*modelvariable.ResourceVariable - for _, resourceVariables := range r.variables { - for _, variable := range resourceVariables { - if variable == nil || *variable == nil { - continue - } - - variableCopy := *variable - variables = append(variables, &variableCopy) - } - } - - return variables + return nil } -func (r *ResourceVariableRepository) Get(ctx context.Context, id string) *modelvariable.ResourceVariable { +func (r *ResourceVariableRepository) GetAllByResourceID(ctx context.Context, resourceID string) []*ResourceVariable { r.mu.RLock() defer r.mu.RUnlock() - for _, resourceVariables := range r.variables { - for _, variable := range resourceVariables { - if variable == nil || *variable == nil { - continue - } - variableCopy := *variable - if variableCopy.GetID() == id { - return &variableCopy - } - } - } - return nil } -func (r *ResourceVariableRepository) GetAllByResourceID(ctx context.Context, resourceID string) []*modelvariable.ResourceVariable { +func (r *ResourceVariableRepository) GetByResourceIDAndKey(ctx context.Context, resourceID, key string) *ResourceVariable { r.mu.RLock() defer r.mu.RUnlock() - var variables []*modelvariable.ResourceVariable - if resourceVariables, ok := r.variables[resourceID]; ok { - for _, variable := range resourceVariables { - if variable == nil || *variable == nil { - continue - } - variableCopy := *variable - variables = append(variables, &variableCopy) - } - } - - return variables + return nil } -func (r *ResourceVariableRepository) GetByResourceIDAndKey(ctx context.Context, resourceID, key string) *modelvariable.ResourceVariable { +func (r *ResourceVariableRepository) Get(ctx context.Context, id string) *ResourceVariable { r.mu.RLock() defer r.mu.RUnlock() - if resourceVariables, ok := r.variables[resourceID]; ok { - if variable, ok := resourceVariables[key]; ok { - if variable == nil || *variable == nil { - return nil - } - variableCopy := *variable - return &variableCopy - } - } - - return nil -} - -func (r *ResourceVariableRepository) ensureVariableUniqueness(resourceID string, variable *modelvariable.ResourceVariable) error { - variableCopy := *variable - if _, ok := r.variables[resourceID][variableCopy.GetKey()]; ok { - return fmt.Errorf("variable already exists for resource %s and key %s", resourceID, variableCopy.GetKey()) - } - - for _, resourceVariables := range r.variables { - for _, existingVariable := range resourceVariables { - if existingVariable == nil || *existingVariable == nil { - continue - } - existingVariableCopy := *existingVariable - if existingVariableCopy.GetID() == variableCopy.GetID() { - return fmt.Errorf("variable already exists with ID %s", variableCopy.GetID()) - } - } - } - return nil } -func (r *ResourceVariableRepository) Create(ctx context.Context, variable *modelvariable.ResourceVariable) error { +func (r *ResourceVariableRepository) Create(ctx context.Context, variable *ResourceVariable) error { r.mu.Lock() defer r.mu.Unlock() - if variable == nil || *variable == nil { - return errors.New("variable is nil") - } - - variableCopy := *variable - resourceID := variableCopy.GetResourceID() - key := variableCopy.GetKey() - - if _, ok := r.variables[resourceID]; !ok { - r.variables[resourceID] = make(map[string]*modelvariable.ResourceVariable) - } - - if err := r.ensureVariableUniqueness(resourceID, variable); err != nil { - return err - } - - r.variables[resourceID][key] = &variableCopy - return nil } -func (r *ResourceVariableRepository) Update(ctx context.Context, variable *modelvariable.ResourceVariable) error { +func (r *ResourceVariableRepository) Update(ctx context.Context, variable *ResourceVariable) error { r.mu.Lock() defer r.mu.Unlock() - if variable == nil || *variable == nil { - return errors.New("variable is nil") - } - - variableCopy := *variable - resourceID := variableCopy.GetResourceID() - key := variableCopy.GetKey() - - if _, ok := r.variables[resourceID]; !ok { - return errors.New("resource not found") - } - - current, ok := r.variables[resourceID][key] - if !ok { - return errors.New("variable key not found") - } - currentCopy := *current - if currentCopy == nil { - return errors.New("current variable is nil") - } - - if currentCopy.GetID() != variableCopy.GetID() { - return errors.New("variable ID mismatch") - } - - r.variables[resourceID][key] = &variableCopy - return nil } @@ -177,18 +70,6 @@ func (r *ResourceVariableRepository) Delete(ctx context.Context, id string) erro r.mu.Lock() defer r.mu.Unlock() - for _, resourceVariables := range r.variables { - for _, variable := range resourceVariables { - if variable == nil || *variable == nil { - continue - } - variableCopy := *variable - if variableCopy.GetID() == id { - delete(resourceVariables, variableCopy.GetKey()) - } - } - } - return nil } @@ -196,16 +77,5 @@ func (r *ResourceVariableRepository) Exists(ctx context.Context, id string) bool r.mu.RLock() defer r.mu.RUnlock() - for _, resourceVariables := range r.variables { - for _, variable := range resourceVariables { - if variable == nil || *variable == nil { - continue - } - variableCopy := *variable - if variableCopy.GetID() == id { - return true - } - } - } return false } diff --git a/apps/workspace-engine/pkg/engine/variable/resource_variable_repository_test.go b/apps/workspace-engine/pkg/engine/variable/resource_variable_repository_test.go deleted file mode 100644 index d54108bd5..000000000 --- a/apps/workspace-engine/pkg/engine/variable/resource_variable_repository_test.go +++ /dev/null @@ -1,508 +0,0 @@ -package variable - -import ( - "context" - "errors" - "testing" - - modelvariable "workspace-engine/pkg/model/variable" - - "gotest.tools/assert" -) - -type resourceVariableRepositoryTestStep struct { - createResourceVariable *modelvariable.DirectResourceVariable - updateResourceVariable *modelvariable.DirectResourceVariable - deleteResourceVariable *modelvariable.DirectResourceVariable - - expectedResourceVariables map[string]map[string]*modelvariable.DirectResourceVariable - expectedError error -} - -type resourceVariableRepositoryTest struct { - name string - steps []resourceVariableRepositoryTestStep -} - -type testBundle struct { - repo *ResourceVariableRepository - ctx context.Context - t *testing.T - step resourceVariableRepositoryTestStep -} - -func (b *testBundle) assertEqualError(actualError error) { - if b.step.expectedError == nil { - assert.NilError(b.t, actualError) - return - } - - assert.Error(b.t, actualError, b.step.expectedError.Error()) -} - -func (b *testBundle) executeStep() *testBundle { - if b.step.createResourceVariable != nil { - var variable modelvariable.ResourceVariable = b.step.createResourceVariable - err := b.repo.Create(b.ctx, &variable) - b.assertEqualError(err) - } - - if b.step.updateResourceVariable != nil { - var variable modelvariable.ResourceVariable = b.step.updateResourceVariable - err := b.repo.Update(b.ctx, &variable) - b.assertEqualError(err) - } - - if b.step.deleteResourceVariable != nil { - err := b.repo.Delete(b.ctx, b.step.deleteResourceVariable.GetID()) - b.assertEqualError(err) - assert.Assert(b.t, b.repo.Exists(b.ctx, b.step.deleteResourceVariable.GetID()) == false) - } - - return b -} - -func (b *testBundle) assertVariableEqual(actualVariable modelvariable.ResourceVariable, expectedVariable *modelvariable.DirectResourceVariable) { - actualVariableCastedPtr := actualVariable.(*modelvariable.DirectResourceVariable) - assert.Equal(b.t, actualVariableCastedPtr.GetID(), expectedVariable.GetID()) - assert.Equal(b.t, actualVariableCastedPtr.GetResourceID(), expectedVariable.GetResourceID()) - assert.Equal(b.t, actualVariableCastedPtr.GetKey(), expectedVariable.GetKey()) - assert.Equal(b.t, actualVariableCastedPtr.GetValue(), expectedVariable.GetValue()) - assert.Equal(b.t, actualVariableCastedPtr.IsSensitive(), expectedVariable.IsSensitive()) -} - -func (b *testBundle) validateVariableReturnedFromGet(variable *modelvariable.DirectResourceVariable) *testBundle { - actualVariable := b.repo.Get(b.ctx, variable.GetID()) - assert.Assert(b.t, actualVariable != nil) - assert.Assert(b.t, *actualVariable != nil) - b.assertVariableEqual(*actualVariable, variable) - return b -} - -func (b *testBundle) validateVariableReturnedFromGetAll(variable *modelvariable.DirectResourceVariable) *testBundle { - allVariables := b.repo.GetAll(b.ctx) - for _, actualVariable := range allVariables { - if actualVariable == nil || *actualVariable == nil { - continue - } - - b.assertVariableEqual(*actualVariable, variable) - return b - } - - b.t.Errorf("variable not found in GetAll") - return b -} - -func (b *testBundle) validateVariableReturnedFromGetAllByResourceID(variable *modelvariable.DirectResourceVariable) *testBundle { - resourceVariables := b.repo.GetAllByResourceID(b.ctx, variable.GetResourceID()) - - for _, actualVariable := range resourceVariables { - if actualVariable == nil || *actualVariable == nil { - continue - } - - b.assertVariableEqual(*actualVariable, variable) - return b - } - - b.t.Errorf("variable not found in GetAllByResourceID") - return b -} - -func (b *testBundle) validateVariableReturnedFromGetByResourceIDAndKey(variable *modelvariable.DirectResourceVariable) *testBundle { - actualVariable := b.repo.GetByResourceIDAndKey(b.ctx, variable.GetResourceID(), variable.GetKey()) - assert.Assert(b.t, actualVariable != nil) - assert.Assert(b.t, *actualVariable != nil) - b.assertVariableEqual(*actualVariable, variable) - return b -} - -func (b *testBundle) validateVariableExists(variable *modelvariable.DirectResourceVariable) *testBundle { - assert.Assert(b.t, b.repo.Exists(b.ctx, variable.GetID())) - return b -} - -func (b *testBundle) validateVariableState() *testBundle { - allVariables := b.repo.GetAll(b.ctx) - numExpectedVariables := 0 - - for _, expectedVariablesForResource := range b.step.expectedResourceVariables { - for _, expectedVariable := range expectedVariablesForResource { - b. - validateVariableReturnedFromGet(expectedVariable). - validateVariableReturnedFromGetAll(expectedVariable). - validateVariableReturnedFromGetAllByResourceID(expectedVariable). - validateVariableReturnedFromGetByResourceIDAndKey(expectedVariable). - validateVariableExists(expectedVariable) - - numExpectedVariables++ - } - } - - assert.Equal(b.t, len(allVariables), numExpectedVariables) - - return b -} - -func TestResourceVariableRepository(t *testing.T) { - createResourceVariable := resourceVariableRepositoryTest{ - name: "creates a resource variable", - steps: []resourceVariableRepositoryTestStep{ - { - createResourceVariable: &modelvariable.DirectResourceVariable{ - ID: "1", - ResourceID: "1", - Key: "key", - Value: "value", - Sensitive: false, - }, - expectedResourceVariables: map[string]map[string]*modelvariable.DirectResourceVariable{ - "1": { - "key": { - ID: "1", - ResourceID: "1", - Key: "key", - Value: "value", - Sensitive: false, - }, - }, - }, - }, - }, - } - - updateResourceVariable := resourceVariableRepositoryTest{ - name: "updates a resource variable", - steps: []resourceVariableRepositoryTestStep{ - { - createResourceVariable: &modelvariable.DirectResourceVariable{ - ID: "1", - ResourceID: "1", - Key: "key", - Value: "value", - Sensitive: false, - }, - expectedResourceVariables: map[string]map[string]*modelvariable.DirectResourceVariable{ - "1": { - "key": { - ID: "1", - ResourceID: "1", - Key: "key", - Value: "value", - Sensitive: false, - }, - }, - }, - }, - { - updateResourceVariable: &modelvariable.DirectResourceVariable{ - ID: "1", - ResourceID: "1", - Key: "key", - Value: "value2", - Sensitive: false, - }, - expectedResourceVariables: map[string]map[string]*modelvariable.DirectResourceVariable{ - "1": { - "key": { - ID: "1", - ResourceID: "1", - Key: "key", - Value: "value2", - Sensitive: false, - }, - }, - }, - }, - }, - } - - deleteResourceVariable := resourceVariableRepositoryTest{ - name: "deletes a resource variable", - steps: []resourceVariableRepositoryTestStep{ - { - createResourceVariable: &modelvariable.DirectResourceVariable{ - ID: "2", - ResourceID: "1", - Key: "key", - Value: "value", - Sensitive: false, - }, - expectedResourceVariables: map[string]map[string]*modelvariable.DirectResourceVariable{ - "1": { - "key": { - ID: "2", - ResourceID: "1", - Key: "key", - Value: "value", - Sensitive: false, - }, - }, - }, - }, - { - deleteResourceVariable: &modelvariable.DirectResourceVariable{ID: "2"}, - expectedResourceVariables: map[string]map[string]*modelvariable.DirectResourceVariable{"1": {}}, - }, - }, - } - - throwsErrorOnDuplicateID := resourceVariableRepositoryTest{ - name: "throws error on duplicate ID", - steps: []resourceVariableRepositoryTestStep{ - { - createResourceVariable: &modelvariable.DirectResourceVariable{ - ID: "3", - ResourceID: "1", - Key: "key2", - Value: "value", - Sensitive: false, - }, - expectedResourceVariables: map[string]map[string]*modelvariable.DirectResourceVariable{ - "1": { - "key2": { - ID: "3", - ResourceID: "1", - Key: "key2", - Value: "value", - Sensitive: false, - }, - }, - }, - }, - { - createResourceVariable: &modelvariable.DirectResourceVariable{ - ID: "3", - ResourceID: "1", - Key: "key3", - Value: "value", - Sensitive: false, - }, - expectedError: errors.New("variable already exists with ID 3"), - expectedResourceVariables: map[string]map[string]*modelvariable.DirectResourceVariable{ - "1": { - "key2": { - ID: "3", - ResourceID: "1", - Key: "key2", - Value: "value", - Sensitive: false, - }, - }, - }, - }, - }, - } - - throwsErrorOnDuplicateKey := resourceVariableRepositoryTest{ - name: "throws error on duplicate key for a resource", - steps: []resourceVariableRepositoryTestStep{ - { - createResourceVariable: &modelvariable.DirectResourceVariable{ - ID: "1", - ResourceID: "1", - Key: "key", - Value: "value", - Sensitive: false, - }, - expectedResourceVariables: map[string]map[string]*modelvariable.DirectResourceVariable{ - "1": { - "key": { - ID: "1", - ResourceID: "1", - Key: "key", - Value: "value", - Sensitive: false, - }, - }, - }, - }, - { - createResourceVariable: &modelvariable.DirectResourceVariable{ - ID: "2", - ResourceID: "1", - Key: "key", - Value: "value2", - Sensitive: false, - }, - expectedError: errors.New("variable already exists for resource 1 and key key"), - expectedResourceVariables: map[string]map[string]*modelvariable.DirectResourceVariable{ - "1": { - "key": { - ID: "1", - ResourceID: "1", - Key: "key", - Value: "value", - Sensitive: false, - }, - }, - }, - }, - }, - } - - throwsErrorOnUpdateNonExistentResource := resourceVariableRepositoryTest{ - name: "throws error on update with non existent resource", - steps: []resourceVariableRepositoryTestStep{ - { - updateResourceVariable: &modelvariable.DirectResourceVariable{ - ID: "1", - ResourceID: "1", - Key: "key", - Value: "value", - Sensitive: false, - }, - expectedError: errors.New("resource not found"), - expectedResourceVariables: map[string]map[string]*modelvariable.DirectResourceVariable{}, - }, - }, - } - - throwsErrorOnUpdateNonExistentKey := resourceVariableRepositoryTest{ - name: "throws error on update with non existent key", - steps: []resourceVariableRepositoryTestStep{ - { - createResourceVariable: &modelvariable.DirectResourceVariable{ - ID: "1", - ResourceID: "1", - Key: "key", - Value: "value", - Sensitive: false, - }, - expectedResourceVariables: map[string]map[string]*modelvariable.DirectResourceVariable{ - "1": { - "key": { - ID: "1", - ResourceID: "1", - Key: "key", - Value: "value", - Sensitive: false, - }, - }, - }, - }, - { - updateResourceVariable: &modelvariable.DirectResourceVariable{ - ID: "1", - ResourceID: "1", - Key: "key2", - Value: "value2", - Sensitive: false, - }, - expectedError: errors.New("variable key not found"), - expectedResourceVariables: map[string]map[string]*modelvariable.DirectResourceVariable{ - "1": { - "key": { - ID: "1", - ResourceID: "1", - Key: "key", - Value: "value", - Sensitive: false, - }, - }, - }, - }, - }, - } - - throwsErrorOnUpdateMismatchedID := resourceVariableRepositoryTest{ - name: "throws error on update with mismatched ID", - steps: []resourceVariableRepositoryTestStep{ - { - createResourceVariable: &modelvariable.DirectResourceVariable{ - ID: "1", - ResourceID: "1", - Key: "key", - Value: "value", - Sensitive: false, - }, - expectedResourceVariables: map[string]map[string]*modelvariable.DirectResourceVariable{ - "1": { - "key": { - ID: "1", - ResourceID: "1", - Key: "key", - Value: "value", - Sensitive: false, - }, - }, - }, - }, - { - updateResourceVariable: &modelvariable.DirectResourceVariable{ - ID: "2", - ResourceID: "1", - Key: "key", - Value: "value2", - Sensitive: false, - }, - expectedError: errors.New("variable ID mismatch"), - expectedResourceVariables: map[string]map[string]*modelvariable.DirectResourceVariable{ - "1": { - "key": { - ID: "1", - ResourceID: "1", - Key: "key", - Value: "value", - Sensitive: false, - }, - }, - }, - }, - }, - } - - tests := []resourceVariableRepositoryTest{ - createResourceVariable, - updateResourceVariable, - deleteResourceVariable, - throwsErrorOnDuplicateID, - throwsErrorOnDuplicateKey, - throwsErrorOnUpdateNonExistentResource, - throwsErrorOnUpdateNonExistentKey, - throwsErrorOnUpdateMismatchedID, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - repo := NewResourceVariableRepository() - ctx := context.Background() - - for _, step := range test.steps { - - bundle := &testBundle{ - repo: repo, - ctx: ctx, - t: t, - step: step, - } - - bundle. - executeStep(). - validateVariableState() - } - }) - } -} - -func TestNilHandling(t *testing.T) { - repo := NewResourceVariableRepository() - ctx := context.Background() - - err := repo.Create(ctx, nil) - assert.Error(t, err, "variable is nil") - - err = repo.Update(ctx, nil) - assert.Error(t, err, "variable is nil") - - var nilIFace modelvariable.ResourceVariable = nil - err = repo.Create(ctx, &nilIFace) - assert.Error(t, err, "variable is nil") - - err = repo.Update(ctx, &nilIFace) - assert.Error(t, err, "variable is nil") - - nonExistent := repo.Get(ctx, "non-existent") - assert.Assert(t, nonExistent == (*modelvariable.ResourceVariable)(nil)) -} diff --git a/apps/workspace-engine/pkg/model/variable/deployment_variable.go b/apps/workspace-engine/pkg/model/variable/deployment_variable.go new file mode 100644 index 000000000..7a6e9d49a --- /dev/null +++ b/apps/workspace-engine/pkg/model/variable/deployment_variable.go @@ -0,0 +1,114 @@ +package variable + +import ( + "fmt" + "workspace-engine/pkg/model" + "workspace-engine/pkg/model/conditions" + "workspace-engine/pkg/model/resource" +) + +type DeploymentVariable struct { + ID string `json:"id"` + DeploymentID string `json:"deploymentId"` + Key string `json:"key"` + DefaultValueID string `json:"defaultValueId"` + + DirectValues []DirectDeploymentVariableValue `json:"directValues"` + ReferenceValues []ReferenceDeploymentVariableValue `json:"referenceValues"` +} + +func (v *DeploymentVariable) GetID() string { + return v.ID +} + +func (v *DeploymentVariable) GetDeploymentID() string { + return v.DeploymentID +} + +func (v *DeploymentVariable) GetKey() string { + return v.Key +} + +func (v *DeploymentVariable) GetDefaultValueID() string { + return v.DefaultValueID +} + +type DirectDeploymentVariableValue struct { + ID string `json:"id"` + VariableID string `json:"variableId"` + Value any `json:"value"` + Sensitive bool `json:"sensitive"` + Priority int `json:"priority"` + ResourceSelector *conditions.JSONCondition `json:"resourceSelector,omitempty"` +} + +func (v *DirectDeploymentVariableValue) GetID() string { + return v.ID +} + +func (v *DirectDeploymentVariableValue) GetVariableID() string { + return v.VariableID +} + +func (v *DirectDeploymentVariableValue) GetValue() any { + return v.Value +} + +func (v *DirectDeploymentVariableValue) IsSensitive() bool { + return v.Sensitive +} + +func (v *DirectDeploymentVariableValue) GetPriority() int { + return v.Priority +} + +func (v *DirectDeploymentVariableValue) MatchAllIfNullSelector(entity model.MatchableEntity) bool { + return false +} + +func (v *DirectDeploymentVariableValue) Selector(entity model.MatchableEntity) (*conditions.JSONCondition, error) { + if _, ok := entity.(resource.Resource); ok { + return v.ResourceSelector, nil + } + return nil, fmt.Errorf("entity is not a supported selector option") +} + +type ReferenceDeploymentVariableValue struct { + ID string `json:"id"` + VariableID string `json:"variableId"` + Reference string `json:"reference"` + Path string `json:"path"` + Priority int `json:"priority"` + ResourceSelector *conditions.JSONCondition `json:"resourceSelector,omitempty"` +} + +func (v *ReferenceDeploymentVariableValue) GetID() string { + return v.ID +} + +func (v *ReferenceDeploymentVariableValue) GetVariableID() string { + return v.VariableID +} + +func (v *ReferenceDeploymentVariableValue) GetReference() string { + return v.Reference +} + +func (v *ReferenceDeploymentVariableValue) GetPath() string { + return v.Path +} + +func (v *ReferenceDeploymentVariableValue) GetPriority() int { + return v.Priority +} + +func (v *ReferenceDeploymentVariableValue) MatchAllIfNullSelector(entity model.MatchableEntity) bool { + return false +} + +func (v *ReferenceDeploymentVariableValue) Selector(entity model.MatchableEntity) (*conditions.JSONCondition, error) { + if _, ok := entity.(resource.Resource); ok { + return v.ResourceSelector, nil + } + return nil, fmt.Errorf("entity is not a supported selector option") +} diff --git a/apps/workspace-engine/pkg/model/variable/resource_variable.go b/apps/workspace-engine/pkg/model/variable/resource_variable.go index 4d6040211..c1322f306 100644 --- a/apps/workspace-engine/pkg/model/variable/resource_variable.go +++ b/apps/workspace-engine/pkg/model/variable/resource_variable.go @@ -1,17 +1,5 @@ package variable -import ( - "context" - "errors" - "fmt" - "workspace-engine/pkg/model/resource" -) - -type ResourceVariable interface { - Variable - GetResourceID() string -} - type DirectResourceVariable struct { ID string `json:"id"` ResourceID string `json:"resourceId"` @@ -39,12 +27,3 @@ func (v *DirectResourceVariable) GetValue() any { func (v *DirectResourceVariable) IsSensitive() bool { return v.Sensitive } - -func (v *DirectResourceVariable) Resolve(ctx context.Context, resource *resource.Resource) (string, error) { - if v.Sensitive { - // TODO: encryption - return "", errors.New("sensitive variable not supported") - } - - return fmt.Sprintf("%v", v.Value), nil -} diff --git a/apps/workspace-engine/pkg/model/variable/variable.go b/apps/workspace-engine/pkg/model/variable/variable.go deleted file mode 100644 index db149d7e4..000000000 --- a/apps/workspace-engine/pkg/model/variable/variable.go +++ /dev/null @@ -1,12 +0,0 @@ -package variable - -import ( - "context" - "workspace-engine/pkg/model/resource" -) - -type Variable interface { - GetID() string - GetKey() string - Resolve(ctx context.Context, resource *resource.Resource) (string, error) -}