Skip to content

Commit c9fee92

Browse files
SSL Mode and Require Connectors Support for AlloyDB (#9238) (#16236)
* support to create instance with ssl mode and require connectors, with acceptance tests * removed client_connection_config in basic instance example, and cleaned up the code a little bit * attempts to set the default ssl mode in the custom code * able to set default value during instance creation and addressing some comments * trying to fix updating ssl mode * fixed updating the instance with ssl mode * cleaning up code and fixing acceptance tests * Fixing spacing issues in instance.yaml * fixing spacing issues again in instance.yaml * fixing formatting in unit test * fixing the acceptance tests for other alloydb resources by explicitly adding the clientconnectionconfig * fixing spacing and removing commented out imports * commenting out createInstanceWithMandatoryFields and createPrimaryAndReadPoolInstance tests because they're failing due to an unrelated service networking issue * fix tests failing due to missing client_connection_config * removing service networking resources from tests since there's a bug in service networking * fix breaking change that causes a permadiff in terraform on update * uncomment out the TestAccAlloydbInstance_createPrimaryAndReadPoolInstance and TestAccAlloydbInstance_createInstanceWithMandatoryFields tests * remove private_ip_alloc from client connection config tests * use BootstrapSharedServiceNetworkingConnection in tests instead of BootstrapSharedTestNetwork in tests * add back in custom code * remove commented out code * fix formatting * match network name to be the same format as the other acceptance tests in the file * change network names in test * remove custom code and update e2e test * remove default test case and add more update steps to update test [upstream:06557f8d065d1b096db68d8f8a817eba13c445ee] Signed-off-by: Modular Magician <[email protected]>
1 parent 4110683 commit c9fee92

File tree

4 files changed

+335
-0
lines changed

4 files changed

+335
-0
lines changed

.changelog/9238.txt

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
```release-note:enhancement
2+
3+
alloydb: added `client_connection_config` field to `google_alloydb_instance` resource
4+
5+
```

google/services/alloydb/resource_alloydb_instance.go

+142
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,40 @@ Zone is automatically chosen from the list of zones in the region specified.
9797
Read pool of size 1 can only have zonal availability. Read pools with node count of 2 or more
9898
can have regional availability (nodes are present in 2 or more zones in a region).' Possible values: ["AVAILABILITY_TYPE_UNSPECIFIED", "ZONAL", "REGIONAL"]`,
9999
},
100+
"client_connection_config": {
101+
Type: schema.TypeList,
102+
Computed: true,
103+
Optional: true,
104+
Description: `Client connection specific configurations.`,
105+
MaxItems: 1,
106+
Elem: &schema.Resource{
107+
Schema: map[string]*schema.Schema{
108+
"require_connectors": {
109+
Type: schema.TypeBool,
110+
Optional: true,
111+
Description: `Configuration to enforce connectors only (ex: AuthProxy) connections to the database.`,
112+
},
113+
"ssl_config": {
114+
Type: schema.TypeList,
115+
Computed: true,
116+
Optional: true,
117+
Description: `SSL config option for this instance.`,
118+
MaxItems: 1,
119+
Elem: &schema.Resource{
120+
Schema: map[string]*schema.Schema{
121+
"ssl_mode": {
122+
Type: schema.TypeString,
123+
Computed: true,
124+
Optional: true,
125+
ValidateFunc: verify.ValidateEnum([]string{"ENCRYPTED_ONLY", "ALLOW_UNENCRYPTED_AND_ENCRYPTED", ""}),
126+
Description: `SSL mode. Specifies client-server SSL/TLS connection behavior. Possible values: ["ENCRYPTED_ONLY", "ALLOW_UNENCRYPTED_AND_ENCRYPTED"]`,
127+
},
128+
},
129+
},
130+
},
131+
},
132+
},
133+
},
100134
"database_flags": {
101135
Type: schema.TypeMap,
102136
Optional: true,
@@ -301,6 +335,12 @@ func resourceAlloydbInstanceCreate(d *schema.ResourceData, meta interface{}) err
301335
} else if v, ok := d.GetOkExists("machine_config"); !tpgresource.IsEmptyValue(reflect.ValueOf(machineConfigProp)) && (ok || !reflect.DeepEqual(v, machineConfigProp)) {
302336
obj["machineConfig"] = machineConfigProp
303337
}
338+
clientConnectionConfigProp, err := expandAlloydbInstanceClientConnectionConfig(d.Get("client_connection_config"), d, config)
339+
if err != nil {
340+
return err
341+
} else if v, ok := d.GetOkExists("client_connection_config"); !tpgresource.IsEmptyValue(reflect.ValueOf(clientConnectionConfigProp)) && (ok || !reflect.DeepEqual(v, clientConnectionConfigProp)) {
342+
obj["clientConnectionConfig"] = clientConnectionConfigProp
343+
}
304344
labelsProp, err := expandAlloydbInstanceEffectiveLabels(d.Get("effective_labels"), d, config)
305345
if err != nil {
306346
return err
@@ -440,6 +480,9 @@ func resourceAlloydbInstanceRead(d *schema.ResourceData, meta interface{}) error
440480
if err := d.Set("machine_config", flattenAlloydbInstanceMachineConfig(res["machineConfig"], d, config)); err != nil {
441481
return fmt.Errorf("Error reading Instance: %s", err)
442482
}
483+
if err := d.Set("client_connection_config", flattenAlloydbInstanceClientConnectionConfig(res["clientConnectionConfig"], d, config)); err != nil {
484+
return fmt.Errorf("Error reading Instance: %s", err)
485+
}
443486
if err := d.Set("terraform_labels", flattenAlloydbInstanceTerraformLabels(res["labels"], d, config)); err != nil {
444487
return fmt.Errorf("Error reading Instance: %s", err)
445488
}
@@ -506,6 +549,12 @@ func resourceAlloydbInstanceUpdate(d *schema.ResourceData, meta interface{}) err
506549
} else if v, ok := d.GetOkExists("machine_config"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, machineConfigProp)) {
507550
obj["machineConfig"] = machineConfigProp
508551
}
552+
clientConnectionConfigProp, err := expandAlloydbInstanceClientConnectionConfig(d.Get("client_connection_config"), d, config)
553+
if err != nil {
554+
return err
555+
} else if v, ok := d.GetOkExists("client_connection_config"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, clientConnectionConfigProp)) {
556+
obj["clientConnectionConfig"] = clientConnectionConfigProp
557+
}
509558
labelsProp, err := expandAlloydbInstanceEffectiveLabels(d.Get("effective_labels"), d, config)
510559
if err != nil {
511560
return err
@@ -555,6 +604,10 @@ func resourceAlloydbInstanceUpdate(d *schema.ResourceData, meta interface{}) err
555604
updateMask = append(updateMask, "machineConfig")
556605
}
557606

