Skip to content

Commit

Permalink
During Update(), load the existing entry to restore private fields.
Browse files Browse the repository at this point in the history
Some parameters can have codegen override set to skip parameter in terraform
provider - this can be used for example when rendering panorama templates to
skip attributes related to importing - import is done implicitly when creating
other resources.

Due to that care has to be taken to make sure those private fields are still
copied to pango structures for the update, otherwise Update() call will end
up removing them.

This implementation follows the old provider, by reading existing entries from
the server during Update() call in the provider, and only copying data that
is known to the provider, leaving everything else intact.
  • Loading branch information
kklimonda-cl committed Sep 6, 2024
1 parent 815437a commit d61ac46
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 73 deletions.
65 changes: 40 additions & 25 deletions pkg/translate/terraform_provider/funcs.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,9 +200,16 @@ const copyToPangoTmpl = `
{{- $diag := .Name.LowerCamelCase | printf "%s_diags" }}
var {{ $result }}_entry *{{ $.Spec.PangoType }}{{ .Name.CamelCase }}
if o.{{ .Name.CamelCase }} != nil {
var {{ $diag }} diag.Diagnostics
{{ $result }}_entry, {{ $diag }} = o.{{ .Name.CamelCase }}.CopyToPango(ctx, encrypted)
diags.Append({{ $diag }}...)
if *obj != nil && (*obj).{{ .Name.CamelCase }} != nil {
{{ $result }}_entry = (*obj).{{ .Name.CamelCase }}
} else {
{{ $result }}_entry = new({{ $.Spec.PangoType }}{{ .Name.CamelCase }})
}
diags.Append(o.{{ .Name.CamelCase }}.CopyToPango(ctx, &{{ $result }}_entry, encrypted)...)
if diags.HasError() {
return diags
}
}
{{- end }}
Expand All @@ -220,17 +227,23 @@ const copyToPangoTmpl = `
{
d := o.{{ .Name.CamelCase }}.ElementsAs(ctx, &{{ $tfEntries }}, false)
diags.Append(d...)
if diags.HasError() {
return diags
}
for _, elt := range {{ $tfEntries }} {
entry, d := elt.CopyToPango(ctx, encrypted)
diags.Append(d...)
var entry *{{ $pangoType }}
diags.Append(elt.CopyToPango(ctx, &entry, encrypted)...)
if diags.HasError() {
return diags
}
{{ $pangoEntries }} = append({{ $pangoEntries }}, *entry)
}
}
{{- else }}
{{ $pangoEntries }} := make([]{{ .ItemsType }}, 0)
{
d := o.{{ .Name.CamelCase }}.ElementsAs(ctx, &{{ $pangoEntries }}, false)
diags.Append(d...)
{{ $pangoEntries }} := make([]{{ .ItemsType }}, 0)
diags.Append(o.{{ .Name.CamelCase }}.ElementsAs(ctx, &{{ $pangoEntries }}, false)...)
if diags.HasError() {
return diags
}
{{- end }}
{{- end }}
Expand All @@ -245,7 +258,7 @@ const copyToPangoTmpl = `
{{- range .Specs }}
{{- $spec := . }}
func (o *{{ .TerraformType }}{{ .ModelOrObject }}) CopyToPango(ctx context.Context, encrypted *map[string]types.String) (*{{ .PangoReturnType }}, diag.Diagnostics) {
func (o *{{ .TerraformType }}{{ .ModelOrObject }}) CopyToPango(ctx context.Context, obj **{{ .PangoReturnType }}, encrypted *map[string]types.String) diag.Diagnostics {
var diags diag.Diagnostics
{{- range .Params }}
{{- $terraformType := printf "%s%s" $spec.TerraformType .Name.CamelCase }}
Expand All @@ -271,32 +284,33 @@ func (o *{{ .TerraformType }}{{ .ModelOrObject }}) CopyToPango(ctx context.Conte
{{- end }}
{{- end }}
result := &{{ .PangoReturnType }}{
if (*obj) == nil {
*obj = new({{ .PangoReturnType }})
}
{{- if .HasEntryName }}
Name: o.Name.ValueString(),
(*obj).Name = o.Name.ValueString()
{{- end }}
{{- range .Params }}
{{- if eq .Type "" }}
{{ .Name.CamelCase }}: {{ .Name.LowerCamelCase }}_entry,
(*obj).{{ .Name.CamelCase }} = {{ .Name.LowerCamelCase }}_entry
{{- else if eq .Type "list" }}
{{ .Name.CamelCase }}: {{ .Name.LowerCamelCase }}_pango_entries,
(*obj).{{ .Name.CamelCase }} = {{ .Name.LowerCamelCase }}_pango_entries
{{- else }}
{{ .Name.CamelCase }}: {{ .Name.LowerCamelCase }}_value,
(*obj).{{ .Name.CamelCase }} = {{ .Name.LowerCamelCase }}_value
{{- end }}
{{- end }}
{{- range .OneOf }}
{{- if eq .Type "" }}
{{ .Name.CamelCase }}: {{ .Name.LowerCamelCase }}_entry,
(*obj).{{ .Name.CamelCase }} = {{ .Name.LowerCamelCase }}_entry
{{- else if eq .Type "list" }}
{{ .Name.CamelCase }}: {{ .Name.LowerCamelCase }}_pango_entries,
(*obj).{{ .Name.CamelCase }} = {{ .Name.LowerCamelCase }}_pango_entries
{{- else }}
{{ .Name.CamelCase }}: {{ .Name.LowerCamelCase }}_value,
(*obj).{{ .Name.CamelCase }} = {{ .Name.LowerCamelCase }}_value
{{- end }}
{{- end }}
}
return result, diags
return diags
}
{{- end }}
`
Expand Down Expand Up @@ -407,23 +421,24 @@ var {{ .Name.LowerCamelCase }}_list types.List
if obj.{{ .Name.CamelCase }} != nil {
{{ $result }}_object = new({{ $.Spec.TerraformType }}{{ .Name.CamelCase }}Object)
var {{ $diag }} diag.Diagnostics
{{ $diag }} = {{ $result }}_object.CopyFromPango(ctx, obj.{{ .Name.CamelCase }}, encrypted)
diags.Append({{ $diag }}...)
diags.Append({{ $result }}_object.CopyFromPango(ctx, obj.{{ .Name.CamelCase }}, encrypted)...)
if diags.HasError() {
return diags
}
}
{{- end }}
{{- end }}
{{- define "terraformCreateEntryAssignment" }}
{{- range .Params }}
{{- if eq .Type "" }}
{{- template "terraformCreateEntryAssignmentForParam" Map "Spec" $ "Parameter" . }}
{{- template "EntryAssignmentForParam" Map "Spec" $ "Parameter" . }}
{{- end }}
{{- end }}
{{- range .OneOf }}
{{- if eq .Type "" }}
{{- template "terraformCreateEntryAssignmentForParam" Map "Spec" $ "Parameter" . }}
{{- template "EntryAssignmentForParam" Map "Spec" $ "Parameter" . }}
{{- end }}
{{- end }}
{{- end }}
Expand Down
114 changes: 67 additions & 47 deletions pkg/translate/terraform_provider/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -410,10 +410,8 @@ state.{{ .ListAttribute.CamelCase }}.ElementsAs(ctx, &elements, false)
entries := make([]*{{ $resourceSDKStructName }}, len(elements))
idx := 0
for name, elt := range elements {
var list_diags diag.Diagnostics
var entry *{{ .resourceSDKName }}.{{ .EntryOrConfig }}
entry, list_diags = elt.CopyToPango(ctx, {{ $ev }})
resp.Diagnostics.Append(list_diags...)
resp.Diagnostics.Append(elt.CopyToPango(ctx, &entry, {{ $ev }})...)
if resp.Diagnostics.HasError() {
return
}
Expand All @@ -433,8 +431,7 @@ for _, elt := range created {
continue
}
var object {{ $resourceTFStructName }}
copy_diags := object.CopyFromPango(ctx, elt, {{ $ev }})
resp.Diagnostics.Append(copy_diags...)
resp.Diagnostics.Append(object.CopyFromPango(ctx, elt, {{ $ev }})...)
if resp.Diagnostics.HasError() {
return
}
Expand Down Expand Up @@ -490,10 +487,8 @@ var elements []{{ $resourceTFStructName }}
state.{{ .ListAttribute.CamelCase }}.ElementsAs(ctx, &elements, false)
entries := make([]*{{ $resourceSDKStructName }}, len(elements))
for idx, elt := range elements {
var list_diags diag.Diagnostics
var entry *{{ $resourceSDKStructName }}
entry, list_diags = elt.CopyToPango(ctx, {{ $ev }})
resp.Diagnostics.Append(list_diags...)
resp.Diagnostics.Append(elt.CopyToPango(ctx, &entry, {{ $ev }})...)
if resp.Diagnostics.HasError() {
return
}
Expand Down Expand Up @@ -614,15 +609,13 @@ const resourceCreateFunction = `
// Load the desired config.
var obj *{{ .resourceSDKName }}.{{ .EntryOrConfig }}
{{ $ev := "nil" }}
{{- if .HasEncryptedResources }}
{{ $ev = "&ev" }}
ev := make(map[string]types.String)
{{- end }}
obj, diags := state.CopyToPango(ctx, {{ $ev }})
resp.Diagnostics.Append(diags...)
if diags.HasError() {
resp.Diagnostics.Append(state.CopyToPango(ctx, &obj, {{ $ev }})...)
if resp.Diagnostics.HasError() {
return
}
Expand Down Expand Up @@ -730,8 +723,8 @@ if resp.Diagnostics.HasError() {
entries := make([]*{{ $resourceSDKStructName }}, 0, len(elements))
for name, elt := range elements {
entry, err := elt.CopyToPango(ctx, {{ $ev }})
resp.Diagnostics.Append(err...)
var entry *{{ $resourceSDKStructName }}
resp.Diagnostics.Append(elt.CopyToPango(ctx, &entry, {{ $ev }})...)
if resp.Diagnostics.HasError() {
return
}
Expand Down Expand Up @@ -818,8 +811,8 @@ var elements []{{ $resourceTFStructName }}
state.{{ .ListAttribute.CamelCase }}.ElementsAs(ctx, &elements, false)
entries := make([]*{{ $resourceSDKStructName }}, 0, len(elements))
for _, elt := range elements {
entry, err := elt.CopyToPango(ctx, {{ $ev }})
resp.Diagnostics.Append(err...)
var entry *{{ $resourceSDKStructName }}
resp.Diagnostics.Append(elt.CopyToPango(ctx, &entry, {{ $ev }})...)
if resp.Diagnostics.HasError() {
return
}
Expand Down Expand Up @@ -985,10 +978,8 @@ state.{{ .ListAttribute.CamelCase }}.ElementsAs(ctx, &elements, false)
stateEntries := make([]*{{ $resourceSDKStructName }}, len(elements))
idx := 0
for name, elt := range elements {
var list_diags diag.Diagnostics
var entry *{{ $resourceSDKStructName }}
entry, list_diags = elt.CopyToPango(ctx, nil)
resp.Diagnostics.Append(list_diags...)
resp.Diagnostics.Append(elt.CopyToPango(ctx, &entry, nil)...)
if resp.Diagnostics.HasError() {
return
}
Expand All @@ -997,17 +988,27 @@ for name, elt := range elements {
idx++
}
existing, err := r.manager.ReadMany(ctx, location, stateEntries)
if err != nil && !sdkerrors.IsObjectNotFound(err) {
resp.Diagnostics.AddError("Error while reading entries from the server", err.Error())
return
}
existingEntriesByName := make(map[string]*{{ $resourceSDKStructName }}, len(existing))
for _, elt := range existing {
existingEntriesByName[elt.Name] = elt
}
plan.{{ .ListAttribute.CamelCase }}.ElementsAs(ctx, &elements, false)
planEntries := make([]*{{ $resourceSDKStructName }}, len(elements))
idx = 0
for name, elt := range elements {
var list_diags diag.Diagnostics
var entry *{{ $resourceSDKStructName }}
entry, list_diags = elt.CopyToPango(ctx, nil)
resp.Diagnostics.Append(list_diags...)
entry, _ := existingEntriesByName[name]
resp.Diagnostics.Append(elt.CopyToPango(ctx, &entry, nil)...)
if resp.Diagnostics.HasError() {
return
}
entry.Name = name
planEntries[idx] = entry
idx++
Expand Down Expand Up @@ -1065,37 +1066,45 @@ var elements []{{ $resourceTFStructName }}
state.{{ .ListAttribute.CamelCase }}.ElementsAs(ctx, &elements, false)
stateEntries := make([]*{{ $resourceSDKStructName }}, len(elements))
for idx, elt := range elements {
var list_diags diag.Diagnostics
var entry *{{ $resourceSDKStructName }}
entry, list_diags = elt.CopyToPango(ctx, nil)
resp.Diagnostics.Append(list_diags...)
resp.Diagnostics.Append(elt.CopyToPango(ctx, &entry, nil)...)
if resp.Diagnostics.HasError() {
return
}
stateEntries[idx] = entry
}
{{ $exhaustive := "sdkmanager.NonExhaustive" }}
{{- if .Exhaustive }}
{{ $exhaustive = "sdkmanager.Exhaustive" }}
trueValue := true
position := rule.Position{First: &trueValue}
{{- else }}
position := state.Position.CopyToPango()
{{- end }}
existing, err := r.manager.ReadMany(ctx, location, stateEntries, {{ $exhaustive }})
if err != nil && !sdkerrors.IsObjectNotFound(err) {
resp.Diagnostics.AddError("Error while reading entries from the server", err.Error())
return
}
existingEntriesByName := make(map[string]*{{ $resourceSDKStructName }}, len(existing))
for _, elt := range existing {
existingEntriesByName[elt.Name] = elt
}
plan.{{ .ListAttribute.CamelCase }}.ElementsAs(ctx, &elements, false)
planEntries := make([]*{{ $resourceSDKStructName }}, len(elements))
for idx, elt := range elements {
var list_diags diag.Diagnostics
var entry *{{ $resourceSDKStructName }}
entry, list_diags = elt.CopyToPango(ctx, nil)
resp.Diagnostics.Append(list_diags...)
entry, _ := existingEntriesByName[elt.Name.ValueString()]
resp.Diagnostics.Append(elt.CopyToPango(ctx, &entry, nil)...)
if resp.Diagnostics.HasError() {
return
}
planEntries[idx] = entry
}
{{ $exhaustive := "sdkmanager.NonExhaustive" }}
{{- if .Exhaustive }}
{{ $exhaustive = "sdkmanager.Exhaustive" }}
trueValue := true
position := rule.Position{First: &trueValue}
{{- else }}
position := state.Position.CopyToPango()
{{- end }}
processed, err := r.manager.UpdateMany(ctx, location, stateEntries, planEntries, {{ $exhaustive }}, position)
if err != nil {
resp.Diagnostics.AddError("Failed to udpate entries", err.Error())
Expand Down Expand Up @@ -1123,6 +1132,8 @@ resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
`

const resourceUpdateFunction = `
{{ $resourceSDKStructName := printf "%s.%s" .resourceSDKName .EntryOrConfig }}
var plan, state {{ .structName }}Model
resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
Expand Down Expand Up @@ -1159,10 +1170,17 @@ const resourceUpdateFunction = `
return
}
// Create the service.
{{- if .HasEntryName }}
obj, err := r.manager.Read(ctx, loc.Location, loc.Name)
{{- else }}
obj, err := r.manager.Read(ctx, loc.Location)
{{- end }}
if err != nil {
resp.Diagnostics.AddError("Error in update", err.Error())
return
}
obj, copy_diags := plan.CopyToPango(ctx, {{ $ev }})
resp.Diagnostics.Append(copy_diags...)
resp.Diagnostics.Append(plan.CopyToPango(ctx, &obj, {{ $ev }})...)
if resp.Diagnostics.HasError() {
return
}
Expand Down Expand Up @@ -1197,7 +1215,7 @@ const resourceUpdateFunction = `
}
state.Tfid = types.StringValue(tfid)
copy_diags = state.CopyFromPango(ctx, updated, {{ $ev }})
copy_diags := state.CopyFromPango(ctx, updated, {{ $ev }})
{{- if .HasEncryptedResources }}
ev_map, ev_diags := types.MapValueFrom(ctx, types.StringType, ev)
state.EncryptedValues = ev_map
Expand Down Expand Up @@ -1264,6 +1282,8 @@ if err != nil {
`

const resourceDeleteFunction = `
{{ $resourceSDKStructName := printf "%s.%s" .resourceSDKName .EntryOrConfig }}
var state {{ .structName }}Model
resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
if resp.Diagnostics.HasError() {
Expand Down Expand Up @@ -1304,14 +1324,14 @@ const resourceDeleteFunction = `
}
{{- else }}
{{- $ev := "nil" }}
{{- if .HasEncryptedResources }}
{{- $ev = "&ev" }}
ev := make(map[string]types.String)
obj, diags := state.CopyToPango(ctx, &ev)
{{- else }}
obj, diags := state.CopyToPango(ctx, nil)
{{- end }}
resp.Diagnostics.Append(diags...)
if diags.HasError() {
var obj *{{ $resourceSDKStructName }}
resp.Diagnostics.Append(state.CopyToPango(ctx, &obj, {{ $ev }})...)
if resp.Diagnostics.HasError() {
return
}
Expand Down
6 changes: 5 additions & 1 deletion pkg/translate/terraform_provider/terraform_provider_file.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,9 +186,13 @@ func (g *GenerateTerraformProvider) GenerateTerraformResource(resourceTyp proper
switch resourceTyp {
case properties.ResourceUuid:
terraformProvider.ImportManager.AddSdkImport("github.com/PaloAltoNetworks/pango/rule", "")
terraformProvider.ImportManager.AddSdkImport("github.com/PaloAltoNetworks/pango/errors", "sdkerrors")
case properties.ResourceEntry:
case properties.ResourceUuidPlural:
case properties.ResourceEntryPlural, properties.ResourceCustom:
terraformProvider.ImportManager.AddSdkImport("github.com/PaloAltoNetworks/pango/errors", "sdkerrors")
case properties.ResourceEntryPlural:
terraformProvider.ImportManager.AddSdkImport("github.com/PaloAltoNetworks/pango/errors", "sdkerrors")
case properties.ResourceCustom:
}

// Generate Resource with entry style
Expand Down

0 comments on commit d61ac46

Please sign in to comment.