Skip to content

Commit 8563341

Browse files
feat: support PSC outbound's network attachment field (#14766) (#23894)
[upstream:97511e34806299ff38bbe77c34ee8a5e4d03f69b] Signed-off-by: Modular Magician <[email protected]>
1 parent 3488f65 commit 8563341

File tree

4 files changed

+210
-0
lines changed

4 files changed

+210
-0
lines changed

.changelog/14766.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:enhancement
2+
sql: added `network_attachment_uri` field to `google_sql_database_instance`
3+
```

google/services/sql/resource_sql_database_instance.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -534,6 +534,11 @@ is set to true. Defaults to ZONAL.`,
534534
Set: schema.HashString,
535535
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).`,
536536
},
537+
"network_attachment_uri": {
538+
Type: schema.TypeString,
539+
Optional: true,
540+
Description: `Name of network attachment resource used to authorize a producer service to connect a PSC interface to the consumer's VPC. For example: "projects/myProject/regions/myRegion/networkAttachments/myNetworkAttachment". This is required to enable outbound connection on a PSC instance.`,
541+
},
537542
"psc_auto_connections": {
538543
Type: schema.TypeList,
539544
Optional: true,
@@ -1598,6 +1603,7 @@ func expandPscConfig(configured []interface{}) *sqladmin.PscConfig {
15981603
return &sqladmin.PscConfig{
15991604
PscEnabled: _entry["psc_enabled"].(bool),
16001605
AllowedConsumerProjects: tpgresource.ConvertStringArr(_entry["allowed_consumer_projects"].(*schema.Set).List()),
1606+
NetworkAttachmentUri: _entry["network_attachment_uri"].(string),
16011607
PscAutoConnections: expandPscAutoConnectionConfig(_entry["psc_auto_connections"].([]interface{})),
16021608
}
16031609
}
@@ -2643,6 +2649,7 @@ func flattenPscConfigs(pscConfig *sqladmin.PscConfig) interface{} {
26432649
data := map[string]interface{}{
26442650
"psc_enabled": pscConfig.PscEnabled,
26452651
"allowed_consumer_projects": schema.NewSet(schema.HashString, tpgresource.ConvertStringArrToInterface(pscConfig.AllowedConsumerProjects)),
2652+
"network_attachment_uri": pscConfig.NetworkAttachmentUri,
26462653
"psc_auto_connections": flattenPscAutoConnections(pscConfig.PscAutoConnections),
26472654
}
26482655

google/services/sql/resource_sql_database_instance_test.go

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1158,6 +1158,84 @@ func TestAccSqlDatabaseInstance_withPSCEnabled_withIpV4Enabled(t *testing.T) {
11581158
})
11591159
}
11601160

