diff --git a/internal/services/oracle/autonomous_database_regular_data_source.go b/internal/services/oracle/autonomous_database_regular_data_source.go new file mode 100644 index 000000000000..52cb61515c90 --- /dev/null +++ b/internal/services/oracle/autonomous_database_regular_data_source.go @@ -0,0 +1,491 @@ +// Copyright © 2024, Oracle and/or its affiliates. All rights reserved + +package oracle + +import ( + "context" + "fmt" + "time" + + "github.com/hashicorp/go-azure-helpers/lang/pointer" + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/go-azure-helpers/resourcemanager/location" + "github.com/hashicorp/go-azure-sdk/resource-manager/oracledatabase/2024-06-01/autonomousdatabases" + "github.com/hashicorp/terraform-provider-azurerm/internal/sdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/oracle/validate" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" +) + +type AutonomousDatabaseRegularDataSource struct{} + +type AutonomousDatabaseRegularDataModel struct { + Location string `tfschema:"location"` + Name string `tfschema:"name"` + ResourceGroupName string `tfschema:"resource_group_name"` + Tags map[string]string `tfschema:"tags"` + + // AutonomousDatabaseProperties + ActualUsedDataStorageSizeInTbs float64 `tfschema:"actual_used_data_storage_size_in_tbs"` + AllocatedStorageSizeInTbs float64 `tfschema:"allocated_storage_size_in_tbs"` + AutonomousDatabaseId string `tfschema:"autonomous_database_id"` + AutoScalingEnabled bool `tfschema:"auto_scaling_enabled"` + AutoScalingForStorageEnabled bool `tfschema:"auto_scaling_for_storage_enabled"` + AvailableUpgradeVersions []string `tfschema:"available_upgrade_versions"` + BackupRetentionPeriodInDays int64 `tfschema:"backup_retention_period_in_days"` + CharacterSet string `tfschema:"character_set"` + ComputeCount float64 `tfschema:"compute_count"` + CpuCoreCount int64 `tfschema:"cpu_core_count"` + DataStorageSizeInGbs int64 `tfschema:"data_storage_size_in_gbs"` + DataStorageSizeInTbs int64 `tfschema:"data_storage_size_in_tbs"` + DbVersion string `tfschema:"db_version"` + DisplayName string `tfschema:"display_name"` + FailedDataRecoveryInSeconds int64 `tfschema:"failed_data_recovery_in_seconds"` + LifecycleDetails string `tfschema:"lifecycle_details"` + LocalAdgAutoFailoverMaxDataLossLimit int64 `tfschema:"local_adg_auto_failover_max_data_loss_limit"` + LocalDataGuardEnabled bool `tfschema:"local_data_guard_enabled"` + MemoryAreaInGbs int64 `tfschema:"in_memory_area_in_gbs"` + MemoryPerOracleComputeUnitInGbs int64 `tfschema:"memory_per_oracle_compute_unit_in_gbs"` + MtlsConnectionRequired bool `tfschema:"mtls_connection_required"` + NcharacterSet string `tfschema:"national_character_set"` + NextLongTermBackupTimeStamp string `tfschema:"next_long_term_backup_time_stamp"` + Ocid string `tfschema:"ocid"` + OciUrl string `tfschema:"oci_url"` + PeerDbId string `tfschema:"peer_db_id"` + PeerDbIds []string `tfschema:"peer_db_ids"` + Preview bool `tfschema:"preview"` + PreviewVersionWithServiceTermsAccepted bool `tfschema:"preview_version_with_service_terms_accepted"` + PrivateEndpoint string `tfschema:"private_endpoint"` + PrivateEndpointIP string `tfschema:"private_endpoint_ip"` + PrivateEndpointLabel string `tfschema:"private_endpoint_label"` + ProvisionableCPUs []int64 `tfschema:"provisionable_cpus"` + RemoteDataGuardEnabled bool `tfschema:"remote_data_guard_enabled"` + ServiceConsoleUrl string `tfschema:"service_console_url"` + SqlWebDeveloperUrl string `tfschema:"sql_web_developer_url"` + SubnetId string `tfschema:"subnet_id"` + SupportedRegionsToCloneTo []string `tfschema:"supported_regions_to_clone_to"` + TimeCreated string `tfschema:"time_created"` + TimeDataGuardRoleChanged string `tfschema:"time_data_guard_role_changed"` + TimeDeletionOfFreeAutonomousDatabase string `tfschema:"time_deletion_of_free_autonomous_database"` + TimeLocalDataGuardEnabled string `tfschema:"time_local_data_guard_enabled_on"` + TimeMaintenanceBegin string `tfschema:"time_maintenance_begin"` + TimeMaintenanceEnd string `tfschema:"time_maintenance_end"` + TimeOfLastFailover string `tfschema:"time_of_last_failover"` + TimeOfLastRefresh string `tfschema:"time_of_last_refresh"` + TimeOfLastRefreshPoint string `tfschema:"time_of_last_refresh_point"` + TimeOfLastSwitchover string `tfschema:"time_of_last_switchover"` + TimeReclamationOfFreeAutonomousDatabase string `tfschema:"time_reclamation_of_free_autonomous_database"` + UsedDataStorageSizeInGbs int64 `tfschema:"used_data_storage_size_in_gbs"` + UsedDataStorageSizeInTbs int64 `tfschema:"used_data_storage_size_in_tbs"` + VnetId string `tfschema:"virtual_network_id"` + AllowedIps []string `tfschema:"allowed_ips"` +} + +func (d AutonomousDatabaseRegularDataSource) Arguments() map[string]*pluginsdk.Schema { + return map[string]*pluginsdk.Schema{ + "resource_group_name": commonschema.ResourceGroupNameForDataSource(), + + "name": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validate.AutonomousDatabaseName, + }, + } +} + +func (d AutonomousDatabaseRegularDataSource) Attributes() map[string]*pluginsdk.Schema { + return map[string]*pluginsdk.Schema{ + "location": commonschema.LocationComputed(), + + // AutonomousDatabaseProperties + "actual_used_data_storage_size_in_tbs": { + Type: pluginsdk.TypeFloat, + Computed: true, + }, + + "allocated_storage_size_in_tbs": { + Type: pluginsdk.TypeFloat, + Computed: true, + }, + + "auto_scaling_enabled": { + Type: pluginsdk.TypeBool, + Computed: true, + }, + + "auto_scaling_for_storage_enabled": { + Type: pluginsdk.TypeBool, + Computed: true, + }, + + "autonomous_database_id": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "available_upgrade_versions": { + Type: pluginsdk.TypeList, + Computed: true, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + }, + }, + + "backup_retention_period_in_days": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + + "character_set": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "compute_count": { + Type: pluginsdk.TypeFloat, + Computed: true, + }, + + "cpu_core_count": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + + "data_storage_size_in_gbs": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + + "data_storage_size_in_tbs": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + + "db_node_storage_size_in_gbs": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + + "db_version": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "display_name": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "failed_data_recovery_in_seconds": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + + "in_memory_area_in_gbs": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + + "lifecycle_details": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "local_adg_auto_failover_max_data_loss_limit": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + + "local_data_guard_enabled": { + Type: pluginsdk.TypeBool, + Computed: true, + }, + + "memory_per_oracle_compute_unit_in_gbs": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + + "mtls_connection_required": { + Type: pluginsdk.TypeBool, + Computed: true, + }, + + "national_character_set": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "next_long_term_backup_time_stamp": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "oci_url": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "ocid": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "preview": { + Type: pluginsdk.TypeBool, + Computed: true, + }, + + "preview_version_with_service_terms_accepted": { + Type: pluginsdk.TypeBool, + Computed: true, + }, + + "remote_data_guard_enabled": { + Type: pluginsdk.TypeBool, + Computed: true, + }, + + "peer_db_id": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "peer_db_ids": { + Type: pluginsdk.TypeList, + Computed: true, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + }, + }, + + "private_endpoint": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "private_endpoint_ip": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "private_endpoint_label": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "provisionable_cpus": { + Type: pluginsdk.TypeList, + Computed: true, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeInt, + }, + }, + + "service_console_url": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "sql_web_developer_url": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "subnet_id": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "supported_regions_to_clone_to": { + Type: pluginsdk.TypeList, + Computed: true, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeInt, + }, + }, + + "time_created": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "time_data_guard_role_changed": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "time_deletion_of_free_autonomous_database": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "time_local_data_guard_enabled_on": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "time_maintenance_begin": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "time_maintenance_end": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "time_of_last_failover": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "time_of_last_refresh": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "time_of_last_refresh_point": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "time_of_last_switchover": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "time_reclamation_of_free_autonomous_database": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "used_data_storage_size_in_gbs": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + + "used_data_storage_size_in_tbs": { + Type: pluginsdk.TypeInt, + Computed: true, + }, + + "virtual_network_id": { + Type: pluginsdk.TypeString, + Computed: true, + }, + + "allowed_ips": { + Type: pluginsdk.TypeList, + Computed: true, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeInt, + }, + }, + + "tags": commonschema.TagsDataSource(), + } +} + +func (d AutonomousDatabaseRegularDataSource) ModelObject() interface{} { + return &AutonomousDatabaseRegularDataModel{} +} + +func (d AutonomousDatabaseRegularDataSource) ResourceType() string { + return "azurerm_oracle_autonomous_database" +} + +func (d AutonomousDatabaseRegularDataSource) IDValidationFunc() pluginsdk.SchemaValidateFunc { + return autonomousdatabases.ValidateAutonomousDatabaseID +} + +func (d AutonomousDatabaseRegularDataSource) Read() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 5 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + client := metadata.Client.Oracle.OracleClient.AutonomousDatabases + subscriptionId := metadata.Client.Account.SubscriptionId + + var state AutonomousDatabaseRegularDataModel + if err := metadata.Decode(&state); err != nil { + return fmt.Errorf("decoding: %+v", err) + } + + id := autonomousdatabases.NewAutonomousDatabaseID(subscriptionId, state.ResourceGroupName, state.Name) + + resp, err := client.Get(ctx, id) + if err != nil { + if response.WasNotFound(resp.HttpResponse) { + return fmt.Errorf("%s was not found", id) + } + return fmt.Errorf("retrieving %s: %+v", id, err) + } + + if model := resp.Model; model != nil { + state.Location = location.Normalize(model.Location) + state.Tags = pointer.From(model.Tags) + if props := model.Properties; props != nil { + adbsProps := props.AutonomousDatabaseBaseProperties() + + state.ActualUsedDataStorageSizeInTbs = pointer.From(adbsProps.ActualUsedDataStorageSizeInTbs) + state.AllocatedStorageSizeInTbs = pointer.From(adbsProps.AllocatedStorageSizeInTbs) + state.AutonomousDatabaseId = pointer.From(adbsProps.AutonomousDatabaseId) + state.AutoScalingEnabled = pointer.From(adbsProps.IsAutoScalingEnabled) + state.AutoScalingForStorageEnabled = pointer.From(adbsProps.IsAutoScalingForStorageEnabled) + state.AvailableUpgradeVersions = pointer.From(adbsProps.AvailableUpgradeVersions) + state.BackupRetentionPeriodInDays = pointer.From(adbsProps.BackupRetentionPeriodInDays) + state.CharacterSet = pointer.From(adbsProps.CharacterSet) + state.ComputeCount = pointer.From(adbsProps.ComputeCount) + state.CpuCoreCount = pointer.From(adbsProps.CpuCoreCount) + state.DataStorageSizeInGbs = pointer.From(adbsProps.DataStorageSizeInGbs) + state.DataStorageSizeInTbs = pointer.From(adbsProps.DataStorageSizeInTbs) + state.DbVersion = pointer.From(adbsProps.DbVersion) + state.DisplayName = pointer.From(adbsProps.DisplayName) + state.FailedDataRecoveryInSeconds = pointer.From(adbsProps.FailedDataRecoveryInSeconds) + state.LifecycleDetails = pointer.From(adbsProps.LifecycleDetails) + state.LocalAdgAutoFailoverMaxDataLossLimit = pointer.From(adbsProps.LocalAdgAutoFailoverMaxDataLossLimit) + state.LocalDataGuardEnabled = pointer.From(adbsProps.IsLocalDataGuardEnabled) + state.MemoryAreaInGbs = pointer.From(adbsProps.InMemoryAreaInGbs) + state.MemoryPerOracleComputeUnitInGbs = pointer.From(adbsProps.MemoryPerOracleComputeUnitInGbs) + state.MtlsConnectionRequired = pointer.From(adbsProps.IsMtlsConnectionRequired) + state.NcharacterSet = pointer.From(adbsProps.NcharacterSet) + state.NextLongTermBackupTimeStamp = pointer.From(adbsProps.NextLongTermBackupTimeStamp) + state.Ocid = pointer.From(adbsProps.Ocid) + state.OciUrl = pointer.From(adbsProps.OciURL) + state.PeerDbId = pointer.From(adbsProps.PeerDbId) + state.PeerDbIds = pointer.From(adbsProps.PeerDbIds) + state.Preview = pointer.From(adbsProps.IsPreview) + state.PreviewVersionWithServiceTermsAccepted = pointer.From(adbsProps.IsPreviewVersionWithServiceTermsAccepted) + state.PrivateEndpoint = pointer.From(adbsProps.PrivateEndpoint) + state.PrivateEndpointIP = pointer.From(adbsProps.PrivateEndpointIP) + state.PrivateEndpointLabel = pointer.From(adbsProps.PrivateEndpointLabel) + state.ProvisionableCPUs = pointer.From(adbsProps.ProvisionableCPUs) + state.RemoteDataGuardEnabled = pointer.From(adbsProps.IsRemoteDataGuardEnabled) + state.ServiceConsoleUrl = pointer.From(adbsProps.ServiceConsoleURL) + state.SqlWebDeveloperUrl = pointer.From(adbsProps.SqlWebDeveloperURL) + state.SubnetId = pointer.From(adbsProps.SubnetId) + state.SupportedRegionsToCloneTo = pointer.From(adbsProps.SupportedRegionsToCloneTo) + state.TimeCreated = pointer.From(adbsProps.TimeCreated) + state.TimeDataGuardRoleChanged = pointer.From(adbsProps.TimeDataGuardRoleChanged) + state.TimeDeletionOfFreeAutonomousDatabase = pointer.From(adbsProps.TimeDeletionOfFreeAutonomousDatabase) + state.TimeLocalDataGuardEnabled = pointer.From(adbsProps.TimeLocalDataGuardEnabled) + state.TimeMaintenanceBegin = pointer.From(adbsProps.TimeMaintenanceBegin) + state.TimeMaintenanceEnd = pointer.From(adbsProps.TimeMaintenanceEnd) + state.TimeOfLastFailover = pointer.From(adbsProps.TimeOfLastFailover) + state.TimeOfLastRefresh = pointer.From(adbsProps.TimeOfLastRefresh) + state.TimeOfLastRefreshPoint = pointer.From(adbsProps.TimeOfLastRefreshPoint) + state.TimeOfLastSwitchover = pointer.From(adbsProps.TimeOfLastSwitchover) + state.TimeReclamationOfFreeAutonomousDatabase = pointer.From(adbsProps.TimeReclamationOfFreeAutonomousDatabase) + state.UsedDataStorageSizeInGbs = pointer.From(adbsProps.UsedDataStorageSizeInGbs) + state.UsedDataStorageSizeInTbs = pointer.From(adbsProps.UsedDataStorageSizeInTbs) + state.VnetId = pointer.From(adbsProps.VnetId) + state.AllowedIps = pointer.From(adbsProps.WhitelistedIPs) + } + } + + metadata.SetID(id) + + return metadata.Encode(&state) + }, + } +} diff --git a/internal/services/oracle/autonomous_database_regular_data_source_test.go b/internal/services/oracle/autonomous_database_regular_data_source_test.go new file mode 100644 index 000000000000..2a1b513c8bb8 --- /dev/null +++ b/internal/services/oracle/autonomous_database_regular_data_source_test.go @@ -0,0 +1,44 @@ +// Copyright © 2024, Oracle and/or its affiliates. All rights reserved + +package oracle_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/oracle" +) + +type AutonomousDatabaseRegularDataSource struct{} + +func TestAdbsRegularDataSource_basic(t *testing.T) { + data := acceptance.BuildTestData(t, oracle.AutonomousDatabaseRegularDataSource{}.ResourceType(), "test") + r := AutonomousDatabaseRegularDataSource{} + + data.DataSourceTest(t, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).Key("location").Exists(), + check.That(data.ResourceName).Key("name").Exists(), + check.That(data.ResourceName).Key("resource_group_name").Exists(), + check.That(data.ResourceName).Key("data_storage_size_in_tbs").Exists(), + check.That(data.ResourceName).Key("display_name").Exists(), + check.That(data.ResourceName).Key("license_model").Exists(), + ), + }, + }) +} + +func (d AutonomousDatabaseRegularDataSource) basic(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +data "azurerm_oracle_autonomous_database" "test" { + name = azurerm_oracle_autonomous_database.test.name + resource_group_name = azurerm_oracle_autonomous_database.test.resource_group_name +} +`, AdbsRegularResource{}.basic(data)) +} diff --git a/internal/services/oracle/autonomous_database_regular_resource.go b/internal/services/oracle/autonomous_database_regular_resource.go new file mode 100644 index 000000000000..13f96d515fb3 --- /dev/null +++ b/internal/services/oracle/autonomous_database_regular_resource.go @@ -0,0 +1,412 @@ +// Copyright © 2024, Oracle and/or its affiliates. All rights reserved + +package oracle + +import ( + "context" + "fmt" + "time" + + "github.com/hashicorp/go-azure-helpers/lang/pointer" + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonids" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/go-azure-helpers/resourcemanager/location" + "github.com/hashicorp/go-azure-sdk/resource-manager/oracledatabase/2024-06-01/autonomousdatabases" + "github.com/hashicorp/terraform-provider-azurerm/internal/sdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/oracle/validate" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" +) + +var _ sdk.Resource = AutonomousDatabaseRegularResource{} + +type AutonomousDatabaseRegularResource struct{} + +type AutonomousDatabaseRegularResourceModel struct { + Location string `tfschema:"location"` + Name string `tfschema:"name"` + ResourceGroupName string `tfschema:"resource_group_name"` + Tags map[string]string `tfschema:"tags"` + + // Required + AdminPassword string `tfschema:"admin_password"` + BackupRetentionPeriodInDays int64 `tfschema:"backup_retention_period_in_days"` + CharacterSet string `tfschema:"character_set"` + ComputeCount float64 `tfschema:"compute_count"` + ComputeModel string `tfschema:"compute_model"` + DataStorageSizeInTbs int64 `tfschema:"data_storage_size_in_tbs"` + DbVersion string `tfschema:"db_version"` + DbWorkload string `tfschema:"db_workload"` + DisplayName string `tfschema:"display_name"` + LicenseModel string `tfschema:"license_model"` + AutoScalingEnabled bool `tfschema:"auto_scaling_enabled"` + AutoScalingForStorageEnabled bool `tfschema:"auto_scaling_for_storage_enabled"` + MtlsConnectionRequired bool `tfschema:"mtls_connection_required"` + NationalCharacterSet string `tfschema:"national_character_set"` + SubnetId string `tfschema:"subnet_id"` + VnetId string `tfschema:"virtual_network_id"` + + // Optional + CustomerContacts []string `tfschema:"customer_contacts"` +} + +func (AutonomousDatabaseRegularResource) Arguments() map[string]*pluginsdk.Schema { + return map[string]*pluginsdk.Schema{ + "location": commonschema.Location(), + + "name": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validate.AutonomousDatabaseName, + ForceNew: true, + }, + + "resource_group_name": commonschema.ResourceGroupName(), + + // Required + "admin_password": { + Type: pluginsdk.TypeString, + Required: true, + Sensitive: true, + ForceNew: true, + ValidateFunc: validate.AutonomousDatabasePassword, + }, + + "backup_retention_period_in_days": { + Type: pluginsdk.TypeInt, + Required: true, + ForceNew: true, + ValidateFunc: validation.IntBetween(1, 60), + }, + + "character_set": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + + "compute_count": { + Type: pluginsdk.TypeFloat, + Required: true, + ValidateFunc: validation.FloatBetween(2.0, 512.0), + }, + + "compute_model": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.AdbsComputeModel, + }, + + "data_storage_size_in_tbs": { + Type: pluginsdk.TypeInt, + Required: true, + ValidateFunc: validation.IntBetween(1, 384), + }, + + "db_version": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + + "db_workload": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice([]string{ + string(autonomousdatabases.WorkloadTypeDW), + string(autonomousdatabases.WorkloadTypeOLTP), + }, false), + }, + + "display_name": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.AutonomousDatabaseName, + }, + + "auto_scaling_enabled": { + Type: pluginsdk.TypeBool, + Required: true, + }, + + "auto_scaling_for_storage_enabled": { + Type: pluginsdk.TypeBool, + Required: true, + }, + + "mtls_connection_required": { + Type: pluginsdk.TypeBool, + Required: true, + ForceNew: true, + }, + + "license_model": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice([]string{ + string(autonomousdatabases.LicenseModelLicenseIncluded), + string(autonomousdatabases.LicenseModelBringYourOwnLicense), + }, false), + }, + + "national_character_set": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + + "subnet_id": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: commonids.ValidateSubnetID, + }, + + "virtual_network_id": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: commonids.ValidateVirtualNetworkID, + }, + + // Optional + "customer_contacts": { + Type: pluginsdk.TypeList, + Optional: true, + Computed: true, + ForceNew: true, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + ValidateFunc: validate.CustomerContactEmail, + }, + }, + + "tags": commonschema.Tags(), + } +} + +func (AutonomousDatabaseRegularResource) Attributes() map[string]*pluginsdk.Schema { + return map[string]*pluginsdk.Schema{} +} + +func (AutonomousDatabaseRegularResource) ModelObject() interface{} { + return &AutonomousDatabaseRegularResource{} +} + +func (AutonomousDatabaseRegularResource) ResourceType() string { + return "azurerm_oracle_autonomous_database" +} + +func (r AutonomousDatabaseRegularResource) Create() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 120 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + client := metadata.Client.Oracle.OracleClient.AutonomousDatabases + subscriptionId := metadata.Client.Account.SubscriptionId + + var model AutonomousDatabaseRegularResourceModel + if err := metadata.Decode(&model); err != nil { + return err + } + + id := autonomousdatabases.NewAutonomousDatabaseID(subscriptionId, + model.ResourceGroupName, + model.Name) + + existing, err := client.Get(ctx, id) + if err != nil && !response.WasNotFound(existing.HttpResponse) { + return fmt.Errorf("checking for presence of existing %s: %+v", id, err) + } + if !response.WasNotFound(existing.HttpResponse) { + return metadata.ResourceRequiresImport(r.ResourceType(), id) + } + + param := autonomousdatabases.AutonomousDatabase{ + Name: pointer.To(model.Name), + Location: location.Normalize(model.Location), + Tags: pointer.To(model.Tags), + Properties: &autonomousdatabases.AutonomousDatabaseProperties{ + AdminPassword: pointer.To(model.AdminPassword), + BackupRetentionPeriodInDays: pointer.To(model.BackupRetentionPeriodInDays), + CharacterSet: pointer.To(model.CharacterSet), + ComputeCount: pointer.To(model.ComputeCount), + ComputeModel: pointer.To(autonomousdatabases.ComputeModel(model.ComputeModel)), + CustomerContacts: pointer.To(expandAdbsCustomerContacts(model.CustomerContacts)), + DataBaseType: "Regular", + DataStorageSizeInTbs: pointer.To(model.DataStorageSizeInTbs), + DbWorkload: pointer.To(autonomousdatabases.WorkloadType(model.DbWorkload)), + DbVersion: pointer.To(model.DbVersion), + DisplayName: pointer.To(model.DisplayName), + IsAutoScalingEnabled: pointer.To(model.AutoScalingEnabled), + IsAutoScalingForStorageEnabled: pointer.To(model.AutoScalingForStorageEnabled), + IsMtlsConnectionRequired: pointer.To(model.MtlsConnectionRequired), + LicenseModel: pointer.To(autonomousdatabases.LicenseModel(model.LicenseModel)), + NcharacterSet: pointer.To(model.NationalCharacterSet), + SubnetId: pointer.To(model.SubnetId), + VnetId: pointer.To(model.VnetId), + }, + } + + if err := client.CreateOrUpdateThenPoll(ctx, id, param); err != nil { + return fmt.Errorf("creating %s: %+v", id, err) + } + + metadata.SetID(id) + return nil + }, + } +} + +func (r AutonomousDatabaseRegularResource) Update() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 30 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + + client := metadata.Client.Oracle.OracleClient.AutonomousDatabases + id, err := autonomousdatabases.ParseAutonomousDatabaseID(metadata.ResourceData.Id()) + if err != nil { + return fmt.Errorf("retrieving %s: %+v", id, err) + } + + var model AutonomousDatabaseRegularResourceModel + if err = metadata.Decode(&model); err != nil { + return fmt.Errorf("decoding err: %+v", err) + } + + _, err = client.Get(ctx, *id) + if err != nil { + return fmt.Errorf("retrieving %s: %+v", *id, err) + } + + update := &autonomousdatabases.AutonomousDatabaseUpdate{ + Properties: &autonomousdatabases.AutonomousDatabaseUpdateProperties{}, + } + if metadata.ResourceData.HasChange("tags") { + update.Tags = pointer.To(model.Tags) + } + if metadata.ResourceData.HasChange("data_storage_size_in_tbs") { + update.Properties.DataStorageSizeInTbs = pointer.To(model.DataStorageSizeInTbs) + } + if metadata.ResourceData.HasChange("compute_count") { + update.Properties.ComputeCount = pointer.To(model.ComputeCount) + } + if metadata.ResourceData.HasChange("auto_scaling_enabled") { + update.Properties.IsAutoScalingEnabled = pointer.To(model.AutoScalingEnabled) + } + if metadata.ResourceData.HasChange("auto_scaling_for_storage_enabled") { + update.Properties.IsAutoScalingForStorageEnabled = pointer.To(model.AutoScalingForStorageEnabled) + } + + err = client.UpdateThenPoll(ctx, *id, *update) + if err != nil { + return fmt.Errorf("updating %s: %v", id, err) + } + + return nil + }, + } +} + +func (AutonomousDatabaseRegularResource) Read() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 5 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + id, err := autonomousdatabases.ParseAutonomousDatabaseID(metadata.ResourceData.Id()) + if err != nil { + return fmt.Errorf("retrieving %s: %+v", id, err) + } + + client := metadata.Client.Oracle.OracleClient.AutonomousDatabases + result, err := client.Get(ctx, *id) + if err != nil { + if response.WasNotFound(result.HttpResponse) { + return metadata.MarkAsGone(id) + } + return fmt.Errorf("retrieving %s: %+v", id, err) + } + + state := AutonomousDatabaseRegularResourceModel{ + Name: id.AutonomousDatabaseName, + ResourceGroupName: id.ResourceGroupName, + } + if model := result.Model; model != nil { + props, ok := model.Properties.(autonomousdatabases.AutonomousDatabaseProperties) + if !ok { + return fmt.Errorf("%s was not of type `Regular`", id) + } + state.AdminPassword = metadata.ResourceData.Get("admin_password").(string) + state.AutoScalingEnabled = pointer.From(props.IsAutoScalingEnabled) + state.BackupRetentionPeriodInDays = pointer.From(props.BackupRetentionPeriodInDays) + state.AutoScalingForStorageEnabled = pointer.From(props.IsAutoScalingForStorageEnabled) + state.CharacterSet = pointer.From(props.CharacterSet) + state.ComputeCount = pointer.From(props.ComputeCount) + state.ComputeModel = string(pointer.From(props.ComputeModel)) + state.CustomerContacts = flattenAdbsCustomerContacts(props.CustomerContacts) + state.DataStorageSizeInTbs = pointer.From(props.DataStorageSizeInTbs) + state.DbWorkload = string(pointer.From(props.DbWorkload)) + state.DbVersion = pointer.From(props.DbVersion) + state.DisplayName = pointer.From(props.DisplayName) + state.LicenseModel = string(pointer.From(props.LicenseModel)) + state.Location = result.Model.Location + state.Name = pointer.ToString(result.Model.Name) + state.NationalCharacterSet = pointer.From(props.NcharacterSet) + state.SubnetId = pointer.From(props.SubnetId) + state.Tags = pointer.From(result.Model.Tags) + state.VnetId = pointer.From(props.VnetId) + } + return metadata.Encode(&state) + }, + } +} + +func (AutonomousDatabaseRegularResource) Delete() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 30 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + client := metadata.Client.Oracle.OracleClient.AutonomousDatabases + + id, err := autonomousdatabases.ParseAutonomousDatabaseID(metadata.ResourceData.Id()) + if err != nil { + return fmt.Errorf("retrieving %s: %+v", id, err) + } + + if err = client.DeleteThenPoll(ctx, *id); err != nil { + return fmt.Errorf("deleting %s: %+v", *id, err) + } + + return nil + }, + } +} + +func (AutonomousDatabaseRegularResource) IDValidationFunc() pluginsdk.SchemaValidateFunc { + return autonomousdatabases.ValidateAutonomousDatabaseID +} + +func expandAdbsCustomerContacts(customerContactsList []string) []autonomousdatabases.CustomerContact { + var customerContacts []autonomousdatabases.CustomerContact + for _, customerContact := range customerContactsList { + customerContacts = append(customerContacts, autonomousdatabases.CustomerContact{ + Email: customerContact, + }) + } + return customerContacts +} + +func flattenAdbsCustomerContacts(customerContactsList *[]autonomousdatabases.CustomerContact) []string { + var customerContacts []string + if customerContactsList != nil { + for _, customerContact := range *customerContactsList { + customerContacts = append(customerContacts, customerContact.Email) + } + } + return customerContacts +} diff --git a/internal/services/oracle/autonomous_database_regular_resource_test.go b/internal/services/oracle/autonomous_database_regular_resource_test.go new file mode 100644 index 000000000000..1457cd6fb5b7 --- /dev/null +++ b/internal/services/oracle/autonomous_database_regular_resource_test.go @@ -0,0 +1,263 @@ +// Copyright © 2024, Oracle and/or its affiliates. All rights reserved + +package oracle_test + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/go-azure-helpers/lang/pointer" + "github.com/hashicorp/go-azure-sdk/resource-manager/oracledatabase/2024-06-01/autonomousdatabases" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" + "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/oracle" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" +) + +type AdbsRegularResource struct{} + +func (a AdbsRegularResource) Exists(ctx context.Context, client *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { + id, err := autonomousdatabases.ParseAutonomousDatabaseID(state.ID) + if err != nil { + return nil, err + } + resp, err := client.Oracle.OracleClient.AutonomousDatabases.Get(ctx, *id) + if err != nil { + return nil, fmt.Errorf("retrieving adbs %s: %+v", id, err) + } + return pointer.To(resp.Model != nil), nil +} + +func TestAdbsRegularResource_basic(t *testing.T) { + data := acceptance.BuildTestData(t, oracle.AutonomousDatabaseRegularResource{}.ResourceType(), "test") + r := AdbsRegularResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("admin_password"), + }) +} + +func TestAdbsRegularResource_complete(t *testing.T) { + data := acceptance.BuildTestData(t, oracle.AutonomousDatabaseRegularResource{}.ResourceType(), "test") + r := AdbsRegularResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.complete(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("admin_password"), + }) +} + +func TestAdbsRegularResource_update(t *testing.T) { + data := acceptance.BuildTestData(t, oracle.AutonomousDatabaseRegularResource{}.ResourceType(), "test") + r := AdbsRegularResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("admin_password"), + { + Config: r.update(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("admin_password"), + }) +} + +func TestAdbsRegularResource_requiresImport(t *testing.T) { + data := acceptance.BuildTestData(t, oracle.AutonomousDatabaseRegularResource{}.ResourceType(), "test") + r := AdbsRegularResource{} + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.RequiresImportErrorStep(r.requiresImport), + }) +} + +func (a AdbsRegularResource) basic(data acceptance.TestData) string { + return fmt.Sprintf(` + + +%s + +provider "azurerm" { + features {} +} + +resource "azurerm_oracle_autonomous_database" "test" { + name = "OFake%[2]d" + display_name = "OFake%[2]d" + resource_group_name = azurerm_resource_group.test.name + location = "%[3]s" + compute_model = "ECPU" + compute_count = 2 + license_model = "BringYourOwnLicense" + backup_retention_period_in_days = 12 + auto_scaling_enabled = false + auto_scaling_for_storage_enabled = false + mtls_connection_required = false + data_storage_size_in_tbs = 1 + db_workload = "OLTP" + admin_password = "TestPass#2024#" + db_version = "19c" + character_set = "AL32UTF8" + national_character_set = "AL16UTF16" + subnet_id = azurerm_subnet.test.id + virtual_network_id = azurerm_virtual_network.test.id +} +`, a.template(data), data.RandomInteger, data.Locations.Primary) +} + +func (a AdbsRegularResource) complete(data acceptance.TestData) string { + return fmt.Sprintf(` + +%s + +provider "azurerm" { + features {} +} + +resource "azurerm_oracle_autonomous_database" "test" { + name = "OFake%[2]d" + + display_name = "OFake%[2]d" + resource_group_name = azurerm_resource_group.test.name + location = "%[3]s" + compute_model = "ECPU" + compute_count = 2 + license_model = "BringYourOwnLicense" + backup_retention_period_in_days = 12 + auto_scaling_enabled = false + auto_scaling_for_storage_enabled = false + mtls_connection_required = false + data_storage_size_in_tbs = 1 + db_workload = "OLTP" + admin_password = "TestPass#2024#" + db_version = "19c" + character_set = "AL32UTF8" + national_character_set = "AL16UTF16" + subnet_id = azurerm_subnet.test.id + virtual_network_id = azurerm_virtual_network.test.id + customer_contacts = ["test@test.com"] +} +`, a.template(data), data.RandomInteger, data.Locations.Primary) +} + +func (a AdbsRegularResource) update(data acceptance.TestData) string { + return fmt.Sprintf(` + +%s + +provider "azurerm" { + features {} +} + +resource "azurerm_oracle_autonomous_database" "test" { + name = "OFake%[2]d" + display_name = "OFake%[2]d" + resource_group_name = azurerm_resource_group.test.name + location = "%[3]s" + compute_model = "ECPU" + compute_count = 3 + license_model = "BringYourOwnLicense" + backup_retention_period_in_days = 12 + auto_scaling_enabled = false + auto_scaling_for_storage_enabled = false + mtls_connection_required = false + data_storage_size_in_tbs = 1 + db_workload = "OLTP" + admin_password = "TestPass#2024#" + db_version = "19c" + character_set = "AL32UTF8" + national_character_set = "AL16UTF16" + subnet_id = azurerm_subnet.test.id + virtual_network_id = azurerm_virtual_network.test.id +} +`, a.template(data), data.RandomInteger, data.Locations.Primary) +} + +func (a AdbsRegularResource) requiresImport(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_oracle_autonomous_database" "import" { + name = azurerm_oracle_autonomous_database.test.name + display_name = azurerm_oracle_autonomous_database.test.display_name + resource_group_name = azurerm_oracle_autonomous_database.test.resource_group_name + location = azurerm_oracle_autonomous_database.test.location + compute_model = azurerm_oracle_autonomous_database.test.compute_model + compute_count = azurerm_oracle_autonomous_database.test.compute_count + license_model = azurerm_oracle_autonomous_database.test.license_model + backup_retention_period_in_days = azurerm_oracle_autonomous_database.test.backup_retention_period_in_days + auto_scaling_enabled = azurerm_oracle_autonomous_database.test.auto_scaling_enabled + auto_scaling_for_storage_enabled = azurerm_oracle_autonomous_database.test.auto_scaling_for_storage_enabled + mtls_connection_required = azurerm_oracle_autonomous_database.test.mtls_connection_required + data_storage_size_in_tbs = azurerm_oracle_autonomous_database.test.data_storage_size_in_tbs + db_workload = azurerm_oracle_autonomous_database.test.db_workload + admin_password = azurerm_oracle_autonomous_database.test.admin_password + db_version = azurerm_oracle_autonomous_database.test.db_version + character_set = azurerm_oracle_autonomous_database.test.character_set + national_character_set = azurerm_oracle_autonomous_database.test.national_character_set + subnet_id = azurerm_oracle_autonomous_database.test.subnet_id + virtual_network_id = azurerm_oracle_autonomous_database.test.virtual_network_id +} +`, a.basic(data)) +} + +func (a AdbsRegularResource) template(data acceptance.TestData) string { + return fmt.Sprintf(` + +data "azurerm_client_config" "current" {} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-%[1]d" + location = "%[2]s" +} + +resource "azurerm_virtual_network" "test" { + name = "acctest%[1]d_vnet" + address_space = ["10.0.0.0/16"] + location = "%[2]s" + resource_group_name = azurerm_resource_group.test.name +} + +resource "azurerm_subnet" "test" { + name = "eacctest%[1]d" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefixes = ["10.0.1.0/24"] + + delegation { + name = "delegation" + + service_delegation { + actions = [ + "Microsoft.Network/networkinterfaces/*", + "Microsoft.Network/virtualNetworks/subnets/join/action", + ] + name = "Oracle.Database/networkAttachments" + } + } +} + +`, data.RandomInteger, data.Locations.Primary, data.RandomString) +} diff --git a/internal/services/oracle/cloud_vm_cluster_data_source.go b/internal/services/oracle/cloud_vm_cluster_data_source.go index 798bbbba760b..e9512a40eec9 100644 --- a/internal/services/oracle/cloud_vm_cluster_data_source.go +++ b/internal/services/oracle/cloud_vm_cluster_data_source.go @@ -498,6 +498,7 @@ func (d CloudVmClusterDataSource) Read() sdk.ResourceFunc { state.SystemVersion = pointer.From(props.SystemVersion) state.TimeCreated = pointer.From(props.TimeCreated) state.TimeZone = pointer.From(props.TimeZone) + state.VnetId = props.VnetId state.ZoneId = pointer.From(props.ZoneId) } } diff --git a/internal/services/oracle/cloud_vm_cluster_resource.go b/internal/services/oracle/cloud_vm_cluster_resource.go index bb99510db90f..15404572bf87 100644 --- a/internal/services/oracle/cloud_vm_cluster_resource.go +++ b/internal/services/oracle/cloud_vm_cluster_resource.go @@ -60,7 +60,6 @@ type CloudVmClusterResourceModel struct { func (CloudVmClusterResource) Arguments() map[string]*pluginsdk.Schema { return map[string]*pluginsdk.Schema{ - // Azure "location": commonschema.Location(), "name": { @@ -493,19 +492,3 @@ func removeHostnameSuffix(hostnameActual string) string { return hostnameActual } } - -// DbSystemHostnameDiffSuppress When submitting a request to DBaaS a suffix will be added to the Hostname, -// therefore when computing the diff if the new Hostname is a prefix of the old then we will ignore the diff. -// Example: Initial plan -> testHostname, final result after DBaaS -> testHostname-abc. -// Since testHostname is a prefix of testHostname-abc, then computed diff is zero. -func DbSystemHostnameDiffSuppress(_ string, old string, new string, _ *schema.ResourceData) bool { - return EqualSuppressDiff(old, new) || NewIsPrefixOfOldDiffSuppress(old, new) -} - -func NewIsPrefixOfOldDiffSuppress(old string, new string) bool { - return strings.HasPrefix(strings.ToLower(old), strings.ToLower(new)) -} - -func EqualSuppressDiff(old string, new string) bool { - return old == new -} diff --git a/internal/services/oracle/registration.go b/internal/services/oracle/registration.go index 4fd63cffb9f4..051e16f60890 100644 --- a/internal/services/oracle/registration.go +++ b/internal/services/oracle/registration.go @@ -14,6 +14,7 @@ var ( func (r Registration) DataSources() []sdk.DataSource { return []sdk.DataSource{ + AutonomousDatabaseRegularDataSource{}, CloudVmClusterDataSource{}, DBServersDataSource{}, ExadataInfraDataSource{}, @@ -22,6 +23,7 @@ func (r Registration) DataSources() []sdk.DataSource { func (r Registration) Resources() []sdk.Resource { return []sdk.Resource{ + AutonomousDatabaseRegularResource{}, CloudVmClusterResource{}, ExadataInfraResource{}, } diff --git a/internal/services/oracle/validate/autonomous_database_regular.go b/internal/services/oracle/validate/autonomous_database_regular.go new file mode 100644 index 000000000000..16abe30266c0 --- /dev/null +++ b/internal/services/oracle/validate/autonomous_database_regular.go @@ -0,0 +1,125 @@ +package validate + +import ( + "fmt" + "net/mail" + "strings" + "unicode" + "unicode/utf8" + + "github.com/hashicorp/go-azure-sdk/resource-manager/oracledatabase/2024-06-01/autonomousdatabases" +) + +func AutonomousDatabaseName(i interface{}, k string) (warnings []string, errors []error) { + v, ok := i.(string) + if !ok { + errors = append(errors, fmt.Errorf("expected type of %s to be string", k)) + return + } + + firstChar, _ := utf8.DecodeRuneInString(v) + if !unicode.IsLetter(firstChar) { + errors = append(errors, fmt.Errorf("%v must start with a letter", k)) + return + } + + for _, r := range v { + if !unicode.IsLetter(r) && !unicode.IsNumber(r) { + errors = append(errors, fmt.Errorf("%v must contain only letters and numbers", k)) + return + } + } + + if len(v) > 30 { + errors = append(errors, fmt.Errorf("%v must be 30 characers max", k)) + return + } + + return +} + +func AutonomousDatabasePassword(i interface{}, k string) (warnings []string, errors []error) { + v, ok := i.(string) + if !ok { + errors = append(errors, fmt.Errorf("expected type of %s to be string", k)) + return + } + + if len(v) < 12 || len(v) > 30 { + errors = append(errors, fmt.Errorf("%v must be 12 to 30 characters", k)) + return + } + + hasUpper := false + hasLower := false + hasNumber := false + hasDoubleQuote := false + for _, r := range v { + if r == '"' { + hasDoubleQuote = true + } + if unicode.IsUpper(r) { + hasUpper = true + } + if unicode.IsLower(r) { + hasLower = true + } + if unicode.IsNumber(r) { + hasNumber = true + } + } + if hasDoubleQuote { + errors = append(errors, fmt.Errorf("%v must not contain the double quote (\") character", k)) + return + } + if !hasUpper { + errors = append(errors, fmt.Errorf("%v must contain at least one uppercase letter", k)) + return + } + if !hasLower { + errors = append(errors, fmt.Errorf("%v must contain at least one lowercase letter", k)) + return + } + if !hasNumber { + errors = append(errors, fmt.Errorf("%v must contain at least one number", k)) + return + } + if strings.Contains(v, "admin") { + errors = append(errors, fmt.Errorf("%v must not contain the username \"admin\"", k)) + return + } + + return +} + +func CustomerContactEmail(i interface{}, k string) (warnings []string, errors []error) { + v, ok := i.(string) + if !ok { + errors = append(errors, fmt.Errorf("expected type of %s to be string", k)) + return + } + + _, err := mail.ParseAddress(v) + if err != nil { + errors = append(errors, fmt.Errorf("%v must be a valid email address", k)) + return + } + + return warnings, errors +} + +func AdbsComputeModel(i interface{}, k string) (warnings []string, errors []error) { + v, ok := i.(string) + if !ok { + errors = append(errors, fmt.Errorf("expected type of %s to be string", k)) + return + } + + if v != string(autonomousdatabases.ComputeModelECPU) && v != string(autonomousdatabases.ComputeModelOCPU) { + errors = append(errors, fmt.Errorf("%v must be %v or %v", k, + string(autonomousdatabases.ComputeModelECPU), string(autonomousdatabases.ComputeModelOCPU))) + return + } + + return +} diff --git a/internal/services/oracledatabase/client/client.go b/internal/services/oracledatabase/client/client.go deleted file mode 100644 index 729c482bc395..000000000000 --- a/internal/services/oracledatabase/client/client.go +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright © 2024, Oracle and/or its affiliates. All rights reserved - -package client - -import ( - "fmt" - - oracedatabase "github.com/hashicorp/go-azure-sdk/resource-manager/oracledatabase/2024-06-01" - "github.com/hashicorp/go-azure-sdk/sdk/client/resourcemanager" - "github.com/hashicorp/terraform-provider-azurerm/internal/common" -) - -type Client struct { - OracleDatabaseClient *oracedatabase.Client -} - -func NewClient(o *common.ClientOptions) (*Client, error) { - o.DisableCorrelationRequestID = true - oracleDatabaseClient, err := oracedatabase.NewClientWithBaseURI(o.Environment.ResourceManager, func(c *resourcemanager.Client) { - o.Configure(c, o.Authorizers.ResourceManager) - }) - if err != nil { - return nil, fmt.Errorf("building Database client: %+v", err) - } - return &Client{ - OracleDatabaseClient: oracleDatabaseClient, - }, nil -} diff --git a/website/docs/d/oracle_autonomous_database_regular.html.markdown b/website/docs/d/oracle_autonomous_database_regular.html.markdown new file mode 100644 index 000000000000..62f44fdafb67 --- /dev/null +++ b/website/docs/d/oracle_autonomous_database_regular.html.markdown @@ -0,0 +1,156 @@ +--- +subcategory: "Oracle" +layout: "azurerm" +page_title: "Azure Resource Manager: Data Source: azurerm_oracle_autonomous_database" +description: |- + Gets information about an existing Autonomous Database. +--- + +# Data Source: azurerm_oracle_autonomous_database + +Use this data source to access information about an existing Autonomous Database. + +## Example Usage + +```hcl +data "azurerm_oracle_autonomous_database" "example" { + name = "existing" + resource_group_name = "existing" +} + +output "id" { + value = data.azurerm_oracle_autonomous_database.example.id +} +``` + +## Arguments Reference + +The following arguments are supported: + +* `name` - (Required) The name of this Autonomous Database. + +* `resource_group_name` - (Required) The name of the Resource Group where the Autonomous Database exists. + +## Attributes Reference + +In addition to the Arguments listed above - the following Attributes are exported: + +* `id` - The ID of the Autonomous Database. + +* `actual_used_data_storage_size_in_tbs` - The current amount of storage in use for user and system data, in terabytes (TB). + +* `allocated_storage_size_in_tbs` - The amount of storage currently allocated for the database tables and billed for, rounded up. When auto-scaling is not enabled, this value is equal to the `dataStorageSizeInTBs` value. You can compare this value to the `actualUsedDataStorageSizeInTBs` value to determine if a manual shrink operation is appropriate for your allocated storage. + +* `autonomous_database_id` - The database [OCID](https://docs.cloud.oracle.com/iaas/Content/General/Concepts/identifiers.htm). + +* `available_upgrade_versions` - List of Oracle Database versions available for a database upgrade. If there are no version upgrades available, this list is empty. + +* `backup_retention_period_in_days` - Retention period, in days, for backups. + +* `character_set` - The character set for the autonomous database. + +* `compute_count` - The compute amount (CPUs) available to the database. + +* `cpu_core_count` - The number of CPU cores to be made available to the database. When the ECPU is selected, the value for cpuCoreCount is 0. For Autonomous Database on Dedicated Exadata infrastructure, the maximum number of cores is determined by the infrastructure shape. See [Characteristics of Infrastructure Shapes](https://www.oracle.com/pls/topic/lookup?ctx=en/cloud/paas/autonomous-database&id=ATPFG-GUID-B0F033C1-CC5A-42F0-B2E7-3CECFEDA1FD1) for shape details. + +* `data_storage_size_in_gbs` - The quantity of data in the database, in gigabytes. + +* `data_storage_size_in_tbs` - The maximum storage that can be allocated for the database, in terabytes. + +* `db_node_storage_size_in_gbs` - The DB node storage size in, in gigabytes. + +* `db_version` - A valid Oracle Database version for Autonomous Database. + +* `display_name` - The user-friendly name for the Autonomous Database. The name does not have to be unique. + +* `failed_data_recovery_in_seconds` - Indicates the number of seconds of data loss for a Data Guard failover. + +* `in_memory_area_in_gbs` - The area assigned to In-Memory tables in Autonomous Database. + +* `auto_scaling_enabled` - Indicates if auto scaling is enabled for the Autonomous Database CPU core count. + +* `auto_scaling_for_storage_enabled` - Indicates if auto scaling is enabled for the Autonomous Database storage. + +* `local_data_guard_enabled` - Indicates whether the Autonomous Database has local (in-region) Data Guard enabled. Not applicable to cross-region Autonomous Data Guard associations, or to Autonomous Databases using dedicated Exadata infrastructure or Exadata Cloud@Customer infrastructure. + +* `mtls_connection_required` - Specifies if the Autonomous Database requires mTLS connections. + +* `preview` - Indicates if the Autonomous Database version is a preview version. + +* `preview_version_with_service_terms_accepted` - Indicates if the Autonomous Database version is a preview version with service terms accepted. + +* `remote_data_guard_enabled` - Indicates whether the Autonomous Database has Cross Region Data Guard enabled. Not applicable to Autonomous Databases using dedicated Exadata infrastructure or Exadata Cloud@Customer infrastructure. + +* `key_history_entry` - Key History Entry. + +* `lifecycle_details` - Information about the current lifecycle state. + +* `local_adg_auto_failover_max_data_loss_limit` - Parameter that allows users to select an acceptable maximum data loss limit in seconds, up to which Automatic Failover will be triggered when necessary for a Local Autonomous Data Guard + +* `location` - The Azure Region where the Autonomous Database exists. + +* `memory_per_oracle_compute_unit_in_gbs` - The amount of memory (in GBs) enabled per ECPU or OCPU. + +* `national_character_set` - The national character set for the autonomous database. The default is AL16UTF16. Allowed values are: AL16UTF16 or UTF8. + +* `next_long_term_backup_time_stamp` - The date and time when the next long-term backup would be created. + +* `oci_url` - The URL of the resource in the OCI console. + +* `ocid` - The [OCID](https://docs.oracle.com/en-us/iaas/Content/General/Concepts/identifiers.htm) of the autonomous database. + +* `peer_db_ids` - The list of [OCIDs](https://docs.oracle.com/iaas/Content/General/Concepts/identifiers.htm) of standby databases located in Autonomous Data Guard remote regions that are associated with the source database. Note that for Autonomous Database Serverless instances, standby databases located in the same region as the source primary database do not have OCIDs. + +* `private_endpoint` - The private endpoint for the resource. + +* `private_endpoint_ip` - The private endpoint Ip address for the resource. + +* `private_endpoint_label` - The private endpoint label for the resource. + +* `provisionable_cpus` - An array of CPU values that an Autonomous Database can be scaled to. + +* `service_console_url` - The URL of the Service Console for the Autonomous Database. + +* `sql_web_developer_url` - The URL of the SQL web developer. + +* `subnet_id` - The [OCID](https://docs.cloud.oracle.com/iaas/Content/General/Concepts/identifiers.htm) of the subnet the resource is associated with. + +* `supported_regions_to_clone_to` - The list of regions that support the creation of an Autonomous Database clone or an Autonomous Data Guard standby database. + +* `tags` - A mapping of tags assigned to the Autonomous Database. + +* `time_created` - The date and time the Autonomous Database was created. + +* `time_data_guard_role_changed` - The date and time the Autonomous Data Guard role was switched for the Autonomous Database. For databases that have standbys in both the primary Data Guard region and a remote Data Guard standby region, this is the latest timestamp of either the database using the "primary" role in the primary Data Guard region, or database located in the remote Data Guard standby region. + +* `time_deletion_of_free_autonomous_database` - The date and time the Always Free database will be automatically deleted because of inactivity. If the database is in the STOPPED state and without activity until this time, it will be deleted. + +* `time_local_data_guard_enabled_on` - The date and time that Autonomous Data Guard was enabled for an Autonomous Database where the standby was provisioned in the same region as the primary database. + +* `time_maintenance_begin` - The date and time when maintenance will begin. + +* `time_maintenance_end` - The date and time when maintenance will end. + +* `time_of_last_failover` - The timestamp of the last failover operation. + +* `time_of_last_refresh` - The date and time when last refresh happened. + +* `time_of_last_refresh_point` - The refresh point timestamp (UTC). The refresh point is the time to which the database was most recently refreshed. Data created after the refresh point is not included in the refresh. + +* `time_of_last_switchover` - The timestamp of the last switchover operation for the Autonomous Database. + +* `time_reclamation_of_free_autonomous_database` - The date and time the Always Free database will be stopped because of inactivity. If this time is reached without any database activity, the database will automatically be put into the STOPPED state. + +* `used_data_storage_size_in_gbs` - The storage space consumed by Autonomous Database in GBs. + +* `used_data_storage_size_in_tbs` - The amount of storage that has been used, in terabytes. + +* `virtual_network_id` - The ID to an Azure Resource Manager vnet resource. + +* `allowed_ips` - The client IP access control list (ACL). This feature is available for [Autonomous Database Serverless] (https://docs.oracle.com/en/cloud/paas/autonomous-database/index.html) and on Exadata Cloud@Customer. Only clients connecting from an IP address included in the ACL may access the Autonomous Database instance. If `arePrimaryWhitelistedIpsUsed` is 'TRUE' then Autonomous Database uses this primary's IP access control list (ACL) for the disaster recovery peer called `standbywhitelistedips`. + +## Timeouts + +The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/language/resources/syntax#operation-timeouts) for certain actions: + +* `read` - (Defaults to 5 minutes) Used when retrieving the Autonomous Database. diff --git a/website/docs/r/oracle_autonomous_database_regular.html.markdown b/website/docs/r/oracle_autonomous_database_regular.html.markdown new file mode 100644 index 000000000000..8bcf81a5eee8 --- /dev/null +++ b/website/docs/r/oracle_autonomous_database_regular.html.markdown @@ -0,0 +1,112 @@ +--- +subcategory: "Oracle" +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_oracle_autonomous_database" +description: |- + Manages an Autonomous Database. +--- + +# azurerm_oracle_autonomous_database + +Manages an Autonomous Database. + +## Example Usage + +```hcl +resource "azurerm_oracle_autonomous_database" "example" { + name = "example" + resource_group_name = "example" + location = "West Europe" + subnet_id = "example" + display_name = "example" + db_workload = "example" + mtls_connection_required = false + backup_retention_period_in_days = 42 + compute_model = "example" + data_storage_size_in_gbs = 42 + auto_scaling_for_storage_enabled = false + virtual_network_id = "example" + admin_password = "example" + auto_scaling_enabled = "example" + character_set = "example" + compute_count = 1.23456 + national_character_set = "example" + license_model = false + db_version = "example" +} +``` + +## Arguments Reference + +The following arguments are supported: + +* `name` - (Required) The name which should be used for this Autonomous Database. + +* `resource_group_name` - (Required) The name of the Resource Group where the Autonomous Database should exist. + +* `location` - (Required) The Azure Region where the Autonomous Database should exist. Changing this forces a new Autonomous Database to be created. + +* `admin_password` - (Required) The password must be between `12` and `30 `characters long, and must contain at least 1 uppercase, 1 lowercase, and 1 numeric character. It cannot contain the double quote symbol (") or the username "admin", regardless of casing. + +* `backup_retention_period_in_days` - (Optional) (Updatable) Retention period, in days, for backups. + +* `character_set` - (Required) The character set for the autonomous database. The default is `AL32UTF8`. Allowed values are: `AL32UTF8`, `AR8ADOS710`, `AR8ADOS720`, `AR8APTEC715`, `AR8ARABICMACS`, `AR8ASMO8X`, `AR8ISO8859P6`, `AR8MSWIN1256`, `AR8MUSSAD768`, `AR8NAFITHA711`, `AR8NAFITHA721`, `AR8SAKHR706`, `AR8SAKHR707`, `AZ8ISO8859P9E`, `BG8MSWIN`, `BG8PC437S`, `BLT8CP921`, `BLT8ISO8859P13`, `BLT8MSWIN1257`, `BLT8PC775`, `BN8BSCII`, `CDN8PC863`, `CEL8ISO8859P14`, `CL8ISO8859P5`, `CL8ISOIR111`, `CL8KOI8R`, `CL8KOI8U`, `CL8MACCYRILLICS`, `CL8MSWIN1251`, `EE8ISO8859P2`, `EE8MACCES`, `EE8MACCROATIANS`, `EE8MSWIN1250`, `EE8PC852`, `EL8DEC`, `EL8ISO8859P7`, `EL8MACGREEKS`, `EL8MSWIN1253`, `EL8PC437S`, `EL8PC851`, `EL8PC869`, `ET8MSWIN923`, `HU8ABMOD`, `HU8CWI2`, `IN8ISCII`, `IS8PC861`, `IW8ISO8859P8`, `IW8MACHEBREWS`, `IW8MSWIN1255`, `IW8PC1507`, `JA16EUC`, `JA16EUCTILDE`, `JA16SJIS`, `JA16SJISTILDE`, `JA16VMS`, `KO16KSC5601`, `KO16KSCCS`, `KO16MSWIN949`, `LA8ISO6937`, `LA8PASSPORT`, `LT8MSWIN921`, `LT8PC772`, `LT8PC774`, `LV8PC1117`, `LV8PC8LR`, `LV8RST104090`, `N8PC865`, `NE8ISO8859P10`, `NEE8ISO8859P4`, `RU8BESTA`, `RU8PC855`, `RU8PC866`, `SE8ISO8859P3`, `TH8MACTHAIS`, `TH8TISASCII`, `TR8DEC`, `TR8MACTURKISHS`, `TR8MSWIN1254`, `TR8PC857`, `US7ASCII`, `US8PC437`, `UTF8`, `VN8MSWIN1258`, `VN8VN3`, `WE8DEC`, `WE8DG`, `WE8ISO8859P1`, `WE8ISO8859P15`, `WE8ISO8859P9`, `WE8MACROMAN8S`, `WE8MSWIN1252`, `WE8NCR4970`, `WE8NEXTSTEP`, `WE8PC850`, `WE8PC858`, `WE8PC860`, `WE8ROMAN8`, `ZHS16CGB231280`, `ZHS16GBK`, `ZHT16BIG5`, `ZHT16CCDC`, `ZHT16DBT`, `ZHT16HKSCS`, `ZHT16MSWIN950`, `ZHT32EUC`, `ZHT32SOPS`, `ZHT32TRIS` + +* `compute_count` - (Required) The compute amount (CPUs) available to the database. Minimum and maximum values depend on the compute model and whether the database is an Autonomous Database Serverless instance or an Autonomous Database on Dedicated Exadata Infrastructure. For an Autonomous Database Serverless instance, the `ECPU` compute model requires a minimum value of one, for databases in the elastic resource pool and minimum value of two, otherwise. Required when using the `computeModel` parameter. When using `cpuCoreCount` parameter, it is an error to specify computeCount to a non-null value. Providing `computeModel` and `computeCount` is the preferred method for both OCPU and ECPU. + +* `compute_model` - (Required) The compute model of the Autonomous Database. This is required if using the `computeCount` parameter. If using `cpuCoreCount` then it is an error to specify `computeModel` to a non-null value. ECPU compute model is the recommended model and OCPU compute model is legacy. + +* `data_storage_size_in_tbs` - (Required) The maximum storage that can be allocated for the database, in terabytes. + +* `db_version` - (Required) A valid Oracle Database version for Autonomous Database. + +* `db_workload` - (Required) The Autonomous Database workload type. The following values are valid: + * OLTP - indicates an Autonomous Transaction Processing database + * DW - indicates an Autonomous Data Warehouse database + * AJD - indicates an Autonomous JSON Database + * APEX - indicates an Autonomous Database with the Oracle APEX Application Development workload type. + +* `display_name` - (Required) The user-friendly name for the Autonomous Database. The name does not have to be unique. + +* `auto_scaling_enabled` - (Required) Indicates if auto scaling is enabled for the Autonomous Database CPU core count. The default value is `true`. + +* `auto_scaling_for_storage_enabled` - (Required) Indicates if auto scaling is enabled for the Autonomous Database storage. The default value is `false`. + +* `mtls_connection_required` - (Required) Specifies if the Autonomous Database requires mTLS connections. + +* `license_model` - (Required) The Oracle license model that applies to the Oracle Autonomous Database. Bring your own license (BYOL) allows you to apply your current on-premises Oracle software licenses to equivalent, highly automated Oracle services in the cloud. License Included allows you to subscribe to new Oracle Database software licenses and the Oracle Database service. Note that when provisioning an [Autonomous Database on dedicated Exadata infrastructure](https://docs.oracle.com/en/cloud/paas/autonomous-database/index.html), this attribute must be null. It is already set at the Autonomous Exadata Infrastructure level. When provisioning an [Autonomous Database Serverless] (https://docs.oracle.com/en/cloud/paas/autonomous-database/index.html) database, if a value is not specified, the system defaults the value to `BRING_YOUR_OWN_LICENSE`. Bring your own license (BYOL) also allows you to select the DB edition using the optional parameter. + +* `national_character_set` - (Required) The national character set for the autonomous database. The default is AL16UTF16. Allowed values are: AL16UTF16 or UTF8. + +* `subnet_id` - (Required) The [OCID](https://docs.cloud.oracle.com/iaas/Content/General/Concepts/identifiers.htm) of the subnet the resource is associated with. + +* `virtual_network_id` - (Required) The ID of the vnet associated with the cloud VM cluster. + +--- + +* `customer_contacts` - (Optional) Specifies a list of customer contacts as email addresses. + +* `tags` - (Optional) A mapping of tags which should be assigned to the Autonomous Database. + +## Attributes Reference + +In addition to the Arguments listed above - the following Attributes are exported: + +* `id` - The ID of the Autonomous Database. + +## Timeouts + +The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/language/resources/syntax#operation-timeouts) for certain actions: + +* `create` - (Defaults to 2 hours) Used when creating the Autonomous Database. +* `read` - (Defaults to 5 minutes) Used when retrieving the Autonomous Database. +* `update` - (Defaults to 30 minutes) Used when updating the Autonomous Database. +* `delete` - (Defaults to 30 minutes) Used when deleting the Autonomous Database. + +## Import + +Autonomous Databases can be imported using the `resource id`, e.g. + +```shell +terraform import azurerm_oracle_autonomous_database.example /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/resourceGroup/providers/Oracle.Database/autonomousDatabases/autonomousDatabases1 +```