Skip to content

Commit

Permalink
Rewrite labels related functions (#10285)
Browse files Browse the repository at this point in the history
  • Loading branch information
zli82016 authored Mar 26, 2024
1 parent e6dbde8 commit 05e5d7c
Show file tree
Hide file tree
Showing 4 changed files with 206 additions and 132 deletions.
216 changes: 119 additions & 97 deletions mmv1/api/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -456,123 +456,145 @@ func (r Resource) GetIdentity() []*Type {

}

// TODO Q1
// def add_labels_related_fields(props, parent)
// props.each do |p|
// if p.is_a? Api::Type::KeyValueLabels
// add_labels_fields(props, parent, p)
// elsif p.is_a? Api::Type::KeyValueAnnotations
// add_annotations_fields(props, parent, p)
// elsif (p.is_a? Api::Type::NestedObject) && !p.all_properties.nil?
// p.properties = add_labels_related_fields(p.all_properties, p)
// end
// end
// props
// end
func (r *Resource) AddLabelsRelatedFields(props []*Type, parent *Type) []*Type {
for _, p := range props {
if p.IsA("KeyValueLabels") {
props = r.addLabelsFields(props, parent, p)
} else if p.IsA("KeyValueAnnotations") {
props = r.addAnnotationsFields(props, parent, p)
} else if p.IsA("NestedObject") && len(p.AllProperties()) > 0 {
p.Properties = r.AddLabelsRelatedFields(p.AllProperties(), p)
}
}
return props
}

// def add_labels_fields(props, parent, labels)
// @custom_diff ||= []
// if parent.nil? || parent.flatten_object
// @custom_diff.append('tpgresource.SetLabelsDiff')
// elsif parent.name == 'metadata'
// @custom_diff.append('tpgresource.SetMetadataLabelsDiff')
// end
func (r *Resource) addLabelsFields(props []*Type, parent *Type, labels *Type) []*Type {
if parent == nil || parent.FlattenObject {
r.CustomDiff = append(r.CustomDiff, "tpgresource.SetLabelsDiff")
} else if parent.Name == "metadata" {
r.CustomDiff = append(r.CustomDiff, "tpgresource.SetMetadataLabelsDiff")
}

// props << build_terraform_labels_field('labels', parent, labels)
// props << build_effective_labels_field('labels', labels)
terraformLabelsField := buildTerraformLabelsField("labels", parent, labels)
effectiveLabelsField := buildEffectiveLabelsField("labels", labels)
props = append(props, terraformLabelsField, effectiveLabelsField)

// // The effective_labels field is used to write to API, instead of the labels field.
// labels.ignore_write = true
// labels.description = "//{labels.description}\n\n//{get_labels_field_note(labels.name)}"
// return unless parent.nil?
// The effective_labels field is used to write to API, instead of the labels field.
labels.IgnoreWrite = true
labels.Description = fmt.Sprintf("%s\n\n%s", labels.Description, getLabelsFieldNote(labels.Name))

// labels.immutable = false
// end
if parent == nil {
labels.Immutable = false
}

return props
}

// def add_annotations_fields(props, parent, annotations)
// // The effective_annotations field is used to write to API,
// // instead of the annotations field.
// annotations.ignore_write = true
// note = get_labels_field_note(annotations.name)
// annotations.description = "//{annotations.description}\n\n//{note}"

// @custom_diff ||= []
// if parent.nil?
// @custom_diff.append('tpgresource.SetAnnotationsDiff')
// elsif parent.name == 'metadata'
// @custom_diff.append('tpgresource.SetMetadataAnnotationsDiff')
// end

// props << build_effective_labels_field('annotations', annotations)
// end
func (r *Resource) addAnnotationsFields(props []*Type, parent *Type, annotations *Type) []*Type {

// The effective_annotations field is used to write to API,
// instead of the annotations field.
annotations.IgnoreWrite = true
annotations.Description = fmt.Sprintf("%s\n\n%s", annotations.Description, getLabelsFieldNote(annotations.Name))

if parent == nil {
r.CustomDiff = append(r.CustomDiff, "tpgresource.SetAnnotationsDiff")
} else if parent.Name == "metadata" {
r.CustomDiff = append(r.CustomDiff, "tpgresource.SetMetadataAnnotationsDiff")
}

effectiveAnnotationsField := buildEffectiveLabelsField("annotations", annotations)
props = append(props, effectiveAnnotationsField)
return props
}

// def build_effective_labels_field(name, labels)
// description = "All of //{name} (key/value pairs)\
// present on the resource in GCP, including the //{name} configured through Terraform,\
// other clients and services."

// Api::Type::KeyValueEffectiveLabels.new(
// name: "effective//{name.capitalize}",
// output: true,
// api_name: name,
// description:,
// min_version: labels.field_min_version,
// update_verb: labels.update_verb,
// update_url: labels.update_url,
// immutable: labels.immutable
// )
// end
func buildEffectiveLabelsField(name string, labels *Type) *Type {
description := fmt.Sprintf("All of %s (key/value pairs) present on the resource in GCP, "+
"including the %s configured through Terraform, other clients and services.", name, name)

t := "KeyValueEffectiveLabels"
if name == "annotations" {
t = "KeyValueEffectiveAnnotations"
}

n := fmt.Sprintf("effective%s", strings.Title(name))

options := []func(*Type){
propertyWithType(t),
propertyWithOutput(true),
propertyWithDescription(description),
propertyWithMinVersion(labels.fieldMinVersion()),
propertyWithUpdateVerb(labels.UpdateVerb),
propertyWithUpdateUrl(labels.UpdateUrl),
propertyWithImmutable(labels.Immutable),
}
return NewProperty(n, name, options)
}

// def build_terraform_labels_field(name, parent, labels)
// description = "The combination of //{name} configured directly on the resource
// and default //{name} configured on the provider."

// immutable = if parent.nil?
// false
// else
// labels.immutable
// end

// Api::Type::KeyValueTerraformLabels.new(
// name: "terraform//{name.capitalize}",
// output: true,
// api_name: name,
// description:,
// min_version: labels.field_min_version,
// ignore_write: true,
// update_url: labels.update_url,
// immutable:
// )
// end
func buildTerraformLabelsField(name string, parent *Type, labels *Type) *Type {
description := fmt.Sprintf("The combination of %s configured directly on the resource "+
"and default %s configured on the provider.", name, name)

immutable := false
if parent != nil {
immutable = labels.Immutable
}

n := fmt.Sprintf("terraform%s", strings.Title(name))

options := []func(*Type){
propertyWithType("KeyValueTerraformLabels"),
propertyWithOutput(true),
propertyWithDescription(description),
propertyWithMinVersion(labels.fieldMinVersion()),
propertyWithIgnoreWrite(true),
propertyWithUpdateUrl(labels.UpdateUrl),
propertyWithImmutable(immutable),
}
return NewProperty(n, name, options)
}

// // Check if the resource has root "labels" field
// def root_labels?
// root_properties.each do |p|
// return true if p.is_a? Api::Type::KeyValueLabels
// end
// false
// end
func (r Resource) RootLabels() bool {
for _, p := range r.RootProperties() {
if p.IsA("KeyValueLabels") {
return true
}
}
return false
}

// // Return labels fields that should be added to ImportStateVerifyIgnore
// def ignore_read_labels_fields(props)
// fields = []
// props.each do |p|
// if (p.is_a? Api::Type::KeyValueLabels) ||
// (p.is_a? Api::Type::KeyValueTerraformLabels) ||
// (p.is_a? Api::Type::KeyValueAnnotations)
// fields << p.terraform_lineage
// elsif (p.is_a? Api::Type::NestedObject) && !p.all_properties.nil?
// fields.concat(ignore_read_labels_fields(p.all_properties))
// end
// end
// fields
// end
func (r Resource) IgnoreReadLabelsFields(props []*Type) []string {
fields := make([]string, 0)
for _, p := range props {
if p.IsA("KeyValueLabels") ||
p.IsA("KeyValueTerraformLabels") ||
p.IsA("KeyValueAnnotations") {
fields = append(fields, p.TerraformLineage())
} else if p.IsA("NestedObject") && len(p.AllProperties()) > 0 {
fields = google.Concat(fields, r.IgnoreReadLabelsFields(p.AllProperties()))
}
}
return fields
}

// def get_labels_field_note(title)
// "**Note**: This field is non-authoritative, and will only manage the //{title} present " \
// "in your configuration.
// Please refer to the field `effective_//{title}` for all of the //{title} present on the resource."
// end
func getLabelsFieldNote(title string) string {
return fmt.Sprintf(
"**Note**: This field is non-authoritative, and will only manage the %s present "+
"in your configuration.\n"+
"Please refer to the field `effective_%s` for all of the %s present on the resource.",
title, title, title)
}

// ====================
// Version-related methods
Expand Down
88 changes: 76 additions & 12 deletions mmv1/api/type.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,6 @@ import (
"github.com/GoogleCloudPlatform/magic-modules/mmv1/google"
)

// require 'api/object'
// require 'google/string_utils'
// require 'provider/terraform/validation'

// Represents a property type
type Type struct {
NamedObject `yaml:",inline"`
Expand Down Expand Up @@ -211,6 +207,11 @@ type Type struct {
// the field in documentation.
KeyDescription string `yaml:"key_description`

// ====================
// KeyValuePairs Fields
// ====================
IgnoreWrite bool `yaml:"ignore_write`

// ====================
// Schema Modifications
// ====================
Expand Down Expand Up @@ -878,10 +879,73 @@ func (t *Type) RootProperties() []*Type {
// end
// end

// // An array of string -> string key -> value pairs, such as labels.
// // While this is technically a map, it's split out because it's a much
// // simpler property to generate and means we can avoid conditional logic
// // in Map.
// An array of string -> string key -> value pairs, such as labels.
// While this is technically a map, it's split out because it's a much
// simpler property to generate and means we can avoid conditional logic
// in Map.

func NewProperty(name, apiName string, options []func(*Type)) *Type {
p := &Type{
NamedObject: NamedObject{
Name: name,
ApiName: apiName,
},
}

for _, option := range options {
option(p)
}
return p
}

func propertyWithType(t string) func(*Type) {
return func(p *Type) {
p.Type = t
}
}

func propertyWithOutput(output bool) func(*Type) {
return func(p *Type) {
p.Output = output
}
}

func propertyWithDescription(description string) func(*Type) {
return func(p *Type) {
p.Description = description
}
}

func propertyWithMinVersion(minVersion string) func(*Type) {
return func(p *Type) {
p.MinVersion = minVersion
}
}

func propertyWithUpdateVerb(updateVerb string) func(*Type) {
return func(p *Type) {
p.UpdateVerb = updateVerb
}
}

func propertyWithUpdateUrl(updateUrl string) func(*Type) {
return func(p *Type) {
p.UpdateUrl = updateUrl
}
}

func propertyWithImmutable(immutable bool) func(*Type) {
return func(p *Type) {
p.Immutable = immutable
}
}

func propertyWithIgnoreWrite(ignoreWrite bool) func(*Type) {
return func(p *Type) {
p.IgnoreWrite = ignoreWrite
}
}

// class KeyValuePairs < Composite
// // Ignore writing the "effective_labels" and "effective_annotations" fields to API.
// ignore_write
Expand Down Expand Up @@ -951,10 +1015,10 @@ func (t *Type) RootProperties() []*Type {
// end
// end

// func (t *Type) field_min_version
// @min_version
// end
// end
// def field_min_version
func (t Type) fieldMinVersion() string {
return t.MinVersion
}

// // An array of string -> string key -> value pairs used specifically for the "labels" field.
// // The field name with this type should be "labels" literally.
Expand Down
Loading

0 comments on commit 05e5d7c

Please sign in to comment.