diff --git a/harness/cd/application_test.go b/harness/cd/application_test.go index 97bd40f0..63a9aa55 100644 --- a/harness/cd/application_test.go +++ b/harness/cd/application_test.go @@ -99,7 +99,7 @@ func TestUpdateApplication(t *testing.T) { // Setup name := fmt.Sprintf("%s-%s", t.Name(), utils.RandStringBytes(5)) - expectedName := "test_name_change" + expectedName := fmt.Sprintf("%s_test_name_change", name) // Create a new app newApp, err := createApplication(name) diff --git a/harness/cd/cac/model_secret_ref.go b/harness/cd/cac/model_secret_ref.go new file mode 100644 index 00000000..662e94ed --- /dev/null +++ b/harness/cd/cac/model_secret_ref.go @@ -0,0 +1,48 @@ +package cac + +import ( + "errors" + "fmt" + "strings" +) + +type SecretRef struct { + Name string +} + +func (r *SecretRef) MarshalYAML() (interface{}, error) { + if (r == &SecretRef{}) { + return []byte{}, nil + } + + if r.Name == "" { + return nil, errors.New("name must be set") + } + + return fmt.Sprintf("secretName:%s", r.Name), nil +} + +func (r *SecretRef) UnmarshalYAML(unmarshal func(interface{}) error) error { + + var val interface{} + err := unmarshal(&val) + if err != nil { + return err + } + + value := val.(string) + + parts := strings.Split(value, ":") + + if len(parts) == 1 { + r.Name = parts[0] + } else if len(parts) == 2 { + r.Name = parts[1] + } + + return nil +} + +func (r *SecretRef) String() string { + return fmt.Sprintf("secretName:%s", r.Name) +} diff --git a/harness/cd/cac/model_service.go b/harness/cd/cac/model_service.go new file mode 100644 index 00000000..afd48f08 --- /dev/null +++ b/harness/cd/cac/model_service.go @@ -0,0 +1,30 @@ +package cac + +import ( + "reflect" + + "github.com/harness/harness-go-sdk/harness/utils" +) + +type Service struct { + HarnessApiVersion HarnessApiVersion `yaml:"harnessApiVersion" json:"harnessApiVersion"` + Type ObjectType `yaml:"type" json:"type"` + Id string `yaml:"-"` + Name string `yaml:"-"` + ArtifactType ArtifactType `yaml:"artifactType,omitempty"` + DeploymentType DeploymentType `yaml:"deploymentType,omitempty"` + Description string `yaml:"description,omitempty"` + Tags map[string]string `yaml:"tags,omitempty"` + HelmVersion HelmVersion `yaml:"helmVersion,omitempty"` + ApplicationId string `yaml:"-"` + DeploymentTypeTemplateUri string `yaml:"deploymentTypeTemplateUri,omitempty"` + ConfigVariables []*ServiceVariable `yaml:"configVariables,omitempty"` +} + +func (a *Service) IsEmpty() bool { + return reflect.DeepEqual(a, &Service{}) +} + +func (s *Service) Validate() (bool, error) { + return utils.RequiredStringFieldsSet(s, []string{"ApplicationId"}) +} diff --git a/harness/cd/cac/model_service_variable.go b/harness/cd/cac/model_service_variable.go new file mode 100644 index 00000000..631bda3c --- /dev/null +++ b/harness/cd/cac/model_service_variable.go @@ -0,0 +1,57 @@ +package cac + +import ( + "gopkg.in/yaml.v3" +) + +type ServiceVariable struct { + Name string `yaml:"name,omitempty"` + Value string `yaml:"value,omitempty"` + ValueType VariableValueType `yaml:"valueType,omitempty"` +} + +// We need to customize the marshaling of this object because of the way the `Value` +// field works. When the ValueType is ENCRYPTED_TEXT the value needs to be secretName:. + +func (s *ServiceVariable) UnmarshalYAML(unmarshal func(interface{}) error) error { + + type Alias ServiceVariable + + aux := &struct { + *Alias + }{ + Alias: (*Alias)(s), + } + + if err := unmarshal(&aux.Alias); err != nil { + return err + } + + if s.ValueType == VariableOverrideValueTypes.Text { + s.Value = aux.Value + } else if s.ValueType == VariableOverrideValueTypes.EncryptedText { + ref := &SecretRef{} + if err := yaml.Unmarshal([]byte(aux.Value), ref); err != nil { + return err + } + + s.Value = ref.Name + } + + return nil +} + +func (r *ServiceVariable) MarshalYAML() (interface{}, error) { + var aux ServiceVariable = *r + + if r.ValueType == VariableOverrideValueTypes.Text { + aux.Value = r.Value + } else if r.ValueType == VariableOverrideValueTypes.EncryptedText { + ref := &SecretRef{ + Name: r.Value, + } + aux.Value = ref.String() + } + + return aux, nil +} diff --git a/harness/cd/cac/types.go b/harness/cd/cac/types.go index 91706f2f..e9f65462 100644 --- a/harness/cd/cac/types.go +++ b/harness/cd/cac/types.go @@ -77,35 +77,6 @@ type ResponseMessage struct { Message string `json:"message"` } -type Service struct { - HarnessApiVersion HarnessApiVersion `yaml:"harnessApiVersion" json:"harnessApiVersion"` - Type ObjectType `yaml:"type" json:"type"` - Id string `yaml:"-"` - Name string `yaml:"-"` - ArtifactType ArtifactType `yaml:"artifactType,omitempty"` - DeploymentType DeploymentType `yaml:"deploymentType,omitempty"` - Description string `yaml:"description,omitempty"` - Tags map[string]string `yaml:"tags,omitempty"` - HelmVersion HelmVersion `yaml:"helmVersion,omitempty"` - ApplicationId string `yaml:"-"` - DeploymentTypeTemplateUri string `yaml:"deploymentTypeTemplateUri,omitempty"` - ConfigVariables []*ServiceVariable `yaml:"configVariables,omitempty"` -} - -func (a *Service) IsEmpty() bool { - return reflect.DeepEqual(a, &Service{}) -} - -func (s *Service) Validate() (bool, error) { - return utils.RequiredStringFieldsSet(s, []string{"ApplicationId"}) -} - -type ServiceVariable struct { - Name string `yaml:"name,omitempty"` - Value string `yaml:"value,omitempty"` - ValueType VariableValueType `yaml:"valueType,omitempty"` -} - type AwsCloudProvider struct { HarnessApiVersion HarnessApiVersion `yaml:"harnessApiVersion" json:"harnessApiVersion"` Type ObjectType `yaml:"type" json:"type"` @@ -273,10 +244,6 @@ type EnvFilter struct { EntityNames []string `yaml:"entityNames,omitempty"` } -type SecretRef struct { - Name string -} - type YamlPath string func (y YamlPath) String() string { diff --git a/harness/cd/cac/utils.go b/harness/cd/cac/utils.go index db698e1c..84ed4800 100644 --- a/harness/cd/cac/utils.go +++ b/harness/cd/cac/utils.go @@ -1,7 +1,6 @@ package cac import ( - "errors" "fmt" "path" "reflect" @@ -96,39 +95,6 @@ var objectTypeMap = map[ObjectType]reflect.Type{ ObjectTypes.SpotInstCloudProvider: reflect.TypeOf(SpotInstCloudProvider{}), } -func (r *SecretRef) MarshalYAML() (interface{}, error) { - if (r == &SecretRef{}) { - return []byte{}, nil - } - - if r.Name == "" { - return nil, errors.New("name must be set") - } - - return fmt.Sprintf("secretName:%s", r.Name), nil -} - -func (r *SecretRef) UnmarshalYAML(unmarshal func(interface{}) error) error { - - var val interface{} - err := unmarshal(&val) - if err != nil { - return err - } - - value := val.(string) - - parts := strings.Split(value, ":") - - if len(parts) == 1 { - r.Name = parts[0] - } else if len(parts) == 2 { - r.Name = parts[1] - } - - return nil -} - func GetEntityNameFromPath(yamlPath YamlPath) string { dir, file := path.Split(string(yamlPath)) diff --git a/harness/cd/cac_service_test.go b/harness/cd/cac_service_test.go index d5484914..2254ecb3 100644 --- a/harness/cd/cac_service_test.go +++ b/harness/cd/cac_service_test.go @@ -38,6 +38,51 @@ func TestCreateService(t *testing.T) { require.Equal(t, app.Id, newService.ApplicationId) } +func TestCreateServiceWithVariables(t *testing.T) { + // Setup + c := getClient() + name := fmt.Sprintf("%s-%s", t.Name(), utils.RandStringBytes(5)) + app, err := createApplication(name) + require.NoError(t, err) + require.NotNil(t, app) + + // Cleanup + defer func() { + err = c.ApplicationClient.DeleteApplication(app.Id) + require.Nil(t, err, "Failed to delete application: %s", err) + }() + + secret, err := createEncryptedTextSecret(name, "secret_value") + require.NoError(t, err) + + // Verify + svc, _ := cac.NewEntity(cac.ObjectTypes.Service).(*cac.Service) + svc.Name = name + svc.ApplicationId = app.Id + svc.DeploymentType = cac.DeploymentTypes.Kubernetes + svc.ArtifactType = cac.ArtifactTypes.Docker + svc.ConfigVariables = []*cac.ServiceVariable{ + { + Name: "var1", + Value: "value1", + ValueType: cac.VariableOverrideValueTypes.Text, + }, + { + Name: "secret", + Value: secret.Name, + ValueType: cac.VariableOverrideValueTypes.EncryptedText, + }, + } + + newService := &cac.Service{} + err = c.ConfigAsCodeClient.UpsertObject(svc, cac.GetServiceYamlPath(app.Name, name), newService) + require.NoError(t, err) + require.NotEmpty(t, newService.Id) + require.Equal(t, len(svc.ConfigVariables), len(newService.ConfigVariables)) + require.Equal(t, app.Id, newService.ApplicationId) + +} + func TestGetService(t *testing.T) { name := fmt.Sprintf("%s_%s", t.Name(), utils.RandStringBytes(4)) // Create application diff --git a/harness/cd/kubernetes_cloudprovider_test.go b/harness/cd/kubernetes_cloudprovider_test.go index 17688050..8a2d5036 100644 --- a/harness/cd/kubernetes_cloudprovider_test.go +++ b/harness/cd/kubernetes_cloudprovider_test.go @@ -66,7 +66,7 @@ func TestUpdateKubernetesCloudProvider(t *testing.T) { Name: updatedName, ClusterDetailsType: graphql.ClusterDetailsTypes.InheritClusterDetails, InheritClusterDetails: &graphql.InheritClusterDetails{ - DelegateSelectors: []string{"Primary"}, + DelegateSelectors: []string{"k8s"}, }, SkipValidation: true, } @@ -75,7 +75,6 @@ func TestUpdateKubernetesCloudProvider(t *testing.T) { require.NoError(t, err) require.NotNil(t, updatedCP) require.Equal(t, updatedName, updatedCP.Name) - err = c.CloudProviderClient.DeleteCloudProvider(cp.Id) require.NoError(t, err) }