Skip to content

Commit

Permalink
Support creating Database Migration Service connection profiles conne…
Browse files Browse the repository at this point in the history
…cted to existing Cloud SQL and AlloyDB instances (#11484) (#19291)

[upstream:c7d11a88c86d088fa451036a98ea9424d4d3f369]

Signed-off-by: Modular Magician <magic-modules@google.com>
  • Loading branch information
modular-magician authored Aug 27, 2024
1 parent a0f2a77 commit 1b34d2d
Show file tree
Hide file tree
Showing 4 changed files with 419 additions and 53 deletions.
3 changes: 3 additions & 0 deletions .changelog/11484.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:enhancement
Support creating DMS connection profiles that link to existing Cloud SQL instances/AlloyDB clusters.
```
Original file line number Diff line number Diff line change
Expand Up @@ -388,33 +388,30 @@ Please refer to the field 'effective_labels' for all of the labels present on th
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"host": {
"cloud_sql_id": {
Type: schema.TypeString,
Required: true,
Description: `Required. The IP or hostname of the source MySQL database.`,
Optional: true,
Description: `If the source is a Cloud SQL database, use this field to provide the Cloud SQL instance ID of the source.`,
},
"host": {
Type: schema.TypeString,
Optional: true,
Description: `The IP or hostname of the source MySQL database.`,
RequiredWith: []string{"mysql.0.port", "mysql.0.username"},
},
"password": {
Type: schema.TypeString,
Required: true,
Optional: true,
ForceNew: true,
Description: `Required. Input only. The password for the user that Database Migration Service will be using to connect to the database.
Description: `Input only. The password for the user that Database Migration Service will be using to connect to the database.
This field is not returned on request, and the value is encrypted when stored in Database Migration Service.`,
Sensitive: true,
},
"port": {
Type: schema.TypeInt,
Required: true,
Description: `Required. The network port of the source MySQL database.`,
},
"username": {
Type: schema.TypeString,
Required: true,
Description: `Required. The username that Database Migration Service will use to connect to the database. The value is encrypted when stored in Database Migration Service.`,
},
"cloud_sql_id": {
Type: schema.TypeString,
Optional: true,
Description: `If the source is a Cloud SQL database, use this field to provide the Cloud SQL instance ID of the source.`,
Type: schema.TypeInt,
Optional: true,
Description: `The network port of the source MySQL database.`,
RequiredWith: []string{"mysql.0.host", "mysql.0.username"},
},
"ssl": {
Type: schema.TypeList,
Expand Down Expand Up @@ -455,6 +452,12 @@ If this field is used then the 'clientCertificate' field is mandatory.`,
},
},
},
"username": {
Type: schema.TypeString,
Optional: true,
Description: `The username that Database Migration Service will use to connect to the database. The value is encrypted when stored in Database Migration Service.`,
RequiredWith: []string{"mysql.0.host", "mysql.0.port"},
},
"password_set": {
Type: schema.TypeBool,
Computed: true,
Expand Down Expand Up @@ -626,33 +629,36 @@ Static IP address connectivity configured on service project.`,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"host": {
"alloydb_cluster_id": {
Type: schema.TypeString,
Required: true,
Description: `Required. The IP or hostname of the source MySQL database.`,
Optional: true,
Description: `If the connected database is an AlloyDB instance, use this field to provide the AlloyDB cluster ID.`,
},
"cloud_sql_id": {
Type: schema.TypeString,
Optional: true,
Description: `If the source is a Cloud SQL database, use this field to provide the Cloud SQL instance ID of the source.`,
},
"host": {
Type: schema.TypeString,
Optional: true,
Description: `The IP or hostname of the source MySQL database.`,
RequiredWith: []string{"postgresql.0.port", "postgresql.0.username", "postgresql.0.password"},
},
"password": {
Type: schema.TypeString,
Required: true,
Optional: true,
ForceNew: true,
Description: `Required. Input only. The password for the user that Database Migration Service will be using to connect to the database.
Description: `Input only. The password for the user that Database Migration Service will be using to connect to the database.
This field is not returned on request, and the value is encrypted when stored in Database Migration Service.`,
Sensitive: true,
Sensitive: true,
RequiredWith: []string{"postgresql.0.host", "postgresql.0.port", "postgresql.0.username"},
},
"port": {
Type: schema.TypeInt,
Required: true,
Description: `Required. The network port of the source MySQL database.`,
},
"username": {
Type: schema.TypeString,
Required: true,
Description: `Required. The username that Database Migration Service will use to connect to the database. The value is encrypted when stored in Database Migration Service.`,
},
"cloud_sql_id": {
Type: schema.TypeString,
Optional: true,
Description: `If the source is a Cloud SQL database, use this field to provide the Cloud SQL instance ID of the source.`,
Type: schema.TypeInt,
Optional: true,
Description: `The network port of the source MySQL database.`,
RequiredWith: []string{"postgresql.0.host", "postgresql.0.username", "postgresql.0.password"},
},
"ssl": {
Type: schema.TypeList,
Expand Down Expand Up @@ -695,6 +701,12 @@ If this field is used then the 'clientCertificate' field is mandatory.`,
},
},
},
"username": {
Type: schema.TypeString,
Optional: true,
Description: `The username that Database Migration Service will use to connect to the database. The value is encrypted when stored in Database Migration Service.`,
RequiredWith: []string{"postgresql.0.host", "postgresql.0.port", "postgresql.0.password"},
},
"network_architecture": {
Type: schema.TypeString,
Computed: true,
Expand Down Expand Up @@ -1386,6 +1398,8 @@ func flattenDatabaseMigrationServiceConnectionProfilePostgresql(v interface{}, d
flattenDatabaseMigrationServiceConnectionProfilePostgresqlSsl(original["ssl"], d, config)
transformed["cloud_sql_id"] =
flattenDatabaseMigrationServiceConnectionProfilePostgresqlCloudSqlId(original["cloudSqlId"], d, config)
transformed["alloydb_cluster_id"] =
flattenDatabaseMigrationServiceConnectionProfilePostgresqlAlloydbClusterId(original["alloydbClusterId"], d, config)
transformed["network_architecture"] =
flattenDatabaseMigrationServiceConnectionProfilePostgresqlNetworkArchitecture(original["networkArchitecture"], d, config)
return []interface{}{transformed}
Expand Down Expand Up @@ -1462,6 +1476,10 @@ func flattenDatabaseMigrationServiceConnectionProfilePostgresqlCloudSqlId(v inte
return v
}

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

func flattenDatabaseMigrationServiceConnectionProfilePostgresqlNetworkArchitecture(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
return v
}
Expand Down Expand Up @@ -2220,6 +2238,13 @@ func expandDatabaseMigrationServiceConnectionProfilePostgresql(v interface{}, d
transformed["cloudSqlId"] = transformedCloudSqlId
}

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

transformedNetworkArchitecture, err := expandDatabaseMigrationServiceConnectionProfilePostgresqlNetworkArchitecture(original["network_architecture"], d, config)
if err != nil {
return nil, err
Expand Down Expand Up @@ -2310,6 +2335,10 @@ func expandDatabaseMigrationServiceConnectionProfilePostgresqlCloudSqlId(v inter
return v, nil
}

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

func expandDatabaseMigrationServiceConnectionProfilePostgresqlNetworkArchitecture(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
return v, nil
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,201 @@ resource "google_database_migration_service_connection_profile" "postgresprofile
`, context)
}

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

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

acctest.VcrTest(t, resource.TestCase{
PreCheck: func() { acctest.AccTestPreCheck(t) },
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
CheckDestroy: testAccCheckDatabaseMigrationServiceConnectionProfileDestroyProducer(t),
Steps: []resource.TestStep{
{
Config: testAccDatabaseMigrationServiceConnectionProfile_databaseMigrationServiceConnectionProfileExistingMysqlExample(context),
},
{
ResourceName: "google_database_migration_service_connection_profile.existing-mysql",
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"connection_profile_id", "labels", "location", "terraform_labels"},
},
},
})
}

func testAccDatabaseMigrationServiceConnectionProfile_databaseMigrationServiceConnectionProfileExistingMysqlExample(context map[string]interface{}) string {
return acctest.Nprintf(`
data "google_project" "project" {
}
resource "google_sql_database_instance" "destination_csql" {
name = "tf-test-destination-csql%{random_suffix}"
database_version = "MYSQL_5_7"
settings {
tier = "db-n1-standard-1"
deletion_protection_enabled = false
}
deletion_protection = false
}
resource "google_database_migration_service_connection_profile" "existing-mysql" {
location = "us-central1"
connection_profile_id = "tf-test-destination-cp%{random_suffix}"
display_name = "tf-test-destination-cp%{random_suffix}_display"
labels = {
foo = "bar"
}
mysql {
cloud_sql_id = "tf-test-destination-csql%{random_suffix}"
}
depends_on = [google_sql_database_instance.destination_csql]
}
`, context)
}

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

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

acctest.VcrTest(t, resource.TestCase{
PreCheck: func() { acctest.AccTestPreCheck(t) },
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
CheckDestroy: testAccCheckDatabaseMigrationServiceConnectionProfileDestroyProducer(t),
Steps: []resource.TestStep{
{
Config: testAccDatabaseMigrationServiceConnectionProfile_databaseMigrationServiceConnectionProfileExistingPostgresExample(context),
},
{
ResourceName: "google_database_migration_service_connection_profile.existing-psql",
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"connection_profile_id", "labels", "location", "terraform_labels"},
},
},
})
}

func testAccDatabaseMigrationServiceConnectionProfile_databaseMigrationServiceConnectionProfileExistingPostgresExample(context map[string]interface{}) string {
return acctest.Nprintf(`
data "google_project" "project" {
}
resource "google_sql_database_instance" "destination_csql" {
name = "tf-test-destination-csql%{random_suffix}"
database_version = "POSTGRES_15"
settings {
tier = "db-custom-2-13312"
deletion_protection_enabled = false
}
deletion_protection = false
}
resource "google_database_migration_service_connection_profile" "existing-psql" {
location = "us-central1"
connection_profile_id = "tf-test-destination-cp%{random_suffix}"
display_name = "tf-test-destination-cp%{random_suffix}_display"
labels = {
foo = "bar"
}
postgresql {
cloud_sql_id = "tf-test-destination-csql%{random_suffix}"
}
depends_on = [google_sql_database_instance.destination_csql]
}
`, context)
}

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

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

acctest.VcrTest(t, resource.TestCase{
PreCheck: func() { acctest.AccTestPreCheck(t) },
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
CheckDestroy: testAccCheckDatabaseMigrationServiceConnectionProfileDestroyProducer(t),
Steps: []resource.TestStep{
{
Config: testAccDatabaseMigrationServiceConnectionProfile_databaseMigrationServiceConnectionProfileExistingAlloydbExample(context),
},
{
ResourceName: "google_database_migration_service_connection_profile.existing-alloydb",
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"connection_profile_id", "labels", "location", "terraform_labels"},
},
},
})
}

func testAccDatabaseMigrationServiceConnectionProfile_databaseMigrationServiceConnectionProfileExistingAlloydbExample(context map[string]interface{}) string {
return acctest.Nprintf(`
data "google_project" "project" {
}
resource "google_alloydb_cluster" "destination_alloydb" {
cluster_id = "tf-test-destination-alloydb%{random_suffix}"
location = "us-central1"
network_config {
network = google_compute_network.default.id
}
database_version = "POSTGRES_15"
initial_user {
user = "tf-test-destination-alloydb%{random_suffix}"
password = "tf-test-destination-alloydb%{random_suffix}"
}
}
resource "google_alloydb_instance" "destination_alloydb_primary" {
cluster = google_alloydb_cluster.destination_alloydb.name
instance_id = "tf-test-destination-alloydb%{random_suffix}-primary"
instance_type = "PRIMARY"
depends_on = [google_service_networking_connection.vpc_connection]
}
resource "google_compute_global_address" "private_ip_alloc" {
name = "tf-test-destination-alloydb%{random_suffix}"
address_type = "INTERNAL"
purpose = "VPC_PEERING"
prefix_length = 16
network = google_compute_network.default.id
}
resource "google_service_networking_connection" "vpc_connection" {
network = google_compute_network.default.id
service = "servicenetworking.googleapis.com"
reserved_peering_ranges = [google_compute_global_address.private_ip_alloc.name]
}
resource "google_compute_network" "default" {
name = "tf-test-destination-alloydb%{random_suffix}"
}
resource "google_database_migration_service_connection_profile" "existing-alloydb" {
location = "us-central1"
connection_profile_id = "tf-test-destination-cp%{random_suffix}"
display_name = "tf-test-destination-cp%{random_suffix}_display"
labels = {
foo = "bar"
}
postgresql {
alloydb_cluster_id = "tf-test-destination-alloydb%{random_suffix}"
}
depends_on = [google_alloydb_cluster.destination_alloydb, google_alloydb_instance.destination_alloydb_primary]
}
`, context)
}

func testAccCheckDatabaseMigrationServiceConnectionProfileDestroyProducer(t *testing.T) func(s *terraform.State) error {
return func(s *terraform.State) error {
for name, rs := range s.RootModule().Resources {
Expand Down
Loading

0 comments on commit 1b34d2d

Please # to comment.