Skip to content

Commit

Permalink
add Read command to go template (GoogleCloudPlatform#10550)
Browse files Browse the repository at this point in the history
  • Loading branch information
NickElliot authored and pengq-google committed May 21, 2024
1 parent 97f7c0b commit 9574a77
Show file tree
Hide file tree
Showing 2 changed files with 270 additions and 7 deletions.
17 changes: 11 additions & 6 deletions mmv1/api/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -964,13 +964,18 @@ func (r Resource) GetIdFormat() string {
// ====================
// Template Methods
// ====================
// Functions used to create slices of resource properties that could not otherwise be called from within generating templates.

// Prints a dot notation path to where the field is nested within the parent
// object when called on a property. eg: parent.meta.label.foo
// Redefined on Resource to terminate the calls up the parent chain.
func (r Resource) ReadProperties() []*Type {
return google.Reject(r.GettableProperties(), func(p *Type) bool {
return p.IgnoreRead
})
}

// checks a resource for if it has properties that have FlattenObject=true on fields where IgnoreRead=false
// used to decide whether or not to import "google.golang.org/api/googleapi"
func (r Resource) FlattenedProperties() []*Type {
return google.Select(google.Reject(r.GettableProperties(), func(p *Type) bool { return p.IgnoreRead }), func(p *Type) bool { return p.FlattenObject })
return google.Select(r.ReadProperties(), func(p *Type) bool {
return p.FlattenObject
})
}


260 changes: 259 additions & 1 deletion mmv1/templates/terraform/resource.go.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,8 @@ func resource{{ $.ResourceName -}}Create(d *schema.ResourceData, meta interface{
}

log.Printf("[DEBUG] Creating new {{ $.Name -}}: %#v", obj)
{{if $.NestedQuery.ModifyByPatch -}}
{{if $.NestedQuery -}}
{{if $.NestedQuery.ModifyByPatch }}
{{/*# Keep this after mutex - patch request data relies on current resource state */}}
obj, err = resource{{ $.ResourceName -}}PatchCreateEncoder(d, meta, obj)
if err != nil {
Expand All @@ -239,6 +240,7 @@ func resource{{ $.ResourceName -}}Create(d *schema.ResourceData, meta interface{
return err
}
{{- end}}
{{- end}}
{{- end}}
billingProject := ""

Expand Down Expand Up @@ -337,6 +339,7 @@ func resource{{ $.ResourceName -}}Create(d *schema.ResourceData, meta interface{
}
{{- end}}

{{if $.NestedQuery -}}
{{if $.NestedQuery.Keys -}}
if _, ok := opRes["{{ index $.NestedQuery.Keys 0 -}}"]; ok {
opRes, err = flattenNested{{ $.ResourceName -}}(d, meta, opRes)
Expand All @@ -356,6 +359,7 @@ func resource{{ $.ResourceName -}}Create(d *schema.ResourceData, meta interface{
return err
}
{{- end}}
{{- end}}
{{- end}}

// This may have caused the ID to update - update it if so.
Expand Down Expand Up @@ -409,3 +413,257 @@ func resource{{ $.ResourceName -}}Create(d *schema.ResourceData, meta interface{
return resource{{ $.ResourceName -}}Read(d, meta)
{{ end -}}
}

{{if ($.GetAsync.IsA "OpAsync")}}
func resource{{ $.ResourceName -}}PollRead(d *schema.ResourceData, meta interface{}) transport_tpg.PollReadFunc {
return func() (map[string]interface{}, error) {
{{if $.GetAsync.CustomPollRead -}}
//TODO custom poll read
{{ else -}}
config := meta.(*transport_tpg.Config)


url, err := tpgresource.ReplaceVars{{if $.LegacyLongFormProject -}}ForId{{ end -}}(d, config, "{{"{{"}}{{$.ProductMetadata.Name}}BasePath{{"}}"}}/{{$.SelfLinkUri}}")

if err != nil {
return nil, err
}

billingProject := ""

{{if $.HasProject -}}
project, err := tpgresource.GetProject(d, config)
if err != nil {
return nil, fmt.Errorf("Error fetching project for {{ $.Name -}}: %s", err)
}
{{if $.LegacyLongFormProject -}}
billingProject = strings.TrimPrefix(project, "projects/")
{{ else -}}
billingProject = project
{{- end}}
{{- end}}

{{if $.SupportsIndirectUserProjectOverride -}}
if parts := regexp.MustCompile(`projects\/([^\/]+)\/`).FindStringSubmatch(url); parts != nil {
billingProject = parts[1]
}
{{- end}}

// err == nil indicates that the billing_project value was found
if bp, err := tpgresource.GetBillingProject(d, config); err == nil {
billingProject = bp
}

userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent)
if err != nil {
return nil, err
}

res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{
Config: config,
Method: "{{ upper $.ReadVerb -}}",
Project: billingProject,
RawURL: url,
UserAgent: userAgent,
{{if $.ErrorRetryPredicates -}}
ErrorRetryPredicates: []transport_tpg.RetryErrorPredicateFunc{{"{"}}{{ join $.ErrorRetryPredicates "," -}}{{"}"}},
{{- end}}
{{if $.ErrorAbortPredicates -}}
ErrorAbortPredicates: []transport_tpg.RetryErrorPredicateFunc{{"{"}}{{ join $.ErrorRetryPredicates "," -}}{{"}"}},
{{- end}}
})
if err != nil {
return res, err
}
{{if $.NestedQuery -}}
res, err = flattenNested{{ $.ResourceName -}}(d, meta, res)
if err != nil {
return nil, err
}

if res == nil {
return nil, tpgresource.Fake404("nested", "{{ $.ResourceName }}")
}

{{- end}}
{{if $.CustomCode.Decoder -}}
res, err = resource{{ $.ResourceName -}}Decoder(d, meta, res)
if err != nil {
return nil, err
}
if res == nil {
return nil, tpgresource.Fake404("decoded", "{{ $.ResourceName }}")
}

{{- end}}
return res, nil
{{ end -}}
}
}
{{ end -}}

func resource{{ $.ResourceName -}}Read(d *schema.ResourceData, meta interface{}) error {
{{if $.SkipRead -}}
// This resource could not be read from the API.
return nil
{{ else -}}
config := meta.(*transport_tpg.Config)
userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent)
if err != nil {
return err
}

url, err := tpgresource.ReplaceVars{{if $.LegacyLongFormProject -}}ForId{{ end -}}(d, config, "{{"{{"}}{{$.ProductMetadata.Name}}BasePath{{"}}"}}/{{$.SelfLinkUri}}{{$.ReadQueryParams}}")
if err != nil {
return err
}

billingProject := ""

{{if $.HasProject -}}
project, err := tpgresource.GetProject(d, config)
if err != nil {
return fmt.Errorf("Error fetching project for {{ $.Name -}}: %s", err)
}
{{if $.LegacyLongFormProject -}}
billingProject = strings.TrimPrefix(project, "projects/")
{{ else -}}
billingProject = project
{{- end}}
{{- end}}

{{if $.SupportsIndirectUserProjectOverride -}}
if parts := regexp.MustCompile(`projects\/([^\/]+)\/`).FindStringSubmatch(url); parts != nil {
billingProject = parts[1]
}
{{- end}}

// err == nil indicates that the billing_project value was found
if bp, err := tpgresource.GetBillingProject(d, config); err == nil {
billingProject = bp
}

headers := make(http.Header)
{{ if $.CustomCode.PreRead -}}
//todo preread
{{ end }}
res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{
Config: config,
Method: "{{ upper $.ReadVerb -}}",
Project: billingProject,
RawURL: url,
UserAgent: userAgent,
{{if $.ErrorRetryPredicates -}}
ErrorRetryPredicates: []transport_tpg.RetryErrorPredicateFunc{{"{"}}{{ join $.ErrorRetryPredicates "," -}}{{"}"}},
{{- end}}
{{if $.ErrorAbortPredicates -}}
ErrorAbortPredicates: []transport_tpg.RetryErrorPredicateFunc{{"{"}}{{ join $.ErrorRetryPredicates "," -}}{{"}"}},
{{- end}}
})
if err != nil {
{{if $.ReadErrorTransform -}}
return transport_tpg.HandleNotFoundError({{ $.ReadErrorTransform }}(err), d, fmt.Sprintf("{{ $.ResourceName -}} %q", d.Id()))
{{ else -}}
return transport_tpg.HandleNotFoundError(err, d, fmt.Sprintf("{{ $.ResourceName -}} %q", d.Id()))
{{- end}}
}

{{if $.NestedQuery -}}
res, err = flattenNested{{ $.ResourceName -}}(d, meta, res)
if err != nil {
return err
}

if res == nil {
// Object isn't there any more - remove it from the state.
log.Printf("[DEBUG] Removing {{ $.ResourceName -}} because it couldn't be matched.")
d.SetId("")
return nil
}

{{- end}}

{{if $.CustomCode.Decoder -}}
res, err = resource{{ $.ResourceName -}}Decoder(d, meta, res)
if err != nil {
return err
}

if res == nil {
// Decoding the $ has resulted in it being gone. It may be marked deleted
log.Printf("[DEBUG] Removing {{ $.ResourceName -}} because it no longer exists.")
d.SetId("")
return nil
}

{{- end}}
{{- if $.VirtualFields -}}
// Explicitly set virtual fields to default values if unset
{{- range $prop := $.VirtualFields }}
{{ if $prop.DefaultValue -}}
if _, ok := d.GetOkExists("{{ $prop.Name -}}"); !ok {
if err := d.Set("{{ $prop.Name -}}", {{ $prop.DefaultValue -}}); err != nil {
return fmt.Errorf("Error setting {{ $prop.Name -}}: %s", err)
}
}
{{- end}}
{{- end}}
{{- end}}
{{if $.HasProject -}}
if err := d.Set("project", project); err != nil {
return fmt.Errorf("Error reading {{ $.Name -}}: %s", err)
}
{{- end}}

{{if $.HasRegion -}}
region, err := tpgresource.GetRegion(d, config)
if err != nil {
return err
}
if err := d.Set("region", region); err != nil {
return fmt.Errorf("Error reading {{ $.Name -}}: %s", err)
}
{{- end}}

{{if $.HasZone -}}
zone, err := tpgresource.GetZone(d, config)
if err != nil {
return err
}
if err := d.Set("zone", zone); err != nil {
return fmt.Errorf("Error reading {{ $.Name -}}: %s", err)
}
{{- end}}

{{- range $prop := $.ReadProperties }}
{{if $prop.FlattenObject -}}
// Terraform must set the top level schema field, but since this $ contains collapsed properties
// it's difficult to know what the top level should be. Instead we just loop over the map returned from flatten.
if flattenedProp := flatten{{ if $.NestedQuery -}}Nested{{end}}{{ $.ResourceName -}}{{ camelize $prop.Name "upper" -}}(res["{{ $prop.ApiName -}}"], d, config); flattenedProp != nil {
if gerr, ok := flattenedProp.(*googleapi.Error); ok {
return fmt.Errorf("Error reading {{ $.Name -}}: %s", gerr)
}
casted := flattenedProp.([]interface{})[0]
if casted != nil {
for k, v := range casted.(map[string]interface{}) {
if err := d.Set(k, v); err != nil {
return fmt.Errorf("Error setting %s: %s", k, err)
}
}
}
}
{{ else -}}
if err := d.Set("{{ underscore $prop.Name -}}", flatten{{ if $.NestedQuery -}}Nested{{end}}{{ $.ResourceName -}}{{ camelize $prop.Name "upper" -}}(res["{{ $prop.ApiName -}}"], d, config)); err != nil {
return fmt.Errorf("Error reading {{ $.Name -}}: %s", err)
}
{{- end}}
{{- end}}
{{if $.HasSelfLink -}}
if err := d.Set("self_link", tpgresource.ConvertSelfLinkToV1(res["selfLink"].(string))); err != nil {
return fmt.Errorf("Error reading {{ $.Name -}}: %s", err)
}
{{- end}}

return nil
{{ end -}}
}

0 comments on commit 9574a77

Please sign in to comment.