From 1b483a1d6a4dddd62006d2454f6b1c10758640a0 Mon Sep 17 00:00:00 2001 From: kklimonda-cl Date: Fri, 16 Aug 2024 16:33:33 +0200 Subject: [PATCH] feat: Extend support for device groups specification (#137) --- pkg/generate/generator.go | 10 +- pkg/translate/assignments.go | 116 +++++++++++++++++----- pkg/translate/terraform_provider/funcs.go | 4 +- specs/panorama/device-group.yaml | 18 +++- 4 files changed, 113 insertions(+), 35 deletions(-) diff --git a/pkg/generate/generator.go b/pkg/generate/generator.go index f89b68a7..ea177daa 100644 --- a/pkg/generate/generator.go +++ b/pkg/generate/generator.go @@ -132,17 +132,19 @@ func (c *Creator) processTemplate(templateName, filePath string) error { // If no data was rendered from the template, skip creating an empty file. dataLength := len(bytes.TrimSpace(data.Bytes())) if dataLength > 0 { - formattedCode, err := format.Source(data.Bytes()) + var formattedCode []byte + formattedCode, err = format.Source(data.Bytes()) if err != nil { - return fmt.Errorf("error formatting code %w", err) + log.Printf("Failed to format source code: %s", err.Error()) + formattedCode = data.Bytes() } formattedBuf := bytes.NewBuffer(formattedCode) - if err := c.createAndWriteFile(filePath, formattedBuf); err != nil { + if writeErr := c.createAndWriteFile(filePath, formattedBuf); writeErr != nil { return fmt.Errorf("error creating and writing to file %s: %w", filePath, err) } } - return nil + return err } // writeFormattedContentToFile formats the content and writes it to a file. diff --git a/pkg/translate/assignments.go b/pkg/translate/assignments.go index 51766a19..bc6050aa 100644 --- a/pkg/translate/assignments.go +++ b/pkg/translate/assignments.go @@ -2,6 +2,7 @@ package translate import ( "fmt" + "log" "strings" "github.com/paloaltonetworks/pan-os-codegen/pkg/properties" @@ -25,10 +26,14 @@ func prepareAssignment(objectType string, param *properties.SpecParam, listFunct var builder strings.Builder if ParamSupportedInVersion(param, version) { + var isNestedListHack bool + if param.Type == "list" { + isNestedListHack = true + } switch { case param.Spec != nil: appendSpecObjectAssignment(param, nil, objectType, paramVersionInAssignment(suffix, version), - listFunction, entryFunction, boolFunction, prefix, suffix, &builder) + listFunction, entryFunction, boolFunction, prefix, suffix, &builder, isNestedListHack) case isParamListAndProfileTypeIsMember(param): appendFunctionAssignment(param, objectType, listFunction, "", &builder) case isParamListAndProfileTypeIsSingleEntry(param): @@ -82,13 +87,28 @@ func appendFunctionAssignment(param *properties.SpecParam, objectType string, fu } } -func appendSpecObjectAssignment(param, parentParam *properties.SpecParam, objectType string, version, listFunction, entryFunction, boolFunction, prefix, suffix string, builder *strings.Builder) { +func appendSpecObjectAssignment(param, parentParam *properties.SpecParam, objectType string, version, listFunction, entryFunction, boolFunction, prefix, suffix string, builder *strings.Builder, isNestedListHack bool) { defineNestedObject([]*properties.SpecParam{param}, param, parentParam, objectType, version, listFunction, entryFunction, boolFunction, prefix, suffix, builder) - builder.WriteString(fmt.Sprintf("%s.%s = nested%s\n", objectType, param.Name.CamelCase, param.Name.CamelCase)) + + if parentParam == nil && param.Type == "list" && param.Items.Type == "entry" { + builder.WriteString(fmt.Sprintf("%s.%s = nested%sCol\n", objectType, param.Name.CamelCase, param.Name.CamelCase)) + } else { + builder.WriteString(fmt.Sprintf("%s.%s = nested%s\n", objectType, param.Name.CamelCase, param.Name.CamelCase)) + } + + if isNestedListHack { + builder.WriteString("}\n") + } } func defineNestedObject(parent []*properties.SpecParam, param, parentParam *properties.SpecParam, objectType string, version, listFunction, entryFunction, boolFunction, prefix, suffix string, builder *strings.Builder) { - declareRootOfNestedObject(parent, builder, version, prefix, suffix) + + var isNestedListHack bool + if parentParam == nil && param.Type == "list" && param.Items.Type == "entry" { + isNestedListHack = true + } + + declareRootOfNestedObject(parent, builder, version, prefix, suffix, isNestedListHack) if ParamSupportedInVersion(param, version) { startIfBlockForParamNotNil(parent, param, parentParam, builder) @@ -114,22 +134,42 @@ func defineNestedObject(parent []*properties.SpecParam, param, parentParam *prop } func startIfBlockForParamNotNil(parent []*properties.SpecParam, param *properties.SpecParam, parentParam *properties.SpecParam, builder *strings.Builder) { - if isParamName(param) { - builder.WriteString(fmt.Sprintf("if o%s != \"\" {\n", - renderNestedVariableName(parent, true, true, true))) + if len(parent) == 2 && parent[0].Type == "list" && parent[0].Items.Type == "entry" { + if isParamName(param) { + builder.WriteString(fmt.Sprintf("if o%s != \"\" {\n", + renderNestedVariableName(parent, true, true, false))) + } else { + builder.WriteString(fmt.Sprintf("if o%s != nil {\n", + renderNestedVariableName(parent, true, true, false))) + } } else { - builder.WriteString(fmt.Sprintf("if o%s != nil {\n", - renderNestedVariableName(parent, true, true, true))) + if isParamName(param) { + builder.WriteString(fmt.Sprintf("if o%s != \"\" {\n", + renderNestedVariableName(parent, true, true, true))) + } else { + builder.WriteString(fmt.Sprintf("if o%s != nil {\n", + renderNestedVariableName(parent, true, true, true))) + } } } func finishNestedObjectIfBlock(parent []*properties.SpecParam, param *properties.SpecParam, builder *strings.Builder) { - if isParamListAndProfileTypeIsExtendedEntry(param) { - builder.WriteString(fmt.Sprintf("nested%s = append(nested%s, nested%s)\n", - renderNestedVariableName(parent, true, true, false), - renderNestedVariableName(parent, true, true, false), - renderNestedVariableName(parent, false, false, false))) + if len(parent) == 1 && parent[0].Type == "list" && parent[0].Items.Type == "entry" { + if isParamListAndProfileTypeIsExtendedEntry(param) { + builder.WriteString(fmt.Sprintf("nested%sCol = append(nested%sCol, nested%s)\n", + renderNestedVariableName(parent, true, true, false), + renderNestedVariableName(parent, true, true, false), + renderNestedVariableName(parent, false, false, false))) + } + } else { + if isParamListAndProfileTypeIsExtendedEntry(param) { + builder.WriteString(fmt.Sprintf("nested%s = append(nested%s, nested%s)\n", + renderNestedVariableName(parent, true, true, false), + renderNestedVariableName(parent, true, true, false), + renderNestedVariableName(parent, false, false, false))) + } } + builder.WriteString("}\n") } @@ -137,8 +177,13 @@ func isParamName(param *properties.SpecParam) bool { return param.Name.CamelCase == "Name" } -func declareRootOfNestedObject(parent []*properties.SpecParam, builder *strings.Builder, version, prefix, suffix string) { - if len(parent) == 1 { +func declareRootOfNestedObject(parent []*properties.SpecParam, builder *strings.Builder, version, prefix, suffix string, isNestedListHack bool) { + if isNestedListHack { + builder.WriteString(fmt.Sprintf("var nested%sCol []%s%s%s%s\n", + renderNestedVariableName(parent, true, true, false), prefix, + renderNestedVariableName(parent, false, false, false), suffix, + CreateGoSuffixFromVersion(version))) + } else if len(parent) == 1 { builder.WriteString(fmt.Sprintf("var nested%s *%s%s%s%s\n", renderNestedVariableName(parent, true, true, false), prefix, renderNestedVariableName(parent, false, false, false), suffix, @@ -165,10 +210,17 @@ func createStructForParamWithSpec(parent []*properties.SpecParam, builder *strin } func createListAndLoopForNestedEntry(parent []*properties.SpecParam, builder *strings.Builder, prefix string, suffix string, version string) { - builder.WriteString(fmt.Sprintf("nested%s = []%s%s%s%s{}\n", - renderNestedVariableName(parent, true, true, false), prefix, - renderNestedVariableName(parent, false, false, false), suffix, - CreateGoSuffixFromVersion(version))) + if len(parent) == 1 && parent[0].Type == "list" && parent[0].Items.Type == "entry" { + builder.WriteString(fmt.Sprintf("nested%sCol = []%s%s%s%s{}\n", + renderNestedVariableName(parent, true, true, false), prefix, + renderNestedVariableName(parent, false, false, false), suffix, + CreateGoSuffixFromVersion(version))) + } else { + builder.WriteString(fmt.Sprintf("nested%s = []%s%s%s%s{}\n", + renderNestedVariableName(parent, true, true, false), prefix, + renderNestedVariableName(parent, false, false, false), suffix, + CreateGoSuffixFromVersion(version))) + } builder.WriteString(fmt.Sprintf("for _, o%s := range o%s {\n", renderNestedVariableName(parent, false, false, false), @@ -215,21 +267,35 @@ func miscForUnknownXmlWithExtendedEntry(parent []*properties.SpecParam, builder } } +var _ = log.Printf + func assignValueForNestedObject(parent []*properties.SpecParam, builder *strings.Builder, param, parentParam *properties.SpecParam) { - builder.WriteString(fmt.Sprintf("nested%s = o%s\n", - renderNestedVariableName(parent, true, true, false), - renderNestedVariableName(parent, true, true, true))) + if len(parent) == 2 && parent[0].Type == "list" && parent[0].Items.Type == "entry" { + builder.WriteString(fmt.Sprintf("nested%s = o%s\n", + renderNestedVariableName(parent, true, true, false), + renderNestedVariableName(parent, true, true, false))) + } else { + builder.WriteString(fmt.Sprintf("nested%s = o%s\n", + renderNestedVariableName(parent, true, true, false), + renderNestedVariableName(parent, true, true, true))) + } } func assignFunctionForNestedObject(parent []*properties.SpecParam, functionName, additionalArguments string, builder *strings.Builder, param, parentParam *properties.SpecParam) { + var startWithDot bool + if len(parent) == 2 && parent[0].Type == "list" && parent[0].Items.Type == "entry" { + startWithDot = false + } else { + startWithDot = true + } if additionalArguments != "" { builder.WriteString(fmt.Sprintf("nested%s = %s(o%s, %s)\n", renderNestedVariableName(parent, true, true, false), functionName, - renderNestedVariableName(parent, true, true, true), additionalArguments)) + renderNestedVariableName(parent, true, true, startWithDot), additionalArguments)) } else { builder.WriteString(fmt.Sprintf("nested%s = %s(o%s)\n", renderNestedVariableName(parent, true, true, false), functionName, - renderNestedVariableName(parent, true, true, true))) + renderNestedVariableName(parent, true, true, startWithDot))) } } diff --git a/pkg/translate/terraform_provider/funcs.go b/pkg/translate/terraform_provider/funcs.go index 3b5dbac0..56c81422 100644 --- a/pkg/translate/terraform_provider/funcs.go +++ b/pkg/translate/terraform_provider/funcs.go @@ -200,7 +200,7 @@ const copyToPangoTmpl = ` {{- define "terraformListElementsAs" }} {{- with .Parameter }} {{- $pangoType := printf "%s%s" $.Spec.PangoType .Name.CamelCase }} - {{- $terraformType := printf "%s%s%s" $.Spec.TerraformType .Name.CamelCase $.Spec.ModelOrObject }} + {{- $terraformType := printf "%s%sObject" $.Spec.TerraformType .Name.CamelCase }} {{- $pangoEntries := printf "%s_pango_entries" .Name.LowerCamelCase }} {{- $tfEntries := printf "%s_tf_entries" .Name.LowerCamelCase }} {{- if eq .ItemsType "entry" }} @@ -344,7 +344,7 @@ var {{ .Name.LowerCamelCase }}_list types.List {{- define "terraformListElementsAsParam" }} {{- with .Parameter }} {{- $pangoType := printf "%s%s" $.Spec.PangoType .Name.CamelCase }} - {{- $terraformType := printf "%s%s%s" $.Spec.TerraformType .Name.CamelCase $.Spec.ModelOrObject }} + {{- $terraformType := printf "%s%sObject" $.Spec.TerraformType .Name.CamelCase }} {{- $terraformList := printf "%s_list" .Name.LowerCamelCase }} {{- $pangoEntries := printf "%s_pango_entries" .Name.LowerCamelCase }} {{- $tfEntries := printf "%s_tf_entries" .Name.LowerCamelCase }} diff --git a/specs/panorama/device-group.yaml b/specs/panorama/device-group.yaml index a7f3c08e..6b9f287d 100644 --- a/specs/panorama/device-group.yaml +++ b/specs/panorama/device-group.yaml @@ -54,12 +54,22 @@ spec: - name: devices description: "List of devices" type: list + profiles: + - type: entry + xpath: ["devices", "entry"] spec: items: - type: string - profiles: - - type: member - xpath: ["devices"] + type: object + spec: + params: + - name: "vsys" + type: list + profiles: + - type: member + xpath: [vsys] + spec: + items: + type: string - name: authorization_code type: string description: "Authorization code"