Skip to content

Commit 8f4b35f

Browse files
feat: support Cloud SQL\'s new field psc_auto_connections. (#12236) (#8682)
[upstream:151435867d85bc67cc73d32365733313abf5b2de] Signed-off-by: Modular Magician <[email protected]>
1 parent 8faddbc commit 8f4b35f

File tree

4 files changed

+270
-7
lines changed

4 files changed

+270
-7
lines changed

Diff for: .changelog/12236.txt

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:enhancement
2+
sql: added `psc_auto_connections` field to `instances` resource
3+
```

Diff for: google-beta/services/sql/resource_sql_database_instance.go

+53
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,25 @@ is set to true. Defaults to ZONAL.`,
491491
Set: schema.HashString,
492492
Description: `List of consumer projects that are allow-listed for PSC connections to this instance. This instance can be connected to with PSC from any network in these projects. Each consumer project in this list may be represented by a project number (numeric) or by a project id (alphanumeric).`,
493493
},
494+
"psc_auto_connections": {
495+
Type: schema.TypeList,
496+
Optional: true,
497+
Elem: &schema.Resource{
498+
Schema: map[string]*schema.Schema{
499+
"consumer_service_project_id": {
500+
Type: schema.TypeString,
501+
Optional: true,
502+
Description: `The project ID of consumer service project of this consumer endpoint.`,
503+
},
504+
"consumer_network": {
505+
Type: schema.TypeString,
506+
Required: true,
507+
Description: `The consumer network of this consumer endpoint. This must be a resource path that includes both the host project and the network name. The consumer host project of this network might be different from the consumer service project.`,
508+
},
509+
},
510+
},
511+
Description: `A comma-separated list of networks or a comma-separated list of network-project pairs. Each project in this list is represented by a project number (numeric) or by a project ID (alphanumeric). This allows Private Service Connect connections to be created automatically for the specified networks.`,
512+
},
494513
},
495514
},
496515
},
@@ -1439,12 +1458,30 @@ func expandIpConfiguration(configured []interface{}, databaseVersion string) *sq
14391458
}
14401459
}
14411460

1461+
func expandPscAutoConnectionConfig(configured []interface{}) []*sqladmin.PscAutoConnectionConfig {
1462+
pscAutoConnections := make([]*sqladmin.PscAutoConnectionConfig, 0, len(configured))
1463+
1464+
for _, _flag := range configured {
1465+
if _flag == nil {
1466+
continue
1467+
}
1468+
_entry := _flag.(map[string]interface{})
1469+
1470+
pscAutoConnections = append(pscAutoConnections, &sqladmin.PscAutoConnectionConfig{
1471+
ConsumerNetwork: _entry["consumer_network"].(string),
1472+
ConsumerProject: _entry["consumer_service_project_id"].(string),
1473+
})
1474+
}
1475+
return pscAutoConnections
1476+
}
1477+
14421478
func expandPscConfig(configured []interface{}) *sqladmin.PscConfig {
14431479
for _, _pscConfig := range configured {
14441480
_entry := _pscConfig.(map[string]interface{})
14451481
return &sqladmin.PscConfig{
14461482
PscEnabled: _entry["psc_enabled"].(bool),
14471483
AllowedConsumerProjects: tpgresource.ConvertStringArr(_entry["allowed_consumer_projects"].(*schema.Set).List()),
1484+
PscAutoConnections: expandPscAutoConnectionConfig(_entry["psc_auto_connections"].([]interface{})),
14481485
}
14491486
}
14501487

@@ -2344,10 +2381,26 @@ func flattenIpConfiguration(ipConfiguration *sqladmin.IpConfiguration, d *schema
23442381
return []map[string]interface{}{data}
23452382
}
23462383

2384+
func flattenPscAutoConnections(pscAutoConnections []*sqladmin.PscAutoConnectionConfig) []map[string]interface{} {
2385+
flags := make([]map[string]interface{}, 0, len(pscAutoConnections))
2386+
2387+
for _, flag := range pscAutoConnections {
2388+
data := map[string]interface{}{
2389+
"consumer_network": flag.ConsumerNetwork,
2390+
"consumer_service_project_id": flag.ConsumerProject,
2391+
}
2392+
2393+
flags = append(flags, data)
2394+
}
2395+
2396+
return flags
2397+
}
2398+
23472399
func flattenPscConfigs(pscConfig *sqladmin.PscConfig) interface{} {
23482400
data := map[string]interface{}{
23492401
"psc_enabled": pscConfig.PscEnabled,
23502402
"allowed_consumer_projects": schema.NewSet(schema.HashString, tpgresource.ConvertStringArrToInterface(pscConfig.AllowedConsumerProjects)),
2403+
"psc_auto_connections": flattenPscAutoConnections(pscConfig.PscAutoConnections),
23512404
}
23522405

23532406
return []map[string]interface{}{data}

Diff for: google-beta/services/sql/resource_sql_database_instance_test.go

+180-7
Original file line numberDiff line numberDiff line change
@@ -946,21 +946,78 @@ func TestAccSqlDatabaseInstance_withPSCEnabled_thenAddAllowedConsumerProjects_th
946946
})
947947
}
948948