607+
if d.HasChange("client_connection_config") {
608+
updateMask = append(updateMask, "clientConnectionConfig")
609+
}
610+
558611
if d.HasChange("effective_labels") {
559612
updateMask = append(updateMask, "labels")
560613
}
@@ -867,6 +920,42 @@ func flattenAlloydbInstanceMachineConfigCpuCount(v interface{}, d *schema.Resour
867920
return v // let terraform core handle it otherwise
868921
}
869922

923+
func flattenAlloydbInstanceClientConnectionConfig(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
924+
if v == nil {
925+
return nil
926+
}
927+
original := v.(map[string]interface{})
928+
if len(original) == 0 {
929+
return nil
930+
}
931+
transformed := make(map[string]interface{})
932+
transformed["require_connectors"] =
933+
flattenAlloydbInstanceClientConnectionConfigRequireConnectors(original["requireConnectors"], d, config)
934+
transformed["ssl_config"] =
935+
flattenAlloydbInstanceClientConnectionConfigSslConfig(original["sslConfig"], d, config)
936+
return []interface{}{transformed}
937+
}
938+
func flattenAlloydbInstanceClientConnectionConfigRequireConnectors(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
939+
return v
940+
}
941+
942+
func flattenAlloydbInstanceClientConnectionConfigSslConfig(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
943+
if v == nil {
944+
return nil
945+
}
946+
original := v.(map[string]interface{})
947+
if len(original) == 0 {
948+
return nil
949+
}
950+
transformed := make(map[string]interface{})
951+
transformed["ssl_mode"] =
952+
flattenAlloydbInstanceClientConnectionConfigSslConfigSslMode(original["sslMode"], d, config)
953+
return []interface{}{transformed}
954+
}
955+
func flattenAlloydbInstanceClientConnectionConfigSslConfigSslMode(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
956+
return v
957+
}
958+
870959
func flattenAlloydbInstanceTerraformLabels(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
871960
if v == nil {
872961
return v
@@ -1019,6 +1108,59 @@ func expandAlloydbInstanceMachineConfigCpuCount(v interface{}, d tpgresource.Ter
10191108
return v, nil
10201109
}
10211110

1111+
func expandAlloydbInstanceClientConnectionConfig(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
1112+
l := v.([]interface{})
1113+
if len(l) == 0 || l[0] == nil {
1114+
return nil, nil
1115+
}
1116+
raw := l[0]
1117+
original := raw.(map[string]interface{})
1118+
transformed := make(map[string]interface{})
1119+
1120+
transformedRequireConnectors, err := expandAlloydbInstanceClientConnectionConfigRequireConnectors(original["require_connectors"], d, config)
1121+
if err != nil {
1122+
return nil, err
1123+
} else if val := reflect.ValueOf(transformedRequireConnectors); val.IsValid() && !tpgresource.IsEmptyValue(val) {
1124+
transformed["requireConnectors"] = transformedRequireConnectors
1125+
}
1126+
1127+
transformedSslConfig, err := expandAlloydbInstanceClientConnectionConfigSslConfig(original["ssl_config"], d, config)
1128+
if err != nil {
1129+
return nil, err
1130+
} else if val := reflect.ValueOf(transformedSslConfig); val.IsValid() && !tpgresource.IsEmptyValue(val) {
1131+
transformed["sslConfig"] = transformedSslConfig
1132+
}
1133+
1134+
return transformed, nil
1135+
}
1136+
1137+
func expandAlloydbInstanceClientConnectionConfigRequireConnectors(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
1138+
return v, nil
1139+
}
1140+
1141+
func expandAlloydbInstanceClientConnectionConfigSslConfig(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
1142+
l := v.([]interface{})
1143+
if len(l) == 0 || l[0] == nil {
1144+
return nil, nil
1145+
}
1146+
raw := l[0]
1147+
original := raw.(map[string]interface{})
1148+
transformed := make(map[string]interface{})
1149+
1150+
transformedSslMode, err := expandAlloydbInstanceClientConnectionConfigSslConfigSslMode(original["ssl_mode"], d, config)
1151+
if err != nil {
1152+
return nil, err
1153+
} else if val := reflect.ValueOf(transformedSslMode); val.IsValid() && !tpgresource.IsEmptyValue(val) {
1154+
transformed["sslMode"] = transformedSslMode
1155+
}
1156+
1157+
return transformed, nil
1158+
}
1159+
1160+
func expandAlloydbInstanceClientConnectionConfigSslConfigSslMode(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
1161+
return v, nil
1162+
}
1163+
10221164
func expandAlloydbInstanceEffectiveLabels(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (map[string]string, error) {
10231165
if v == nil {
10241166
return map[string]string{}, nil

google/services/alloydb/resource_alloydb_instance_test.go

+164
Original file line numberDiff line numberDiff line change
@@ -407,3 +407,167 @@ data "google_compute_global_address" "private_ip_alloc" {
407407
}
408408
`, context)
409409
}
410+
411+
// This test passes if an instance is able to be created specifying require
412+
// connectors and the ssl mode; if the instance is able to update require
413+
// connectors, and the ssl mode in the client connection config; if the ssl
414+
// mode specified is removed it doesn't not change the ssl mode; and if the
415+
// require connectors is remove it doesn't change require connectors either.
416+
func TestAccAlloydbInstance_clientConnectionConfig(t *testing.T) {
417+
t.Parallel()
418+
419+
suffix := acctest.RandString(t, 10)
420+
networkName := acctest.BootstrapSharedServiceNetworkingConnection(t, "alloydbinstance-clientconnectionconfig")
421+
422+
context := map[string]interface{}{
423+
"random_suffix": suffix,
424+
"network_name": networkName,
425+
"require_connectors": true,
426+
"ssl_mode": "ENCRYPTED_ONLY",
427+
}
428+
context2 := map[string]interface{}{
429+
"random_suffix": suffix,
430+
"network_name": networkName,
431+
"require_connectors": false,
432+
"ssl_mode": "ALLOW_UNENCRYPTED_AND_ENCRYPTED",
433+
}
434+
context3 := map[string]interface{}{
435+
"random_suffix": suffix,
436+
"network_name": networkName,
437+
"require_connectors": false,
438+
}
439+
context4 := map[string]interface{}{
440+
"random_suffix": suffix,
441+
"network_name": networkName,
442+
"require_connectors": false,
443+
"ssl_mode": "ENCRYPTED_ONLY",
444+
}
445+
446+
acctest.VcrTest(t, resource.TestCase{
447+
PreCheck: func() { acctest.AccTestPreCheck(t) },
448+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
449+
CheckDestroy: testAccCheckAlloydbInstanceDestroyProducer(t),
450+
Steps: []resource.TestStep{
451+
{
452+
Config: testAccAlloydbInstance_clientConnectionConfig(context),
453+
Check: resource.ComposeTestCheckFunc(
454+
resource.TestCheckResourceAttr("google_alloydb_instance.default", "client_connection_config.0.require_connectors", "true"),
455+
resource.TestCheckResourceAttr("google_alloydb_instance.default", "client_connection_config.0.ssl_config.0.ssl_mode", "ENCRYPTED_ONLY"),
456+
),
457+
},
458+
{
459+
ResourceName: "google_alloydb_instance.default",
460+
ImportState: true,
461+
ImportStateVerify: true,
462+
ImportStateVerifyIgnore: []string{"cluster", "instance_id", "reconciling", "update_time"},
463+
},
464+
{
465+
Config: testAccAlloydbInstance_clientConnectionConfig(context2),
466+
Check: resource.ComposeTestCheckFunc(
467+
resource.TestCheckResourceAttr("google_alloydb_instance.default", "client_connection_config.0.require_connectors", "false"),
468+
resource.TestCheckResourceAttr("google_alloydb_instance.default", "client_connection_config.0.ssl_config.0.ssl_mode", "ALLOW_UNENCRYPTED_AND_ENCRYPTED"),
469+
),
470+
},
471+
{
472+
ResourceName: "google_alloydb_instance.default",
473+
ImportState: true,
474+
ImportStateVerify: true,
475+
ImportStateVerifyIgnore: []string{"cluster", "instance_id", "reconciling", "update_time"},
476+
},
477+
{
478+
Config: testAccAlloydbInstance_noSSLModeConfig(context3),
479+
Check: resource.ComposeTestCheckFunc(
480+
resource.TestCheckResourceAttr("google_alloydb_instance.default", "client_connection_config.0.require_connectors", "false"),
481+
resource.TestCheckResourceAttr("google_alloydb_instance.default", "client_connection_config.0.ssl_config.0.ssl_mode", "ALLOW_UNENCRYPTED_AND_ENCRYPTED"),
482+
),
483+
},
484+
{
485+
ResourceName: "google_alloydb_instance.default",
486+
ImportState: true,
487+
ImportStateVerify: true,
488+
ImportStateVerifyIgnore: []string{"cluster", "instance_id", "reconciling", "update_time"},
489+
},
490+
{
491+
Config: testAccAlloydbInstance_clientConnectionConfig(context4),
492+
Check: resource.ComposeTestCheckFunc(
493+
resource.TestCheckResourceAttr("google_alloydb_instance.default", "client_connection_config.0.require_connectors", "false"),
494+
resource.TestCheckResourceAttr("google_alloydb_instance.default", "client_connection_config.0.ssl_config.0.ssl_mode", "ENCRYPTED_ONLY"),
495+
),
496+
},
497+
{
498+
ResourceName: "google_alloydb_instance.default",
499+
ImportState: true,
500+
ImportStateVerify: true,
501+
ImportStateVerifyIgnore: []string{"cluster", "instance_id", "reconciling", "update_time"},
502+
},
503+
{
504+
Config: testAccAlloydbInstance_noSSLModeConfig(context3),
505+
Check: resource.ComposeTestCheckFunc(
506+
resource.TestCheckResourceAttr("google_alloydb_instance.default", "client_connection_config.0.require_connectors", "false"),
507+
resource.TestCheckResourceAttr("google_alloydb_instance.default", "client_connection_config.0.ssl_config.0.ssl_mode", "ENCRYPTED_ONLY"),
508+
),
509+
},
510+
{
511+
ResourceName: "google_alloydb_instance.default",
512+
ImportState: true,
513+
ImportStateVerify: true,
514+
ImportStateVerifyIgnore: []string{"cluster", "instance_id", "reconciling", "update_time"},
515+
},
516+
},
517+
})
518+
}
519+
520+
func testAccAlloydbInstance_noSSLModeConfig(context map[string]interface{}) string {
521+
return acctest.Nprintf(`
522+
resource "google_alloydb_instance" "default" {
523+
cluster = google_alloydb_cluster.default.name
524+
instance_id = "tf-test-alloydb-instance%{random_suffix}"
525+
instance_type = "PRIMARY"
526+
527+
client_connection_config {
528+
require_connectors = %{require_connectors}
529+
}
530+
}
531+
532+
resource "google_alloydb_cluster" "default" {
533+
cluster_id = "tf-test-alloydb-cluster%{random_suffix}"
534+
location = "us-central1"
535+
network = data.google_compute_network.default.id
536+
}
537+
538+
data "google_project" "project" {}
539+
540+
data "google_compute_network" "default" {
541+
name = "%{network_name}"
542+
}
543+
`, context)
544+
}
545+
546+
func testAccAlloydbInstance_clientConnectionConfig(context map[string]interface{}) string {
547+
return acctest.Nprintf(`
548+
resource "google_alloydb_instance" "default" {
549+
cluster = google_alloydb_cluster.default.name
550+
instance_id = "tf-test-alloydb-instance%{random_suffix}"
551+
instance_type = "PRIMARY"
552+
553+
client_connection_config {
554+
require_connectors = %{require_connectors}
555+
ssl_config {
556+
ssl_mode = "%{ssl_mode}"
557+
}
558+
}
559+
}
560+
561+
resource "google_alloydb_cluster" "default" {
562+
cluster_id = "tf-test-alloydb-cluster%{random_suffix}"
563+
location = "us-central1"
564+
network = data.google_compute_network.default.id
565+
}
566+
567+
data "google_project" "project" {}
568+
569+
data "google_compute_network" "default" {
570+
name = "%{network_name}"
571+
}
572+
`, context)
573+
}

0 commit comments

Comments
 (0)