Skip to content

Commit

Permalink
ECSW-3173: StackPath Terraform Provider - Add args support to terrafo…
Browse files Browse the repository at this point in the history
…rm and pulumi provider
  • Loading branch information
jasonmillerstackpath committed May 16, 2024
1 parent 664dec4 commit 01b7085
Show file tree
Hide file tree
Showing 4 changed files with 165 additions and 26 deletions.
50 changes: 50 additions & 0 deletions stackpath/resource_stackpath_compute_workload.go
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,56 @@ func resourceComputeWorkloadResourcesSchema() *schema.Schema {
}
}

func resourceComputeWorkloadEnvVars() *schema.Schema {
return &schema.Schema{
Type: schema.TypeList,
Optional: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"key": {
Type: schema.TypeString,
Required: true,
},
"value": {
Type: schema.TypeString,
Optional: true,
},
"secret_value": {
Type: schema.TypeString,
Optional: true,
Sensitive: true,
},
"value_from": {
Type: schema.TypeList,
MaxItems: 1,
Optional: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"instance_field_ref": {
Type: schema.TypeList,
MaxItems: 1,
Optional: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"field_path": {
Type: schema.TypeString,
Optional: true,
},
"optional": {
Type: schema.TypeBool,
Optional: true,
},
},
},
},
},
},
},
},
},
}
}

func resourceComputeWorkloadPortSchema() *schema.Schema {
return &schema.Schema{
Type: schema.TypeList,
Expand Down
67 changes: 63 additions & 4 deletions stackpath/resource_stackpath_compute_workload_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,14 @@ func TestComputeWorkloadContainers(t *testing.T) {
testAccComputeWorkloadCheckContainerEnvVar(workload, "app", "MY_ENVIRONMENT_VARIABLE", "value"),
testAccComputeWorkloadCheckInitContainerImage(workload, "init-app", "docker/whalesay:latest"),
testAccComputeWorkloadCheckInitContainerEnvVar(workload, "init-app", "MY_INIT_ENVIRONMENT_VARIABLE", "value"),
testAccComputeWorkloadCheckInitContainerCommand(workload, "init-app", []string{"cowsay", "stackpath"}),
testAccComputeWorkloadCheckInitContainerEnvVarValueFrom(workload, "init-app", "MY_INIT_ENVVAR_VALUE_FROM", &workload_models.V1EnvironmentVariableSource{
InstanceFieldRef: &workload_models.V1InstanceFieldRef{
Optional: true,
FieldPath: ".location.cityCode",
},
}),
testAccComputeWorkloadCheckInitContainerCommand(workload, "init-app", []string{"cowsay"}),
testAccComputeWorkloadCheckInitContainerArgs(workload, "init-app", []string{"stackpath", "anotherarg"}),
testAccComputeWorkloadCheckTarget(workload, "us", "cityCode", "in", 1, "AMS"),
testAccComputeWorkloadCheckInterface(workload, 0, "default", true, "", "", IPv4IPFamilies),
),
Expand Down Expand Up @@ -738,6 +745,28 @@ func testAccComputeWorkloadCheckInitContainerEnvVar(workload *workload_models.V1
}
}

func testAccComputeWorkloadCheckInitContainerEnvVarValueFrom(workload *workload_models.V1Workload, containerName, envVar string, valueFrom *workload_models.V1EnvironmentVariableSource) resource.TestCheckFunc {
return func(*terraform.State) error {
containerSpec, found := workload.Spec.InitContainers[containerName]
if !found {
return fmt.Errorf("init container not found: %s", containerName)
} else if envVarSpec, found := containerSpec.Env[envVar]; !found {
return fmt.Errorf("environment variable not found: %s", envVar)
} else if envVarSpec.ValueFrom == nil {
return fmt.Errorf("environment variable is nil: %s", envVar)
} else if envVarSpec.ValueFrom.InstanceFieldRef == nil {
return fmt.Errorf("environment variable value_from instance_field_ref is nil: %s", envVar)
} else if valueFrom != nil && envVarSpec.ValueFrom.InstanceFieldRef.Optional != valueFrom.InstanceFieldRef.Optional {
return fmt.Errorf(`environment variable value_from optional '%v' does not match expected value_from optional '%v'`,
envVarSpec.ValueFrom.InstanceFieldRef.Optional, valueFrom.InstanceFieldRef.Optional)
} else if valueFrom != nil && envVarSpec.ValueFrom.InstanceFieldRef.FieldPath != valueFrom.InstanceFieldRef.FieldPath {
return fmt.Errorf(`environment variable value_from field_path '%s' does not match expected value_from field_path '%s'`,
envVarSpec.ValueFrom.InstanceFieldRef.FieldPath, valueFrom.InstanceFieldRef.FieldPath)
}
return nil
}
}

func testAccComputeWorkloadCheckInitContainerCommand(workload *workload_models.V1Workload, containerName string, command []string) resource.TestCheckFunc {
return func(*terraform.State) error {
containerSpec, found := workload.Spec.InitContainers[containerName]
Expand All @@ -756,6 +785,24 @@ func testAccComputeWorkloadCheckInitContainerCommand(workload *workload_models.V
}
}

func testAccComputeWorkloadCheckInitContainerArgs(workload *workload_models.V1Workload, containerName string, args []string) resource.TestCheckFunc {
return func(*terraform.State) error {
containerSpec, found := workload.Spec.InitContainers[containerName]
if !found {
return fmt.Errorf("init container not found: %s", containerName)
} else if len(containerSpec.Args) != len(args) {
return fmt.Errorf("number of args %d does not match expected value %d", len(containerSpec.Args), len(args))
}

for i := range containerSpec.Args {
if containerSpec.Args[i] != args[i] {
return fmt.Errorf("args '%s' does not match expected value '%s'", containerSpec.Args[i], args[i])
}
}
return nil
}
}

func testAccComputeWorkloadCheckContainerEnvVarNotExist(workload *workload_models.V1Workload, containerName, envVar string) resource.TestCheckFunc {
return func(*terraform.State) error {
containerSpec, found := workload.Spec.Containers[containerName]
Expand Down Expand Up @@ -1241,11 +1288,23 @@ resource "stackpath_compute_workload" "foo" {
}
command = [
"cowsay",
"stackpath",
]
args = [
"stackpath",
"anotherarg",
]
env {
key = "MY_INIT_ENVIRONMENT_VARIABLE"
value = "value"
key = "MY_INIT_ENVIRONMENT_VARIABLE"
value = "value"
}
env {
key = "MY_INIT_ENVVAR_VALUE_FROM"
value_from {
instance_field_ref {
field_path = ".location.cityCode"
optional = true
}
}
}
}
Expand Down
21 changes: 4 additions & 17 deletions stackpath/resource_stackpath_core.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,27 +45,14 @@ func resourceComputeWorkloadContainer() *schema.Resource {
Type: schema.TypeString,
},
},
"env": {
"args": {
Type: schema.TypeList,
Optional: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"key": {
Type: schema.TypeString,
Required: true,
},
"value": {
Type: schema.TypeString,
Optional: true,
},
"secret_value": {
Type: schema.TypeString,
Optional: true,
Sensitive: true,
},
},
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
"env": resourceComputeWorkloadEnvVars(),
"port": resourceComputeWorkloadPortSchema(),
"readiness_probe": resourceComputeWorkloadProbeSchema(),
"liveness_probe": resourceComputeWorkloadProbeSchema(),
Expand Down
53 changes: 48 additions & 5 deletions stackpath/structure_compute_workload.go
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ func convertComputeWorkloadContainer(prefix string, data *schema.ResourceData) w
Resources: convertComputeWorkloadResourceRequirements(prefix+".resources", data),
VolumeMounts: convertComputeWorkloadVolumeMounts(prefix+".volume_mount", data),
SecurityContext: convertComputeWorkloadSecurityContext(prefix+".security_context", data),
Args: convertToStringArray(data.Get(prefix + ".args").([]interface{})),
}
}

Expand Down Expand Up @@ -324,10 +325,23 @@ func convertComputeWorkloadEnvironmentVariables(prefix string, data *schema.Reso
envVarData := s.(map[string]interface{})
log.Printf("[DEBUG] setting environment variable '%s'", envVarData["key"])
envVarNames[envVarData["key"]] = true
envVars[envVarData["key"].(string)] = workload_models.V1EnvironmentVariable{
environmentVariables := workload_models.V1EnvironmentVariable{
Value: envVarData["value"].(string),
SecretValue: envVarData["secret_value"].(string),
}
if len(envVarData["value_from"].([]interface{})) > 0 {
valueFromData := envVarData["value_from"].([]interface{})[0].(map[string]interface{})
if len(valueFromData["instance_field_ref"].([]interface{})) > 0 {
interfaceFieldRefData := valueFromData["instance_field_ref"].([]interface{})[0].(map[string]interface{})
environmentVariables.ValueFrom = &workload_models.V1EnvironmentVariableSource{
InstanceFieldRef: &workload_models.V1InstanceFieldRef{
Optional: interfaceFieldRefData["optional"].(bool),
FieldPath: interfaceFieldRefData["field_path"].(string),
},
}
}
}
envVars[envVarData["key"].(string)] = environmentVariables
}
// in a PUT world, we don't need to track old vs new
return envVars
Expand Down Expand Up @@ -849,6 +863,7 @@ func flattenComputeWorkloadContainerOrdered(prefix, name string, data *schema.Re
"resources": flattenComputeWorkloadResourceRequirements(container.Resources),
"volume_mount": flattenComputeWorkloadVolumeMounts(container.VolumeMounts),
"security_context": flattenComputeWorkloadSecurityContext(container.SecurityContext),
"args": flattenStringArray(container.Args),
}
}

Expand All @@ -867,6 +882,7 @@ func flattenComputeWorkloadContainer(name string, container workload_models.V1Co
"resources": flattenComputeWorkloadResourceRequirements(container.Resources),
"volume_mount": flattenComputeWorkloadVolumeMounts(container.VolumeMounts),
"security_context": flattenComputeWorkloadSecurityContext(container.SecurityContext),
"args": flattenStringArray(container.Args),
}
}

