diff --git a/examples/odb/autonomous_vm_cluster.tf b/examples/odb/autonomous_vm_cluster.tf new file mode 100644 index 000000000000..a46bdd011c6b --- /dev/null +++ b/examples/odb/autonomous_vm_cluster.tf @@ -0,0 +1,25 @@ +//Copyright © 2025, Oracle and/or its affiliates. All rights reserved. + +//Autonomous VM Cluster with default maintenance window +resource "aws_odb_cloud_autonomous_vm_cluster" "test" { + cloud_exadata_infrastructure_id = "" //refer your exadata infra id + odb_network_id = "" //refer_your_odb_net_id + display_name = "Ofake-avmc-my_avmc" + autonomous_data_storage_size_in_tbs = 5 + memory_per_oracle_compute_unit_in_gbs = 2 + total_container_databases = 1 + cpu_core_count_per_node = 40 + license_model = "LICENSE_INCLUDED" + db_servers = [] //ids of db server. refer your exa infra + scan_listener_port_tls = 8561 + scan_listener_port_non_tls = 1024 + maintenance_window = { + preference = "NO_PREFERENCE" + days_of_week = [] + hours_of_day = [] + months = [] + weeks_of_month =[] + lead_time_in_weeks = 0 + } + +} diff --git a/examples/odb/exadata_infra.tf b/examples/odb/exadata_infra.tf new file mode 100644 index 000000000000..1710f4ddd4ba --- /dev/null +++ b/examples/odb/exadata_infra.tf @@ -0,0 +1,30 @@ +//Copyright © 2025, Oracle and/or its affiliates. All rights reserved. + +//Exadata Infrastructure with customer managed maintenance window +resource "aws_odb_cloud_exadata_infrastructure" "test" { + display_name = "Ofake_odb_exadata_infra" //Required Field + shape = "Exadata.X11M" //Required Field + storage_count = 3 + compute_count = 2 + availability_zone_id = "use1-az6" //Required Field + customer_contacts_to_send_to_oci = ["abc@example.com"] + database_server_type = "X11M" + storage_server_type = "X11M-HC" + maintenance_window = { //Required + custom_action_timeout_in_mins = 16 + days_of_week = ["MONDAY", "TUESDAY"] + hours_of_day = [11, 16] + is_custom_action_timeout_enabled = true + lead_time_in_weeks = 3 + months = ["FEBRUARY", "MAY", "AUGUST", "NOVEMBER"] + patching_mode = "ROLLING" + preference = "CUSTOM_PREFERENCE" + weeks_of_month = [2, 4] + } + tags = { + "env" = "dev" + } + +} + +//Exadata Infrastructure with default maintenance window \ No newline at end of file diff --git a/examples/odb/main.tf b/examples/odb/main.tf index 8a402fb2dd5e..58cccaccb19c 100644 --- a/examples/odb/main.tf +++ b/examples/odb/main.tf @@ -1,74 +1,10 @@ //Copyright © 2025, Oracle and/or its affiliates. All rights reserved. - -provider "aws" { - region = "us-east-1" -} - -resource "aws_odb_cloud_exadata_infrastructure" "test" { - display_name = "Ofake-exa-4157426154220451194" - shape = "Exadata.X9M" - storage_count = 3 - compute_count = 2 - availability_zone_id = "use1-az6" - customer_contacts_to_send_to_oci = ["abc@example.com"] - maintenance_window = { - custom_action_timeout_in_mins = 16 - days_of_week = [] - hours_of_day = [] - is_custom_action_timeout_enabled = true - lead_time_in_weeks = 0 - months = [] - patching_mode = "ROLLING" - preference = "NO_PREFERENCE" - weeks_of_month =[] +terraform { + required_version = ">= 0.15.3" + required_providers { + aws = { + source = "hashicorp/aws" + version = "3.50.0" + } } -} - - - - - - -resource "aws_odb_network" "test" { - display_name = "odb-net-6310376148776971562" - availability_zone_id = "use1-az6" - client_subnet_cidr = "10.2.0.0/24" - backup_subnet_cidr = "10.2.1.0/24" - s3_access = "DISABLED" - zero_etl_access = "DISABLED" -} - - - -data "aws_odb_db_servers_list" "test" { - cloud_exadata_infrastructure_id = aws_odb_cloud_exadata_infrastructure.test.id -} - -resource "aws_odb_cloud_autonomous_vm_cluster" "test" { - cloud_exadata_infrastructure_id = aws_odb_cloud_exadata_infrastructure.test.id - odb_network_id =aws_odb_network.test.id - display_name = "Ofake-avmc-1515523754357569237" - autonomous_data_storage_size_in_tbs = 5 - memory_per_oracle_compute_unit_in_gbs = 2 - total_container_databases = 1 - cpu_core_count_per_node = 40 - license_model = "LICENSE_INCLUDED" - db_servers = [ for db_server in data.aws_odb_db_servers_list.test.db_servers : db_server.id] - scan_listener_port_tls = 8561 - scan_listener_port_non_tls = 1024 - maintenance_window = { - preference = "NO_PREFERENCE" - days_of_week = [] - hours_of_day = [] - months = [] - weeks_of_month =[] - lead_time_in_weeks = 0 - } - -} - - -data "aws_odb_cloud_autonomous_vm_cluster" "test" { - id = aws_odb_cloud_autonomous_vm_cluster.test.id - } \ No newline at end of file diff --git a/examples/odb/odb_network.tf b/examples/odb/odb_network.tf new file mode 100644 index 000000000000..495db44c3eb7 --- /dev/null +++ b/examples/odb/odb_network.tf @@ -0,0 +1,27 @@ +//Copyright © 2025, Oracle and/or its affiliates. All rights reserved. + +//odb network without managed service +resource "aws_odb_network" "test" { + display_name = "odb-my-net" + availability_zone_id = "use1-az6" + client_subnet_cidr = "10.2.0.0/24" + backup_subnet_cidr = "10.2.1.0/24" + s3_access = "DISABLED" + zero_etl_access = "DISABLED" + tags = { + "env" = "dev" + } +} + +//odb network with managed service +resource "aws_odb_network" "test" { + display_name = "odb-my-net" + availability_zone_id = "use1-az6" + client_subnet_cidr = "10.2.0.0/24" + backup_subnet_cidr = "10.2.1.0/24" + s3_access = "ENABLED" + zero_etl_access = "ENABLED" + tags = { + "env" = "dev" + } +} \ No newline at end of file diff --git a/examples/odb/odb_network_peering.tf b/examples/odb/odb_network_peering.tf new file mode 100644 index 000000000000..66397b3328ee --- /dev/null +++ b/examples/odb/odb_network_peering.tf @@ -0,0 +1,7 @@ +//Copyright © 2025, Oracle and/or its affiliates. All rights reserved. + +resource "aws_odb_network_peering_connection" "test" { + display_name = "my_odb_net_peering" + odb_network_id = aws_odb_network.test.id + peer_network_id = "vpc_id" +} \ No newline at end of file diff --git a/examples/odb/variables.tf b/examples/odb/variables.tf deleted file mode 100644 index 4e5b298e3298..000000000000 --- a/examples/odb/variables.tf +++ /dev/null @@ -1 +0,0 @@ -//Copyright © 2025, Oracle and/or its affiliates. All rights reserved. diff --git a/examples/odb/vm_cluster.tf b/examples/odb/vm_cluster.tf new file mode 100644 index 000000000000..ce068ab82c6f --- /dev/null +++ b/examples/odb/vm_cluster.tf @@ -0,0 +1,21 @@ +//Copyright © 2025, Oracle and/or its affiliates. All rights reserved. + +resource "aws_odb_cloud_vm_cluster" "vmcluster" { + display_name = "Ofake_my_vmc" + cloud_exadata_infrastructure_id = aws_odb_cloud_exadata_infrastructure.test.id + cpu_core_count = 6 + gi_version = "23.0.0.0" + hostname_prefix = "apollo12" + ssh_public_keys = [""] //public ssh keys + odb_network_id = aws_odb_network.test.id + is_local_backup_enabled = true + is_sparse_diskgroup_enabled = true + license_model = "LICENSE_INCLUDED" + data_storage_size_in_tbs = 20.0 + db_servers = [""] //db-servers + db_node_storage_size_in_gbs = 120.0 + memory_size_in_gbs = 60 + tags = { + "env" = "dev" + } +} \ No newline at end of file diff --git a/internal/service/odb/cloud_autonomous_vm_cluster_test.go b/internal/service/odb/cloud_autonomous_vm_cluster_test.go index f3591806a98c..b46517573f90 100644 --- a/internal/service/odb/cloud_autonomous_vm_cluster_test.go +++ b/internal/service/odb/cloud_autonomous_vm_cluster_test.go @@ -53,7 +53,6 @@ func TestAccODBCloudAutonomousVmClusterCreationBasic(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) - //acctest.PreCheckPartitionHasService(t, names.ODBServiceID) autonomousVMClusterResourceTestEntity.testAccPreCheck(ctx, t) }, ErrorCheck: acctest.ErrorCheck(t, names.ODBServiceID), @@ -75,6 +74,41 @@ func TestAccODBCloudAutonomousVmClusterCreationBasic(t *testing.T) { }) } +func TestAccODBCloudAutonomousVmClusterCreationWithAllParams(t *testing.T) { + ctx := acctest.Context(t) + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + var cloudAVMC odbtypes.CloudAutonomousVmCluster + + resourceName := "aws_odb_cloud_autonomous_vm_cluster.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + //acctest.PreCheckPartitionHasService(t, names.ODBServiceID) + autonomousVMClusterResourceTestEntity.testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.ODBServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: autonomousVMClusterResourceTestEntity.testAccCheckCloudAutonomousVmClusterDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: autonomousVMClusterResourceTestEntity.avmcAllParamsConfig(), + Check: resource.ComposeAggregateTestCheckFunc( + autonomousVMClusterResourceTestEntity.checkCloudAutonomousVmClusterExists(ctx, resourceName, &cloudAVMC), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func TestAccODBCloudAutonomousVmClusterTagging(t *testing.T) { fmt.Println("Update tags test") ctx := acctest.Context(t) @@ -84,7 +118,7 @@ func TestAccODBCloudAutonomousVmClusterTagging(t *testing.T) { var avmc1, avmc2 odbtypes.CloudAutonomousVmCluster resourceName := "aws_odb_cloud_autonomous_vm_cluster.test" - + withoutTag, withTag := autonomousVMClusterResourceTestEntity.avmcNoTagWithTag() resource.Test(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) @@ -93,9 +127,11 @@ func TestAccODBCloudAutonomousVmClusterTagging(t *testing.T) { ErrorCheck: acctest.ErrorCheck(t, names.ODBServiceID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, CheckDestroy: autonomousVMClusterResourceTestEntity.testAccCheckCloudAutonomousVmClusterDestroy(ctx), + Steps: []resource.TestStep{ { - Config: autonomousVMClusterResourceTestEntity.avmcBasic(), + Config: withoutTag, + Check: resource.ComposeAggregateTestCheckFunc( autonomousVMClusterResourceTestEntity.checkCloudAutonomousVmClusterExists(ctx, resourceName, &avmc1), resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), @@ -107,7 +143,7 @@ func TestAccODBCloudAutonomousVmClusterTagging(t *testing.T) { ImportStateVerify: true, }, { - Config: autonomousVMClusterResourceTestEntity.avmcBasicWithTags(), + Config: withTag, Check: resource.ComposeAggregateTestCheckFunc( autonomousVMClusterResourceTestEntity.checkCloudAutonomousVmClusterExists(ctx, resourceName, &avmc2), resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), @@ -237,16 +273,6 @@ func (autonomousVMClusterResourceTest) findAVMC(ctx context.Context, conn *odb.C return out.CloudAutonomousVmCluster, nil } -/*func testAccCheckCloudAutonomousVmClusterNotRecreated(before, after *odb.DescribeCloudAutonomousVmClusterResponse) resource.TestCheckFunc { - return func(s *terraform.State) error { - if before, after := aws.ToString(before.CloudAutonomousVmClusterId), aws.ToString(after.CloudAutonomousVmClusterId); before != after { - return create.Error(names.ODB, create.ErrActionCheckingNotRecreated, tfodb.ResNameCloudAutonomousVmCluster, aws.ToString(before.CloudAutonomousVmClusterId), errors.New("recreated")) - } - - return nil - } -}*/ - func (autonomousVMClusterResourceTest) avmcBasic() string { exaInfraDisplayName := sdkacctest.RandomWithPrefix(autonomousVMClusterDSTestEntity.exaInfraDisplayNamePrefix) @@ -292,15 +318,14 @@ resource "aws_odb_cloud_autonomous_vm_cluster" "test" { return res } -func (autonomousVMClusterResourceTest) avmcBasicWithTags() string { - +func (autonomousVMClusterResourceTest) avmcNoTagWithTag() (string, string) { exaInfraDisplayName := sdkacctest.RandomWithPrefix(autonomousVMClusterDSTestEntity.exaInfraDisplayNamePrefix) odbNetworkDisplayName := sdkacctest.RandomWithPrefix(autonomousVMClusterDSTestEntity.odbNetDisplayNamePrefix) avmcDisplayName := sdkacctest.RandomWithPrefix(autonomousVMClusterDSTestEntity.autonomousVmClusterDisplayNamePrefix) exaInfraRes := autonomousVMClusterDSTestEntity.exaInfra(exaInfraDisplayName) odbNetRes := autonomousVMClusterDSTestEntity.odbNet(odbNetworkDisplayName) - res := fmt.Sprintf(` + noTag := fmt.Sprintf(` %s %s @@ -329,6 +354,89 @@ resource "aws_odb_cloud_autonomous_vm_cluster" "test" { weeks_of_month =[] lead_time_in_weeks = 0 } + +} + +`, exaInfraRes, odbNetRes, avmcDisplayName) + withTag := fmt.Sprintf(` +%s + +%s + +data "aws_odb_db_servers_list" "test" { + cloud_exadata_infrastructure_id = aws_odb_cloud_exadata_infrastructure.test.id +} + +resource "aws_odb_cloud_autonomous_vm_cluster" "test" { + cloud_exadata_infrastructure_id = aws_odb_cloud_exadata_infrastructure.test.id + odb_network_id =aws_odb_network.test.id + display_name = %[3]q + autonomous_data_storage_size_in_tbs = 5 + memory_per_oracle_compute_unit_in_gbs = 2 + total_container_databases = 1 + cpu_core_count_per_node = 40 + license_model = "LICENSE_INCLUDED" + db_servers = [ for db_server in data.aws_odb_db_servers_list.test.db_servers : db_server.id] + scan_listener_port_tls = 8561 + scan_listener_port_non_tls = 1024 + maintenance_window = { + preference = "NO_PREFERENCE" + days_of_week = [] + hours_of_day = [] + months = [] + weeks_of_month =[] + lead_time_in_weeks = 0 + } + tags = { + "env"= "dev" + } + +} + +`, exaInfraRes, odbNetRes, avmcDisplayName) + + return noTag, withTag +} + +func (autonomousVMClusterResourceTest) avmcAllParamsConfig() string { + + exaInfraDisplayName := sdkacctest.RandomWithPrefix(autonomousVMClusterDSTestEntity.exaInfraDisplayNamePrefix) + odbNetworkDisplayName := sdkacctest.RandomWithPrefix(autonomousVMClusterDSTestEntity.odbNetDisplayNamePrefix) + avmcDisplayName := sdkacctest.RandomWithPrefix(autonomousVMClusterDSTestEntity.autonomousVmClusterDisplayNamePrefix) + + exaInfraRes := autonomousVMClusterDSTestEntity.exaInfra(exaInfraDisplayName) + odbNetRes := autonomousVMClusterDSTestEntity.odbNet(odbNetworkDisplayName) + res := fmt.Sprintf(` +%s + +%s + +data "aws_odb_db_servers_list" "test" { + cloud_exadata_infrastructure_id = aws_odb_cloud_exadata_infrastructure.test.id +} + +resource "aws_odb_cloud_autonomous_vm_cluster" "test" { + description = "my first avmc" + time_zone = "UTC" + cloud_exadata_infrastructure_id = aws_odb_cloud_exadata_infrastructure.test.id + odb_network_id =aws_odb_network.test.id + display_name = %[3]q + autonomous_data_storage_size_in_tbs = 5 + memory_per_oracle_compute_unit_in_gbs = 2 + total_container_databases = 1 + cpu_core_count_per_node = 40 + license_model = "LICENSE_INCLUDED" + db_servers = [ for db_server in data.aws_odb_db_servers_list.test.db_servers : db_server.id] + scan_listener_port_tls = 8561 + scan_listener_port_non_tls = 1024 + maintenance_window = { + preference = "CUSTOM_PREFERENCE" + days_of_week = ["MONDAY", "TUESDAY"] + hours_of_day = [4,16] + months = ["FEBRUARY","MAY","AUGUST","NOVEMBER"] + weeks_of_month =[2,4] + lead_time_in_weeks = 3 + } tags = { "env"= "dev" } diff --git a/internal/service/odb/db_server_data_source.go b/internal/service/odb/db_server_data_source.go new file mode 100644 index 000000000000..e0d24697b412 --- /dev/null +++ b/internal/service/odb/db_server_data_source.go @@ -0,0 +1,197 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package odb + +import ( + "context" + "github.com/hashicorp/terraform-plugin-framework/attr" + "time" + + "github.com/aws/aws-sdk-go-v2/service/odb" + odbtypes "github.com/aws/aws-sdk-go-v2/service/odb/types" + + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-provider-aws/internal/create" + "github.com/hashicorp/terraform-provider-aws/internal/framework" + "github.com/hashicorp/terraform-provider-aws/internal/framework/flex" + fwtypes "github.com/hashicorp/terraform-provider-aws/internal/framework/types" + "github.com/hashicorp/terraform-provider-aws/names" +) + +// Function annotations are used for datasource registration to the Provider. DO NOT EDIT. +// @FrameworkDataSource("aws_odb_db_server", name="Db Server") +func newDataSourceDbServer(context.Context) (datasource.DataSourceWithConfigure, error) { + return &dataSourceDbServer{}, nil +} + +const ( + DSNameDbServer = "Db Server Data Source" +) + +type dataSourceDbServer struct { + framework.DataSourceWithModel[dbServerDataSourceModel] +} + +func (d *dataSourceDbServer) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { + resp.Schema = schema.Schema{ + Attributes: map[string]schema.Attribute{ + names.AttrID: schema.StringAttribute{ + Description: "The identifier of the the database server.", + Required: true, + }, + "cloud_exadata_infrastructure_id": schema.StringAttribute{ + Description: "The identifier of the database server to retrieve information about.", + Required: true, + }, + "status": schema.StringAttribute{ + CustomType: fwtypes.StringEnumType[odbtypes.ResourceStatus](), + Computed: true, + }, + "status_reason": schema.StringAttribute{ + Computed: true, + }, + "cpu_core_count": schema.Int32Attribute{ + Computed: true, + }, + "db_node_ids": schema.ListAttribute{ + Computed: true, + CustomType: fwtypes.ListOfStringType, + ElementType: types.StringType, + }, + "db_node_storage_size_in_gbs": schema.Int32Attribute{ + Computed: true, + }, + "db_server_patching_details": schema.ObjectAttribute{ + Computed: true, + CustomType: fwtypes.NewObjectTypeOf[dbNodePatchingDetailsDbServerDataSourceModel](ctx), + AttributeTypes: map[string]attr.Type{ + "estimated_patch_duration": types.Int32Type, + "patching_status": types.StringType, + "time_patching_ended": types.StringType, + "time_patching_started": types.StringType, + }, + }, + "display_name": schema.StringAttribute{ + Computed: true, + }, + "exadata_infrastructure_id": schema.StringAttribute{ + Computed: true, + }, + "ocid": schema.StringAttribute{ + Computed: true, + }, + "oci_resource_anchor_name": schema.StringAttribute{ + Computed: true, + }, + "max_cpu_count": schema.Int32Attribute{ + Computed: true, + }, + "max_db_node_storage_in_gbs": schema.Int32Attribute{ + Computed: true, + }, + "max_memory_in_gbs": schema.Int32Attribute{ + Computed: true, + }, + "memory_size_in_gbs": schema.Int32Attribute{ + Computed: true, + }, + "shape": schema.StringAttribute{ + Computed: true, + }, + "created_at": schema.StringAttribute{ + Computed: true, + }, + "vm_cluster_ids": schema.ListAttribute{ + Computed: true, + CustomType: fwtypes.ListOfStringType, + ElementType: types.StringType, + }, + "compute_model": schema.StringAttribute{ + Computed: true, + CustomType: fwtypes.StringEnumType[odbtypes.ComputeModel](), + }, + "autonomous_vm_cluster_ids": schema.ListAttribute{ + Computed: true, + CustomType: fwtypes.ListOfStringType, + ElementType: types.StringType, + }, + "autonomous_virtual_machine_ids": schema.ListAttribute{ + Computed: true, + CustomType: fwtypes.ListOfStringType, + ElementType: types.StringType, + }, + }, + } +} + +func (d *dataSourceDbServer) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + + conn := d.Meta().ODBClient(ctx) + + var data dbServerDataSourceModel + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + + input := odb.GetDbServerInput{ + DbServerId: data.DbServerID.ValueStringPointer(), + CloudExadataInfrastructureId: data.CloudExadataInfrastructureID.ValueStringPointer(), + } + + out, err := conn.GetDbServer(ctx, &input) + if err != nil { + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.ODB, create.ErrActionReading, DSNameDbServer, data.DbServerID.ValueString(), err), + err.Error(), + ) + return + } + + if out.DbServer.CreatedAt != nil { + data.CreatedAt = types.StringValue(out.DbServer.CreatedAt.Format(time.RFC3339)) + } + + resp.Diagnostics.Append(flex.Flatten(ctx, out.DbServer, &data)...) + if resp.Diagnostics.HasError() { + return + } + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +type dbServerDataSourceModel struct { + framework.WithRegionModel + DbServerID types.String `tfsdk:"id"` + CloudExadataInfrastructureID types.String `tfsdk:"cloud_exadata_infrastructure_id"` + Status fwtypes.StringEnum[odbtypes.ResourceStatus] `tfsdk:"status"` + StatusReason types.String `tfsdk:"status_reason"` + CpuCoreCount types.Int32 `tfsdk:"cpu_core_count"` + DbNodeIds fwtypes.ListOfString `tfsdk:"db_node_ids"` + DbNodeStorageSizeInGBs types.Int32 `tfsdk:"db_node_storage_size_in_gbs"` + DbServerPatchingDetails fwtypes.ObjectValueOf[dbNodePatchingDetailsDbServerDataSourceModel] `tfsdk:"db_server_patching_details"` + DisplayName types.String `tfsdk:"display_name"` + ExadataInfrastructureId types.String `tfsdk:"exadata_infrastructure_id"` + OCID types.String `tfsdk:"ocid"` + OciResourceAnchorName types.String `tfsdk:"oci_resource_anchor_name"` + MaxCpuCount types.Int32 `tfsdk:"max_cpu_count"` + MaxDbNodeStorageInGBs types.Int32 `tfsdk:"max_db_node_storage_in_gbs"` + MaxMemoryInGBs types.Int32 `tfsdk:"max_memory_in_gbs"` + MemorySizeInGBs types.Int32 `tfsdk:"memory_size_in_gbs"` + Shape types.String `tfsdk:"shape"` + CreatedAt types.String `tfsdk:"created_at" autoflex:",noflatten"` + VmClusterIds fwtypes.ListOfString `tfsdk:"vm_cluster_ids"` + ComputeModel fwtypes.StringEnum[odbtypes.ComputeModel] `tfsdk:"compute_model"` + AutonomousVmClusterIds fwtypes.ListOfString `tfsdk:"autonomous_vm_cluster_ids"` + AutonomousVirtualMachineIds fwtypes.ListOfString `tfsdk:"autonomous_virtual_machine_ids"` +} + +type dbNodePatchingDetailsDbServerDataSourceModel struct { + EstimatedPatchDuration types.Int32 `tfsdk:"estimated_patch_duration"` + PatchingStatus types.String `tfsdk:"patching_status"` + TimePatchingEnded types.String `tfsdk:"time_patching_ended"` + TimePatchingStarted types.String `tfsdk:"time_patching_started"` +} diff --git a/internal/service/odb/db_server_data_source_test.go b/internal/service/odb/db_server_data_source_test.go new file mode 100644 index 000000000000..3eee595e9544 --- /dev/null +++ b/internal/service/odb/db_server_data_source_test.go @@ -0,0 +1,196 @@ +//Copyright © 2025, Oracle and/or its affiliates. All rights reserved. + +package odb_test + +import ( + "context" + "errors" + "fmt" + "github.com/aws/aws-sdk-go-v2/aws" + odbtypes "github.com/aws/aws-sdk-go-v2/service/odb/types" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" + sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest" + "github.com/hashicorp/terraform-provider-aws/internal/errs" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" + "testing" + + "github.com/aws/aws-sdk-go-v2/service/odb" + "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" + "github.com/hashicorp/terraform-provider-aws/internal/create" + + tfodb "github.com/hashicorp/terraform-provider-aws/internal/service/odb" + "github.com/hashicorp/terraform-provider-aws/names" +) + +type testDbServerDataSourceTest struct { + exaDisplayNamePrefix string +} + +var dbServerDataSourceTestEntity = testDbServerDataSourceTest{ + exaDisplayNamePrefix: "Ofake-exa", +} + +// Acceptance test access AWS and cost money to run. +func TestAccODBDbServerDataSource(t *testing.T) { + ctx := acctest.Context(t) + + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + var dbServer odb.GetDbServerOutput + exaInfraDisplayName := sdkacctest.RandomWithPrefix(dbServersListDataSourceTests.displayNamePrefix) + + dataSourceName := "data.aws_odb_db_server.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.ODBServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: dbServerDataSourceTestEntity.testAccCheckDbServersDestroyed(ctx), + Steps: []resource.TestStep{ + { + Config: dbServerDataSourceTestEntity.basic(dbServerDataSourceTestEntity.exaInfra(exaInfraDisplayName)), + Check: resource.ComposeAggregateTestCheckFunc( + dbServerDataSourceTestEntity.testAccCheckDbServerExists(ctx, dataSourceName, &dbServer), + ), + }, + }, + }) +} + +func (testDbServerDataSourceTest) testAccCheckDbServerExists(ctx context.Context, name string, output *odb.GetDbServerOutput) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[name] + if !ok { + return create.Error(names.ODB, create.ErrActionCheckingExistence, tfodb.DSNameDbServer, name, errors.New("not found")) + } + conn := acctest.Provider.Meta().(*conns.AWSClient).ODBClient(ctx) + var dbServerId = rs.Primary.ID + var attributes = rs.Primary.Attributes + exaId := attributes["exadata_infrastructure_id"] + resp, err := dbServerDataSourceTestEntity.findDbServer(ctx, conn, &dbServerId, &exaId) + if err != nil { + return create.Error(names.ODB, create.ErrActionCheckingExistence, tfodb.DSNameDbServer, rs.Primary.ID, err) + } + *output = *resp + return nil + } +} + +func (testDbServerDataSourceTest) testAccCheckDbServersDestroyed(ctx context.Context) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := acctest.Provider.Meta().(*conns.AWSClient).ODBClient(ctx) + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_odb_cloud_exadata_infrastructure" { + continue + } + + _, err := dbServerDataSourceTestEntity.findExaInfra(ctx, conn, rs.Primary.ID) + + if tfresource.NotFound(err) { + return nil + } + if err != nil { + return create.Error(names.ODB, create.ErrActionCheckingDestroyed, tfodb.DSNameDbServer, rs.Primary.ID, err) + } + + return create.Error(names.ODB, create.ErrActionCheckingDestroyed, tfodb.DSNameDbServer, rs.Primary.ID, errors.New("not destroyed")) + } + + return nil + } +} + +func (testDbServerDataSourceTest) findExaInfra(ctx context.Context, conn *odb.Client, id string) (*odbtypes.CloudExadataInfrastructure, error) { + input := odb.GetCloudExadataInfrastructureInput{ + CloudExadataInfrastructureId: aws.String(id), + } + + out, err := conn.GetCloudExadataInfrastructure(ctx, &input) + if err != nil { + if errs.IsA[*odbtypes.ResourceNotFoundException](err) { + return nil, &retry.NotFoundError{ + LastError: err, + LastRequest: &input, + } + } + + return nil, err + } + + if out == nil || out.CloudExadataInfrastructure == nil { + return nil, tfresource.NewEmptyResultError(&input) + } + + return out.CloudExadataInfrastructure, nil +} + +func (testDbServerDataSourceTest) findDbServer(ctx context.Context, conn *odb.Client, dbServerId *string, exaInfraId *string) (*odb.GetDbServerOutput, error) { + inputWithExaId := &odb.GetDbServerInput{ + DbServerId: dbServerId, + CloudExadataInfrastructureId: exaInfraId, + } + output, err := conn.GetDbServer(ctx, inputWithExaId) + if err != nil { + return nil, err + } + return output, nil +} + +func (testDbServerDataSourceTest) basic(exaInfra string) string { + return fmt.Sprintf(` +%s + +data "aws_odb_db_servers_list" "test" { + cloud_exadata_infrastructure_id = aws_odb_cloud_exadata_infrastructure.test.id +} + +data "aws_odb_db_server" "test" { + id = data.aws_odb_db_servers_list.test.db_servers[0].id + cloud_exadata_infrastructure_id = aws_odb_cloud_exadata_infrastructure.test.id +} +`, exaInfra) +} + +func (testDbServerDataSourceTest) exaInfra(rName string) string { + exaRes := fmt.Sprintf(` +resource "aws_odb_cloud_exadata_infrastructure" "test" { + display_name = "%[1]s" + shape = "Exadata.X9M" + storage_count = 3 + compute_count = 2 + availability_zone_id = "use1-az6" + customer_contacts_to_send_to_oci = ["abc@example.com"] + maintenance_window = { + custom_action_timeout_in_mins = 16 + days_of_week = [] + hours_of_day = [] + is_custom_action_timeout_enabled = true + lead_time_in_weeks = 0 + months = [] + patching_mode = "ROLLING" + preference = "NO_PREFERENCE" + weeks_of_month =[] + } +} +`, rName) + return exaRes +} + +/*func (testDbServerDataSourceTest) foo(dbServerId, exaInfraId string) string { + return fmt.Sprintf(` + +data "aws_odb_db_server" "test" { + id = %[1]q +cloud_exadata_infrastructure_id = %[2]q +} +`, dbServerId, exaInfraId) +} +*/ diff --git a/internal/service/odb/network.go b/internal/service/odb/network.go index 4119d3f536c7..cc81deb4f37a 100644 --- a/internal/service/odb/network.go +++ b/internal/service/odb/network.go @@ -59,6 +59,7 @@ type resourceNetwork struct { } var OdbNetwork = newResourceNetwork +var managedServiceTimeout = 15 * time.Minute func (r *resourceNetwork) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { statusType := fwtypes.StringEnumType[odbtypes.ResourceStatus]() @@ -158,6 +159,12 @@ func (r *resourceNetwork) Schema(ctx context.Context, req resource.SchemaRequest }, }, }, + "peered_cidrs": schema.SetAttribute{ + CustomType: fwtypes.SetOfStringType, + ElementType: types.StringType, + Computed: true, + Description: "The list of CIDR ranges from the peered VPC that are allowed access to the ODB network. Please refer odb network peering documentation.", + }, "oci_network_anchor_id": schema.StringAttribute{ Computed: true, Description: "The unique identifier of the OCI network anchor for the ODB network.", @@ -264,7 +271,7 @@ func (r *resourceNetwork) Create(ctx context.Context, req resource.CreateRequest Tags: getTagsIn(ctx), } - resp.Diagnostics.Append(flex.Expand(ctx, plan, &input, flex.WithIgnoredFieldNamesAppend("PeeredCidrs"))...) + resp.Diagnostics.Append(flex.Expand(ctx, plan, &input)...) if resp.Diagnostics.HasError() { return } @@ -293,70 +300,66 @@ func (r *resourceNetwork) Create(ctx context.Context, req resource.CreateRequest ) return } + //set zero etl access + if plan.ZeroEtlAccess.ValueEnum() == odbtypes.AccessEnabled { + _, err = waitManagedServiceEnabled(ctx, conn, *createdOdbNetwork.OdbNetworkId, managedServiceTimeout, func(managedService *odbtypes.ManagedServices) odbtypes.ManagedResourceStatus { + return managedService.ZeroEtlAccess.Status + }) + if err != nil { + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.ODB, create.ErrActionWaitingForUpdate, ResNameNetwork, plan.OdbNetworkId.String(), err), + err.Error(), + ) + return + } + plan.ZeroEtlAccess = fwtypes.StringEnumValue(odbtypes.AccessEnabled) - createdOdbNetwork, err = waitOdbNetworkManagedServiceResponse(ctx, conn, *out.OdbNetworkId, createTimeout, func(managedService *odbtypes.ManagedServices) odbtypes.ManagedResourceStatus { - return managedService.ZeroEtlAccess.Status - }) - if err != nil { - resp.Diagnostics.AddError( - create.ProblemStandardMessage(names.ODB, create.ErrActionWaitingForCreation, ResNameNetwork, plan.DisplayName.String(), err), - err.Error(), - ) - return - } - returnedZeroEtlAccess, err := managedServiceStatusToAccessStatus(createdOdbNetwork.ManagedServices.ZeroEtlAccess.Status) - if err != nil { - resp.Diagnostics.AddError( - create.ProblemStandardMessage(names.ODB, create.ErrActionWaitingForCreation, ResNameNetwork, plan.DisplayName.String(), err), - err.Error(), - ) - return + } else if plan.ZeroEtlAccess.ValueEnum() == odbtypes.AccessDisabled { + _, err = waitManagedServiceDisabled(ctx, conn, *createdOdbNetwork.OdbNetworkId, managedServiceTimeout, func(managedService *odbtypes.ManagedServices) odbtypes.ManagedResourceStatus { + return managedService.ZeroEtlAccess.Status + }) + if err != nil { + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.ODB, create.ErrActionWaitingForUpdate, ResNameNetwork, plan.OdbNetworkId.String(), err), + err.Error(), + ) + return + } + plan.ZeroEtlAccess = fwtypes.StringEnumValue(odbtypes.AccessDisabled) } - if returnedZeroEtlAccess != input.ZeroEtlAccess { - resp.Diagnostics.AddError( - create.ProblemStandardMessage(names.ODB, create.ErrActionWaitingForCreation, ResNameNetwork, plan.DisplayName.String(), errors.New("unexpected status of zero_tl_access")), - "Inconsistent zero_tl_access state", - ) - return - } - plan.ZeroEtlAccess = fwtypes.StringEnumValue(returnedZeroEtlAccess) + //set s3 access + if plan.S3Access.ValueEnum() == odbtypes.AccessEnabled { + _, err = waitManagedServiceEnabled(ctx, conn, *createdOdbNetwork.OdbNetworkId, managedServiceTimeout, func(managedService *odbtypes.ManagedServices) odbtypes.ManagedResourceStatus { + return managedService.S3Access.Status + }) + if err != nil { + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.ODB, create.ErrActionWaitingForUpdate, ResNameNetwork, plan.OdbNetworkId.String(), err), + err.Error(), + ) + return + } + plan.S3Access = fwtypes.StringEnumValue(odbtypes.AccessEnabled) - createdOdbNetwork, err = waitOdbNetworkManagedServiceResponse(ctx, conn, *out.OdbNetworkId, createTimeout, func(managedService *odbtypes.ManagedServices) odbtypes.ManagedResourceStatus { - return managedService.S3Access.Status - }) - if err != nil { - resp.Diagnostics.AddError( - create.ProblemStandardMessage(names.ODB, create.ErrActionWaitingForCreation, ResNameNetwork, plan.DisplayName.String(), err), - err.Error(), - ) - return - } - returnedS3Access, err := managedServiceStatusToAccessStatus(createdOdbNetwork.ManagedServices.S3Access.Status) - if err != nil { - resp.Diagnostics.AddError( - create.ProblemStandardMessage(names.ODB, create.ErrActionWaitingForCreation, ResNameNetwork, plan.DisplayName.String(), err), - err.Error(), - ) - return - } - if returnedS3Access != input.S3Access { - resp.Diagnostics.AddError( - create.ProblemStandardMessage(names.ODB, create.ErrActionWaitingForCreation, ResNameNetwork, plan.DisplayName.String(), errors.New("unexpected status of s3_access")), - "Inconsistent s3_access state", - ) - return + } else if plan.S3Access.ValueEnum() == odbtypes.AccessDisabled { + _, err = waitManagedServiceDisabled(ctx, conn, *createdOdbNetwork.OdbNetworkId, managedServiceTimeout, func(managedService *odbtypes.ManagedServices) odbtypes.ManagedResourceStatus { + return managedService.S3Access.Status + }) + if err != nil { + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.ODB, create.ErrActionWaitingForUpdate, ResNameNetwork, plan.OdbNetworkId.String(), err), + err.Error(), + ) + return + } + plan.S3Access = fwtypes.StringEnumValue(odbtypes.AccessDisabled) } - plan.S3Access = fwtypes.StringEnumValue(returnedS3Access) - plan.S3PolicyDocument = types.StringPointerValue(createdOdbNetwork.ManagedServices.S3Access.S3PolicyDocument) + plan.S3PolicyDocument = types.StringPointerValue(createdOdbNetwork.ManagedServices.S3Access.S3PolicyDocument) plan.CreatedAt = types.StringValue(createdOdbNetwork.CreatedAt.Format(time.RFC3339)) - resp.Diagnostics.Append(flex.Flatten(ctx, createdOdbNetwork, &plan, flex.WithIgnoredFieldNamesAppend("CreatedAt"), - flex.WithIgnoredFieldNamesAppend("S3Access"), - flex.WithIgnoredFieldNamesAppend("ZeroEtlAccess"), - flex.WithIgnoredFieldNamesAppend("S3PolicyDocument"))...) - + resp.Diagnostics.Append(flex.Flatten(ctx, createdOdbNetwork, &plan)...) if resp.Diagnostics.HasError() { return } @@ -417,9 +420,7 @@ func (r *resourceNetwork) Read(ctx context.Context, req resource.ReadRequest, re return } state.CreatedAt = types.StringValue(out.CreatedAt.Format(time.RFC3339)) - resp.Diagnostics.Append(flex.Flatten(ctx, out, &state, flex.WithIgnoredFieldNamesAppend("CreatedAt"), - flex.WithIgnoredFieldNamesAppend("S3Access"), flex.WithIgnoredFieldNamesAppend("ZeroEtlAccess"), - flex.WithIgnoredFieldNamesAppend("S3PolicyDocument"))...) + resp.Diagnostics.Append(flex.Flatten(ctx, out, &state)...) if resp.Diagnostics.HasError() { return } @@ -444,27 +445,18 @@ func (r *resourceNetwork) Update(ctx context.Context, req resource.UpdateRequest isUpdateRequired = true input.DisplayName = plan.DisplayName.ValueStringPointer() } - isS3AccessUpdated := false + if !plan.S3Access.Equal(state.S3Access) { isUpdateRequired = true - isS3AccessUpdated = true - if !plan.S3Access.IsNull() || !state.S3Access.IsUnknown() { - input.S3Access = plan.S3Access.ValueEnum() - } - + input.S3Access = plan.S3Access.ValueEnum() } - isZeroEtlAccessUpdated := false + if !plan.ZeroEtlAccess.Equal(state.ZeroEtlAccess) { isUpdateRequired = true - if !plan.ZeroEtlAccess.IsNull() || !plan.ZeroEtlAccess.IsUnknown() { - input.ZeroEtlAccess = plan.ZeroEtlAccess.ValueEnum() - } - isZeroEtlAccessUpdated = true + input.ZeroEtlAccess = plan.ZeroEtlAccess.ValueEnum() } - isS3EndpointPolicyUpdated := false if !plan.S3PolicyDocument.Equal(state.S3PolicyDocument) { isUpdateRequired = true - isS3EndpointPolicyUpdated = true if !plan.S3PolicyDocument.IsNull() || !plan.S3PolicyDocument.IsUnknown() { input.S3PolicyDocument = plan.S3PolicyDocument.ValueStringPointer() } @@ -499,66 +491,63 @@ func (r *resourceNetwork) Update(ctx context.Context, req resource.UpdateRequest return } - if isS3AccessUpdated || isS3EndpointPolicyUpdated { + if plan.S3Access.ValueEnum() == odbtypes.AccessEnabled { + _, err = waitManagedServiceEnabled(ctx, conn, *input.OdbNetworkId, managedServiceTimeout, func(managedService *odbtypes.ManagedServices) odbtypes.ManagedResourceStatus { + return managedService.S3Access.Status + }) + if err != nil { + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.ODB, create.ErrActionWaitingForUpdate, ResNameNetwork, plan.OdbNetworkId.String(), err), + err.Error(), + ) + return + } + plan.S3Access = fwtypes.StringEnumValue(odbtypes.AccessEnabled) - if plan.S3Access.ValueEnum() == odbtypes.AccessEnabled { - _, err = waitManagedServiceEnabled(ctx, conn, *input.OdbNetworkId, updateTimeout, func(managedService *odbtypes.ManagedServices) odbtypes.ManagedResourceStatus { - return managedService.S3Access.Status - }) - if err != nil { - resp.Diagnostics.AddError( - create.ProblemStandardMessage(names.ODB, create.ErrActionWaitingForUpdate, ResNameNetwork, plan.OdbNetworkId.String(), err), - err.Error(), - ) - return - } - plan.S3Access = fwtypes.StringEnumValue(odbtypes.AccessEnabled) - } else if plan.S3Access.ValueEnum() == odbtypes.AccessDisabled { - _, err = waitManagedServiceDisabled(ctx, conn, *input.OdbNetworkId, updateTimeout, func(managedService *odbtypes.ManagedServices) odbtypes.ManagedResourceStatus { - return managedService.S3Access.Status - }) - if err != nil { - resp.Diagnostics.AddError( - create.ProblemStandardMessage(names.ODB, create.ErrActionWaitingForUpdate, ResNameNetwork, plan.OdbNetworkId.String(), err), - err.Error(), - ) - return - } - plan.S3Access = fwtypes.StringEnumValue(odbtypes.AccessDisabled) + } else if plan.S3Access.ValueEnum() == odbtypes.AccessDisabled { + _, err = waitManagedServiceDisabled(ctx, conn, *input.OdbNetworkId, managedServiceTimeout, func(managedService *odbtypes.ManagedServices) odbtypes.ManagedResourceStatus { + return managedService.S3Access.Status + }) + if err != nil { + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.ODB, create.ErrActionWaitingForUpdate, ResNameNetwork, plan.OdbNetworkId.String(), err), + err.Error(), + ) + return } + plan.S3Access = fwtypes.StringEnumValue(odbtypes.AccessDisabled) } - if isZeroEtlAccessUpdated { - if plan.ZeroEtlAccess.ValueEnum() == odbtypes.AccessEnabled { - _, err = waitManagedServiceEnabled(ctx, conn, *input.OdbNetworkId, updateTimeout, func(managedService *odbtypes.ManagedServices) odbtypes.ManagedResourceStatus { - return managedService.ZeroEtlAccess.Status - }) - if err != nil { - resp.Diagnostics.AddError( - create.ProblemStandardMessage(names.ODB, create.ErrActionWaitingForUpdate, ResNameNetwork, plan.OdbNetworkId.String(), err), - err.Error(), - ) - return - } - plan.ZeroEtlAccess = fwtypes.StringEnumValue(odbtypes.AccessEnabled) - } else if plan.ZeroEtlAccess.ValueEnum() == odbtypes.AccessDisabled { - _, err = waitManagedServiceEnabled(ctx, conn, *input.OdbNetworkId, updateTimeout, func(managedService *odbtypes.ManagedServices) odbtypes.ManagedResourceStatus { - return managedService.ZeroEtlAccess.Status - }) - if err != nil { - resp.Diagnostics.AddError( - create.ProblemStandardMessage(names.ODB, create.ErrActionWaitingForUpdate, ResNameNetwork, plan.OdbNetworkId.String(), err), - err.Error(), - ) - return - } - plan.ZeroEtlAccess = fwtypes.StringEnumValue(odbtypes.AccessDisabled) + if plan.ZeroEtlAccess.ValueEnum() == odbtypes.AccessEnabled { + _, err = waitManagedServiceEnabled(ctx, conn, *input.OdbNetworkId, managedServiceTimeout, func(managedService *odbtypes.ManagedServices) odbtypes.ManagedResourceStatus { + return managedService.ZeroEtlAccess.Status + }) + if err != nil { + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.ODB, create.ErrActionWaitingForUpdate, ResNameNetwork, plan.OdbNetworkId.String(), err), + err.Error(), + ) + return } - } + plan.ZeroEtlAccess = fwtypes.StringEnumValue(odbtypes.AccessEnabled) + } else if plan.ZeroEtlAccess.ValueEnum() == odbtypes.AccessDisabled { + _, err = waitManagedServiceDisabled(ctx, conn, *input.OdbNetworkId, managedServiceTimeout, func(managedService *odbtypes.ManagedServices) odbtypes.ManagedResourceStatus { + return managedService.ZeroEtlAccess.Status + }) + if err != nil { + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.ODB, create.ErrActionWaitingForUpdate, ResNameNetwork, plan.OdbNetworkId.String(), err), + err.Error(), + ) + return + } + plan.ZeroEtlAccess = fwtypes.StringEnumValue(odbtypes.AccessDisabled) + } + plan.S3PolicyDocument = types.StringPointerValue(updatedOdbNwk.ManagedServices.S3Access.S3PolicyDocument) plan.CreatedAt = types.StringValue(updatedOdbNwk.CreatedAt.Format(time.RFC3339)) - resp.Diagnostics.Append(flex.Flatten(ctx, updatedOdbNwk, &plan, flex.WithIgnoredFieldNamesAppend("CreatedAt"))..., //flex.WithIgnoredFieldNamesAppend("PeeredCidrs") - ) + + resp.Diagnostics.Append(flex.Flatten(ctx, updatedOdbNwk, &plan)...) resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) } @@ -632,22 +621,6 @@ func managedServiceStatusToAccessStatus(mangedStatus odbtypes.ManagedResourceSta return "", errors.New("can not convert managed status to access status") } -func waitOdbNetworkManagedServiceResponse(ctx context.Context, conn *odb.Client, id string, timeout time.Duration, managedResourceStatus func(managedService *odbtypes.ManagedServices) odbtypes.ManagedResourceStatus) (*odbtypes.OdbNetwork, error) { - stateConf := &retry.StateChangeConf{ - Pending: enum.Slice(odbtypes.ManagedResourceStatusEnabling, odbtypes.ManagedResourceStatusDisabling), - Target: enum.Slice(odbtypes.ManagedResourceStatusEnabled, odbtypes.ManagedResourceStatusDisabled), - Refresh: statusManagedService(ctx, conn, id, managedResourceStatus), - Timeout: timeout, - } - - outputRaw, err := stateConf.WaitForStateContext(ctx) - if out, ok := outputRaw.(*odbtypes.OdbNetwork); ok { - return out, err - } - - return nil, err -} - func waitManagedServiceEnabled(ctx context.Context, conn *odb.Client, id string, timeout time.Duration, managedResourceStatus func(managedService *odbtypes.ManagedServices) odbtypes.ManagedResourceStatus) (*odbtypes.OdbNetwork, error) { stateConf := &retry.StateChangeConf{ Pending: enum.Slice(odbtypes.ManagedResourceStatusEnabling), @@ -797,10 +770,11 @@ type odbNetworkResourceModel struct { BackupSubnetCidr types.String `tfsdk:"backup_subnet_cidr"` CustomDomainName types.String `tfsdk:"custom_domain_name"` DefaultDnsPrefix types.String `tfsdk:"default_dns_prefix"` - S3Access fwtypes.StringEnum[odbtypes.Access] `tfsdk:"s3_access"` - ZeroEtlAccess fwtypes.StringEnum[odbtypes.Access] `tfsdk:"zero_etl_access"` - S3PolicyDocument types.String `tfsdk:"s3_policy_document"` + S3Access fwtypes.StringEnum[odbtypes.Access] `tfsdk:"s3_access" autoflex:",noflatten"` + ZeroEtlAccess fwtypes.StringEnum[odbtypes.Access] `tfsdk:"zero_etl_access" autoflex:",noflatten"` + S3PolicyDocument types.String `tfsdk:"s3_policy_document" autoflex:",noflatten"` OdbNetworkId types.String `tfsdk:"id"` + PeeredCidrs fwtypes.SetValueOf[types.String] `tfsdk:"peered_cidrs"` OciDnsForwardingConfigs fwtypes.ListNestedObjectValueOf[odbNwkOciDnsForwardingConfigResourceModel] `tfsdk:"oci_dns_forwarding_configs"` OciNetworkAnchorId types.String `tfsdk:"oci_network_anchor_id"` OciNetworkAnchorUrl types.String `tfsdk:"oci_network_anchor_url"` @@ -813,7 +787,7 @@ type odbNetworkResourceModel struct { StatusReason types.String `tfsdk:"status_reason"` Timeouts timeouts.Value `tfsdk:"timeouts"` ManagedServices fwtypes.ObjectValueOf[odbNetworkManagedServicesResourceModel] `tfsdk:"managed_services"` - CreatedAt types.String `tfsdk:"created_at"` + CreatedAt types.String `tfsdk:"created_at" autoflex:",noflatten"` Tags tftags.Map `tfsdk:"tags"` TagsAll tftags.Map `tfsdk:"tags_all"` } diff --git a/internal/service/odb/network_data_source.go b/internal/service/odb/network_data_source.go index 570bfc38d12b..1f7e94865848 100644 --- a/internal/service/odb/network_data_source.go +++ b/internal/service/odb/network_data_source.go @@ -82,6 +82,12 @@ func (d *dataSourceNetwork) Schema(ctx context.Context, req datasource.SchemaReq "percent_progress": schema.Float64Attribute{ Computed: true, }, + "peered_cidrs": schema.SetAttribute{ + CustomType: fwtypes.SetOfStringType, + ElementType: types.StringType, + Computed: true, + Description: "The list of CIDR ranges from the peered VPC that are allowed access to the ODB network. Please refer odb network peering documentation.", + }, "status": schema.StringAttribute{ CustomType: statusType, Computed: true, @@ -195,6 +201,7 @@ type odbNetworkDataSourceModel struct { OciVcnUrl types.String `tfsdk:"oci_vcn_url"` OdbNetworkArn types.String `tfsdk:"arn"` OdbNetworkId types.String `tfsdk:"id"` + PeeredCidrs fwtypes.SetValueOf[types.String] `tfsdk:"peered_cidrs"` PercentProgress types.Float64 `tfsdk:"percent_progress"` Status fwtypes.StringEnum[odbtypes.ResourceStatus] `tfsdk:"status"` StatusReason types.String `tfsdk:"status_reason"` diff --git a/internal/service/odb/network_peering_connection.go b/internal/service/odb/network_peering_connection.go index ea9613cf63cf..46f057869e4c 100644 --- a/internal/service/odb/network_peering_connection.go +++ b/internal/service/odb/network_peering_connection.go @@ -59,6 +59,7 @@ type resourceNetworkPeeringConnection struct { func (r *resourceNetworkPeeringConnection) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { resp.Schema = schema.Schema{ + Description: "Information about an ODB network. Also refer odb_network_peering resource : A peering connection between an ODB network and either another ODB network or a customer-owned VPC.", Attributes: map[string]schema.Attribute{ names.AttrARN: framework.ARNAttributeComputedOnly(), names.AttrID: framework.IDAttribute(), diff --git a/internal/service/odb/network_test.go b/internal/service/odb/network_test.go index cdd2278f63d5..e5864fb21190 100644 --- a/internal/service/odb/network_test.go +++ b/internal/service/odb/network_test.go @@ -16,6 +16,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/create" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/names" + "strings" "testing" tfodb "github.com/hashicorp/terraform-provider-aws/internal/service/odb" @@ -101,21 +102,19 @@ func TestOdbNetworkWithAllParams(t *testing.T) { }) } -// TestAccODBNetwork_Update -func TestAccODBNetwork_Delete_Create(t *testing.T) { +func TestAccODBNetworkUpdateManagedService(t *testing.T) { ctx := acctest.Context(t) if testing.Short() { t.Skip("skipping long-running test in short mode") } - var network odbtypes.OdbNetwork + var network1, network2 odbtypes.OdbNetwork rName := sdkacctest.RandomWithPrefix(odbNetResourceTest.displayNamePrefix) resourceName := "aws_odb_network.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) - //acctest.PreCheckPartitionHasService(t, names.ODBEndpointID) odbNetResourceTest.testAccPreCheck(ctx, t) }, ErrorCheck: acctest.ErrorCheck(t, names.ODBServiceID), @@ -124,19 +123,76 @@ func TestAccODBNetwork_Delete_Create(t *testing.T) { Steps: []resource.TestStep{ { Config: odbNetResourceTest.basicOdbNetwork(rName), - Check: resource.ComposeAggregateTestCheckFunc( - odbNetResourceTest.testAccCheckNetworkExists(ctx, resourceName, &network), + odbNetResourceTest.testAccCheckNetworkExists(ctx, resourceName, &network1), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: odbNetResourceTest.basicOdbNetworkWithActiveManagedService(rName), + Check: resource.ComposeAggregateTestCheckFunc( + odbNetResourceTest.testAccCheckNetworkExists(ctx, resourceName, &network2), resource.ComposeTestCheckFunc(func(state *terraform.State) error { - fmt.Println(state) + if strings.Compare(*(network1.OdbNetworkId), *(network2.OdbNetworkId)) != 0 { + return errors.New("should not create a new cloud odb network") + } return nil }), ), }, { - Config: odbNetResourceTest.updateOdbNetworkDisplayName(rName + "_foo"), + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccODBNetworkDisableManagedService(t *testing.T) { + ctx := acctest.Context(t) + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + var network1, network2 odbtypes.OdbNetwork + rName := sdkacctest.RandomWithPrefix(odbNetResourceTest.displayNamePrefix) + resourceName := "aws_odb_network.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + odbNetResourceTest.testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.ODBServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: odbNetResourceTest.testAccCheckNetworkDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: odbNetResourceTest.basicOdbNetworkWithActiveManagedService(rName), + Check: resource.ComposeAggregateTestCheckFunc( + odbNetResourceTest.testAccCheckNetworkExists(ctx, resourceName, &network1), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: odbNetResourceTest.basicOdbNetwork(rName), Check: resource.ComposeAggregateTestCheckFunc( - odbNetResourceTest.testAccCheckNetworkExists(ctx, resourceName, &network), + odbNetResourceTest.testAccCheckNetworkExists(ctx, resourceName, &network2), + resource.ComposeTestCheckFunc(func(state *terraform.State) error { + if strings.Compare(*(network1.OdbNetworkId), *(network2.OdbNetworkId)) != 0 { + return errors.New("should not create a new cloud odb network") + } + return nil + }), ), }, { @@ -154,7 +210,7 @@ func TestAccODBNetwork_Update_Tags(t *testing.T) { t.Skip("skipping long-running test in short mode") } - var network odbtypes.OdbNetwork + var network1, network2 odbtypes.OdbNetwork rName := sdkacctest.RandomWithPrefix(odbNetResourceTest.displayNamePrefix) resourceName := "aws_odb_network.test" @@ -172,17 +228,21 @@ func TestAccODBNetwork_Update_Tags(t *testing.T) { Config: odbNetResourceTest.basicOdbNetwork(rName), Check: resource.ComposeAggregateTestCheckFunc( - odbNetResourceTest.testAccCheckNetworkExists(ctx, resourceName, &network), - resource.ComposeTestCheckFunc(func(state *terraform.State) error { - fmt.Println(state) - return nil - }), + odbNetResourceTest.testAccCheckNetworkExists(ctx, resourceName, &network1), ), }, { Config: odbNetResourceTest.updateOdbNetworkTags(rName), Check: resource.ComposeAggregateTestCheckFunc( - odbNetResourceTest.testAccCheckNetworkExists(ctx, resourceName, &network), + odbNetResourceTest.testAccCheckNetworkExists(ctx, resourceName, &network2), + resource.ComposeTestCheckFunc(func(state *terraform.State) error { + if strings.Compare(*(network1.OdbNetworkId), *(network2.OdbNetworkId)) != 0 { + return errors.New("should not create a new cloud odb network") + } + return nil + }), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.env", "dev"), ), }, { @@ -318,6 +378,23 @@ resource "aws_odb_network" "test" { return networkRes } +func (odbNetworkResourceTest) basicOdbNetworkWithActiveManagedService(rName string) string { + networkRes := fmt.Sprintf(` + + +resource "aws_odb_network" "test" { + display_name = %[1]q + availability_zone_id = "use1-az6" + client_subnet_cidr = "10.2.0.0/24" + backup_subnet_cidr = "10.2.1.0/24" + s3_access = "ENABLED" + zero_etl_access = "ENABLED" +} + +`, rName) + return networkRes +} + func (odbNetworkResourceTest) odbNetworkWithAllParams(rName, customDomainName string) string { networkRes := fmt.Sprintf(` @@ -365,7 +442,6 @@ resource "aws_odb_network" "test" { zero_etl_access = "DISABLED" tags = { "env"= "dev" - "foo"= "bar" } } `, rName) diff --git a/internal/service/odb/service_package.go b/internal/service/odb/service_package.go index 232a650ad021..32a962a8ab63 100644 --- a/internal/service/odb/service_package.go +++ b/internal/service/odb/service_package.go @@ -15,6 +15,7 @@ func (p *servicePackage) NewClient(ctx context.Context, config map[string]any) ( return odb.NewFromConfig(cfg, odb.WithEndpointResolverV2(newEndpointResolverV2()), withBaseEndpoint(config[names.AttrEndpoint].(string)), - func(o *odb.Options) {}, + func(o *odb.Options) { + }, ), nil } diff --git a/internal/service/odb/service_package_gen.go b/internal/service/odb/service_package_gen.go index be8267f9c2d1..68efcabb4e0b 100644 --- a/internal/service/odb/service_package_gen.go +++ b/internal/service/odb/service_package_gen.go @@ -51,6 +51,12 @@ func (p *servicePackage) FrameworkDataSources(ctx context.Context) []*inttypes.S Name: "Cloud Vm Clusters List", Region: unique.Make(inttypes.ResourceRegionDefault()), }, + { + Factory: newDataSourceDbServer, + TypeName: "aws_odb_db_server", + Name: "Db Server", + Region: unique.Make(inttypes.ResourceRegionDefault()), + }, { Factory: newDataSourceDbServersList, TypeName: "aws_odb_db_servers_list",