diff --git a/.changelog/45516.txt b/.changelog/45516.txt new file mode 100644 index 000000000000..0c9ca181d70b --- /dev/null +++ b/.changelog/45516.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +aws_dms_data_provider +``` diff --git a/internal/service/dms/data_provider.go b/internal/service/dms/data_provider.go new file mode 100644 index 000000000000..fbc1d47165da --- /dev/null +++ b/internal/service/dms/data_provider.go @@ -0,0 +1,488 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package dms + +import ( + "context" + "log" + "reflect" + + "github.com/aws/aws-sdk-go-v2/aws" + dms "github.com/aws/aws-sdk-go-v2/service/databasemigrationservice" + awstypes "github.com/aws/aws-sdk-go-v2/service/databasemigrationservice/types" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + sdkretry "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/errs" + "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" + tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" + "github.com/hashicorp/terraform-provider-aws/names" +) + +// @SDKResource("aws_dms_data_provider", name="Data Provider") +// @Tags(identifierAttribute="data_provider_arn") +func resourceDataProvider() *schema.Resource { + return &schema.Resource{ + CreateWithoutTimeout: resourceDataProviderCreate, + ReadWithoutTimeout: resourceDataProviderRead, + UpdateWithoutTimeout: resourceDataProviderUpdate, + DeleteWithoutTimeout: resourceDataProviderDelete, + + Importer: &schema.ResourceImporter{ + StateContext: schema.ImportStatePassthroughContext, + }, + + Schema: map[string]*schema.Schema{ + "data_provider_arn": { + Type: schema.TypeString, + Computed: true, + }, + "data_provider_name": { + Type: schema.TypeString, + Optional: true, + }, + names.AttrDescription: { + Type: schema.TypeString, + Optional: true, + }, + names.AttrEngine: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "settings": { + Type: schema.TypeList, + Required: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "docdb_settings": dataProviderSettingsSchema(), + "ibm_db2_luw_settings": dataProviderSettingsSchema(), + "ibm_db2_zos_settings": dataProviderSettingsSchema(), + "mariadb_settings": dataProviderSettingsSchema(), + "microsoft_sql_server_settings": dataProviderSettingsSchema(), + "mongodb_settings": dataProviderSettingsSchema(), + "mysql_settings": dataProviderSettingsSchema(), + "oracle_settings": dataProviderSettingsSchema(), + "postgres_settings": dataProviderSettingsSchema(), + "redshift_settings": dataProviderSettingsSchema(), + "sybase_ase_settings": dataProviderSettingsSchema(), + }, + }, + }, + names.AttrTags: tftags.TagsSchema(), + names.AttrTagsAll: tftags.TagsSchemaComputed(), + "virtual": { + Type: schema.TypeBool, + Optional: true, + }, + }, + } +} + +func dataProviderSettingsSchema() *schema.Schema { + return &schema.Schema{ + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + names.AttrCertificateARN: { + Type: schema.TypeString, + Optional: true, + }, + names.AttrDatabaseName: { + Type: schema.TypeString, + Optional: true, + }, + names.AttrPort: { + Type: schema.TypeInt, + Optional: true, + }, + "server_name": { + Type: schema.TypeString, + Optional: true, + }, + "ssl_mode": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + } +} + +func resourceDataProviderCreate(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { + var diags diag.Diagnostics + conn := meta.(*conns.AWSClient).DMSClient(ctx) + + input := &dms.CreateDataProviderInput{ + Engine: aws.String(d.Get(names.AttrEngine).(string)), + Settings: expandDataProviderSettings(d.Get("settings").([]any)), + Tags: getTagsIn(ctx), + } + + if v, ok := d.GetOk("data_provider_name"); ok { + input.DataProviderName = aws.String(v.(string)) + } + + if v, ok := d.GetOk(names.AttrDescription); ok { + input.Description = aws.String(v.(string)) + } + + if v, ok := d.GetOk("virtual"); ok { + input.Virtual = aws.Bool(v.(bool)) + } + + output, err := conn.CreateDataProvider(ctx, input) + + if err != nil { + return sdkdiag.AppendErrorf(diags, "creating DMS Data Provider: %s", err) + } + + d.SetId(aws.ToString(output.DataProvider.DataProviderArn)) + + return append(diags, resourceDataProviderRead(ctx, d, meta)...) +} + +func resourceDataProviderRead(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { + var diags diag.Diagnostics + conn := meta.(*conns.AWSClient).DMSClient(ctx) + + provider, err := findDataProviderByARN(ctx, conn, d.Id()) + + if !d.IsNewResource() && tfresource.NotFound(err) { + log.Printf("[WARN] DMS Data Provider (%s) not found, removing from state", d.Id()) + d.SetId("") + return diags + } + + if err != nil { + return sdkdiag.AppendErrorf(diags, "reading DMS Data Provider (%s): %s", d.Id(), err) + } + + d.Set("data_provider_arn", provider.DataProviderArn) + d.Set("data_provider_name", provider.DataProviderName) + d.Set(names.AttrDescription, provider.Description) + d.Set(names.AttrEngine, provider.Engine) + d.Set("virtual", provider.Virtual) + if err := d.Set("settings", flattenDataProviderSettings(provider.Settings)); err != nil { + return sdkdiag.AppendErrorf(diags, "setting settings: %s", err) + } + + return diags +} + +func resourceDataProviderUpdate(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { + var diags diag.Diagnostics + conn := meta.(*conns.AWSClient).DMSClient(ctx) + + if d.HasChangesExcept(names.AttrTags, names.AttrTagsAll) { + input := &dms.ModifyDataProviderInput{ + DataProviderIdentifier: aws.String(d.Id()), + } + + if d.HasChange("data_provider_name") { + input.DataProviderName = aws.String(d.Get("data_provider_name").(string)) + } + + if d.HasChange(names.AttrDescription) { + input.Description = aws.String(d.Get(names.AttrDescription).(string)) + } + + if d.HasChange("settings") { + input.Settings = expandDataProviderSettings(d.Get("settings").([]any)) + } + + _, err := conn.ModifyDataProvider(ctx, input) + + if err != nil { + return sdkdiag.AppendErrorf(diags, "updating DMS Data Provider (%s): %s", d.Id(), err) + } + } + + return append(diags, resourceDataProviderRead(ctx, d, meta)...) +} + +func resourceDataProviderDelete(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { + var diags diag.Diagnostics + conn := meta.(*conns.AWSClient).DMSClient(ctx) + + log.Printf("[DEBUG] Deleting DMS Data Provider: %s", d.Id()) + input := dms.DeleteDataProviderInput{ + DataProviderIdentifier: aws.String(d.Id()), + } + _, err := conn.DeleteDataProvider(ctx, &input) + + if errs.IsA[*awstypes.ResourceNotFoundFault](err) { + return diags + } + + if err != nil { + return sdkdiag.AppendErrorf(diags, "deleting DMS Data Provider (%s): %s", d.Id(), err) + } + + return diags +} + +func findDataProviderByARN(ctx context.Context, conn *dms.Client, arn string) (*awstypes.DataProvider, error) { + input := &dms.DescribeDataProvidersInput{ + Filters: []awstypes.Filter{ + { + Name: aws.String("data-provider-arn"), + Values: []string{arn}, + }, + }, + } + + output, err := conn.DescribeDataProviders(ctx, input) + + if errs.IsA[*awstypes.ResourceNotFoundFault](err) { + return nil, &sdkretry.NotFoundError{ + LastError: err, + LastRequest: input, + } + } + + if err != nil { + return nil, err + } + + return tfresource.AssertSingleValueResult(output.DataProviders) +} + +func expandDataProviderSettings(tfList []any) awstypes.DataProviderSettings { + if len(tfList) == 0 || tfList[0] == nil { + return nil + } + + tfMap := tfList[0].(map[string]any) + + if v, ok := tfMap["docdb_settings"].([]any); ok && len(v) > 0 && v[0] != nil { + return &awstypes.DataProviderSettingsMemberDocDbSettings{ + Value: *expandDocDBDataProviderSettings(v), + } + } + + if v, ok := tfMap["ibm_db2_luw_settings"].([]any); ok && len(v) > 0 && v[0] != nil { + return &awstypes.DataProviderSettingsMemberIbmDb2LuwSettings{ + Value: *expandIBMDB2LUWDataProviderSettings(v), + } + } + + if v, ok := tfMap["ibm_db2_zos_settings"].([]any); ok && len(v) > 0 && v[0] != nil { + return &awstypes.DataProviderSettingsMemberIbmDb2zOsSettings{ + Value: *expandIBMDB2zOSDataProviderSettings(v), + } + } + + if v, ok := tfMap["mariadb_settings"].([]any); ok && len(v) > 0 && v[0] != nil { + return &awstypes.DataProviderSettingsMemberMariaDbSettings{ + Value: *expandMariaDBDataProviderSettings(v), + } + } + + if v, ok := tfMap["microsoft_sql_server_settings"].([]any); ok && len(v) > 0 && v[0] != nil { + return &awstypes.DataProviderSettingsMemberMicrosoftSqlServerSettings{ + Value: *expandMicrosoftSQLServerDataProviderSettings(v), + } + } + + if v, ok := tfMap["mongodb_settings"].([]any); ok && len(v) > 0 && v[0] != nil { + return &awstypes.DataProviderSettingsMemberMongoDbSettings{ + Value: *expandMongoDBDataProviderSettings(v), + } + } + + if v, ok := tfMap["mysql_settings"].([]any); ok && len(v) > 0 && v[0] != nil { + return &awstypes.DataProviderSettingsMemberMySqlSettings{ + Value: *expandMySQLDataProviderSettings(v), + } + } + + if v, ok := tfMap["oracle_settings"].([]any); ok && len(v) > 0 && v[0] != nil { + return &awstypes.DataProviderSettingsMemberOracleSettings{ + Value: *expandOracleDataProviderSettings(v), + } + } + + if v, ok := tfMap["postgres_settings"].([]any); ok && len(v) > 0 && v[0] != nil { + return &awstypes.DataProviderSettingsMemberPostgreSqlSettings{ + Value: *expandPostgreSQLDataProviderSettings(v), + } + } + + if v, ok := tfMap["redshift_settings"].([]any); ok && len(v) > 0 && v[0] != nil { + return &awstypes.DataProviderSettingsMemberRedshiftSettings{ + Value: *expandRedshiftDataProviderSettings(v), + } + } + + if v, ok := tfMap["sybase_ase_settings"].([]any); ok && len(v) > 0 && v[0] != nil { + return &awstypes.DataProviderSettingsMemberSybaseAseSettings{ + Value: *expandSybaseAseDataProviderSettings(v), + } + } + + return nil +} + +func expandPostgreSQLDataProviderSettings(tfList []any) *awstypes.PostgreSqlDataProviderSettings { + return expandGenericDataProviderSettings[awstypes.PostgreSqlDataProviderSettings](tfList) +} + +func expandMySQLDataProviderSettings(tfList []any) *awstypes.MySqlDataProviderSettings { + return expandGenericDataProviderSettings[awstypes.MySqlDataProviderSettings](tfList) +} + +func expandDocDBDataProviderSettings(tfList []any) *awstypes.DocDbDataProviderSettings { + return expandGenericDataProviderSettings[awstypes.DocDbDataProviderSettings](tfList) +} + +func expandIBMDB2LUWDataProviderSettings(tfList []any) *awstypes.IbmDb2LuwDataProviderSettings { + return expandGenericDataProviderSettings[awstypes.IbmDb2LuwDataProviderSettings](tfList) +} + +func expandIBMDB2zOSDataProviderSettings(tfList []any) *awstypes.IbmDb2zOsDataProviderSettings { + return expandGenericDataProviderSettings[awstypes.IbmDb2zOsDataProviderSettings](tfList) +} + +func expandMariaDBDataProviderSettings(tfList []any) *awstypes.MariaDbDataProviderSettings { + return expandGenericDataProviderSettings[awstypes.MariaDbDataProviderSettings](tfList) +} + +func expandSybaseAseDataProviderSettings(tfList []any) *awstypes.SybaseAseDataProviderSettings { + return expandGenericDataProviderSettings[awstypes.SybaseAseDataProviderSettings](tfList) +} + +func expandMicrosoftSQLServerDataProviderSettings(tfList []any) *awstypes.MicrosoftSqlServerDataProviderSettings { + return expandGenericDataProviderSettings[awstypes.MicrosoftSqlServerDataProviderSettings](tfList) +} + +func expandMongoDBDataProviderSettings(tfList []any) *awstypes.MongoDbDataProviderSettings { + return expandGenericDataProviderSettings[awstypes.MongoDbDataProviderSettings](tfList) +} + +func expandOracleDataProviderSettings(tfList []any) *awstypes.OracleDataProviderSettings { + return expandGenericDataProviderSettings[awstypes.OracleDataProviderSettings](tfList) +} + +func expandRedshiftDataProviderSettings(tfList []any) *awstypes.RedshiftDataProviderSettings { + return expandGenericDataProviderSettings[awstypes.RedshiftDataProviderSettings](tfList) +} + +func expandGenericDataProviderSettings[T any](tfList []any) *T { + if len(tfList) == 0 || tfList[0] == nil { + return nil + } + + tfMap := tfList[0].(map[string]any) + var settings T + v := &settings + + // Use reflection to set common fields + val := reflect.ValueOf(v).Elem() + + if certArn, ok := tfMap[names.AttrCertificateARN].(string); ok && certArn != "" { + if field := val.FieldByName("CertificateArn"); field.IsValid() && field.CanSet() { + field.Set(reflect.ValueOf(aws.String(certArn))) + } + } + + if dbName, ok := tfMap[names.AttrDatabaseName].(string); ok && dbName != "" { + if field := val.FieldByName("DatabaseName"); field.IsValid() && field.CanSet() { + field.Set(reflect.ValueOf(aws.String(dbName))) + } + } + + if port, ok := tfMap[names.AttrPort].(int); ok && port != 0 { + if field := val.FieldByName("Port"); field.IsValid() && field.CanSet() { + field.Set(reflect.ValueOf(aws.Int32(int32(port)))) + } + } + + if serverName, ok := tfMap["server_name"].(string); ok && serverName != "" { + if field := val.FieldByName("ServerName"); field.IsValid() && field.CanSet() { + field.Set(reflect.ValueOf(aws.String(serverName))) + } + } + + if sslMode, ok := tfMap["ssl_mode"].(string); ok && sslMode != "" { + if field := val.FieldByName("SslMode"); field.IsValid() && field.CanSet() { + field.Set(reflect.ValueOf(awstypes.DmsSslModeValue(sslMode))) + } + } + + return v +} + +func flattenDataProviderSettings(settings awstypes.DataProviderSettings) []any { + if settings == nil { + return []any{} + } + + m := map[string]any{} + + switch v := settings.(type) { + case *awstypes.DataProviderSettingsMemberDocDbSettings: + m["docdb_settings"] = flattenGenericDataProviderSettings(&v.Value) + case *awstypes.DataProviderSettingsMemberIbmDb2LuwSettings: + m["ibm_db2_luw_settings"] = flattenGenericDataProviderSettings(&v.Value) + case *awstypes.DataProviderSettingsMemberIbmDb2zOsSettings: + m["ibm_db2_zos_settings"] = flattenGenericDataProviderSettings(&v.Value) + case *awstypes.DataProviderSettingsMemberMariaDbSettings: + m["mariadb_settings"] = flattenGenericDataProviderSettings(&v.Value) + case *awstypes.DataProviderSettingsMemberMicrosoftSqlServerSettings: + m["microsoft_sql_server_settings"] = flattenGenericDataProviderSettings(&v.Value) + case *awstypes.DataProviderSettingsMemberMongoDbSettings: + m["mongodb_settings"] = flattenGenericDataProviderSettings(&v.Value) + case *awstypes.DataProviderSettingsMemberMySqlSettings: + m["mysql_settings"] = flattenGenericDataProviderSettings(&v.Value) + case *awstypes.DataProviderSettingsMemberOracleSettings: + m["oracle_settings"] = flattenGenericDataProviderSettings(&v.Value) + case *awstypes.DataProviderSettingsMemberPostgreSqlSettings: + m["postgres_settings"] = flattenGenericDataProviderSettings(&v.Value) + case *awstypes.DataProviderSettingsMemberRedshiftSettings: + m["redshift_settings"] = flattenGenericDataProviderSettings(&v.Value) + case *awstypes.DataProviderSettingsMemberSybaseAseSettings: + m["sybase_ase_settings"] = flattenGenericDataProviderSettings(&v.Value) + } + + return []any{m} +} + +func flattenGenericDataProviderSettings(settings any) []any { + if settings == nil { + return []any{} + } + + m := map[string]any{} + val := reflect.ValueOf(settings).Elem() + + if field := val.FieldByName("CertificateArn"); field.IsValid() && !field.IsNil() { + m[names.AttrCertificateARN] = aws.ToString(field.Interface().(*string)) + } + + if field := val.FieldByName("DatabaseName"); field.IsValid() && !field.IsNil() { + m[names.AttrDatabaseName] = aws.ToString(field.Interface().(*string)) + } + + if field := val.FieldByName("Port"); field.IsValid() && !field.IsNil() { + m[names.AttrPort] = aws.ToInt32(field.Interface().(*int32)) + } + + if field := val.FieldByName("ServerName"); field.IsValid() && !field.IsNil() { + m["server_name"] = aws.ToString(field.Interface().(*string)) + } + + if field := val.FieldByName("SslMode"); field.IsValid() { + if sslMode := field.Interface().(awstypes.DmsSslModeValue); sslMode != "" { + m["ssl_mode"] = string(sslMode) + } + } + + return []any{m} +} diff --git a/internal/service/dms/data_provider_test.go b/internal/service/dms/data_provider_test.go new file mode 100644 index 000000000000..ad996edf9447 --- /dev/null +++ b/internal/service/dms/data_provider_test.go @@ -0,0 +1,179 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package dms_test + +import ( + "context" + "fmt" + "testing" + + sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/terraform" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" + "github.com/hashicorp/terraform-provider-aws/internal/conns" + tfdms "github.com/hashicorp/terraform-provider-aws/internal/service/dms" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" + "github.com/hashicorp/terraform-provider-aws/names" +) + +func TestAccDMSDataProvider_basic(t *testing.T) { + ctx := acctest.Context(t) + resourceName := "aws_dms_data_provider.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.DMSServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckDataProviderDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccDataProviderConfig_basic(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckDataProviderExists(ctx, resourceName), + resource.TestCheckResourceAttrSet(resourceName, "data_provider_arn"), + resource.TestCheckResourceAttr(resourceName, "data_provider_name", rName), + resource.TestCheckResourceAttr(resourceName, names.AttrEngine, "postgres"), + resource.TestCheckResourceAttr(resourceName, "settings.#", "1"), + resource.TestCheckResourceAttr(resourceName, "settings.0.postgres_settings.#", "1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccDMSDataProvider_update(t *testing.T) { + ctx := acctest.Context(t) + resourceName := "aws_dms_data_provider.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.DMSServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckDataProviderDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccDataProviderConfig_basic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckDataProviderExists(ctx, resourceName), + resource.TestCheckResourceAttr(resourceName, "settings.0.postgres_settings.0.port", "5432"), + ), + }, + { + Config: testAccDataProviderConfig_updated(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckDataProviderExists(ctx, resourceName), + resource.TestCheckResourceAttr(resourceName, "settings.0.postgres_settings.0.port", "5433"), + ), + }, + }, + }) +} + +func TestAccDMSDataProvider_disappears(t *testing.T) { + ctx := acctest.Context(t) + resourceName := "aws_dms_data_provider.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.DMSServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckDataProviderDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccDataProviderConfig_basic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckDataProviderExists(ctx, resourceName), + acctest.CheckResourceDisappears(ctx, acctest.Provider, tfdms.ResourceDataProvider(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func testAccCheckDataProviderExists(ctx context.Context, n string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + conn := acctest.Provider.Meta().(*conns.AWSClient).DMSClient(ctx) + + _, err := tfdms.FindDataProviderByARN(ctx, conn, rs.Primary.ID) + + return err + } +} + +func testAccCheckDataProviderDestroy(ctx context.Context) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := acctest.Provider.Meta().(*conns.AWSClient).DMSClient(ctx) + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_dms_data_provider" { + continue + } + + _, err := tfdms.FindDataProviderByARN(ctx, conn, rs.Primary.ID) + + if tfresource.NotFound(err) { + continue + } + + if err != nil { + return err + } + + return fmt.Errorf("DMS Data Provider %s still exists", rs.Primary.ID) + } + + return nil + } +} + +func testAccDataProviderConfig_basic(rName string) string { + return fmt.Sprintf(` +resource "aws_dms_data_provider" "test" { + data_provider_name = %[1]q + engine = "postgres" + + settings { + postgres_settings { + server_name = "%[1]s.example.com" + port = 5432 + database_name = "testdb" + ssl_mode = "none" + } + } +} +`, rName) +} + +func testAccDataProviderConfig_updated(rName string) string { + return fmt.Sprintf(` +resource "aws_dms_data_provider" "test" { + data_provider_name = %[1]q + engine = "postgres" + + settings { + postgres_settings { + server_name = "%[1]s.example.com" + port = 5433 + database_name = "testdb" + ssl_mode = "none" + } + } +} +`, rName) +} diff --git a/internal/service/dms/exports_test.go b/internal/service/dms/exports_test.go index ac96699f63ff..c280127318ff 100644 --- a/internal/service/dms/exports_test.go +++ b/internal/service/dms/exports_test.go @@ -6,6 +6,7 @@ package dms // Exports for use in tests only. var ( ResourceCertificate = resourceCertificate + ResourceDataProvider = resourceDataProvider ResourceEndpoint = resourceEndpoint ResourceEventSubscription = resourceEventSubscription ResourceReplicationConfig = resourceReplicationConfig @@ -15,6 +16,7 @@ var ( ResourceS3Endpoint = resourceS3Endpoint FindCertificateByID = findCertificateByID + FindDataProviderByARN = findDataProviderByARN FindEndpointByID = findEndpointByID FindEventSubscriptionByName = findEventSubscriptionByName FindReplicationConfigByARN = findReplicationConfigByARN diff --git a/internal/service/dms/service_package_gen.go b/internal/service/dms/service_package_gen.go index dbb8ca640336..83969dccac3a 100644 --- a/internal/service/dms/service_package_gen.go +++ b/internal/service/dms/service_package_gen.go @@ -86,6 +86,15 @@ func (p *servicePackage) SDKResources(ctx context.Context) []*inttypes.ServicePa }), Region: unique.Make(inttypes.ResourceRegionDefault()), }, + { + Factory: resourceDataProvider, + TypeName: "aws_dms_data_provider", + Name: "Data Provider", + Tags: unique.Make(inttypes.ServicePackageResourceTags{ + IdentifierAttribute: "data_provider_arn", + }), + Region: unique.Make(inttypes.ResourceRegionDefault()), + }, { Factory: resourceEndpoint, TypeName: "aws_dms_endpoint", diff --git a/internal/service/dms/testdata/tmpl/data_provider_tags.gtpl b/internal/service/dms/testdata/tmpl/data_provider_tags.gtpl new file mode 100644 index 000000000000..6c8733ff5cdb --- /dev/null +++ b/internal/service/dms/testdata/tmpl/data_provider_tags.gtpl @@ -0,0 +1,15 @@ +resource "aws_dms_data_provider" "test" { + data_provider_name = var.rName + engine = "postgres" + + settings { + postgres_settings { + server_name = "example.com" + port = 5432 + database_name = "testdb" + ssl_mode = "none" + } + } + +{{- template "tags" . }} +} diff --git a/website/docs/r/dms_data_provider.html.markdown b/website/docs/r/dms_data_provider.html.markdown new file mode 100644 index 000000000000..44b46c8d6954 --- /dev/null +++ b/website/docs/r/dms_data_provider.html.markdown @@ -0,0 +1,114 @@ +--- +subcategory: "DMS (Database Migration)" +layout: "aws" +page_title: "AWS: aws_dms_data_provider" +description: |- + Provides a DMS (Data Migration Service) data provider resource. +--- + +# Resource: aws_dms_data_provider + +Provides a DMS (Data Migration Service) data provider resource. DMS data providers store database connection information. + +## Example Usage + +### PostgreSQL Data Provider + +```terraform +resource "aws_dms_data_provider" "postgres" { + data_provider_name = "my-postgres-provider" + engine = "postgres" + + settings { + postgres_settings { + server_name = "mydb.example.com" + port = 5432 + database_name = "mydb" + ssl_mode = "require" + } + } + + tags = { + Name = "postgres-provider" + } +} +``` + +### MySQL Data Provider + +```terraform +resource "aws_dms_data_provider" "mysql" { + data_provider_name = "my-mysql-provider" + engine = "mysql" + + settings { + mysql_settings { + server_name = "mydb.example.com" + port = 3306 + ssl_mode = "require" + } + } +} +``` + +## Argument Reference + +This resource supports the following arguments: + +* `engine` - (Required) Database engine type. Valid values: `aurora`, `aurora-postgresql`, `mysql`, `oracle`, `postgres`, `sqlserver`, `redshift`, `mariadb`, `mongodb`, `db2`, `db2-zos`, `docdb`, `sybase`. +* `settings` - (Required) Configuration block for data provider settings. See [`settings`](#settings) below. +* `data_provider_name` - (Optional) User-friendly name for the data provider. +* `description` - (Optional) Description of the data provider. +* `region` - (Optional) Region where this resource will be [managed](https://docs.aws.amazon.com/general/latest/gr/rande.html#regional-endpoints). Defaults to the Region set in the [provider configuration](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#aws-configuration-reference). +* `virtual` - (Optional) Indicates whether the data provider is virtual. +* `tags` - (Optional) Map of tags to assign to the resource. If configured with a provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block) present, tags with matching keys will overwrite those defined at the provider-level. + +### settings + +The `settings` block supports one of the following: + +* `docdb_settings` - (Optional) Configuration for DocumentDB. See [common settings](#common-settings) below. +* `ibm_db2_luw_settings` - (Optional) Configuration for IBM DB2 LUW. See [common settings](#common-settings) below. +* `ibm_db2_zos_settings` - (Optional) Configuration for IBM DB2 for z/OS. See [common settings](#common-settings) below. +* `mariadb_settings` - (Optional) Configuration for MariaDB. See [common settings](#common-settings) below. +* `microsoft_sql_server_settings` - (Optional) Configuration for Microsoft SQL Server. See [common settings](#common-settings) below. +* `mongodb_settings` - (Optional) Configuration for MongoDB. See [common settings](#common-settings) below. +* `mysql_settings` - (Optional) Configuration for MySQL. See [common settings](#common-settings) below. +* `oracle_settings` - (Optional) Configuration for Oracle. See [common settings](#common-settings) below. +* `postgres_settings` - (Optional) Configuration for PostgreSQL. See [common settings](#common-settings) below. +* `redshift_settings` - (Optional) Configuration for Redshift. See [common settings](#common-settings) below. +* `sybase_ase_settings` - (Optional) Configuration for SAP ASE. See [common settings](#common-settings) below. + +### Common Settings + +All settings blocks support the following common attributes: + +* `server_name` - (Optional) Server name. +* `port` - (Optional) Port number. +* `database_name` - (Optional) Database name. +* `ssl_mode` - (Optional) SSL mode. Valid values: `none`, `require`, `verify-ca`, `verify-full`. +* `certificate_arn` - (Optional) ARN of the certificate for SSL connection. + +## Attribute Reference + +This resource exports the following attributes in addition to the arguments above: + +* `data_provider_arn` - ARN of the data provider. +* `tags_all` - Map of tags assigned to the resource, including those inherited from the provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block). + +## Import + +In Terraform v1.5.0 and later, use an [`import` block](https://developer.hashicorp.com/terraform/language/import) to import data providers using the `data_provider_arn`. For example: + +```terraform +import { + to = aws_dms_data_provider.example + id = "arn:aws:dms:us-east-1:123456789012:data-provider:ABCDEFGHIJKLMNOPQRSTUVWXYZ" +} +``` + +Using `terraform import`, import data providers using the `data_provider_arn`. For example: + +```console +% terraform import aws_dms_data_provider.example arn:aws:dms:us-east-1:123456789012:data-provider:ABCDEFGHIJKLMNOPQRSTUVWXYZ +```