Expand Down Expand Up @@ -946,8 +962,10 @@ func flattenComputeWorkloadEnvVarsOrdered(prefix string, data *schema.ResourceDa
e := make([]interface{}, data.Get(prefix+".#").(int))
for key, v := range envVars {
val := map[string]interface{}{
"key": key,
"value": v.Value,
"key": key,
"value": v.Value,
"secret_value": v.SecretValue,
"value_from": flattenComputeWorkloadEnvVarValueFrom(v.ValueFrom),
}

if index, exists := ordered[key]; exists {
Expand All @@ -963,13 +981,38 @@ func flattenComputeWorkloadEnvVars(envVars workload_models.V1EnvironmentVariable
e := make([]interface{}, 0, len(envVars))
for k, v := range envVars {
e = append(e, map[string]interface{}{
"key": k,
"value": v.Value,
"key": k,
"value": v.Value,
"secret_value": v.SecretValue,
"value_from": flattenComputeWorkloadEnvVarValueFrom(v.ValueFrom),
})
}
return e
}

func flattenComputeWorkloadEnvVarValueFrom(valueFrom *workload_models.V1EnvironmentVariableSource) []interface{} {
if valueFrom == nil {
return nil
}

return []interface{}{map[string]interface{}{
"instance_field_ref": flattenComputeWorkloadEnvVarValueFromInstanceFieldRef(valueFrom.InstanceFieldRef),
}}
}

func flattenComputeWorkloadEnvVarValueFromInstanceFieldRef(instanceFieldRef *workload_models.V1InstanceFieldRef) []interface{} {
if instanceFieldRef == nil {
return nil
}

fieldRef := map[string]interface{}{
"optional": instanceFieldRef.Optional,
"field_path": instanceFieldRef.FieldPath,
}

return []interface{}{fieldRef}
}

// Convert the model to "array" of maps, order of capabilities not maintained.
func flattenComputeWorkloadSecurityContext(securityContext *workload_models.V1ContainerSecurityContext) []interface{} {
if securityContext == nil {
Expand Down

0 comments on commit 01b7085

Please sign in to comment.