Skip to content

Commit

Permalink
Bridge gap between Terraform and API for AlloyDB (#8781) (#6363)
Browse files Browse the repository at this point in the history
* Add display name to backup

* Add alll the fields for backup

* Fix indentation

* Fix indentation

* Fix documentation and  attribute type

* Add attributes for cluster and instance with tests

* Remove annotations and displayName as not supported by GET API

* Misc

* Mark queryInsightsConfig as default_from_api instead of its sub-fields

* Mark Backup type as default_from_api

* Delete ignore_only section in alloydb_backup_basic

* Re-run tests

* Comment out tests failing due to networking service bug

Signed-off-by: Modular Magician <[email protected]>
  • Loading branch information
modular-magician authored Sep 25, 2023
1 parent 803502a commit 517ddf8
Show file tree
Hide file tree
Showing 9 changed files with 645 additions and 39 deletions.
4 changes: 4 additions & 0 deletions .changelog/8781.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
```release-note:enhancement
alloydb: added additional fields to `google_alloydb_instance` and `google_alloydb_backup`

```
296 changes: 269 additions & 27 deletions google-beta/services/alloydb/resource_alloydb_backup.go

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ resource "google_alloydb_backup" "default" {
cluster_name = google_alloydb_cluster.default.name
description = "example description"
type = "ON_DEMAND"
labels = {
"label" = "key"
}
Expand Down
99 changes: 99 additions & 0 deletions google-beta/services/alloydb/resource_alloydb_cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,13 @@ func ResourceAlloydbCluster() *schema.Resource {
ForceNew: true,
Description: `The location where the alloydb cluster should reside.`,
},
"annotations": {
Type: schema.TypeMap,
Optional: true,
Description: `Annotations to allow client tools to store small amount of arbitrary data. This is distinct from labels. https://google.aip.dev/128
An object containing a list of "key": value pairs. Example: { "name": "wrench", "mass": "1.3kg", "count": "3" }.`,
Elem: &schema.Schema{Type: schema.TypeString},
},
"automated_backup_policy": {
Type: schema.TypeList,
Computed: true,
Expand Down Expand Up @@ -261,6 +268,11 @@ If not set, defaults to 14 days.`,
},
},
},
"etag": {
Type: schema.TypeString,
Optional: true,
Description: `For Resource freshness validation (https://google.aip.dev/154)`,
},
"initial_user": {
Type: schema.TypeList,
Optional: true,
Expand Down Expand Up @@ -485,6 +497,18 @@ It is specified in the form: "projects/{projectNumber}/global/networks/{network_
Computed: true,
Description: `The name of the cluster resource.`,
},
"reconciling": {
Type: schema.TypeBool,
Computed: true,
Description: `Output only. Reconciling (https://google.aip.dev/128#reconciliation).
Set to true if the current state of Cluster does not match the user's intended state, and the service is actively updating the resource to reconcile them.
This can happen due to user-triggered updates or system actions like failover or maintenance.`,
},
"state": {
Type: schema.TypeString,
Computed: true,
Description: `Output only. The current serving state of the cluster.`,
},
"uid": {
Type: schema.TypeString,
Computed: true,
Expand Down Expand Up @@ -539,6 +563,18 @@ func resourceAlloydbClusterCreate(d *schema.ResourceData, meta interface{}) erro
} else if v, ok := d.GetOkExists("display_name"); !tpgresource.IsEmptyValue(reflect.ValueOf(displayNameProp)) && (ok || !reflect.DeepEqual(v, displayNameProp)) {
obj["displayName"] = displayNameProp
}
etagProp, err := expandAlloydbClusterEtag(d.Get("etag"), d, config)
if err != nil {
return err
} else if v, ok := d.GetOkExists("etag"); !tpgresource.IsEmptyValue(reflect.ValueOf(etagProp)) && (ok || !reflect.DeepEqual(v, etagProp)) {
obj["etag"] = etagProp
}
annotationsProp, err := expandAlloydbClusterAnnotations(d.Get("annotations"), d, config)
if err != nil {
return err
} else if v, ok := d.GetOkExists("annotations"); !tpgresource.IsEmptyValue(reflect.ValueOf(annotationsProp)) && (ok || !reflect.DeepEqual(v, annotationsProp)) {
obj["annotations"] = annotationsProp
}
initialUserProp, err := expandAlloydbClusterInitialUser(d.Get("initial_user"), d, config)
if err != nil {
return err
Expand Down Expand Up @@ -724,6 +760,18 @@ func resourceAlloydbClusterRead(d *schema.ResourceData, meta interface{}) error
if err := d.Set("display_name", flattenAlloydbClusterDisplayName(res["displayName"], d, config)); err != nil {
return fmt.Errorf("Error reading Cluster: %s", err)
}
if err := d.Set("etag", flattenAlloydbClusterEtag(res["etag"], d, config)); err != nil {
return fmt.Errorf("Error reading Cluster: %s", err)
}
if err := d.Set("reconciling", flattenAlloydbClusterReconciling(res["reconciling"], d, config)); err != nil {
return fmt.Errorf("Error reading Cluster: %s", err)
}
if err := d.Set("state", flattenAlloydbClusterState(res["state"], d, config)); err != nil {
return fmt.Errorf("Error reading Cluster: %s", err)
}
if err := d.Set("annotations", flattenAlloydbClusterAnnotations(res["annotations"], d, config)); err != nil {
return fmt.Errorf("Error reading Cluster: %s", err)
}
if err := d.Set("database_version", flattenAlloydbClusterDatabaseVersion(res["databaseVersion"], d, config)); err != nil {
return fmt.Errorf("Error reading Cluster: %s", err)
}
Expand Down Expand Up @@ -789,6 +837,18 @@ func resourceAlloydbClusterUpdate(d *schema.ResourceData, meta interface{}) erro
} else if v, ok := d.GetOkExists("display_name"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, displayNameProp)) {
obj["displayName"] = displayNameProp
}
etagProp, err := expandAlloydbClusterEtag(d.Get("etag"), d, config)
if err != nil {
return err
} else if v, ok := d.GetOkExists("etag"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, etagProp)) {
obj["etag"] = etagProp
}
annotationsProp, err := expandAlloydbClusterAnnotations(d.Get("annotations"), d, config)
if err != nil {
return err
} else if v, ok := d.GetOkExists("annotations"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, annotationsProp)) {
obj["annotations"] = annotationsProp
}
initialUserProp, err := expandAlloydbClusterInitialUser(d.Get("initial_user"), d, config)
if err != nil {
return err
Expand Down Expand Up @@ -836,6 +896,14 @@ func resourceAlloydbClusterUpdate(d *schema.ResourceData, meta interface{}) erro
updateMask = append(updateMask, "displayName")
}

if d.HasChange("etag") {
updateMask = append(updateMask, "etag")
}

if d.HasChange("annotations") {
updateMask = append(updateMask, "annotations")
}

if d.HasChange("initial_user") {
updateMask = append(updateMask, "initialUser")
}
Expand Down Expand Up @@ -1097,6 +1165,22 @@ func flattenAlloydbClusterDisplayName(v interface{}, d *schema.ResourceData, con
return v
}

func flattenAlloydbClusterEtag(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
return v
}

func flattenAlloydbClusterReconciling(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
return v
}

func flattenAlloydbClusterState(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
return v
}

func flattenAlloydbClusterAnnotations(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
return v
}

func flattenAlloydbClusterDatabaseVersion(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
return v
}
Expand Down Expand Up @@ -1494,6 +1578,21 @@ func expandAlloydbClusterDisplayName(v interface{}, d tpgresource.TerraformResou
return v, nil
}

func expandAlloydbClusterEtag(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
return v, nil
}

func expandAlloydbClusterAnnotations(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (map[string]string, error) {
if v == nil {
return map[string]string{}, nil
}
m := make(map[string]string)
for k, val := range v.(map[string]interface{}) {
m[k] = val.(string)
}
return m, nil
}

func expandAlloydbClusterInitialUser(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
l := v.([]interface{})
if len(l) == 0 || l[0] == nil {
Expand Down
167 changes: 167 additions & 0 deletions google-beta/services/alloydb/resource_alloydb_instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,37 @@ can have regional availability (nodes are present in 2 or more zones in a region
},
},
},
"query_insights_config": {
Type: schema.TypeList,
Computed: true,
Optional: true,
Description: `Configuration for query insights.`,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"query_plans_per_minute": {
Type: schema.TypeInt,
Optional: true,
Description: `Number of query execution plans captured by Insights per minute for all queries combined. The default value is 5. Any integer between 0 and 20 is considered valid.`,
},
"query_string_length": {
Type: schema.TypeInt,
Optional: true,
Description: `Query string length. The default value is 1024. Any integer between 256 and 4500 is considered valid.`,
},
"record_application_tags": {
Type: schema.TypeBool,
Optional: true,
Description: `Record application tags for an instance. This flag is turned "on" by default.`,
},
"record_client_address": {
Type: schema.TypeBool,
Optional: true,
Description: `Record client address for an instance. Client address is PII information. This flag is turned "on" by default.`,
},
},
},
},
"read_pool_config": {
Type: schema.TypeList,
Optional: true,
Expand Down Expand Up @@ -233,6 +264,12 @@ func resourceAlloydbInstanceCreate(d *schema.ResourceData, meta interface{}) err
} else if v, ok := d.GetOkExists("instance_type"); !tpgresource.IsEmptyValue(reflect.ValueOf(instanceTypeProp)) && (ok || !reflect.DeepEqual(v, instanceTypeProp)) {
obj["instanceType"] = instanceTypeProp
}
queryInsightsConfigProp, err := expandAlloydbInstanceQueryInsightsConfig(d.Get("query_insights_config"), d, config)
if err != nil {
return err
} else if v, ok := d.GetOkExists("query_insights_config"); !tpgresource.IsEmptyValue(reflect.ValueOf(queryInsightsConfigProp)) && (ok || !reflect.DeepEqual(v, queryInsightsConfigProp)) {
obj["queryInsightsConfig"] = queryInsightsConfigProp
}
readPoolConfigProp, err := expandAlloydbInstanceReadPoolConfig(d.Get("read_pool_config"), d, config)
if err != nil {
return err
Expand Down Expand Up @@ -363,6 +400,9 @@ func resourceAlloydbInstanceRead(d *schema.ResourceData, meta interface{}) error
if err := d.Set("ip_address", flattenAlloydbInstanceIpAddress(res["ipAddress"], d, config)); err != nil {
return fmt.Errorf("Error reading Instance: %s", err)
}
if err := d.Set("query_insights_config", flattenAlloydbInstanceQueryInsightsConfig(res["queryInsightsConfig"], d, config)); err != nil {
return fmt.Errorf("Error reading Instance: %s", err)
}
if err := d.Set("read_pool_config", flattenAlloydbInstanceReadPoolConfig(res["readPoolConfig"], d, config)); err != nil {
return fmt.Errorf("Error reading Instance: %s", err)
}
Expand Down Expand Up @@ -420,6 +460,12 @@ func resourceAlloydbInstanceUpdate(d *schema.ResourceData, meta interface{}) err
} else if v, ok := d.GetOkExists("availability_type"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, availabilityTypeProp)) {
obj["availabilityType"] = availabilityTypeProp
}
queryInsightsConfigProp, err := expandAlloydbInstanceQueryInsightsConfig(d.Get("query_insights_config"), d, config)
if err != nil {
return err
} else if v, ok := d.GetOkExists("query_insights_config"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, queryInsightsConfigProp)) {
obj["queryInsightsConfig"] = queryInsightsConfigProp
}
readPoolConfigProp, err := expandAlloydbInstanceReadPoolConfig(d.Get("read_pool_config"), d, config)
if err != nil {
return err
Expand Down Expand Up @@ -465,6 +511,10 @@ func resourceAlloydbInstanceUpdate(d *schema.ResourceData, meta interface{}) err
updateMask = append(updateMask, "availabilityType")
}

if d.HasChange("query_insights_config") {
updateMask = append(updateMask, "queryInsightsConfig")
}

if d.HasChange("read_pool_config") {
updateMask = append(updateMask, "readPoolConfig")
}
Expand Down Expand Up @@ -631,6 +681,67 @@ func flattenAlloydbInstanceIpAddress(v interface{}, d *schema.ResourceData, conf
return v
}

func flattenAlloydbInstanceQueryInsightsConfig(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
if v == nil {
return nil
}
original := v.(map[string]interface{})
if len(original) == 0 {
return nil
}
transformed := make(map[string]interface{})
transformed["query_string_length"] =
flattenAlloydbInstanceQueryInsightsConfigQueryStringLength(original["queryStringLength"], d, config)
transformed["record_application_tags"] =
flattenAlloydbInstanceQueryInsightsConfigRecordApplicationTags(original["recordApplicationTags"], d, config)
transformed["record_client_address"] =
flattenAlloydbInstanceQueryInsightsConfigRecordClientAddress(original["recordClientAddress"], d, config)
transformed["query_plans_per_minute"] =
flattenAlloydbInstanceQueryInsightsConfigQueryPlansPerMinute(original["queryPlansPerMinute"], d, config)
return []interface{}{transformed}
}
func flattenAlloydbInstanceQueryInsightsConfigQueryStringLength(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
// Handles the string fixed64 format
if strVal, ok := v.(string); ok {
if intVal, err := tpgresource.StringToFixed64(strVal); err == nil {
return intVal
}
}

// number values are represented as float64
if floatVal, ok := v.(float64); ok {
intVal := int(floatVal)
return intVal
}

return v // let terraform core handle it otherwise
}

func flattenAlloydbInstanceQueryInsightsConfigRecordApplicationTags(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
return v
}

func flattenAlloydbInstanceQueryInsightsConfigRecordClientAddress(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
return v
}

func flattenAlloydbInstanceQueryInsightsConfigQueryPlansPerMinute(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
// Handles the string fixed64 format
if strVal, ok := v.(string); ok {
if intVal, err := tpgresource.StringToFixed64(strVal); err == nil {
return intVal
}
}

// number values are represented as float64
if floatVal, ok := v.(float64); ok {
intVal := int(floatVal)
return intVal
}

return v // let terraform core handle it otherwise
}

func flattenAlloydbInstanceReadPoolConfig(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
if v == nil {
return nil
Expand Down Expand Up @@ -740,6 +851,62 @@ func expandAlloydbInstanceInstanceType(v interface{}, d tpgresource.TerraformRes
return v, nil
}

func expandAlloydbInstanceQueryInsightsConfig(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
l := v.([]interface{})
if len(l) == 0 || l[0] == nil {
return nil, nil
}
raw := l[0]
original := raw.(map[string]interface{})
transformed := make(map[string]interface{})

transformedQueryStringLength, err := expandAlloydbInstanceQueryInsightsConfigQueryStringLength(original["query_string_length"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedQueryStringLength); val.IsValid() && !tpgresource.IsEmptyValue(val) {
transformed["queryStringLength"] = transformedQueryStringLength
}

transformedRecordApplicationTags, err := expandAlloydbInstanceQueryInsightsConfigRecordApplicationTags(original["record_application_tags"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedRecordApplicationTags); val.IsValid() && !tpgresource.IsEmptyValue(val) {
transformed["recordApplicationTags"] = transformedRecordApplicationTags
}

transformedRecordClientAddress, err := expandAlloydbInstanceQueryInsightsConfigRecordClientAddress(original["record_client_address"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedRecordClientAddress); val.IsValid() && !tpgresource.IsEmptyValue(val) {
transformed["recordClientAddress"] = transformedRecordClientAddress
}

transformedQueryPlansPerMinute, err := expandAlloydbInstanceQueryInsightsConfigQueryPlansPerMinute(original["query_plans_per_minute"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedQueryPlansPerMinute); val.IsValid() && !tpgresource.IsEmptyValue(val) {
transformed["queryPlansPerMinute"] = transformedQueryPlansPerMinute
}

return transformed, nil
}

func expandAlloydbInstanceQueryInsightsConfigQueryStringLength(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
return v, nil
}

func expandAlloydbInstanceQueryInsightsConfigRecordApplicationTags(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
return v, nil
}

func expandAlloydbInstanceQueryInsightsConfigRecordClientAddress(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
return v, nil
}

func expandAlloydbInstanceQueryInsightsConfigQueryPlansPerMinute(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
return v, nil
}

func expandAlloydbInstanceReadPoolConfig(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
l := v.([]interface{})
if len(l) == 0 || l[0] == nil {
Expand Down
Loading

0 comments on commit 517ddf8

Please sign in to comment.