1161+
func TestAccSqlDatabaseInstance_withPscEnabled_withNetworkAttachmentUri_thenRemoveNetworkAttachment(t *testing.T) {
1162+
t.Parallel()
1163+
1164+
random_suffix := acctest.RandString(t, 10)
1165+
instanceName := "tf-test-" + random_suffix
1166+
projectId := envvar.GetTestProjectFromEnv()
1167+
region := "us-central1"
1168+
networkNameStr := "tf-test-cloud-sql-network-" + random_suffix
1169+
subnetworkNameStr := "tf-test-cloud-sql-subnetwork-" + random_suffix
1170+
networkAttachmentNameStr := "tf-test-cloud-sql-update-na-" + random_suffix
1171+
networkName := acctest.BootstrapSharedTestNetwork(t, networkNameStr)
1172+
subnetworkName := acctest.BootstrapSubnet(t, subnetworkNameStr, networkName)
1173+
networkAttachmentName := acctest.BootstrapNetworkAttachment(t, networkAttachmentNameStr, subnetworkName)
1174+
networkAttachmentUri := fmt.Sprintf("projects/%s/regions/%s/networkAttachments/%s", projectId, region, networkAttachmentName)
1175+
1176+
acctest.VcrTest(t, resource.TestCase{
1177+
PreCheck: func() { acctest.AccTestPreCheck(t) },
1178+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
1179+
CheckDestroy: testAccSqlDatabaseInstanceDestroyProducer(t),
1180+
Steps: []resource.TestStep{
1181+
{
1182+
Config: testAccSqlDatabaseInstance_withPSCEnabled_withoutPscOutbound(instanceName),
1183+
Check: resource.ComposeTestCheckFunc(verifyPscNetorkAttachmentOperation("google_sql_database_instance.instance", true, true, "")),
1184+
},
1185+
{
1186+
ResourceName: "google_sql_database_instance.instance",
1187+
ImportState: true,
1188+
ImportStateVerify: true,
1189+
ImportStateIdPrefix: fmt.Sprintf("%s/", projectId),
1190+
ImportStateVerifyIgnore: []string{"deletion_protection"},
1191+
},
1192+
{
1193+
Config: testAccSqlDatabaseInstance_withPSCEnabled_withNetworkAttachmentUri(instanceName, networkAttachmentUri),
1194+
Check: resource.ComposeTestCheckFunc(verifyPscNetorkAttachmentOperation("google_sql_database_instance.instance", true, true, networkAttachmentUri)),
1195+
},
1196+
{
1197+
ResourceName: "google_sql_database_instance.instance",
1198+
ImportState: true,
1199+
ImportStateVerify: true,
1200+
ImportStateIdPrefix: fmt.Sprintf("%s/", projectId),
1201+
ImportStateVerifyIgnore: []string{"deletion_protection"},
1202+
},
1203+
{
1204+
Config: testAccSqlDatabaseInstance_withPSCEnabled_withoutPscOutbound(instanceName),
1205+
Check: resource.ComposeTestCheckFunc(verifyPscNetorkAttachmentOperation("google_sql_database_instance.instance", true, true, "")),
1206+
},
1207+
},
1208+
})
1209+
}
1210+
1211+
func TestAccSqlDatabaseInstance_withPscEnabled_withNetworkAttachmentUriOnCreate(t *testing.T) {
1212+
t.Parallel()
1213+
1214+
random_suffix := acctest.RandString(t, 10)
1215+
instanceName := "tf-test-" + random_suffix
1216+
projectId := envvar.GetTestProjectFromEnv()
1217+
region := "us-central1"
1218+
networkNameStr := "tf-test-cloud-sql-network-" + random_suffix
1219+
subnetworkNameStr := "tf-test-cloud-sql-subnetwork-" + random_suffix
1220+
networkAttachmentNameStr := "tf-test-cloud-sql-update-na-" + random_suffix
1221+
networkName := acctest.BootstrapSharedTestNetwork(t, networkNameStr)
1222+
subnetworkName := acctest.BootstrapSubnet(t, subnetworkNameStr, networkName)
1223+
networkAttachmentName := acctest.BootstrapNetworkAttachment(t, networkAttachmentNameStr, subnetworkName)
1224+
networkAttachmentUri := fmt.Sprintf("projects/%s/regions/%s/networkAttachments/%s", projectId, region, networkAttachmentName)
1225+
1226+
acctest.VcrTest(t, resource.TestCase{
1227+
PreCheck: func() { acctest.AccTestPreCheck(t) },
1228+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
1229+
CheckDestroy: testAccSqlDatabaseInstanceDestroyProducer(t),
1230+
Steps: []resource.TestStep{
1231+
{
1232+
Config: testAccSqlDatabaseInstance_withPSCEnabled_withNetworkAttachmentUri(instanceName, networkAttachmentUri),
1233+
ExpectError: regexp.MustCompile(`.*Network attachment used for Private Service Connect interfaces can not be assigned with instance creation.*`),
1234+
},
1235+
},
1236+
})
1237+
}
1238+
11611239
func TestAccSqlDatabaseInstance_withPrivateNetwork_withAllocatedIpRange(t *testing.T) {
11621240

11631241
t.Parallel()
@@ -4923,6 +5001,49 @@ func verifyPscAutoConnectionsOperation(resourceName string, isPscConfigExpected
49235001
}
49245002
}
49255003

5004+
func verifyPscNetorkAttachmentOperation(resourceName string, isPscConfigExpected bool, expectedPscEnabled bool, expectedNetworkAttachmentUri string) func(*terraform.State) error {
5005+
return func(s *terraform.State) error {
5006+
resource, ok := s.RootModule().Resources[resourceName]
5007+
if !ok {
5008+
return fmt.Errorf("Can't find %s in state", resourceName)
5009+
}
5010+
5011+
resourceAttributes := resource.Primary.Attributes
5012+
_, ok = resourceAttributes["settings.0.ip_configuration.#"]
5013+
if !ok {
5014+
return fmt.Errorf("settings.0.ip_configuration.# block is not present in state for %s", resourceName)
5015+
}
5016+
5017+
if isPscConfigExpected {
5018+
_, ok := resourceAttributes["settings.0.ip_configuration.0.psc_config.#"]
5019+
if !ok {
5020+
return fmt.Errorf("settings.0.ip_configuration.0.psc_config property is not present or set in state of %s", resourceName)
5021+
}
5022+
5023+
pscEnabledStr, ok := resourceAttributes["settings.0.ip_configuration.0.psc_config.0.psc_enabled"]
5024+
pscEnabled, err := strconv.ParseBool(pscEnabledStr)
5025+
if err != nil || pscEnabled != expectedPscEnabled {
5026+
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)
5027+
}
5028+
5029+
networkAttachmentUriStr, ok := resourceAttributes["settings.0.ip_configuration.0.psc_config.0.network_attachment_uri"]
5030+
if !ok {
5031+
return fmt.Errorf("settings.0.ip_configuration.0.psc_config.0.network_attachment_uri block is not present in state for %s", resourceName)
5032+
}
5033+
5034+
if networkAttachmentUriStr != expectedNetworkAttachmentUri && len(networkAttachmentUriStr) == 0 {
5035+
return fmt.Errorf("settings.0.ip_configuration.0.psc_config.0.network_attachment_uri block is not set in state for %s", resourceName)
5036+
}
5037+
5038+
if networkAttachmentUriStr != expectedNetworkAttachmentUri {
5039+
return fmt.Errorf("settings.0.ip_configuration.0.psc_config.0.network_attachment_uri block does not match the expected value for %s", resourceName)
5040+
}
5041+
}
5042+
5043+
return nil
5044+
}
5045+
}
5046+
49265047
func testAccSqlDatabaseInstance_withoutMCPEnabled(instanceName string) string {
49275048
return fmt.Sprintf(`
49285049
resource "google_sql_database_instance" "instance" {
@@ -4983,6 +5104,32 @@ resource "google_sql_database_instance" "instance" {
49835104
`, instanceName)
49845105
}
49855106

