From a6e7dada925e89b02b70e90a648002cc5ee394a9 Mon Sep 17 00:00:00 2001 From: kklimonda-cl Date: Fri, 13 Dec 2024 09:02:01 +0100 Subject: [PATCH] Add codegen support for rendering single-elements list as strings (#200) --- .../test/resource_security_policy_test.go | 10 +- pkg/properties/normalized.go | 21 +++++ pkg/translate/terraform_provider/funcs.go | 92 ++++++++++++++----- specs/policies/security-policy-rule.yaml | 3 +- 4 files changed, 97 insertions(+), 29 deletions(-) diff --git a/assets/terraform/test/resource_security_policy_test.go b/assets/terraform/test/resource_security_policy_test.go index 0bfd017d..c943219d 100644 --- a/assets/terraform/test/resource_security_policy_test.go +++ b/assets/terraform/test/resource_security_policy_test.go @@ -156,7 +156,7 @@ resource "panos_security_policy" "policy" { # source_hips = ["hip-profile"] negate_source = false - destination_zones = ["any"] + destination_zone = "any" destination_addresses = ["any"] # destination_hips = ["hip-device"] @@ -262,10 +262,8 @@ func TestAccSecurityPolicyExtended(t *testing.T) { "panos_security_policy.policy", tfjsonpath.New("rules"). AtSliceIndex(0). - AtMapKey("destination_zones"), - knownvalue.ListExact([]knownvalue.Check{ - knownvalue.StringExact("any"), - }), + AtMapKey("destination_zone"), + knownvalue.StringExact("any"), ), statecheck.ExpectKnownValue( "panos_security_policy.policy", @@ -412,7 +410,7 @@ resource "panos_security_policy" "policy" { source_zones = ["any"] source_addresses = ["any"] - destination_zones = ["any"] + destination_zone = "any" destination_addresses = ["any"] services = ["any"] diff --git a/pkg/properties/normalized.go b/pkg/properties/normalized.go index 52172b02..bcc7020c 100644 --- a/pkg/properties/normalized.go +++ b/pkg/properties/normalized.go @@ -227,6 +227,27 @@ func (o *SpecParam) NameVariant() *NameVariant { return o.Name } +func (o *SpecParam) ComplexType() string { + var terraformType *string + if o.TerraformProviderConfig != nil { + terraformType = o.TerraformProviderConfig.Type + } + + if terraformType != nil && o.Type == "list" && o.Items.Type == "string" { + return "string-as-member" + } + + return "" +} + +func (o *SpecParam) FinalType() string { + if o.TerraformProviderConfig != nil && o.TerraformProviderConfig.Type != nil { + return *o.TerraformProviderConfig.Type + } + + return o.Type +} + func (o *SpecParam) FinalSensitive() bool { if o.TerraformProviderConfig != nil && o.TerraformProviderConfig.Sensitive != nil { return *o.TerraformProviderConfig.Sensitive diff --git a/pkg/translate/terraform_provider/funcs.go b/pkg/translate/terraform_provider/funcs.go index dabeb016..0fb4335b 100644 --- a/pkg/translate/terraform_provider/funcs.go +++ b/pkg/translate/terraform_provider/funcs.go @@ -32,6 +32,7 @@ type parameterEncryptionSpec struct { type parameterSpec struct { PangoName *properties.NameVariant TerraformName *properties.NameVariant + ComplexType string Type string Required bool ItemsType string @@ -73,7 +74,8 @@ func renderSpecsForParams(params map[string]*properties.SpecParam, parentNames [ specs = append(specs, parameterSpec{ PangoName: elt.Name, TerraformName: elt.NameVariant(), - Type: elt.Type, + ComplexType: elt.ComplexType(), + Type: elt.FinalType(), ItemsType: itemsType, Encryption: encryptionSpec, }) @@ -253,6 +255,14 @@ const copyToPangoTmpl = ` {{- end }} {{- end }} +{{- define "renderStringAsMemberAssignment" }} + {{- with .Parameter }} + {{- $pangoType := printf "%s%s" $.Spec.PangoType .PangoName.CamelCase }} + {{- $pangoEntries := printf "%s_pango_entries" .TerraformName.LowerCamelCase }} + {{ $pangoEntries }} := []string{o.{{ .TerraformName.CamelCase }}.ValueString()} + {{- end }} +{{- end }} + {{- define "renderSimpleAssignment" }} {{- if .Encryption }} (*encrypted)["{{ .Encryption.PlaintextPath }}"] = o.{{ .TerraformName.CamelCase }} @@ -266,7 +276,9 @@ func (o *{{ .TerraformType }}{{ .ModelOrObject }}) CopyToPango(ctx context.Conte var diags diag.Diagnostics {{- range .Params }} {{- $terraformType := printf "%s%s" $spec.TerraformType .TerraformName.CamelCase }} - {{- if eq .Type "" }} + {{- if eq .ComplexType "string-as-member" }} + {{- template "renderStringAsMemberAssignment" Map "Parameter" . "Spec" $spec }} + {{- else if eq .Type "" }} {{- $pangoType := printf "%sObject" $spec.PangoType }} {{- template "terraformNestedElementsAssign" Map "Parameter" . "Spec" $spec }} {{- else if eq .Type "list" }} @@ -278,7 +290,9 @@ func (o *{{ .TerraformType }}{{ .ModelOrObject }}) CopyToPango(ctx context.Conte {{- end }} {{- range .OneOf }} - {{- if eq .Type "" }} + {{- if eq .ComplexType "string-as-member" }} + {{- template "renderStringAsMemberAssignment" Map "Parameter" . "Spec" $spec }} + {{- else if eq .Type "" }} {{- $pangoType := printf "%sObject" $spec.PangoType }} {{- template "terraformNestedElementsAssign" Map "Parameter" . "Spec" $spec }} {{- else if eq .Type "list" }} @@ -295,7 +309,9 @@ func (o *{{ .TerraformType }}{{ .ModelOrObject }}) CopyToPango(ctx context.Conte (*obj).Name = o.Name.ValueString() {{- end }} {{- range .Params }} - {{- if eq .Type "" }} + {{- if eq .ComplexType "string-as-member" }} + (*obj).{{ .PangoName.CamelCase }} = {{ .TerraformName.LowerCamelCase }}_pango_entries + {{- else if eq .Type "" }} (*obj).{{ .PangoName.CamelCase }} = {{ .TerraformName.LowerCamelCase }}_entry {{- else if eq .Type "list" }} (*obj).{{ .PangoName.CamelCase }} = {{ .TerraformName.LowerCamelCase }}_pango_entries @@ -305,7 +321,9 @@ func (o *{{ .TerraformType }}{{ .ModelOrObject }}) CopyToPango(ctx context.Conte {{- end }} {{- range .OneOf }} - {{- if eq .Type "" }} + {{- if eq .ComplexType "string-as-member" }} + (*obj).{{ .PangoName.CamelCase }} = {{ .TerraformName.LowerCamelCase }}_pango_entries + {{- else if eq .Type "" }} (*obj).{{ .PangoName.CamelCase }} = {{ .TerraformName.LowerCamelCase }}_entry {{- else if eq .Type "list" }} (*obj).{{ .PangoName.CamelCase }} = {{ .TerraformName.LowerCamelCase }}_pango_entries @@ -447,10 +465,26 @@ var {{ .TerraformName.LowerCamelCase }}_list types.List {{- end }} {{- end }} +{{- define "terraformCreateStringAsMemberValues" }} + {{- range .Params }} + {{ if not (eq .ComplexType "string-as-member") }} + {{- continue }} + {{- end }} + {{ .TerraformName.LowerCamelCase }}_value := types.StringValue(obj.{{ .PangoName.CamelCase }}[0]) + {{- end }} + + {{- range .OneOf }} + {{ if not (eq .ComplexType "string-as-member") }} + {{- continue }} + {{- end }} + {{ .TerraformName.LowerCamelCase }}_value := types.StringValue(*obj.{{ .PangoName.CamelCase }}[0]) + {{- end }} +{{- end }} + {{- define "terraformCreateSimpleValues" }} {{- range .Params }} {{- $terraformType := printf "types.%s" (.Type | PascalCase) }} - {{- if (not (or (eq .Type "") (eq .Type "list"))) }} + {{- if (not (or (eq .Type "") (eq .Type "list") (eq .ComplexType "string-as-member"))) }} var {{ .TerraformName.LowerCamelCase }}_value {{ $terraformType }} if obj.{{ .PangoName.CamelCase }} != nil { {{- if .Encryption }} @@ -467,7 +501,7 @@ var {{ .TerraformName.LowerCamelCase }}_list types.List {{- range .OneOf }} {{- $terraformType := printf "types.%s" (.Type | PascalCase) }} - {{- if (not (or (eq .Type "") (eq .Type "list"))) }} + {{- if (not (or (eq .Type "") (eq .Type "list") (eq .ComplexType "string-as-member"))) }} var {{ .TerraformName.LowerCamelCase }}_value {{ $terraformType }} if obj.{{ .PangoName.CamelCase }} != nil { {{ .TerraformName.LowerCamelCase }}_value = types.{{ .Type | PascalCase }}Value(*obj.{{ .PangoName.CamelCase }}) @@ -478,7 +512,9 @@ var {{ .TerraformName.LowerCamelCase }}_list types.List {{- define "assignFromPangoToTerraform" }} {{- with .Parameter }} - {{- if eq .Type "" }} + {{- if eq .ComplexType "string-as-member" }} + o.{{ .TerraformName.CamelCase }} = {{ .TerraformName.LowerCamelCase }}_value + {{- else if eq .Type "" }} o.{{ .TerraformName.CamelCase }} = {{ .TerraformName.LowerCamelCase }}_object {{- else if eq .Type "list" }} o.{{ .TerraformName.CamelCase }} = {{ .TerraformName.LowerCamelCase }}_list @@ -496,6 +532,7 @@ func (o *{{ $terraformType }}) CopyFromPango(ctx context.Context, obj *{{ .Pango {{- template "terraformListElementsAs" $spec }} {{- template "terraformCreateEntryAssignment" $spec }} + {{- template "terraformCreateStringAsMemberValues" $spec }} {{- template "terraformCreateSimpleValues" $spec }} {{- if .HasEntryName }} @@ -1217,22 +1254,28 @@ func createSchemaSpecForParameter(schemaTyp properties.SchemaType, manager *impo func createSchemaAttributeForParameter(schemaTyp properties.SchemaType, manager *imports.Manager, packageName string, param *properties.SpecParam, validators *validatorCtx) attributeCtx { var schemaType, elementType string - switch param.Type { - case "": - schemaType = "SingleNestedAttribute" - case "list": - switch param.Items.Type { - case "entry": - schemaType = "ListNestedAttribute" - case "member": - schemaType = "ListAttribute" - elementType = "types.StringType" + + switch param.ComplexType() { + case "string-as-member": + schemaType = "StringAttribute" + default: + switch param.Type { + case "": + schemaType = "SingleNestedAttribute" + case "list": + switch param.Items.Type { + case "entry": + schemaType = "ListNestedAttribute" + case "member": + schemaType = "ListAttribute" + elementType = "types.StringType" + default: + schemaType = "ListAttribute" + elementType = fmt.Sprintf("types.%sType", pascalCase(param.Items.Type)) + } default: - schemaType = "ListAttribute" - elementType = fmt.Sprintf("types.%sType", pascalCase(param.Items.Type)) + schemaType = fmt.Sprintf("%sAttribute", pascalCase(param.Type)) } - default: - schemaType = fmt.Sprintf("%sAttribute", pascalCase(param.Type)) } var defaultValue *defaultCtx @@ -2101,6 +2144,11 @@ func terraformTypeForProperty(structPrefix string, prop *properties.SpecParam) s return fmt.Sprintf("*%s%sObject", structPrefix, prop.NameVariant().CamelCase) } + switch prop.ComplexType() { + case "string-as-member": + return "types.String" + } + if prop.Type == "list" && prop.Items.Type == "entry" { return "types.List" } diff --git a/specs/policies/security-policy-rule.yaml b/specs/policies/security-policy-rule.yaml index 42f39e10..79855685 100644 --- a/specs/policies/security-policy-rule.yaml +++ b/specs/policies/security-policy-rule.yaml @@ -752,7 +752,8 @@ spec: required: false codegen_overrides: terraform: - name: destination_zones + name: destination_zone + type: string - name: uuid type: string profiles: