Skip to content

Adding zone distribution mode in the Cluster resource for Memorystore Redis cluster #18307

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 90 additions & 0 deletions google/services/redis/resource_redis_cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,30 @@ https://cloud.google.com/memorystore/docs/cluster/supported-instance-configurati
If not provided, encryption is disabled for the cluster. Default value: "TRANSIT_ENCRYPTION_MODE_DISABLED" Possible values: ["TRANSIT_ENCRYPTION_MODE_UNSPECIFIED", "TRANSIT_ENCRYPTION_MODE_DISABLED", "TRANSIT_ENCRYPTION_MODE_SERVER_AUTHENTICATION"]`,
Default: "TRANSIT_ENCRYPTION_MODE_DISABLED",
},
"zone_distribution_config": {
Type: schema.TypeList,
Optional: true,
ForceNew: true,
Description: `Immutable. Zone distribution config for Memorystore Redis cluster.`,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"mode": {
Type: schema.TypeString,
Computed: true,
Optional: true,
ValidateFunc: verify.ValidateEnum([]string{"MULTI_ZONE", "SINGLE_ZONE", ""}),
Description: `Immutable. The mode for zone distribution for Memorystore Redis cluster.
If not provided, MULTI_ZONE will be used as default Possible values: ["MULTI_ZONE", "SINGLE_ZONE"]`,
},
"zone": {
Type: schema.TypeString,
Optional: true,
Description: `Immutable. The zone for single zone Memorystore Redis cluster.`,
},
},
},
},
"create_time": {
Type: schema.TypeString,
Computed: true,
Expand Down Expand Up @@ -299,6 +323,12 @@ func resourceRedisClusterCreate(d *schema.ResourceData, meta interface{}) error
} else if v, ok := d.GetOkExists("node_type"); !tpgresource.IsEmptyValue(reflect.ValueOf(nodeTypeProp)) && (ok || !reflect.DeepEqual(v, nodeTypeProp)) {
obj["nodeType"] = nodeTypeProp
}
zoneDistributionConfigProp, err := expandRedisClusterZoneDistributionConfig(d.Get("zone_distribution_config"), d, config)
if err != nil {
return err
} else if v, ok := d.GetOkExists("zone_distribution_config"); !tpgresource.IsEmptyValue(reflect.ValueOf(zoneDistributionConfigProp)) && (ok || !reflect.DeepEqual(v, zoneDistributionConfigProp)) {
obj["zoneDistributionConfig"] = zoneDistributionConfigProp
}
pscConfigsProp, err := expandRedisClusterPscConfigs(d.Get("psc_configs"), d, config)
if err != nil {
return err
Expand Down Expand Up @@ -448,6 +478,9 @@ func resourceRedisClusterRead(d *schema.ResourceData, meta interface{}) error {
if err := d.Set("node_type", flattenRedisClusterNodeType(res["nodeType"], d, config)); err != nil {
return fmt.Errorf("Error reading Cluster: %s", err)
}
if err := d.Set("zone_distribution_config", flattenRedisClusterZoneDistributionConfig(res["zoneDistributionConfig"], d, config)); err != nil {
return fmt.Errorf("Error reading Cluster: %s", err)
}
if err := d.Set("discovery_endpoints", flattenRedisClusterDiscoveryEndpoints(res["discoveryEndpoints"], d, config)); err != nil {
return fmt.Errorf("Error reading Cluster: %s", err)
}
Expand Down Expand Up @@ -685,6 +718,29 @@ func flattenRedisClusterNodeType(v interface{}, d *schema.ResourceData, config *
return v
}

func flattenRedisClusterZoneDistributionConfig(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["mode"] =
flattenRedisClusterZoneDistributionConfigMode(original["mode"], d, config)
transformed["zone"] =
flattenRedisClusterZoneDistributionConfigZone(original["zone"], d, config)
return []interface{}{transformed}
}
func flattenRedisClusterZoneDistributionConfigMode(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
return v
}

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

func flattenRedisClusterDiscoveryEndpoints(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
if v == nil {
return v
Expand Down Expand Up @@ -918,6 +974,40 @@ func expandRedisClusterNodeType(v interface{}, d tpgresource.TerraformResourceDa
return v, nil
}

func expandRedisClusterZoneDistributionConfig(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{})

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

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

return transformed, nil
}

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

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

func expandRedisClusterPscConfigs(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
l := v.([]interface{})
req := make([]interface{}, 0, len(l))
Expand Down
76 changes: 76 additions & 0 deletions google/services/redis/resource_redis_cluster_generated_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,82 @@ resource "google_redis_cluster" "cluster-ha" {
redis_configs = {
maxmemory-policy = "volatile-ttl"
}
zone_distribution_config {
mode = "MULTI_ZONE"
}
depends_on = [
google_network_connectivity_service_connection_policy.default
]

lifecycle {
prevent_destroy = %{prevent_destroy}
}
}

resource "google_network_connectivity_service_connection_policy" "default" {
name = "mypolicy%{random_suffix}"
location = "us-central1"
service_class = "gcp-memorystore-redis"
description = "my basic service connection policy"
network = google_compute_network.producer_net.id
psc_config {
subnetworks = [google_compute_subnetwork.producer_subnet.id]
}
}

resource "google_compute_subnetwork" "producer_subnet" {
name = "mysubnet%{random_suffix}"
ip_cidr_range = "10.0.0.248/29"
region = "us-central1"
network = google_compute_network.producer_net.id
}

resource "google_compute_network" "producer_net" {
name = "mynetwork%{random_suffix}"
auto_create_subnetworks = false
}
`, context)
}

func TestAccRedisCluster_redisClusterHaSingleZoneExample(t *testing.T) {
t.Parallel()

context := map[string]interface{}{
"prevent_destroy": false,
"random_suffix": acctest.RandString(t, 10),
}

acctest.VcrTest(t, resource.TestCase{
PreCheck: func() { acctest.AccTestPreCheck(t) },
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
CheckDestroy: testAccCheckRedisClusterDestroyProducer(t),
Steps: []resource.TestStep{
{
Config: testAccRedisCluster_redisClusterHaSingleZoneExample(context),
},
{
ResourceName: "google_redis_cluster.cluster-ha-single-zone",
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"name", "psc_configs", "region"},
},
},
})
}

func testAccRedisCluster_redisClusterHaSingleZoneExample(context map[string]interface{}) string {
return acctest.Nprintf(`
resource "google_redis_cluster" "cluster-ha-single-zone" {
name = "tf-test-ha-cluster-single-zone%{random_suffix}"
shard_count = 3
psc_configs {
network = google_compute_network.producer_net.id
}
region = "us-central1"
zone_distribution_config {
mode = "SINGLE_ZONE"
zone = "us-central1-f"
}
depends_on = [
google_network_connectivity_service_connection_policy.default
]
Expand Down
72 changes: 72 additions & 0 deletions website/docs/r/redis_cluster.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,61 @@ resource "google_redis_cluster" "cluster-ha" {
redis_configs = {
maxmemory-policy = "volatile-ttl"
}
zone_distribution_config {
mode = "MULTI_ZONE"
}
depends_on = [
google_network_connectivity_service_connection_policy.default
]

lifecycle {
prevent_destroy = true
}
}

resource "google_network_connectivity_service_connection_policy" "default" {
name = "mypolicy"
location = "us-central1"
service_class = "gcp-memorystore-redis"
description = "my basic service connection policy"
network = google_compute_network.producer_net.id
psc_config {
subnetworks = [google_compute_subnetwork.producer_subnet.id]
}
}

resource "google_compute_subnetwork" "producer_subnet" {
name = "mysubnet"
ip_cidr_range = "10.0.0.248/29"
region = "us-central1"
network = google_compute_network.producer_net.id
}

resource "google_compute_network" "producer_net" {
name = "mynetwork"
auto_create_subnetworks = false
}
```
<div class = "oics-button" style="float: right; margin: 0 0 -15px">
<a href="https://console.cloud.google.com/cloudshell/open?cloudshell_git_repo=https%3A%2F%2Fgithub.com%2Fterraform-google-modules%2Fdocs-examples.git&cloudshell_image=gcr.io%2Fcloudshell-images%2Fcloudshell%3Alatest&cloudshell_print=.%2Fmotd&cloudshell_tutorial=.%2Ftutorial.md&cloudshell_working_dir=redis_cluster_ha_single_zone&open_in_editor=main.tf" target="_blank">
<img alt="Open in Cloud Shell" src="//gstatic.com/cloudssh/images/open-btn.svg" style="max-height: 44px; margin: 32px auto; max-width: 100%;">
</a>
</div>
## Example Usage - Redis Cluster Ha Single Zone


```hcl
resource "google_redis_cluster" "cluster-ha-single-zone" {
name = "ha-cluster-single-zone"
shard_count = 3
psc_configs {
network = google_compute_network.producer_net.id
}
region = "us-central1"
zone_distribution_config {
mode = "SINGLE_ZONE"
zone = "us-central1-f"
}
depends_on = [
google_network_connectivity_service_connection_policy.default
]
Expand Down Expand Up @@ -136,6 +191,11 @@ The following arguments are supported:
If not provided, REDIS_HIGHMEM_MEDIUM will be used as default
Possible values are: `REDIS_SHARED_CORE_NANO`, `REDIS_HIGHMEM_MEDIUM`, `REDIS_HIGHMEM_XLARGE`, `REDIS_STANDARD_SMALL`.

* `zone_distribution_config` -
(Optional)
Immutable. Zone distribution config for Memorystore Redis cluster.
Structure is [documented below](#nested_zone_distribution_config).

* `replica_count` -
(Optional)
Optional. The number of replica nodes per shard.
Expand All @@ -154,6 +214,18 @@ The following arguments are supported:
If it is not provided, the provider project is used.


<a name="nested_zone_distribution_config"></a>The `zone_distribution_config` block supports:

* `mode` -
(Optional)
Immutable. The mode for zone distribution for Memorystore Redis cluster.
If not provided, MULTI_ZONE will be used as default
Possible values are: `MULTI_ZONE`, `SINGLE_ZONE`.

* `zone` -
(Optional)
Immutable. The zone for single zone Memorystore Redis cluster.

## Attributes Reference

In addition to the arguments listed above, the following computed attributes are exported:
Expand Down