diff --git a/.changelog/27949.txt b/.changelog/27949.txt new file mode 100644 index 000000000000..45a60447096a --- /dev/null +++ b/.changelog/27949.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/aws_dms_endpoint: Add ability to use AWS Secrets Manager with the `sybase` engine +``` \ No newline at end of file diff --git a/internal/service/dms/endpoint.go b/internal/service/dms/endpoint.go index f2703e6aaa71..4255bd19a461 100644 --- a/internal/service/dms/endpoint.go +++ b/internal/service/dms/endpoint.go @@ -866,6 +866,25 @@ func resourceEndpointCreate(d *schema.ResourceData, meta interface{}) error { DatabaseName: aws.String(d.Get("database_name").(string)), } + // Set connection info in top-level namespace as well + expandTopLevelConnectionInfo(d, input) + } + case engineNameSybase: + if _, ok := d.GetOk("secrets_manager_arn"); ok { + input.SybaseSettings = &dms.SybaseSettings{ + SecretsManagerAccessRoleArn: aws.String(d.Get("secrets_manager_access_role_arn").(string)), + SecretsManagerSecretId: aws.String(d.Get("secrets_manager_arn").(string)), + DatabaseName: aws.String(d.Get("database_name").(string)), + } + } else { + input.SybaseSettings = &dms.SybaseSettings{ + Username: aws.String(d.Get("username").(string)), + Password: aws.String(d.Get("password").(string)), + ServerName: aws.String(d.Get("server_name").(string)), + Port: aws.Int64(int64(d.Get("port").(int))), + DatabaseName: aws.String(d.Get("database_name").(string)), + } + // Set connection info in top-level namespace as well expandTopLevelConnectionInfo(d, input) } @@ -1185,6 +1204,30 @@ func resourceEndpointUpdate(d *schema.ResourceData, meta interface{}) error { } input.EngineName = aws.String(engineName) // Must be included (should be 'postgres') + // Update connection info in top-level namespace as well + expandTopLevelConnectionInfoModify(d, input) + } + } + case engineNameSybase: + if d.HasChanges( + "username", "password", "server_name", "port", "database_name", "secrets_manager_access_role_arn", + "secrets_manager_arn") { + if _, ok := d.GetOk("secrets_manager_arn"); ok { + input.SybaseSettings = &dms.SybaseSettings{ + DatabaseName: aws.String(d.Get("database_name").(string)), + SecretsManagerAccessRoleArn: aws.String(d.Get("secrets_manager_access_role_arn").(string)), + SecretsManagerSecretId: aws.String(d.Get("secrets_manager_arn").(string)), + } + } else { + input.SybaseSettings = &dms.SybaseSettings{ + Username: aws.String(d.Get("username").(string)), + Password: aws.String(d.Get("password").(string)), + ServerName: aws.String(d.Get("server_name").(string)), + Port: aws.Int64(int64(d.Get("port").(int))), + DatabaseName: aws.String(d.Get("database_name").(string)), + } + input.EngineName = aws.String(engineName) // Must be included (should be 'postgres') + // Update connection info in top-level namespace as well expandTopLevelConnectionInfoModify(d, input) } @@ -1407,6 +1450,17 @@ func resourceEndpointSetState(d *schema.ResourceData, endpoint *dms.Endpoint) er } else { flattenTopLevelConnectionInfo(d, endpoint) } + case engineNameSybase: + if endpoint.SybaseSettings != nil { + d.Set("username", endpoint.SybaseSettings.Username) + d.Set("server_name", endpoint.SybaseSettings.ServerName) + d.Set("port", endpoint.SybaseSettings.Port) + d.Set("database_name", endpoint.SybaseSettings.DatabaseName) + d.Set("secrets_manager_access_role_arn", endpoint.SybaseSettings.SecretsManagerAccessRoleArn) + d.Set("secrets_manager_arn", endpoint.SybaseSettings.SecretsManagerSecretId) + } else { + flattenTopLevelConnectionInfo(d, endpoint) + } case engineNameS3: if err := d.Set("s3_settings", flattenS3Settings(endpoint.S3Settings)); err != nil { return fmt.Errorf("Error setting s3_settings for DMS: %s", err) diff --git a/internal/service/dms/endpoint_test.go b/internal/service/dms/endpoint_test.go index 6bad83866605..a25849f3759d 100644 --- a/internal/service/dms/endpoint_test.go +++ b/internal/service/dms/endpoint_test.go @@ -284,7 +284,7 @@ func TestAccDMSEndpoint_S3_basic(t *testing.T) { Config: testAccEndpointConfig_s3Update(rName), Check: resource.ComposeTestCheckFunc( testAccCheckEndpointExists(resourceName), - resource.TestMatchResourceAttr(resourceName, "extra_connection_attributes", regexp.MustCompile(`key=value;`)), + resource.TestMatchResourceAttr(resourceName, "extra_connection_attributes", regexp.MustCompile(``)), resource.TestCheckResourceAttr(resourceName, "s3_settings.#", "1"), resource.TestCheckResourceAttr(resourceName, "s3_settings.0.external_table_definition", "new-external_table_definition"), resource.TestCheckResourceAttr(resourceName, "s3_settings.0.csv_row_delimiter", "\\r"), @@ -895,7 +895,7 @@ func TestAccDMSEndpoint_MySQL_update(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "password", "tftest-new-password"), resource.TestCheckResourceAttr(resourceName, "database_name", "tftest-new-database_name"), resource.TestCheckResourceAttr(resourceName, "ssl_mode", "none"), - resource.TestMatchResourceAttr(resourceName, "extra_connection_attributes", regexp.MustCompile(`key=value;`)), + resource.TestMatchResourceAttr(resourceName, "extra_connection_attributes", regexp.MustCompile(`CleanSrcMetadataOnMismatch=false;`)), ), }, { @@ -1231,6 +1231,121 @@ func TestAccDMSEndpoint_SQLServer_kmsKey(t *testing.T) { }) } +func TestAccDMSEndpoint_Sybase_basic(t *testing.T) { + resourceName := "aws_dms_endpoint.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, dms.EndpointsID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckEndpointDestroy, + Steps: []resource.TestStep{ + { + Config: testAccEndpointConfig_sybase(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckEndpointExists(resourceName), + resource.TestCheckResourceAttrSet(resourceName, "endpoint_arn"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"password"}, + }, + }, + }) +} + +func TestAccDMSEndpoint_Sybase_secretID(t *testing.T) { + resourceName := "aws_dms_endpoint.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, dms.EndpointsID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckEndpointDestroy, + Steps: []resource.TestStep{ + { + Config: testAccEndpointConfig_sybaseSecretID(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckEndpointExists(resourceName), + resource.TestCheckResourceAttrSet(resourceName, "endpoint_arn"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccDMSEndpoint_Sybase_update(t *testing.T) { + resourceName := "aws_dms_endpoint.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, dms.EndpointsID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckEndpointDestroy, + Steps: []resource.TestStep{ + { + Config: testAccEndpointConfig_sybase(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckEndpointExists(resourceName), + resource.TestCheckResourceAttrSet(resourceName, "endpoint_arn"), + ), + }, + { + Config: testAccEndpointConfig_sybaseUpdate(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckEndpointExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "server_name", "tftest-new-server_name"), + resource.TestCheckResourceAttr(resourceName, "port", "27018"), + resource.TestCheckResourceAttr(resourceName, "username", "tftest-new-username"), + resource.TestCheckResourceAttr(resourceName, "password", "tftest-new-password"), + resource.TestCheckResourceAttr(resourceName, "database_name", "tftest-new-database_name"), + resource.TestCheckResourceAttr(resourceName, "ssl_mode", "none"), + resource.TestMatchResourceAttr(resourceName, "extra_connection_attributes", regexp.MustCompile(`key=value;`)), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"password"}, + }, + }, + }) +} + +// https://github.com/hashicorp/terraform-provider-aws/issues/23143 +func TestAccDMSEndpoint_Sybase_kmsKey(t *testing.T) { + resourceName := "aws_dms_endpoint.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, dms.EndpointsID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckEndpointDestroy, + Steps: []resource.TestStep{ + { + Config: testAccEndpointConfig_sybaseKey(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckEndpointExists(resourceName), + resource.TestCheckResourceAttrSet(resourceName, "endpoint_arn"), + ), + }, + }, + }) +} + func TestAccDMSEndpoint_docDB(t *testing.T) { resourceName := "aws_dms_endpoint.test" rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) @@ -2041,7 +2156,7 @@ resource "aws_dms_endpoint" "test" { endpoint_type = "target" engine_name = "s3" ssl_mode = "none" - extra_connection_attributes = "key=value;" + extra_connection_attributes = "" tags = { Name = %[1]q @@ -2602,7 +2717,7 @@ resource "aws_dms_endpoint" "test" { password = "tftest-new-password" database_name = "tftest-new-database_name" ssl_mode = "none" - extra_connection_attributes = "key=value;" + extra_connection_attributes = "CleanSrcMetadataOnMismatch=false;" tags = { Name = %[1]q @@ -2817,6 +2932,74 @@ resource "aws_dms_endpoint" "test" { `, rName)) } +func testAccEndpointConfig_sybase(rName string) string { + return fmt.Sprintf(` +resource "aws_dms_endpoint" "test" { + endpoint_id = %[1]q + endpoint_type = "source" + engine_name = "sybase" + server_name = "tftest" + port = 27017 + username = "tftest" + password = "tftest" + database_name = "tftest" + ssl_mode = "none" + extra_connection_attributes = "" + + tags = { + Name = %[1]q + Update = "to-update" + Remove = "to-remove" + } +} +`, rName) +} + +func testAccEndpointConfig_sybaseUpdate(rName string) string { + return fmt.Sprintf(` +resource "aws_dms_endpoint" "test" { + endpoint_id = %[1]q + endpoint_type = "source" + engine_name = "sybase" + server_name = "tftest-new-server_name" + port = 27018 + username = "tftest-new-username" + password = "tftest-new-password" + database_name = "tftest-new-database_name" + ssl_mode = "none" + extra_connection_attributes = "key=value;" + + tags = { + Name = %[1]q + Update = "updated" + Add = "added" + } +} +`, rName) +} + +func testAccEndpointConfig_sybaseSecretID(rName string) string { + return acctest.ConfigCompose(testAccEndpointConfig_secretBase(rName), fmt.Sprintf(` +resource "aws_dms_endpoint" "test" { + endpoint_id = %[1]q + endpoint_type = "source" + engine_name = "sybase" + secrets_manager_access_role_arn = aws_iam_role.test.arn + secrets_manager_arn = aws_secretsmanager_secret.test.id + + database_name = "tftest" + ssl_mode = "none" + extra_connection_attributes = "" + + tags = { + Name = %[1]q + Update = "to-update" + Remove = "to-remove" + } +} +`, rName)) +} + func testAccEndpointConfig_docDB(rName string) string { return fmt.Sprintf(` resource "aws_dms_endpoint" "test" { @@ -2967,6 +3150,33 @@ resource "aws_dms_endpoint" "test" { `, rName) } +func testAccEndpointConfig_sybaseKey(rName string) string { + return fmt.Sprintf(` +resource "aws_kms_key" "test" { + description = %[1]q + deletion_window_in_days = 7 +} + +resource "aws_dms_endpoint" "test" { + endpoint_id = %[1]q + endpoint_type = "source" + engine_name = "sybase" + server_name = "tftest" + port = 27018 + username = "tftest" + password = "tftest" + database_name = "tftest" + ssl_mode = "none" + extra_connection_attributes = "" + kms_key_arn = aws_kms_key.test.arn + + tags = { + Name = %[1]q + } +} +`, rName) +} + func testAccEndpointConfig_redis(rName string) string { return fmt.Sprintf(` resource "aws_dms_endpoint" "test" {