diff --git a/codefresh/cfclient/project.go b/codefresh/cfclient/project.go index daf524d..04a053d 100644 --- a/codefresh/cfclient/project.go +++ b/codefresh/cfclient/project.go @@ -19,9 +19,9 @@ func (project *Project) GetID() string { } // SetVariables project variables -func (project *Project) SetVariables(variables map[string]interface{}) { +func (project *Project) SetVariables(variables map[string]interface{}, encrypted bool) { for key, value := range variables { - project.Variables = append(project.Variables, Variable{Key: key, Value: value.(string)}) + project.Variables = append(project.Variables, Variable{Key: key, Value: value.(string), Encrypted: encrypted}) } } diff --git a/codefresh/cfclient/utils.go b/codefresh/cfclient/utils.go index 011fb72..45b7589 100644 --- a/codefresh/cfclient/utils.go +++ b/codefresh/cfclient/utils.go @@ -9,7 +9,7 @@ import ( type Variable struct { Key string `json:"key"` Value string `json:"value"` - Encrypted bool `json:"encrypted",omitempty` + Encrypted bool `json:"encrypted",omitempty` } // CodefreshObject codefresh interface diff --git a/codefresh/internal/datautil/strings.go b/codefresh/internal/datautil/strings.go index 5a1f6f5..227b577 100644 --- a/codefresh/internal/datautil/strings.go +++ b/codefresh/internal/datautil/strings.go @@ -23,17 +23,17 @@ func ConvertAndMapStringArr(ifaceArr []interface{}, f func(string) string) []str } // ConvertVariables converts an array of cfclient. Variables to 2 maps of key/value pairs - first one for un-encrypted variables second one for encrypted variables. -func ConvertVariables(vars []cfclient.Variable) (map[string]string,map[string]string) { - +func ConvertVariables(vars []cfclient.Variable) (map[string]string, map[string]string) { + numberOfEncryptedVars := 0 - + for _, v := range vars { if v.Encrypted { numberOfEncryptedVars++ } } - resUnencrptedVars := make(map[string]string, len(vars) - numberOfEncryptedVars) + resUnencrptedVars := make(map[string]string, len(vars)-numberOfEncryptedVars) resEncryptedVars := make(map[string]string, numberOfEncryptedVars) for _, v := range vars { @@ -44,7 +44,7 @@ func ConvertVariables(vars []cfclient.Variable) (map[string]string,map[string]st } } - return resUnencrptedVars,resEncryptedVars + return resUnencrptedVars, resEncryptedVars } // FlattenStringArr flattens an array of strings. diff --git a/codefresh/resource_pipeline.go b/codefresh/resource_pipeline.go index 0b04aab..0da0da6 100644 --- a/codefresh/resource_pipeline.go +++ b/codefresh/resource_pipeline.go @@ -156,7 +156,7 @@ Or: original_yaml_string = file("/path/to/my/codefresh.yml") Type: schema.TypeMap, Optional: true, Elem: &schema.Schema{ - Type: schema.TypeString, + Type: schema.TypeString, Sensitive: true, }, }, @@ -350,7 +350,7 @@ Or: original_yaml_string = file("/path/to/my/codefresh.yml") Type: schema.TypeMap, Optional: true, Elem: &schema.Schema{ - Type: schema.TypeString, + Type: schema.TypeString, Sensitive: true, }, }, @@ -490,7 +490,7 @@ Or: original_yaml_string = file("/path/to/my/codefresh.yml") Type: schema.TypeMap, Optional: true, Elem: &schema.Schema{ - Type: schema.TypeString, + Type: schema.TypeString, Sensitive: true, }, }, @@ -635,8 +635,8 @@ Pipeline concurrency policy: Builds on 'Pending Approval' state should be: }, "enable_notifications": { Type: schema.TypeBool, - Optional: true, - Default: false, + Optional: true, + Default: false, }, }, }, @@ -748,7 +748,7 @@ func mapPipelineToResource(pipeline cfclient.Pipeline, d *schema.ResourceData) e // Set encrypted variables from resource data, as otherwise they cause constant diff as the value is always returned as ***** encryptedVariables, ok := flattenedSpec[0]["encrypted_variables"].(map[string]string) - + if ok { if len(encryptedVariables) > 0 { setEncryptedVariablesValuesFromResource(d, encryptedVariables, "spec.0.encrypted_variables") @@ -758,14 +758,14 @@ func mapPipelineToResource(pipeline cfclient.Pipeline, d *schema.ResourceData) e // Set trigger encrypted variables from resource data triggers, getTriggersOK := flattenedSpec[0]["trigger"] - if (getTriggersOK) { + if getTriggersOK { for triggerIndex, triggerSpec := range triggers.([]map[string]interface{}) { - + triggerEncryptedVariables, ok := triggerSpec["encrypted_variables"].(map[string]string) - + if ok { if len(triggerEncryptedVariables) > 0 { - setEncryptedVariablesValuesFromResource(d, triggerEncryptedVariables, fmt.Sprintf("spec.0.trigger.%d.encrypted_variables",triggerIndex)) + setEncryptedVariablesValuesFromResource(d, triggerEncryptedVariables, fmt.Sprintf("spec.0.trigger.%d.encrypted_variables", triggerIndex)) } } } @@ -774,14 +774,14 @@ func mapPipelineToResource(pipeline cfclient.Pipeline, d *schema.ResourceData) e // Set cron trigger encrypted variables from resource data cronTriggers, getCronTriggersOK := flattenedSpec[0]["cron_trigger"] - if (getCronTriggersOK) { + if getCronTriggersOK { for triggerIndex, triggerSpec := range cronTriggers.([]map[string]interface{}) { - + triggerEncryptedVariables, ok := triggerSpec["encrypted_variables"].(map[string]string) - + if ok { if len(triggerEncryptedVariables) > 0 { - setEncryptedVariablesValuesFromResource(d, triggerEncryptedVariables, fmt.Sprintf("spec.0.cron_trigger.%d.encrypted_variables",triggerIndex)) + setEncryptedVariablesValuesFromResource(d, triggerEncryptedVariables, fmt.Sprintf("spec.0.cron_trigger.%d.encrypted_variables", triggerIndex)) } } } @@ -1080,7 +1080,7 @@ func mapResourceToPipeline(d *schema.ResourceData) (*cfclient.Pipeline, error) { } variables := d.Get(fmt.Sprintf("spec.0.trigger.%v.variables", idx)).(map[string]interface{}) codefreshTrigger.SetVariables(variables, false) - + encryptedVariables := d.Get(fmt.Sprintf("spec.0.trigger.%v.encrypted_variables", idx)).(map[string]interface{}) codefreshTrigger.SetVariables(encryptedVariables, true) diff --git a/codefresh/resource_pipeline_test.go b/codefresh/resource_pipeline_test.go index dd29000..9c82d82 100644 --- a/codefresh/resource_pipeline_test.go +++ b/codefresh/resource_pipeline_test.go @@ -160,13 +160,13 @@ func TestAccCodefreshPipeline_Variables(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, ImportStateVerifyIgnore: []string{"spec.0.encrypted_variables"}, }, { - Config: testAccCodefreshPipelineBasicConfigVariables(name, "codefresh-contrib/react-sample-app", "./codefresh.yml", "master", "git", "var1", "val1_updated", "var2", "val2_updated","var1", "val1_updated", "var2", "val2_updated"), + Config: testAccCodefreshPipelineBasicConfigVariables(name, "codefresh-contrib/react-sample-app", "./codefresh.yml", "master", "git", "var1", "val1_updated", "var2", "val2_updated", "var1", "val1_updated", "var2", "val2_updated"), Check: resource.ComposeTestCheckFunc( testAccCheckCodefreshPipelineExists(resourceName, &pipeline), resource.TestCheckResourceAttr(resourceName, "spec.0.variables.var1", "val1_updated"), @@ -395,9 +395,9 @@ func TestAccCodefreshPipeline_Triggers(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, ImportStateVerifyIgnore: []string{"spec.0.trigger.1.encrypted_variables"}, }, { diff --git a/codefresh/resource_project.go b/codefresh/resource_project.go index 465fe1a..4eb49cf 100644 --- a/codefresh/resource_project.go +++ b/codefresh/resource_project.go @@ -1,6 +1,7 @@ package codefresh import ( + "fmt" "log" "time" @@ -46,6 +47,15 @@ You are free to use projects as you see fit. For example, you could create a pro Type: schema.TypeString, }, }, + "encrypted_variables": { + Description: "Project level encrypted variables. Please note that drift will not be detected for encrypted variables", + Type: schema.TypeMap, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + Sensitive: true, + }, + }, }, } } @@ -133,12 +143,27 @@ func mapProjectToResource(project *cfclient.Project, d *schema.ResourceData) err return err } - vars, _ := datautil.ConvertVariables(project.Variables) + vars, encryptedVars := datautil.ConvertVariables(project.Variables) err = d.Set("variables", vars) if err != nil { return err } + + // Set encrypted vars from resource data to avoid constant diff + if len(encryptedVars) > 0 { + // Iterate over variables and set the value from resource data + for k := range encryptedVars { + encryptedVars[k] = d.Get(fmt.Sprintf("encrypted_variables.%s", k)).(string) + } + } + + err = d.Set("encrypted_variables", encryptedVars) + + if err != nil { + return err + } + return nil } @@ -150,6 +175,8 @@ func mapResourceToProject(d *schema.ResourceData) *cfclient.Project { Tags: datautil.ConvertStringArr(tags), } variables := d.Get("variables").(map[string]interface{}) - project.SetVariables(variables) + project.SetVariables(variables, false) + encryptedVariables := d.Get("encrypted_variables").(map[string]interface{}) + project.SetVariables(encryptedVariables, true) return project } diff --git a/codefresh/resource_project_test.go b/codefresh/resource_project_test.go index 6123c19..e94de0a 100644 --- a/codefresh/resource_project_test.go +++ b/codefresh/resource_project_test.go @@ -74,24 +74,27 @@ func TestAccCodefreshProject_Variables(t *testing.T) { CheckDestroy: testAccCheckCodefreshProjectDestroy, Steps: []resource.TestStep{ { - Config: testAccCodefreshProjectBasicConfigVariables(name, "var1", "val1", "var2", "val2"), + Config: testAccCodefreshProjectBasicConfigVariables(name, "var1", "val1", "var2", "val2", "encvar1", "encval1"), Check: resource.ComposeTestCheckFunc( testAccCheckCodefreshProjectExists(resourceName), resource.TestCheckResourceAttr(resourceName, "variables.var1", "val1"), resource.TestCheckResourceAttr(resourceName, "variables.var2", "val2"), + resource.TestCheckResourceAttr(resourceName, "encrypted_variables.encvar1", "encval1"), ), }, { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"encrypted_variables"}, }, { - Config: testAccCodefreshProjectBasicConfigVariables(name, "var1", "val1_updated", "var2", "val2_updated"), + Config: testAccCodefreshProjectBasicConfigVariables(name, "var1", "val1_updated", "var2", "val2_updated", "encvar1", "encvar1_updated"), Check: resource.ComposeTestCheckFunc( testAccCheckCodefreshProjectExists(resourceName), resource.TestCheckResourceAttr(resourceName, "variables.var1", "val1_updated"), resource.TestCheckResourceAttr(resourceName, "variables.var2", "val2_updated"), + resource.TestCheckResourceAttr(resourceName, "encrypted_variables.encvar1", "encvar1_updated"), // resource.TestCheckResourceAttr(resourceName, "variables.", name), ), }, @@ -167,7 +170,7 @@ resource "codefresh_project" "test" { `, rName, tag1, tag2) } -func testAccCodefreshProjectBasicConfigVariables(rName, var1Name, var1Value, var2Name, var2Value string) string { +func testAccCodefreshProjectBasicConfigVariables(rName, var1Name, var1Value, var2Name, var2Value, encrytedVar1Name,encrytedVar1Value string) string { return fmt.Sprintf(` resource "codefresh_project" "test" { name = "%s" @@ -175,6 +178,10 @@ resource "codefresh_project" "test" { %q = %q %q = %q } + + encrypted_variables = { + %q = %q + } } -`, rName, var1Name, var1Value, var2Name, var2Value) +`, rName, var1Name, var1Value, var2Name, var2Value, encrytedVar1Name,encrytedVar1Value) }