diff --git a/docs/data-sources/rediscloud_active_active_private_link.md b/docs/data-sources/rediscloud_active_active_private_link.md index faf042ca..180bdb8a 100644 --- a/docs/data-sources/rediscloud_active_active_private_link.md +++ b/docs/data-sources/rediscloud_active_active_private_link.md @@ -1,19 +1,19 @@ --- layout: "rediscloud" -page_title: "Redis Cloud: rediscloud_private_link" +page_title: "Redis Cloud: rediscloud_active_active_private_link" description: |- - PrivateLink data source for Pro Subscription in the Redis Cloud Terraform provider. + PrivateLink data source for Active-Active subscriptions in the Redis Cloud Terraform provider. --- # Data Source: rediscloud_active_active_private_link -The PrivateLink data source allows the user to retrieve information about an existing PrivateLink for an Active Active Subscription in the provider. +Retrieves information about an existing PrivateLink for an Active-Active subscription region. ## Example Usage ```hcl data "rediscloud_active_active_private_link" "example" { subscription_id = "1234" - region_id = 1 + region_id = 1 } output "rediscloud_private_link_principals" { @@ -23,31 +23,31 @@ output "rediscloud_private_link_principals" { ## Argument Reference -* `subscription_id` - (Required) The ID of the Active Active Subscription the PrivateLink is attached to. -* `region_id` - (Required) The region ID within the Active Active subscription that the PrivateLink is attached to. +* `subscription_id` - (Required) The ID of the Active-Active subscription the PrivateLink is attached to. +* `region_id` - (Required) The region ID within the Active-Active subscription that the PrivateLink is attached to. -## Attribute reference +## Attribute Reference -* `principals` - The principal(s) attached to the PrivateLink. -* `resource_configuration_id` - ID of the resource configuration to attach to this PrivateLink -* `resource_configuration_arn` - ARN of the resource configuration to attach to this PrivateLink -* `share_arn` - Share ARN of this PrivateLink. -* `connections` - List of connections associated with the PrivateLink. -* `databases` - List of databases associated with the PrivateLink. +* `principals` - A list of principals attached to the PrivateLink. +* `resource_configuration_id` - The ID of the resource configuration attached to this PrivateLink. +* `resource_configuration_arn` - The ARN of the resource configuration attached to this PrivateLink. +* `share_arn` - The share ARN of this PrivateLink. +* `connections` - A list of connections associated with the PrivateLink. +* `databases` - A list of databases associated with the PrivateLink. -The `principals` object is a list, with these attributes: +The `principals` object is a list with these attributes: * `principal` - The principal attached to this PrivateLink. -* `principal_type` - The principal type. -* `principal_alias` - The friendly name to refer to the principal. - -The `connections` object is a list, with these attributes: -* `association_id` - Association ID of the PrivateLink connection. -* `connection_id` - Connection ID of the PrivateLink connection -* `connection_type` - The PrivateLink connection type. -* `owner_id` - Owner ID of the connection. -* `association_date` - Date the connection was associated. - -The `databases` object is a list, with these attributes: -* `database_id` - ID of the database. -* `port` - The port which the database is available on. +* `principal_type` - The type of principal. +* `principal_alias` - A friendly name for the principal. + +The `connections` object is a list with these attributes: +* `association_id` - The association ID of the PrivateLink connection. +* `connection_id` - The connection ID of the PrivateLink connection. +* `connection_type` - The type of the PrivateLink connection. +* `owner_id` - The owner ID of the connection. +* `association_date` - The date the connection was associated. + +The `databases` object is a list with these attributes: +* `database_id` - The ID of the database. +* `port` - The port the database is available on. * `resource_link_endpoint` - The resource link endpoint for the database. diff --git a/docs/data-sources/rediscloud_private_link.md b/docs/data-sources/rediscloud_private_link.md index f3098bd2..91854a43 100644 --- a/docs/data-sources/rediscloud_private_link.md +++ b/docs/data-sources/rediscloud_private_link.md @@ -6,7 +6,7 @@ description: |- --- # Data Source: rediscloud_private_link -The PrivateLink data source allows the user to retrieve information about an existing PrivateLink in the provider. +Retrieves details of an existing PrivateLink for a Pro Subscription. ## Example Usage @@ -24,29 +24,28 @@ output "rediscloud_private_link_principals" { * `subscription_id` - (Required) The ID of the Pro Subscription the PrivateLink is attached to. -## Attribute reference +## Attribute Reference -* `principals` - The principal(s) attached to the PrivateLink. -* `resource_configuration_id` - ID of the resource configuration to attach to this PrivateLink -* `resource_configuration_arn` - ARN of the resource configuration to attach to this PrivateLink -* `share_arn` - Share ARN of this PrivateLink. -* `connections` - List of connections associated with the PrivateLink. -* `databases` - List of databases associated with the PrivateLink. +* `principals` - A list of principals attached to the PrivateLink. +* `resource_configuration_id` - The ID of the resource configuration attached to this PrivateLink. +* `resource_configuration_arn` - The ARN of the resource configuration attached to this PrivateLink. +* `share_arn` - The share ARN of this PrivateLink. +* `connections` - A list of connections associated with the PrivateLink. +* `databases` - A list of databases associated with the PrivateLink. - -The `principals` object is a list, with these attributes: +The `principals` object supports the following attributes: * `principal` - The principal attached to this PrivateLink. -* `principal_type` - The principal type. -* `principal_alias` - The friendly name to refer to the principal. - -The `connections` object is a list, with these attributes: -* `association_id` - Association ID of the PrivateLink connection. -* `connection_id` - Connection ID of the PrivateLink connection -* `connection_type` - The PrivateLink connection type. -* `owner_id` - Owner ID of the connection. -* `association_date` - Date the connection was associated. - -The `databases` object is a list, with these attributes: -* `database_id` - ID of the database. -* `port` - The port which the database is available on. +* `principal_type` - The type of principal. +* `principal_alias` - A friendly name for the principal. + +The `connections` object supports the following attributes: +* `association_id` - The association ID of the PrivateLink connection. +* `connection_id` - The connection ID of the PrivateLink connection. +* `connection_type` - The type of the PrivateLink connection. +* `owner_id` - The owner ID of the connection. +* `association_date` - The date the connection was associated. + +The `databases` object supports the following attributes: +* `database_id` - The ID of the database. +* `port` - The port the database is available on. * `resource_link_endpoint` - The resource link endpoint for the database. diff --git a/docs/resources/rediscloud_active_active_private_link.md b/docs/resources/rediscloud_active_active_private_link.md index 8cb278b6..09454b20 100644 --- a/docs/resources/rediscloud_active_active_private_link.md +++ b/docs/resources/rediscloud_active_active_private_link.md @@ -2,12 +2,14 @@ layout: "rediscloud" page_title: "Redis Cloud: rediscloud_active_active_private_link" description: |- - PrivateLink resource for Active Active Subscription in the Redis Cloud Terraform provider. + PrivateLink resource for an Active-Active Subscription in the Redis Cloud Terraform provider. --- # Resource: rediscloud_active_active_private_link -Manages a PrivateLink to a Active Active Subscription in your Redis Enterprise Cloud Account. +Manages a PrivateLink to an Active-Active Subscription in your Redis Enterprise Cloud Account. + +Note the forced dependency on the Active-Active database. Currently, you require a database to be attached to your subscription in order for a `region_id` to be assigned. ## Example Usage @@ -30,41 +32,48 @@ data "rediscloud_cloud_account" "account" { name = local.rediscloud_cloud_account } -resource "rediscloud_active_active_subscription" "subscription" { +resource "rediscloud_active_active_subscription" "aa_subscription" { name = local.rediscloud_subscription_name + payment_method = "credit-card" payment_method_id = data.rediscloud_payment_method.card.id + cloud_provider = "AWS" - cloud_provider { - provider = data.rediscloud_cloud_account.account.provider_type - cloud_account_id = data.rediscloud_cloud_account.account.id + creation_plan { + memory_limit_in_gb = 1 + quantity = 1 region { - region = "eu-west-1" - networking_deployment_cidr = "10.0.0.0/24" - preferred_availability_zones = ["eu-west-1a"] + region = "eu-west-1" + networking_deployment_cidr = "192.168.0.0/24" + write_operations_per_second = 1000 + read_operations_per_second = 1000 + } + region { + region = "eu-west-2" + networking_deployment_cidr = "10.0.1.0/24" + write_operations_per_second = 1000 + read_operations_per_second = 1000 } - } - - creation_plan { - dataset_size_in_gb = 15 - quantity = 1 - replication = true - throughput_measurement_by = "operations-per-second" - throughput_measurement_value = 20000 } } -resource "rediscloud_active_active_subscription_database" "database_resource" { - subscription_id = rediscloud_active_active_subscription.subscription.id +resource "rediscloud_active_active_subscription_database" "aa_database" { + subscription_id = rediscloud_active_active_subscription.aa_subscription.id name = "db" memory_limit_in_gb = 1 global_data_persistence = "aof-every-1-second" global_password = local.rediscloud_database_password } +data "rediscloud_active_active_subscription_regions" "aa_regions_info" { + subscription_name = rediscloud_active_active_subscription.aa_subscription.name + depends_on = [rediscloud_active_active_subscription_database.aa_database] +} + -resource "rediscloud_private_link" "private_link" { - subscription_id = rediscloud_subscription.subscription.id - share_name = local.rediscloud_private_link_share_name +resource "rediscloud_active_active_private_link" "private_link" { + subscription_id = rediscloud_active_active_subscription.aa_subscription.id + region_id = data.rediscloud_active_active_subscription_regions.aa_regions_info.regions[0].region_id + share_name = local.rediscloud_private_link_share_name principal { principal = "123456789012" @@ -82,8 +91,8 @@ resource "rediscloud_private_link" "private_link" { ## Argument Reference -* `subscription_id` - (Required) The ID of the Active Active Subscription to link to. **Modifying this attribute will force creation of a new resource.** -* `region_id` - (Required) +* `subscription_id` - (Required) The ID of the Active-Active Subscription to link to. **Modifying this attribute will force creation of a new resource.** +* `region_id` - (Required) The region ID within the Active-Active subscription that the PrivateLink is attached to. **Modifying this attribute will force creation of a new resource.** * `share_name` - (Required) The share name of the PrivateLink. * `principal` - (Required) The principal(s) attached to the PrivateLink. @@ -94,14 +103,27 @@ The `principal` block supports: ## Attribute Reference -* `resource_configuration_id` - Configuration I -* `resource_configuration_arn` -* `share_arn` -* `connections` (block) -* `databases` (block) +* `resource_configuration_id` - ID of the resource configuration to attach to this PrivateLink +* `resource_configuration_arn` - ARN of the resource configuration to attach to this PrivateLink +* `share_arn` - Share ARN of this PrivateLink. +* `connections` - List of connections associated with the PrivateLink. +* `databases` - List of databases associated with the PrivateLink. + +The `connections` object has these attributes: + +* `association_id` - Association ID of the PrivateLink connection. +* `connection_id` - Connection ID of the PrivateLink connection. +* `connection_type` - Type of the PrivateLink connection. +* `owner_id` - Owner ID of the connection. +* `association_date` - Date the connection was associated. + +The `databases` object has these attributes: +* `database_id` - ID of the database. +* `port` - The port which the database is available on. +* `resource_link_endpoint` - The resource link endpoint for the database. ## Import -`rediscloud_active_active_private_link` can be imported using the ID of the subscription and the region id, e.g. +`rediscloud_active_active_private_link` can be imported using the ID of the subscription and the region id in the format SUB_ID/REGION_ID, e.g. ``` $ terraform import rediscloud_active_active_private_link.id 123456/1 diff --git a/go.mod b/go.mod index e37d0513..d37976b4 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.24.0 toolchain go1.24.1 require ( - github.com/RedisLabs/rediscloud-go-api v0.36.3 + github.com/RedisLabs/rediscloud-go-api v0.36.4 github.com/bflad/tfproviderlint v0.31.0 github.com/hashicorp/go-cty v1.5.0 github.com/hashicorp/terraform-plugin-sdk/v2 v2.37.0 diff --git a/go.sum b/go.sum index 67acf80e..c9cf4727 100644 --- a/go.sum +++ b/go.sum @@ -4,8 +4,8 @@ github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERo github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/ProtonMail/go-crypto v1.1.6 h1:ZcV+Ropw6Qn0AX9brlQLAUXfqLBc7Bl+f/DmNxpLfdw= github.com/ProtonMail/go-crypto v1.1.6/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE= -github.com/RedisLabs/rediscloud-go-api v0.36.3 h1:HEMJ6h+HbVj42bB1wabqTi9wgHjGcS0NIhxuJBvFFns= -github.com/RedisLabs/rediscloud-go-api v0.36.3/go.mod h1:Hkh3i/EsHnyfgV0ijednbofz/EmZC3sFnSNNruF3G6I= +github.com/RedisLabs/rediscloud-go-api v0.36.4 h1:EBoyJ3SyvfX4MjTB5MNs5s+hhYTVSVzjdhNtPJDcfMw= +github.com/RedisLabs/rediscloud-go-api v0.36.4/go.mod h1:Hkh3i/EsHnyfgV0ijednbofz/EmZC3sFnSNNruF3G6I= github.com/agext/levenshtein v1.2.2 h1:0S/Yg6LYmFJ5stwQeRp6EeOcCbj7xiqQSdNelsXvaqE= github.com/agext/levenshtein v1.2.2/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= github.com/apparentlymart/go-textseg/v12 v12.0.0/go.mod h1:S/4uRK2UtaQttw1GenVJEynmyUenKwP++x/+DdGV/Ec= diff --git a/provider/activeactive/testdata/testAccResourceRedisCloudActiveActiveSubscription.tf b/provider/activeactive/testdata/testAccResourceRedisCloudActiveActiveSubscription.tf new file mode 100644 index 00000000..b28bcbce --- /dev/null +++ b/provider/activeactive/testdata/testAccResourceRedisCloudActiveActiveSubscription.tf @@ -0,0 +1,94 @@ +locals { + rediscloud_subscription_name = "%s" +} + +data "rediscloud_payment_method" "card" { + card_type = "Visa" + last_four_numbers = "5556" +} + +resource "rediscloud_active_active_subscription" "example" { + name = local.rediscloud_subscription_name + payment_method_id = data.rediscloud_payment_method.card.id + cloud_provider = "AWS" + + creation_plan { + memory_limit_in_gb = 1 + modules = ["RedisJSON"] + quantity = 1 + region { + region = "us-east-1" + networking_deployment_cidr = "192.168.0.0/24" + write_operations_per_second = 1000 + read_operations_per_second = 1000 + } + region { + region = "us-east-2" + networking_deployment_cidr = "10.0.1.0/24" + write_operations_per_second = 1000 + read_operations_per_second = 1000 + } + } + + maintenance_windows { + mode = "manual" + window { + start_hour = 22 + duration_in_hours = 8 + days = ["Monday", "Thursday"] + } + window { + start_hour = 12 + duration_in_hours = 6 + days = ["Friday", "Saturday", "Sunday"] + } + } +} + +resource "rediscloud_active_active_subscription_database" "example" { + subscription_id = rediscloud_active_active_subscription.example.id + name = local.rediscloud_subscription_name + dataset_size_in_gb = 1 + global_data_persistence = "aof-every-1-second" + global_password = "some-random-pass-2" + global_source_ips = ["192.168.0.0/16"] + global_alert { + name = "dataset-size" + value = 40 + } + + global_modules = ["RedisJSON"] + + + + override_region { + name = "us-east-2" + enable_default_user = true + override_global_source_ips = ["192.10.0.0/16"] + } + + override_region { + name = "us-east-1" + override_global_data_persistence = "none" + override_global_password = "region-specific-password" + override_global_alert { + name = "dataset-size" + value = 60 + } + } + + tags = { + "environment" = "production" + "cost_center" = "0700" + } +} + + +data "rediscloud_active_active_subscription" "example" { + name = rediscloud_active_active_subscription.example.name +} + +data "rediscloud_active_active_subscription_regions" "example" { + subscription_name = rediscloud_active_active_subscription.example.name +} + diff --git a/provider/activeactive/testdata/testAccResourceRedisCloudActiveActiveSubscriptionUpdate.tf b/provider/activeactive/testdata/testAccResourceRedisCloudActiveActiveSubscriptionUpdate.tf new file mode 100644 index 00000000..d3222800 --- /dev/null +++ b/provider/activeactive/testdata/testAccResourceRedisCloudActiveActiveSubscriptionUpdate.tf @@ -0,0 +1,61 @@ +locals { + rediscloud_subscription_name = "%s" + rediscloud_cloud_provider_name = "%s" +} + +data "rediscloud_payment_method" "card" { + card_type = "Visa" + last_four_numbers = "5556" +} + +resource "rediscloud_active_active_subscription" "example" { + name = local.rediscloud_subscription_name + payment_method_id = data.rediscloud_payment_method.card.id + cloud_provider = local.rediscloud_cloud_provider_name + + maintenance_windows { + mode = "automatic" + } +} + +data "rediscloud_active_active_subscription" "example" { + name = rediscloud_active_active_subscription.example.name +} + +resource "rediscloud_active_active_subscription_database" "example" { + subscription_id = rediscloud_active_active_subscription.example.id + name = local.rediscloud_subscription_name + dataset_size_in_gb = 1 + global_data_persistence = "aof-every-1-second" + global_password = "some-random-pass-2" + global_source_ips = ["192.168.0.0/16"] + global_alert { + name = "dataset-size" + value = 40 + } + + global_modules = ["RedisJSON"] + + + + override_region { + name = "us-east-2" + enable_default_user = false + override_global_source_ips = ["192.10.0.0/16"] + } + + override_region { + name = "us-east-1" + override_global_data_persistence = "none" + override_global_password = "region-specific-password" + override_global_alert { + name = "dataset-size" + value = 60 + } + } + + tags = { + "environment" = "production" + "cost_center" = "0700" + } +} diff --git a/provider/datasource_rediscloud_pro_database_test.go b/provider/datasource_rediscloud_pro_database_test.go index b1971de0..a3a1c0d0 100644 --- a/provider/datasource_rediscloud_pro_database_test.go +++ b/provider/datasource_rediscloud_pro_database_test.go @@ -72,7 +72,7 @@ func getRedisProDbDatasourceConfig(t *testing.T, password string) string { testCloudAccountName := os.Getenv("AWS_TEST_CLOUD_ACCOUNT_NAME") subscriptionName := acctest.RandomWithPrefix(testResourcePrefix) - content, err := os.ReadFile("./testdata/testAccDatasourceRedisCloudProDatabase.tf") + content, err := os.ReadFile("./pro/testdata/testAccDatasourceRedisCloudProDatabase.tf") if err != nil { t.Fatalf("failed to read file: %v", err) } diff --git a/provider/testdata/testAccDatasourceRedisCloudProDatabase.tf b/provider/pro/testdata/testAccDatasourceRedisCloudProDatabase.tf similarity index 100% rename from provider/testdata/testAccDatasourceRedisCloudProDatabase.tf rename to provider/pro/testdata/testAccDatasourceRedisCloudProDatabase.tf diff --git a/provider/testdata/testAccResourceRedisCloudProDatabaseUpgrade.tf b/provider/pro/testdata/testAccResourceRedisCloudProDatabaseUpgrade.tf similarity index 100% rename from provider/testdata/testAccResourceRedisCloudProDatabaseUpgrade.tf rename to provider/pro/testdata/testAccResourceRedisCloudProDatabaseUpgrade.tf diff --git a/provider/testdata/testPrivateServiceConnect1.tf b/provider/psc/testdata/testPrivateServiceConnect1.tf similarity index 100% rename from provider/testdata/testPrivateServiceConnect1.tf rename to provider/psc/testdata/testPrivateServiceConnect1.tf diff --git a/provider/rediscloud_active_active_database_test.go b/provider/rediscloud_active_active_database_test.go index 35536eaf..517fa8af 100644 --- a/provider/rediscloud_active_active_database_test.go +++ b/provider/rediscloud_active_active_database_test.go @@ -169,7 +169,7 @@ func TestAccResourceRedisCloudActiveActiveDatabase_CRUDI(t *testing.T) { }, // Test database is updated, including deletion of global and local alerts and replacing modules { - Config: fmt.Sprintf(testAccResourceRedisCloudActiveActiveDatabaseUpdateNoAlerts, subscriptionName, databaseName), + Config: fmt.Sprintf(testAccResourceRedisCloudActiveActiveDatabaseUpdateNoAlertsDefaultUser, subscriptionName, databaseName), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr(databaseResourceName, "dataset_size_in_gb", "1"), resource.TestCheckResourceAttr(databaseResourceName, "support_oss_cluster_api", "true"), @@ -209,6 +209,7 @@ func TestAccResourceRedisCloudActiveActiveDatabase_CRUDI(t *testing.T) { "override_region.0.override_global_alert.0.value", "override_region.0.override_global_data_persistence", "override_region.0.override_global_password", + "override_region.0.enable_default_user", }, }, }, @@ -303,7 +304,7 @@ resource "rediscloud_active_active_subscription_database" "example" { external_endpoint_for_oss_cluster_api = false enable_tls = false redis_version = "7.2" - + global_data_persistence = "none" global_password = "%s" global_source_ips = ["192.168.0.0/16", "192.170.0.0/16"] @@ -378,14 +379,14 @@ data "rediscloud_active_active_subscription_database" "example" { } ` -const testAccResourceRedisCloudActiveActiveDatabaseUpdateNoAlerts = activeActiveSubscriptionBoilerplate + ` +const testAccResourceRedisCloudActiveActiveDatabaseUpdateNoAlertsDefaultUser = activeActiveSubscriptionBoilerplate + ` resource "rediscloud_active_active_subscription_database" "example" { subscription_id = rediscloud_active_active_subscription.example.id name = "%s" dataset_size_in_gb = 1 support_oss_cluster_api = true external_endpoint_for_oss_cluster_api = true - + global_data_persistence = "aof-every-1-second" global_password = "updated-password" global_source_ips = ["192.170.0.0/16"] diff --git a/provider/rediscloud_active_active_subscription_test.go b/provider/rediscloud_active_active_subscription_test.go index 0c9cb6a5..a74cd424 100644 --- a/provider/rediscloud_active_active_subscription_test.go +++ b/provider/rediscloud_active_active_subscription_test.go @@ -4,12 +4,13 @@ import ( "context" "flag" "fmt" - client2 "github.com/RedisLabs/terraform-provider-rediscloud/provider/client" + "os" "regexp" "strconv" "testing" "github.com/RedisLabs/rediscloud-go-api/redis" + client2 "github.com/RedisLabs/terraform-provider-rediscloud/provider/client" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -40,7 +41,7 @@ func TestAccResourceRedisCloudActiveActiveSubscription_CRUDI(t *testing.T) { CheckDestroy: testAccCheckActiveActiveSubscriptionDestroy, Steps: []resource.TestStep{ { - Config: fmt.Sprintf(testAccResourceRedisCloudActiveActiveSubscription, name, name), + Config: testAccResourceRedisCloudActiveActiveSubscription(t, name), Check: resource.ComposeAggregateTestCheckFunc( // Test the resource resource.TestCheckResourceAttr(resourceName, "name", name), @@ -175,11 +176,14 @@ func TestAccResourceRedisCloudActiveActiveSubscription_CRUDI(t *testing.T) { resource.TestCheckResourceAttr(datasourceRegionName, "regions.1.region", "us-east-2"), resource.TestCheckResourceAttr(datasourceRegionName, "regions.1.networking_deployment_cidr", "10.0.1.0/24"), resource.TestCheckResourceAttrSet(datasourceRegionName, "regions.1.vpc_id"), + + // checks enabling default user is true + //resource.TestCheckResourceAttr(resourceName, "regions.1.enable_default_user", "true"), ), }, { // Checks if the changes in the creation plan are ignored. - Config: fmt.Sprintf(testAccResourceRedisCloudActiveActiveSubscriptionNoCreationPlan, name, "AWS"), + Config: testAccResourceRedisCloudActiveActiveSubscriptionUpdate(t, name, "AWS"), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr(resourceName, "name", name), resource.TestCheckResourceAttr(resourceName, "cloud_provider", "AWS"), @@ -194,6 +198,9 @@ func TestAccResourceRedisCloudActiveActiveSubscription_CRUDI(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "creation_plan.0.region.1.write_operations_per_second", "1000"), resource.TestCheckResourceAttr(resourceName, "creation_plan.0.region.1.read_operations_per_second", "1000"), + // also checks user has removed default user + //resource.TestCheckResourceAttr(resourceName, "regions.1.enable_default_user", "false"), + // maintenance windows spec is omitted so should default back to automatic resource.TestCheckResourceAttr(resourceName, "maintenance_windows.0.mode", "automatic"), resource.TestCheckResourceAttr(resourceName, "maintenance_windows.0.window.#", "0"), @@ -343,96 +350,6 @@ func testAccCheckActiveActiveSubscriptionDestroy(s *terraform.State) error { return nil } -// TF config for provisioning a new subscription. -const testAccResourceRedisCloudActiveActiveSubscription = ` -data "rediscloud_payment_method" "card" { - card_type = "Visa" - last_four_numbers = "5556" -} - -resource "rediscloud_active_active_subscription" "example" { - name = "%s" - payment_method_id = data.rediscloud_payment_method.card.id - cloud_provider = "AWS" - - creation_plan { - memory_limit_in_gb = 1 - modules = ["RedisJSON"] - quantity = 1 - region { - region = "us-east-1" - networking_deployment_cidr = "192.168.0.0/24" - write_operations_per_second = 1000 - read_operations_per_second = 1000 - } - region { - region = "us-east-2" - networking_deployment_cidr = "10.0.1.0/24" - write_operations_per_second = 1000 - read_operations_per_second = 1000 - } - } - - maintenance_windows { - mode = "manual" - window { - start_hour = 22 - duration_in_hours = 8 - days = ["Monday", "Thursday"] - } - window { - start_hour = 12 - duration_in_hours = 6 - days = ["Friday", "Saturday", "Sunday"] - } - } -} - -resource "rediscloud_active_active_subscription_database" "example" { - subscription_id = rediscloud_active_active_subscription.example.id - name = "%s" - dataset_size_in_gb = 1 - global_data_persistence = "aof-every-1-second" - global_password = "some-random-pass-2" - global_source_ips = ["192.168.0.0/16"] - global_alert { - name = "dataset-size" - value = 40 - } - - global_modules = ["RedisJSON"] - - override_region { - name = "us-east-2" - override_global_source_ips = ["192.10.0.0/16"] - } - - override_region { - name = "us-east-1" - override_global_data_persistence = "none" - override_global_password = "region-specific-password" - override_global_alert { - name = "dataset-size" - value = 60 - } - } - - tags = { - "environment" = "production" - "cost_center" = "0700" - } -} - - -data "rediscloud_active_active_subscription" "example" { - name = rediscloud_active_active_subscription.example.name -} - -data "rediscloud_active_active_subscription_regions" "example" { - subscription_name = rediscloud_active_active_subscription.example.name -} -` - const testAccResourceRedisCloudActiveActiveSubscriptionNoCreationPlan = ` data "rediscloud_payment_method" "card" { @@ -536,3 +453,23 @@ resource "rediscloud_active_active_subscription" "example" { } } ` + +func testAccResourceRedisCloudActiveActiveSubscription(t *testing.T, subscriptionName string) string { + + content, err := os.ReadFile("./activeactive/testdata//testAccResourceRedisCloudActiveActiveSubscription.tf") + if err != nil { + t.Fatalf("failed to read file: %v", err) + } + + return fmt.Sprintf(string(content), subscriptionName) +} + +func testAccResourceRedisCloudActiveActiveSubscriptionUpdate(t *testing.T, subscriptionName string, cloudProvider string) string { + + content, err := os.ReadFile("./activeactive/testdata/testAccResourceRedisCloudActiveActiveSubscriptionUpdate.tf") + if err != nil { + t.Fatalf("failed to read file: %v", err) + } + + return fmt.Sprintf(string(content), subscriptionName, cloudProvider) +} diff --git a/provider/resource_rediscloud_active_active_database.go b/provider/resource_rediscloud_active_active_database.go index 3787df86..b9ba3ffe 100644 --- a/provider/resource_rediscloud_active_active_database.go +++ b/provider/resource_rediscloud_active_active_database.go @@ -252,6 +252,12 @@ func resourceRedisCloudActiveActiveDatabase() *schema.Resource { Type: schema.TypeString, Optional: true, }, + "enable_default_user": { + Description: "When 'true', enables connecting to the database with the 'default' user. Default: 'true'", + Type: schema.TypeBool, + Optional: true, + Default: true, + }, "remote_backup": { Description: "An object that specifies the backup options for the database in this region", Type: schema.TypeList, @@ -452,7 +458,7 @@ func resourceRedisCloudActiveActiveDatabaseCreate(ctx context.Context, d *schema d.SetId(buildResourceId(subId, dbId)) // Confirm Database Active status - err = waitForDatabaseToBeActive(ctx, subId, dbId, api) + err = utils.WaitForDatabaseToBeActive(ctx, subId, dbId, api) if err != nil { utils.SubscriptionMutex.Unlock(subId) return diag.FromErr(err) @@ -580,6 +586,8 @@ func resourceRedisCloudActiveActiveDatabaseRead(ctx context.Context, d *schema.R regionDbConfig["remote_backup"] = flattenBackupPlan(regionDb.Backup, getStateRemoteBackup(d, region), "") + regionDbConfig["enable_default_user"] = redis.BoolValue(regionDb.Security.EnableDefaultUser) + regionDbConfigs = append(regionDbConfigs, regionDbConfig) } @@ -631,7 +639,7 @@ func resourceRedisCloudActiveActiveDatabaseDelete(ctx context.Context, d *schema utils.SubscriptionMutex.Lock(subId) defer utils.SubscriptionMutex.Unlock(subId) - if err := waitForDatabaseToBeActive(ctx, subId, dbId, api); err != nil { + if err := utils.WaitForDatabaseToBeActive(ctx, subId, dbId, api); err != nil { return diag.FromErr(err) } @@ -688,7 +696,8 @@ func resourceRedisCloudActiveActiveDatabaseUpdate(ctx context.Context, d *schema } regionProps := &databases.LocalRegionProperties{ - Region: redis.String(dbRegion["name"].(string)), + Region: redis.String(dbRegion["name"].(string)), + EnableDefaultUser: redis.Bool(dbRegion["enable_default_user"].(bool)), } if len(overrideAlerts) > 0 { @@ -786,7 +795,7 @@ func resourceRedisCloudActiveActiveDatabaseUpdate(ctx context.Context, d *schema return diag.FromErr(err) } - if err := waitForDatabaseToBeActive(ctx, subId, dbId, api); err != nil { + if err := utils.WaitForDatabaseToBeActive(ctx, subId, dbId, api); err != nil { return diag.FromErr(err) } diff --git a/provider/resource_rediscloud_active_active_subscription.go b/provider/resource_rediscloud_active_active_subscription.go index 39b9ffad..fc9d3e43 100644 --- a/provider/resource_rediscloud_active_active_subscription.go +++ b/provider/resource_rediscloud_active_active_subscription.go @@ -405,7 +405,7 @@ func resourceRedisCloudActiveActiveSubscriptionCreate(ctx context.Context, d *sc for dbList.Next() { dbId := *dbList.Value().ID - if err := waitForDatabaseToBeActive(ctx, subId, dbId, api); err != nil { + if err := utils.WaitForDatabaseToBeActive(ctx, subId, dbId, api); err != nil { return diag.FromErr(err) } // Delete each creation-plan database diff --git a/provider/resource_rediscloud_essentials_database_test.go b/provider/resource_rediscloud_essentials_database_test.go index d28e6d36..29b88d28 100644 --- a/provider/resource_rediscloud_essentials_database_test.go +++ b/provider/resource_rediscloud_essentials_database_test.go @@ -1,9 +1,10 @@ package provider import ( - "fmt" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + "fmt" "regexp" "testing" ) diff --git a/provider/resource_rediscloud_pro_database.go b/provider/resource_rediscloud_pro_database.go index 8d59978d..f77d34e1 100644 --- a/provider/resource_rediscloud_pro_database.go +++ b/provider/resource_rediscloud_pro_database.go @@ -450,7 +450,7 @@ func resourceRedisCloudProDatabaseCreate(ctx context.Context, d *schema.Resource d.SetId(buildResourceId(subId, dbId)) // Confirm db + sub active status - if err := waitForDatabaseToBeActive(ctx, subId, dbId, api); err != nil { + if err := utils.WaitForDatabaseToBeActive(ctx, subId, dbId, api); err != nil { utils.SubscriptionMutex.Unlock(subId) return diag.FromErr(err) } @@ -649,7 +649,7 @@ func resourceRedisCloudProDatabaseDelete(ctx context.Context, d *schema.Resource if err := utils.WaitForSubscriptionToBeActive(ctx, subId, api); err != nil { return diag.FromErr(err) } - if err := waitForDatabaseToBeActive(ctx, subId, dbId, api); err != nil { + if err := utils.WaitForDatabaseToBeActive(ctx, subId, dbId, api); err != nil { return diag.FromErr(err) } @@ -782,7 +782,7 @@ func resourceRedisCloudProDatabaseUpdate(ctx context.Context, d *schema.Resource utils.SubscriptionMutex.Unlock(subId) return diag.FromErr(err) } - if err := waitForDatabaseToBeActive(ctx, subId, dbId, api); err != nil { + if err := utils.WaitForDatabaseToBeActive(ctx, subId, dbId, api); err != nil { utils.SubscriptionMutex.Unlock(subId) return diag.FromErr(err) } @@ -812,7 +812,7 @@ func resourceRedisCloudProDatabaseUpdate(ctx context.Context, d *schema.Resource } // Confirm db + sub active status - if err := waitForDatabaseToBeActive(ctx, subId, dbId, api); err != nil { + if err := utils.WaitForDatabaseToBeActive(ctx, subId, dbId, api); err != nil { utils.SubscriptionMutex.Unlock(subId) return diag.FromErr(err) } @@ -845,7 +845,7 @@ func upgradeRedisVersion(ctx context.Context, api *client.ApiClient, subId int, log.Printf("[INFO] Redis version change request to %s accepted by API", newVersion) // wait for upgrade - if err := waitForDatabaseToBeActive(ctx, subId, dbId, api); err != nil { + if err := utils.WaitForDatabaseToBeActive(ctx, subId, dbId, api); err != nil { utils.SubscriptionMutex.Unlock(subId) return diag.FromErr(err), true } diff --git a/provider/resource_rediscloud_pro_database_upgrade_test.go b/provider/resource_rediscloud_pro_database_upgrade_test.go index bf8b95a5..074f08e2 100644 --- a/provider/resource_rediscloud_pro_database_upgrade_test.go +++ b/provider/resource_rediscloud_pro_database_upgrade_test.go @@ -9,7 +9,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) -const testFileName = "./testdata/testAccResourceRedisCloudProDatabaseUpgrade.tf" +const testFileName = "./pro/testdata/testAccResourceRedisCloudProDatabaseUpgrade.tf" func TestAccResourceRedisCloudProDatabase_Upgrade(t *testing.T) { diff --git a/provider/resource_rediscloud_pro_subscription.go b/provider/resource_rediscloud_pro_subscription.go index 8ea32428..3fc61ebf 100644 --- a/provider/resource_rediscloud_pro_subscription.go +++ b/provider/resource_rediscloud_pro_subscription.go @@ -4,8 +4,6 @@ import ( "bytes" "context" "fmt" - "github.com/RedisLabs/terraform-provider-rediscloud/provider/client" - "github.com/RedisLabs/terraform-provider-rediscloud/provider/utils" "log" "reflect" "regexp" @@ -18,6 +16,8 @@ import ( "github.com/RedisLabs/rediscloud-go-api/service/maintenance" "github.com/RedisLabs/rediscloud-go-api/service/pricing" "github.com/RedisLabs/rediscloud-go-api/service/subscriptions" + "github.com/RedisLabs/terraform-provider-rediscloud/provider/client" + "github.com/RedisLabs/terraform-provider-rediscloud/provider/utils" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -655,7 +655,7 @@ func resourceRedisCloudProSubscriptionCreate(ctx context.Context, d *schema.Reso for dbList.Next() { dbId := *dbList.Value().ID - if err := waitForDatabaseToBeActive(ctx, subId, dbId, api); err != nil { + if err := utils.WaitForDatabaseToBeActive(ctx, subId, dbId, api); err != nil { return append(diags, diag.FromErr(err)...) } // Delete each creation-plan database @@ -1192,44 +1192,6 @@ func waitForSubscriptionToBeDeleted(ctx context.Context, id int, api *client.Api return nil } -func waitForDatabaseToBeActive(ctx context.Context, subId, id int, api *client.ApiClient) error { - wait := &retry.StateChangeConf{ - Pending: []string{ - databases.StatusDraft, - databases.StatusPending, - databases.StatusActiveChangePending, - databases.StatusRCPActiveChangeDraft, - databases.StatusActiveChangeDraft, - databases.StatusRCPDraft, - databases.StatusRCPChangePending, - databases.StatusProxyPolicyChangePending, - databases.StatusProxyPolicyChangeDraft, - databases.StatusDynamicEndpointsCreationPending, - databases.StatusActiveUpgradePending, - }, - Target: []string{databases.StatusActive}, - Timeout: utils.SafetyTimeout, - Delay: 10 * time.Second, - PollInterval: 30 * time.Second, - - Refresh: func() (result interface{}, state string, err error) { - log.Printf("[DEBUG] Waiting for database %d to be active", id) - - database, err := api.Client.Database.Get(ctx, subId, id) - if err != nil { - return nil, "", err - } - - return redis.StringValue(database.Status), redis.StringValue(database.Status), nil - }, - } - if _, err := wait.WaitForStateContext(ctx); err != nil { - return err - } - - return nil -} - func flattenSubscriptionAllowlist(ctx context.Context, subId int, api *client.ApiClient) ([]map[string]interface{}, error) { allowlist, err := api.Client.Subscription.GetCIDRAllowlist(ctx, subId) if err != nil { diff --git a/provider/utils/wait.go b/provider/utils/wait.go index c687eb11..92244de8 100644 --- a/provider/utils/wait.go +++ b/provider/utils/wait.go @@ -2,6 +2,7 @@ package utils import ( "context" + "github.com/RedisLabs/rediscloud-go-api/service/databases" "log" "time" @@ -36,3 +37,41 @@ func WaitForSubscriptionToBeActive(ctx context.Context, id int, api *client.ApiC return nil } + +func WaitForDatabaseToBeActive(ctx context.Context, subId, id int, api *client.ApiClient) error { + wait := &retry.StateChangeConf{ + Pending: []string{ + databases.StatusDraft, + databases.StatusPending, + databases.StatusActiveChangePending, + databases.StatusRCPActiveChangeDraft, + databases.StatusActiveChangeDraft, + databases.StatusRCPDraft, + databases.StatusRCPChangePending, + databases.StatusProxyPolicyChangePending, + databases.StatusProxyPolicyChangeDraft, + databases.StatusDynamicEndpointsCreationPending, + databases.StatusActiveUpgradePending, + }, + Target: []string{databases.StatusActive}, + Timeout: SafetyTimeout, + Delay: 10 * time.Second, + PollInterval: 30 * time.Second, + + Refresh: func() (result interface{}, state string, err error) { + log.Printf("[DEBUG] Waiting for database %d to be active", id) + + database, err := api.Client.Database.Get(ctx, subId, id) + if err != nil { + return nil, "", err + } + + return redis.StringValue(database.Status), redis.StringValue(database.Status), nil + }, + } + if _, err := wait.WaitForStateContext(ctx); err != nil { + return err + } + + return nil +}