5107+
func testAccSqlDatabaseInstance_withPSCEnabled_withoutPscOutbound(instanceName string) string {
5108+
return fmt.Sprintf(`
5109+
resource "google_sql_database_instance" "instance" {
5110+
name = "%s"
5111+
region = "us-central1"
5112+
database_version = "MYSQL_8_0"
5113+
deletion_protection = false
5114+
settings {
5115+
tier = "db-g1-small"
5116+
ip_configuration {
5117+
psc_config {
5118+
psc_enabled = true
5119+
network_attachment_uri = ""
5120+
}
5121+
ipv4_enabled = false
5122+
}
5123+
backup_configuration {
5124+
enabled = true
5125+
binary_log_enabled = true
5126+
}
5127+
availability_type = "REGIONAL"
5128+
}
5129+
}
5130+
`, instanceName)
5131+
}
5132+
49865133
func testAccSqlDatabaseInstance_withPSCEnabled_withPscAutoConnections(instanceName string, projectId string, networkName string) string {
49875134
return fmt.Sprintf(`
49885135
data "google_compute_network" "testnetwork" {
@@ -5016,6 +5163,32 @@ resource "google_sql_database_instance" "instance" {
50165163
`, networkName, instanceName, projectId, networkName, projectId)
50175164
}
50185165

5166+
func testAccSqlDatabaseInstance_withPSCEnabled_withNetworkAttachmentUri(instanceName string, networkAttachmentUri string) string {
5167+
return fmt.Sprintf(`
5168+
5169+
resource "google_sql_database_instance" "instance" {
5170+
name = "%s"
5171+
region = "us-central1"
5172+
database_version = "MYSQL_8_0"
5173+
deletion_protection = false
5174+
settings {
5175+
tier = "db-g1-small"
5176+
ip_configuration {
5177+
psc_config {
5178+
psc_enabled = true
5179+
network_attachment_uri = "%s"
5180+
}
5181+
ipv4_enabled = false
5182+
}
5183+
backup_configuration {
5184+
enabled = true
5185+
binary_log_enabled = true
5186+
}
5187+
availability_type = "REGIONAL"
5188+
}
5189+
}`, instanceName, networkAttachmentUri)
5190+
}
5191+
50195192
func testAccSqlDatabaseInstance_withPrivateNetwork_withoutAllocatedIpRange(databaseName, networkName string, specifyPrivatePathOption bool, enablePrivatePath bool) string {
50205193
privatePathOption := ""
50215194
if specifyPrivatePathOption {

website/docs/r/sql_database_instance.html.markdown

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,31 @@ resource "google_sql_database_instance" "main" {
258258
}
259259
```
260260

261+
### Cloud SQL Instance with PSC outbound
262+
263+
```hcl
264+
resource "google_sql_database_instance" "main" {
265+
name = "psc-enabled-main-instance"
266+
database_version = "MYSQL_8_0"
267+
settings {
268+
tier = "db-f1-micro"
269+
ip_configuration {
270+
psc_config {
271+
psc_enabled = true
272+
allowed_consumer_projects = ["allowed-consumer-project-name"]
273+
network_attachment_uri = "network-attachment-uri"
274+
}
275+
ipv4_enabled = false
276+
}
277+
backup_configuration {
278+
enabled = true
279+
binary_log_enabled = true
280+
}
281+
availability_type = "REGIONAL"
282+
}
283+
}
284+
```
285+
261286
## Argument Reference
262287

263288
The following arguments are supported:
@@ -479,6 +504,8 @@ The optional `settings.ip_configuration.psc_config` sublist supports:
479504

480505
* `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."
481506

507+
* `network_attachment_uri` - (Optional) Network Attachment URI in the format `projects/project1/regions/region1/networkAttachments/networkAttachment1` to enable outbound connectivity on PSC instance.
508+
482509
* `consumer_service_project_id` - (Optional) The project ID of consumer service project of this consumer endpoint.
483510

484511
The optional `settings.location_preference` subblock supports:

0 commit comments

Comments
 (0)