949-
func TestAccSqlDatabaseInstance_basicInstance_thenPSCEnabled(t *testing.T) {
949+
func TestAccSqlDatabaseInstance_withPSCEnabled_withoutPscAutoConnections(t *testing.T) {
950950
t.Parallel()
951951

952952
instanceName := "tf-test-" + acctest.RandString(t, 10)
953-
projectId := "psctestproject" + acctest.RandString(t, 10)
954-
orgId := envvar.GetTestOrgFromEnv(t)
955-
billingAccount := envvar.GetTestBillingAccountFromEnv(t)
953+
projectId := envvar.GetTestProjectFromEnv()
954+
955+
acctest.VcrTest(t, resource.TestCase{
956+
PreCheck: func() { acctest.AccTestPreCheck(t) },
957+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
958+
CheckDestroy: testAccSqlDatabaseInstanceDestroyProducer(t),
959+
Steps: []resource.TestStep{
960+
{
961+
Config: testAccSqlDatabaseInstance_withPSCEnabled_withoutPscAutoConnections(instanceName),
962+
Check: resource.ComposeTestCheckFunc(verifyPscAutoConnectionsOperation("google_sql_database_instance.instance", true, true, false, "", "")),
963+
},
964+
{
965+
ResourceName: "google_sql_database_instance.instance",
966+
ImportState: true,
967+
ImportStateVerify: true,
968+
ImportStateIdPrefix: fmt.Sprintf("%s/", projectId),
969+
ImportStateVerifyIgnore: []string{"deletion_protection"},
970+
},
971+
},
972+
})
973+
}
974+
975+
func TestAccSqlDatabaseInstance_withPSCEnabled_withPscAutoConnections(t *testing.T) {
976+
t.Parallel()
977+
978+
testId := "test-psc-auto-con" + acctest.RandString(t, 10)
979+
instanceName := "tf-test-" + acctest.RandString(t, 10)
980+
projectId := envvar.GetTestProjectFromEnv()
981+
networkName := acctest.BootstrapSharedTestNetwork(t, testId)
982+
network_short_link_name := fmt.Sprintf("projects/%s/global/networks/%s", projectId, networkName)
983+
984+
acctest.VcrTest(t, resource.TestCase{
985+
PreCheck: func() { acctest.AccTestPreCheck(t) },
986+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
987+
CheckDestroy: testAccSqlDatabaseInstanceDestroyProducer(t),
988+
Steps: []resource.TestStep{
989+
{
990+
Config: testAccSqlDatabaseInstance_withPSCEnabled_withPscAutoConnections(instanceName, projectId, networkName),
991+
Check: resource.ComposeTestCheckFunc(verifyPscAutoConnectionsOperation("google_sql_database_instance.instance", true, true, true, network_short_link_name, projectId)),
992+
},
993+
{
994+
ResourceName: "google_sql_database_instance.instance",
995+
ImportState: true,
996+
ImportStateVerify: true,
997+
ImportStateIdPrefix: fmt.Sprintf("%s/", projectId),
998+
ImportStateVerifyIgnore: []string{"deletion_protection"},
999+
},
1000+
},
1001+
})
1002+
}
1003+
1004+
func TestAccSqlDatabaseInstance_withPSCEnabled_thenAddPscAutoConnections_thenRemovePscAutoConnections(t *testing.T) {
1005+
t.Parallel()
1006+
1007+
testId := "test-psc-auto-con" + acctest.RandString(t, 10)
1008+
instanceName := "tf-test-" + acctest.RandString(t, 10)
1009+
projectId := envvar.GetTestProjectFromEnv()
1010+
networkName := acctest.BootstrapSharedTestNetwork(t, testId)
1011+
network_short_link_name := fmt.Sprintf("projects/%s/global/networks/%s", projectId, networkName)
9561012

9571013
acctest.VcrTest(t, resource.TestCase{
9581014
PreCheck: func() { acctest.AccTestPreCheck(t) },
9591015
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
9601016
CheckDestroy: testAccSqlDatabaseInstanceDestroyProducer(t),
9611017
Steps: []resource.TestStep{
9621018
{
963-
Config: testAccSqlDatabaseInstance_basicInstanceForPsc(instanceName, projectId, orgId, billingAccount),
1019+
Config: testAccSqlDatabaseInstance_withPSCEnabled_withoutPscAutoConnections(instanceName),
1020+
Check: resource.ComposeTestCheckFunc(verifyPscAutoConnectionsOperation("google_sql_database_instance.instance", true, true, false, "", "")),
9641021
},
9651022
{
9661023
ResourceName: "google_sql_database_instance.instance",
@@ -970,8 +1027,19 @@ func TestAccSqlDatabaseInstance_basicInstance_thenPSCEnabled(t *testing.T) {
9701027
ImportStateVerifyIgnore: []string{"deletion_protection"},
9711028
},
9721029
{
973-
Config: testAccSqlDatabaseInstance_withPSCEnabled_withoutAllowedConsumerProjects(instanceName, projectId, orgId, billingAccount),
974-
ExpectError: regexp.MustCompile("PSC connectivity can not be enabled"),
1030+
Config: testAccSqlDatabaseInstance_withPSCEnabled_withPscAutoConnections(instanceName, projectId, networkName),
1031+
Check: resource.ComposeTestCheckFunc(verifyPscAutoConnectionsOperation("google_sql_database_instance.instance", true, true, true, network_short_link_name, projectId)),
1032+
},
1033+
{
1034+
ResourceName: "google_sql_database_instance.instance",
1035+
ImportState: true,
1036+
ImportStateVerify: true,
1037+
ImportStateIdPrefix: fmt.Sprintf("%s/", projectId),
1038+
ImportStateVerifyIgnore: []string{"deletion_protection"},
1039+
},
1040+
{
1041+
Config: testAccSqlDatabaseInstance_withPSCEnabled_withoutPscAutoConnections(instanceName),
1042+
Check: resource.ComposeTestCheckFunc(verifyPscAutoConnectionsOperation("google_sql_database_instance.instance", true, true, false, "", "")),
9751043
},
9761044
},
9771045
})
@@ -3571,6 +3639,111 @@ func verifyPscOperation(resourceName string, isPscConfigExpected bool, expectedP
35713639
}
35723640
}
35733641

3642+
func verifyPscAutoConnectionsOperation(resourceName string, isPscConfigExpected bool, expectedPscEnabled bool, isPscAutoConnectionConfigExpected bool, expectedConsumerNetwork string, expectedConsumerProject string) func(*terraform.State) error {
3643+
return func(s *terraform.State) error {
3644+
resource, ok := s.RootModule().Resources[resourceName]
3645+
if !ok {
3646+
return fmt.Errorf("Can't find %s in state", resourceName)
3647+
}
3648+
3649+
resourceAttributes := resource.Primary.Attributes
3650+
_, ok = resourceAttributes["settings.0.ip_configuration.#"]
3651+
if !ok {
3652+
return fmt.Errorf("settings.0.ip_configuration.# block is not present in state for %s", resourceName)
3653+
}
3654+
3655+
if isPscConfigExpected {
3656+
_, ok := resourceAttributes["settings.0.ip_configuration.0.psc_config.#"]
3657+
if !ok {
3658+
return fmt.Errorf("settings.0.ip_configuration.0.psc_config property is not present or set in state of %s", resourceName)
3659+
}
3660+
3661+
pscEnabledStr, ok := resourceAttributes["settings.0.ip_configuration.0.psc_config.0.psc_enabled"]
3662+
pscEnabled, err := strconv.ParseBool(pscEnabledStr)
3663+
if err != nil || pscEnabled != expectedPscEnabled {
3664+
return fmt.Errorf("settings.0.ip_configuration.0.psc_config.0.psc_enabled property value is not set as expected in state of %s, expected %v, actual %v", resourceName, expectedPscEnabled, pscEnabled)
3665+
}
3666+
3667+
_, ok = resourceAttributes["settings.0.ip_configuration.0.psc_config.0.psc_auto_connections.#"]
3668+
if !ok {
3669+
return fmt.Errorf("settings.0.ip_configuration.0.psc_config.0.psc_auto_connections property is not present or set in state of %s", resourceName)
3670+
}
3671+
3672+
if isPscAutoConnectionConfigExpected {
3673+
consumerNetwork, ok := resourceAttributes["settings.0.ip_configuration.0.psc_config.0.psc_auto_connections.0.consumer_network"]
3674+
if !ok || consumerNetwork != expectedConsumerNetwork {
3675+
return fmt.Errorf("settings.0.ip_configuration.0.psc_config.0.psc_auto_connections.0.consumer_network property is not present or set as expected in state of %s", resourceName)
3676+
}
3677+
3678+
consumerProject, ok := resourceAttributes["settings.0.ip_configuration.0.psc_config.0.psc_auto_connections.0.consumer_service_project_id"]
3679+
if !ok || consumerProject != expectedConsumerProject {
3680+
return fmt.Errorf("settings.0.ip_configuration.0.psc_config.0.psc_auto_connections.0.consumer_service_project_id property is not present or set as expected in state of %s", resourceName)
3681+
}
3682+
}
3683+
}
3684+
3685+
return nil
3686+
}
3687+
}
3688+
3689+
func testAccSqlDatabaseInstance_withPSCEnabled_withoutPscAutoConnections(instanceName string) string {
3690+
return fmt.Sprintf(`
3691+
resource "google_sql_database_instance" "instance" {
3692+
name = "%s"
3693+
region = "us-west2"
3694+
database_version = "MYSQL_8_0"
3695+
deletion_protection = false
3696+
settings {
3697+
tier = "db-g1-small"
3698+
ip_configuration {
3699+
psc_config {
3700+
psc_enabled = true
3701+
}
3702+
ipv4_enabled = false
3703+
}
3704+
backup_configuration {
3705+
enabled = true
3706+
binary_log_enabled = true
3707+
}
3708+
availability_type = "REGIONAL"
3709+
}
3710+
}
3711+
`, instanceName)
3712+
}
3713+
3714+
func testAccSqlDatabaseInstance_withPSCEnabled_withPscAutoConnections(instanceName string, projectId string, networkName string) string {
3715+
return fmt.Sprintf(`
3716+
data "google_compute_network" "testnetwork" {
3717+
name = "%s"
3718+
}
3719+
3720+
resource "google_sql_database_instance" "instance" {
3721+
name = "%s"
3722+
region = "us-west2"
3723+
database_version = "MYSQL_8_0"
3724+
deletion_protection = false
3725+
settings {
3726+
tier = "db-g1-small"
3727+
ip_configuration {
3728+
psc_config {
3729+
psc_enabled = true
3730+
psc_auto_connections {
3731+
consumer_network = "projects/%s/global/networks/%s"
3732+
consumer_service_project_id = "%s"
3733+
}
3734+
}
3735+
ipv4_enabled = false
3736+
}
3737+
backup_configuration {
3738+
enabled = true
3739+
binary_log_enabled = true
3740+
}
3741+
availability_type = "REGIONAL"
3742+
}
3743+
}
3744+
`, networkName, instanceName, projectId, networkName, projectId)
3745+
}
3746+
35743747
func testAccSqlDatabaseInstance_withPrivateNetwork_withoutAllocatedIpRange(databaseName, networkName string, specifyPrivatePathOption bool, enablePrivatePath bool) string {
35753748
privatePathOption := ""
35763749
if specifyPrivatePathOption {

Diff for: website/docs/r/sql_database_instance.html.markdown

+34
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,34 @@ resource "google_sql_database_instance" "main" {
197197
}
198198
```
199199

200+
### Cloud SQL Instance with PSC auto connections
201+
202+
```hcl
203+
resource "google_sql_database_instance" "main" {
204+
name = "psc-enabled-main-instance"
205+
database_version = "MYSQL_8_0"
206+
settings {
207+
tier = "db-f1-micro"
208+
ip_configuration {
209+
psc_config {
210+
psc_enabled = true
211+
allowed_consumer_projects = ["allowed-consumer-project-name"]
212+
psc_auto_connections {
213+
consumer_network = "network-name"
214+
consumer_service_project_id = "project-id"
215+
}
216+
}
217+
ipv4_enabled = false
218+
}
219+
backup_configuration {
220+
enabled = true
221+
binary_log_enabled = true
222+
}
223+
availability_type = "REGIONAL"
224+
}
225+
}
226+
```
227+
200228
## Argument Reference
201229

202230
The following arguments are supported:
@@ -404,6 +432,12 @@ The optional `settings.ip_configuration.psc_config` sublist supports:
404432

405433
* `allowed_consumer_projects` - (Optional) List of consumer projects that are allow-listed for PSC connections to this instance. This instance can be connected to with PSC from any network in these projects. Each consumer project in this list may be represented by a project number (numeric) or by a project id (alphanumeric).
406434

435+
* The optional `psc_config.psc_auto_connections` subblock - (Optional) A comma-separated list of networks or a comma-separated list of network-project pairs. Each project in this list is represented by a project number (numeric) or by a project ID (alphanumeric). This allows Private Service Connect connections to be created automatically for the specified networks.
436+
437+
* `consumer_network` - "The consumer network of this consumer endpoint. This must be a resource path that includes both the host project and the network name. For example, `projects/project1/global/networks/network1`. The consumer host project of this network might be different from the consumer service project."
438+
439+
* `consumer_service_project_id` - (Optional) The project ID of consumer service project of this consumer endpoint.
440+
407441
The optional `settings.location_preference` subblock supports:
408442

409443
* `follow_gae_application` - (Optional) A GAE application whose zone to remain

0 commit comments

Comments
 (0)