diff --git a/.github/workflows/terraform_provider_pr.yml b/.github/workflows/terraform_provider_pr.yml index cf80a88c..e050127a 100644 --- a/.github/workflows/terraform_provider_pr.yml +++ b/.github/workflows/terraform_provider_pr.yml @@ -140,7 +140,7 @@ jobs: go_test_smoke_misc: name: go test smoke misc - needs: [go_build] + needs: [ go_build ] runs-on: ubuntu-latest steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 @@ -149,18 +149,17 @@ jobs: go-version-file: go.mod - run: EXECUTE_TESTS=true make testacc TESTARGS='-run="TestAccResourceRedisCloud(PrivateServiceConnect_CRUDI|AclRule_CRUDI)"' - # TODO: remove this after release - # qpf = query performance factor - go_test_smoke_qpf: - name: go test smoke qpf - needs: [ go_build ] + # TODO: remove, temporary: tests the subscription regions + go_test_smoke_aa_sub_regions: + name: go test smoke aa sub regions + needs: [go_build] runs-on: ubuntu-latest steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5.4.0 with: go-version-file: go.mod - - run: EXECUTE_TESTS=true make testacc TESTARGS='-run="TestAccResourceRedisCloudProDatabase_qpf.*"' + - run: EXECUTE_TESTS=true make testacc TESTARGS='-run="TestAccResourceRedisCloudActiveActiveSubscriptionRegions_CRUDI"' tfproviderlint: name: tfproviderlint diff --git a/go.mod b/go.mod index 0a9ba814..282bc8c0 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/RedisLabs/terraform-provider-rediscloud go 1.22.4 require ( - github.com/RedisLabs/rediscloud-go-api v0.25.0 + github.com/RedisLabs/rediscloud-go-api v0.26.0 github.com/bflad/tfproviderlint v0.31.0 github.com/hashicorp/go-cty v1.5.0 github.com/hashicorp/terraform-plugin-sdk/v2 v2.36.1 diff --git a/go.sum b/go.sum index 476114d8..abd0f506 100644 --- a/go.sum +++ b/go.sum @@ -4,8 +4,8 @@ github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migc github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= github.com/ProtonMail/go-crypto v1.1.3 h1:nRBOetoydLeUb4nHajyO2bKqMLfWQ/ZPwkXqXxPxCFk= github.com/ProtonMail/go-crypto v1.1.3/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE= -github.com/RedisLabs/rediscloud-go-api v0.25.0 h1:44q7fPxjkS94slkUxZCueaDB5i+axxjkFqOXIx3D44M= -github.com/RedisLabs/rediscloud-go-api v0.25.0/go.mod h1:3/oVb71rv2OstFRYEc65QCIbfwnJTgZeQhtPCcdHook= +github.com/RedisLabs/rediscloud-go-api v0.26.0 h1:ka6CN2O+Ti6igkfH8lDT9Ua1/ksEh2H5dj1GF/pnKKQ= +github.com/RedisLabs/rediscloud-go-api v0.26.0/go.mod h1:3/oVb71rv2OstFRYEc65QCIbfwnJTgZeQhtPCcdHook= 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/datasource_rediscloud_active_active_subscription.go b/provider/datasource_rediscloud_active_active_subscription.go index 1e6cca4d..6fafbe91 100644 --- a/provider/datasource_rediscloud_active_active_subscription.go +++ b/provider/datasource_rediscloud_active_active_subscription.go @@ -155,7 +155,7 @@ func dataSourceRedisCloudActiveActiveSubscriptionRead(ctx context.Context, d *sc var filters []func(method *subscriptions.Subscription) bool - // Filter to AA subscriptions only (active-active subs) come from the same endpoint + // Filter to AA subscriptions only (pro subs come from the same endpoint) filters = append(filters, func(sub *subscriptions.Subscription) bool { return redis.StringValue(sub.DeploymentType) == "active-active" }) diff --git a/provider/datasource_rediscloud_active_active_subscription_regions.go b/provider/datasource_rediscloud_active_active_subscription_regions.go new file mode 100644 index 00000000..28ae1d0c --- /dev/null +++ b/provider/datasource_rediscloud_active_active_subscription_regions.go @@ -0,0 +1,163 @@ +package provider + +import ( + "context" + "fmt" + "github.com/RedisLabs/rediscloud-go-api/redis" + "github.com/RedisLabs/rediscloud-go-api/service/subscriptions" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func dataSourceRedisCloudActiveActiveSubscriptionRegions() *schema.Resource { + return &schema.Resource{ + Description: "Gets a list of regions in the specified Active-Active subscription.", + ReadContext: dataSourceRedisCloudActiveActiveRegionsRead, + + Schema: map[string]*schema.Schema{ + "subscription_name": { + Description: "The name of the subscription", + Type: schema.TypeString, + Required: true, + }, + "regions": { + Description: "A list of regions from an active active subscription", + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "region": { + Description: "Deployment region as defined by cloud provider", + Type: schema.TypeString, + Computed: true, + }, + "networking_deployment_cidr": { + Description: "Deployment CIDR mask", + Type: schema.TypeString, + Computed: true, + }, + "vpc_id": { + Description: "VPC ID for the region", + Computed: true, + Type: schema.TypeString, + }, + "databases": { + Description: "A list of databases found in the region", + Computed: true, + Type: schema.TypeList, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "database_id": { + Description: "A numeric id for the database", + Type: schema.TypeInt, + Computed: true, + }, + "database_name": { + Description: "A meaningful name to identify the database", + Type: schema.TypeString, + Computed: true, + }, + "write_operations_per_second": { + Description: "Write operations per second for the database", + Type: schema.TypeInt, + Computed: true, + }, + "read_operations_per_second": { + Description: "Read operations per second for the database", + Type: schema.TypeInt, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func dataSourceRedisCloudActiveActiveRegionsRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + var diags diag.Diagnostics + api := meta.(*apiClient) + + subs, err := api.client.Subscription.List(ctx) + + if err != nil { + return diag.FromErr(err) + } + + var filters []func(method *subscriptions.Subscription) bool + + // Filter to active-active subscriptions only (pro subs come from the same endpoint) + filters = append(filters, func(sub *subscriptions.Subscription) bool { + return redis.StringValue(sub.DeploymentType) == "active-active" + }) + + // Filter down to requested subscription by name + if name, ok := d.GetOk("subscription_name"); ok { + filters = append(filters, func(sub *subscriptions.Subscription) bool { + return redis.StringValue(sub.Name) == name + }) + } + + subs = filterSubscriptions(subs, filters) + + if len(subs) == 0 { + return diag.Errorf("Your query returned no results. Please change your search criteria and try again.") + } + + if len(subs) > 1 { + return diag.Errorf("Your query returned more than one result. Please change try a more specific search criteria and try again.") + } + + sub := subs[0] + + regions, err := api.client.Subscription.ListActiveActiveRegions(ctx, *sub.ID) + + if err != nil { + return diag.FromErr(err) + } + + if len(regions) == 0 { + return diag.Errorf("Your query returned no results. Please change your search criteria and try again.") + } + + var genericRegions = flattenActiveActiveRegions(regions) + + id := fmt.Sprintf("%d-active-active-regions", *sub.ID) + d.SetId(id) + + if err := d.Set("regions", genericRegions); err != nil { + return diag.FromErr(err) + } + + return diags +} + +// generifies the region/db data so it can be put into the terraform schema +func flattenActiveActiveRegions(regionList []*subscriptions.ActiveActiveRegion) []map[string]interface{} { + var rl []map[string]interface{} + for _, currentRegion := range regionList { + + var dbs []map[string]interface{} + for _, db := range currentRegion.Databases { + dbMap := map[string]interface{}{ + "database_id": db.DatabaseId, + "database_name": db.DatabaseName, + "write_operations_per_second": db.WriteOperationsPerSecond, + "read_operations_per_second": db.ReadOperationsPerSecond, + } + dbs = append(dbs, dbMap) + } + + regionMap := map[string]interface{}{ + "region": currentRegion.Region, + "networking_deployment_cidr": currentRegion.DeploymentCIDR, + "vpc_id": currentRegion.VpcId, + "databases": dbs, + } + rl = append(rl, regionMap) + } + return rl +} diff --git a/provider/datasource_rediscloud_pro_subscription.go b/provider/datasource_rediscloud_pro_subscription.go index d33a7374..8fe6554b 100644 --- a/provider/datasource_rediscloud_pro_subscription.go +++ b/provider/datasource_rediscloud_pro_subscription.go @@ -63,7 +63,7 @@ func dataSourceRedisCloudProSubscription() *schema.Resource { Computed: true, }, "region": { - Description: "Cloud networking details, per region (single region or multiple regions for Active-Active cluster only)", + Description: "Cloud networking details, per region", Type: schema.TypeSet, Computed: true, Elem: &schema.Resource{ @@ -231,7 +231,7 @@ func dataSourceRedisCloudProSubscriptionRead(ctx context.Context, d *schema.Reso var filters []func(method *subscriptions.Subscription) bool - // Filter to pro subscriptions only (active-active subs) come from the same endpoint + // Filter to pro subscriptions only (active-active subs come from the same endpoint) filters = append(filters, func(sub *subscriptions.Subscription) bool { return redis.StringValue(sub.DeploymentType) != "active-active" }) diff --git a/provider/provider.go b/provider/provider.go index 8e660bad..8275ab6e 100644 --- a/provider/provider.go +++ b/provider/provider.go @@ -46,18 +46,20 @@ func New(version string) func() *schema.Provider { // Note the difference in public data-source name and the file/method name. // This is to help the developer relate their changes to what they would see happening in the Redis Console. // == flexible == pro - "rediscloud_subscription": dataSourceRedisCloudProSubscription(), - "rediscloud_database": dataSourceRedisCloudProDatabase(), - "rediscloud_database_modules": dataSourceRedisCloudDatabaseModules(), - "rediscloud_payment_method": dataSourceRedisCloudPaymentMethod(), - "rediscloud_regions": dataSourceRedisCloudRegions(), - "rediscloud_essentials_plan": dataSourceRedisCloudEssentialsPlan(), - "rediscloud_essentials_subscription": dataSourceRedisCloudEssentialsSubscription(), - "rediscloud_essentials_database": dataSourceRedisCloudEssentialsDatabase(), - "rediscloud_subscription_peerings": dataSourceRedisCloudSubscriptionPeerings(), - "rediscloud_private_service_connect": dataSourcePrivateServiceConnect(), - "rediscloud_private_service_connect_endpoints": dataSourcePrivateServiceConnectEndpoints(), - "rediscloud_active_active_subscription": dataSourceRedisCloudActiveActiveSubscription(), + "rediscloud_subscription": dataSourceRedisCloudProSubscription(), + "rediscloud_database": dataSourceRedisCloudProDatabase(), + "rediscloud_database_modules": dataSourceRedisCloudDatabaseModules(), + "rediscloud_payment_method": dataSourceRedisCloudPaymentMethod(), + "rediscloud_regions": dataSourceRedisCloudRegions(), + "rediscloud_essentials_plan": dataSourceRedisCloudEssentialsPlan(), + "rediscloud_essentials_subscription": dataSourceRedisCloudEssentialsSubscription(), + "rediscloud_essentials_database": dataSourceRedisCloudEssentialsDatabase(), + "rediscloud_subscription_peerings": dataSourceRedisCloudSubscriptionPeerings(), + "rediscloud_private_service_connect": dataSourcePrivateServiceConnect(), + "rediscloud_private_service_connect_endpoints": dataSourcePrivateServiceConnectEndpoints(), + "rediscloud_active_active_subscription": dataSourceRedisCloudActiveActiveSubscription(), + "rediscloud_active_active_subscription_regions": dataSourceRedisCloudActiveActiveSubscriptionRegions(), + // Note the difference in public data-source name and the file/method name. // active_active_subscription_database == active_active_database "rediscloud_active_active_subscription_database": dataSourceRedisCloudActiveActiveDatabase(), diff --git a/provider/rediscloud_active_active_database_test.go b/provider/rediscloud_active_active_database_test.go index 5802ef68..3b69ba2a 100644 --- a/provider/rediscloud_active_active_database_test.go +++ b/provider/rediscloud_active_active_database_test.go @@ -14,16 +14,15 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" ) -// Checks CRUDI (CREATE,READ,UPDATE,IMPORT) operations on the database resource. +// Checks CRUDI (CREATE, READ, UPDATE, IMPORT) operations on the database resource. func TestAccResourceRedisCloudActiveActiveDatabase_CRUDI(t *testing.T) { - testAccRequiresEnvVar(t, "EXECUTE_TESTS") - subscriptionName := acctest.RandomWithPrefix(testResourcePrefix) + "-subscription" - name := acctest.RandomWithPrefix(testResourcePrefix) + "-database" + databaseName := acctest.RandomWithPrefix(testResourcePrefix) + "-database" password := acctest.RandString(20) - const resourceName = "rediscloud_active_active_subscription_database.example" + const databaseResourceName = "rediscloud_active_active_subscription_database.example" const datasourceName = "data.rediscloud_active_active_subscription_database.example" + const datasourceRegionName = "data.rediscloud_active_active_subscription_regions.example" const subscriptionResourceName = "rediscloud_active_active_subscription.example" var subId int @@ -35,44 +34,44 @@ func TestAccResourceRedisCloudActiveActiveDatabase_CRUDI(t *testing.T) { Steps: []resource.TestStep{ // Test database creation { - Config: fmt.Sprintf(testAccResourceRedisCloudActiveActiveDatabase, subscriptionName, name, password), + Config: fmt.Sprintf(testAccResourceRedisCloudActiveActiveDatabase, subscriptionName, databaseName, password), Check: resource.ComposeAggregateTestCheckFunc( // Test resource - resource.TestCheckResourceAttr(resourceName, "name", name), - resource.TestCheckResourceAttr(resourceName, "dataset_size_in_gb", "3"), - resource.TestCheckResourceAttr(resourceName, "support_oss_cluster_api", "false"), - resource.TestCheckResourceAttr(resourceName, "global_data_persistence", "none"), - resource.TestCheckResourceAttr(resourceName, "external_endpoint_for_oss_cluster_api", "false"), - resource.TestCheckResourceAttr(resourceName, "global_password", password), - resource.TestCheckResourceAttr(resourceName, "enable_tls", "false"), - resource.TestCheckResourceAttr(resourceName, "data_eviction", "volatile-lru"), - resource.TestCheckResourceAttr(resourceName, "global_alert.#", "1"), - resource.TestCheckResourceAttr(resourceName, "global_alert.0.name", "dataset-size"), - resource.TestCheckResourceAttr(resourceName, "global_alert.0.value", "1"), - resource.TestCheckResourceAttr(resourceName, "global_modules.#", "1"), - resource.TestCheckResourceAttr(resourceName, "global_modules.0", "RedisJSON"), - resource.TestCheckResourceAttr(resourceName, "global_source_ips.#", "2"), - - resource.TestCheckResourceAttr(resourceName, "override_region.#", "2"), - resource.TestCheckResourceAttr(resourceName, "override_region.0.name", "us-east-1"), - resource.TestCheckResourceAttr(resourceName, "override_region.0.override_global_data_persistence", "aof-every-write"), - resource.TestCheckResourceAttr(resourceName, "override_region.0.override_global_password", "region-specific-password"), + resource.TestCheckResourceAttr(databaseResourceName, "name", databaseName), + resource.TestCheckResourceAttr(databaseResourceName, "dataset_size_in_gb", "3"), + resource.TestCheckResourceAttr(databaseResourceName, "support_oss_cluster_api", "false"), + resource.TestCheckResourceAttr(databaseResourceName, "global_data_persistence", "none"), + resource.TestCheckResourceAttr(databaseResourceName, "external_endpoint_for_oss_cluster_api", "false"), + resource.TestCheckResourceAttr(databaseResourceName, "global_password", password), + resource.TestCheckResourceAttr(databaseResourceName, "enable_tls", "false"), + resource.TestCheckResourceAttr(databaseResourceName, "data_eviction", "volatile-lru"), + resource.TestCheckResourceAttr(databaseResourceName, "global_alert.#", "1"), + resource.TestCheckResourceAttr(databaseResourceName, "global_alert.0.name", "dataset-size"), + resource.TestCheckResourceAttr(databaseResourceName, "global_alert.0.value", "1"), + resource.TestCheckResourceAttr(databaseResourceName, "global_modules.#", "1"), + resource.TestCheckResourceAttr(databaseResourceName, "global_modules.0", "RedisJSON"), + resource.TestCheckResourceAttr(databaseResourceName, "global_source_ips.#", "2"), + + resource.TestCheckResourceAttr(databaseResourceName, "override_region.#", "2"), + resource.TestCheckResourceAttr(databaseResourceName, "override_region.0.name", "us-east-1"), + resource.TestCheckResourceAttr(databaseResourceName, "override_region.0.override_global_data_persistence", "aof-every-write"), + resource.TestCheckResourceAttr(databaseResourceName, "override_region.0.override_global_password", "region-specific-password"), // check override region alert block - resource.TestCheckResourceAttr(resourceName, "override_region.0.override_global_alert.#", "1"), - resource.TestCheckResourceAttr(resourceName, "override_region.0.override_global_alert.0.name", "dataset-size"), - resource.TestCheckResourceAttr(resourceName, "override_region.0.override_global_alert.0.value", "42"), - resource.TestCheckResourceAttr(resourceName, "override_region.0.override_global_source_ips.#", "1"), - resource.TestCheckResourceAttr(resourceName, "override_region.0.override_global_source_ips.0", "192.175.0.0/16"), + resource.TestCheckResourceAttr(databaseResourceName, "override_region.0.override_global_alert.#", "1"), + resource.TestCheckResourceAttr(databaseResourceName, "override_region.0.override_global_alert.0.name", "dataset-size"), + resource.TestCheckResourceAttr(databaseResourceName, "override_region.0.override_global_alert.0.value", "42"), + resource.TestCheckResourceAttr(databaseResourceName, "override_region.0.override_global_source_ips.#", "1"), + resource.TestCheckResourceAttr(databaseResourceName, "override_region.0.override_global_source_ips.0", "192.175.0.0/16"), // Check that global values are used for the second region where no override is set - resource.TestCheckResourceAttr(resourceName, "override_region.1.name", "us-east-2"), - resource.TestCheckResourceAttr(resourceName, "override_region.1.override_global_data_persistence", ""), - resource.TestCheckResourceAttr(resourceName, "override_region.1.override_global_password", ""), - resource.TestCheckResourceAttr(resourceName, "override_region.1.override_global_alert.#", "0"), - resource.TestCheckResourceAttr(resourceName, "override_region.1.override_source_ips.#", "0"), + resource.TestCheckResourceAttr(databaseResourceName, "override_region.1.name", "us-east-2"), + resource.TestCheckResourceAttr(databaseResourceName, "override_region.1.override_global_data_persistence", ""), + resource.TestCheckResourceAttr(databaseResourceName, "override_region.1.override_global_password", ""), + resource.TestCheckResourceAttr(databaseResourceName, "override_region.1.override_global_alert.#", "0"), + resource.TestCheckResourceAttr(databaseResourceName, "override_region.1.override_source_ips.#", "0"), - resource.TestCheckResourceAttr(resourceName, "tags.deployment_family", "blue"), - resource.TestCheckResourceAttr(resourceName, "tags.priority", "code-2"), + resource.TestCheckResourceAttr(databaseResourceName, "tags.deployment_family", "blue"), + resource.TestCheckResourceAttr(databaseResourceName, "tags.priority", "code-2"), // Test databases exist func(s *terraform.State) error { @@ -105,10 +104,10 @@ func TestAccResourceRedisCloudActiveActiveDatabase_CRUDI(t *testing.T) { return nil }, - // Test datasource + // Test subscription datasource resource.TestCheckResourceAttrSet(datasourceName, "subscription_id"), resource.TestCheckResourceAttrSet(datasourceName, "db_id"), - resource.TestCheckResourceAttr(datasourceName, "name", name), + resource.TestCheckResourceAttr(datasourceName, "name", databaseName), resource.TestCheckResourceAttr(datasourceName, "dataset_size_in_gb", "3"), resource.TestCheckResourceAttr(datasourceName, "support_oss_cluster_api", "false"), resource.TestCheckResourceAttr(datasourceName, "external_endpoint_for_oss_cluster_api", "false"), @@ -119,34 +118,43 @@ func TestAccResourceRedisCloudActiveActiveDatabase_CRUDI(t *testing.T) { resource.TestCheckResourceAttr(datasourceName, "tags.deployment_family", "blue"), resource.TestCheckResourceAttr(datasourceName, "tags.priority", "code-2"), + + // Test the db region datasource + resource.TestCheckResourceAttr(datasourceRegionName, "subscription_name", subscriptionName), + resource.TestCheckResourceAttrSet(datasourceRegionName, "regions.0.vpc_id"), + resource.TestCheckResourceAttr(datasourceRegionName, "regions.0.region", "us-east-1"), + resource.TestCheckResourceAttr(datasourceRegionName, "regions.0.networking_deployment_cidr", "192.168.0.0/24"), + resource.TestCheckResourceAttrSet(datasourceRegionName, "regions.1.vpc_id"), + resource.TestCheckResourceAttr(datasourceRegionName, "regions.1.region", "us-east-2"), + resource.TestCheckResourceAttr(datasourceRegionName, "regions.1.networking_deployment_cidr", "10.0.1.0/24"), ), }, // Test database is updated successfully, including updates to both global and local alerts and clearing modules { - Config: fmt.Sprintf(testAccResourceRedisCloudActiveActiveDatabaseUpdate, subscriptionName, name), + Config: fmt.Sprintf(testAccResourceRedisCloudActiveActiveDatabaseUpdate, subscriptionName, databaseName), Check: resource.ComposeAggregateTestCheckFunc( // Test resource - resource.TestCheckResourceAttr(resourceName, "dataset_size_in_gb", "1"), - resource.TestCheckResourceAttr(resourceName, "support_oss_cluster_api", "true"), - resource.TestCheckResourceAttr(resourceName, "external_endpoint_for_oss_cluster_api", "true"), - resource.TestCheckResourceAttr(resourceName, "global_data_persistence", "aof-every-1-second"), - resource.TestCheckResourceAttr(resourceName, "global_password", "updated-password"), - resource.TestCheckResourceAttr(resourceName, "global_alert.#", "1"), - resource.TestCheckResourceAttr(resourceName, "global_alert.0.name", "dataset-size"), - resource.TestCheckResourceAttr(resourceName, "global_alert.0.value", "60"), + resource.TestCheckResourceAttr(databaseResourceName, "dataset_size_in_gb", "1"), + resource.TestCheckResourceAttr(databaseResourceName, "support_oss_cluster_api", "true"), + resource.TestCheckResourceAttr(databaseResourceName, "external_endpoint_for_oss_cluster_api", "true"), + resource.TestCheckResourceAttr(databaseResourceName, "global_data_persistence", "aof-every-1-second"), + resource.TestCheckResourceAttr(databaseResourceName, "global_password", "updated-password"), + resource.TestCheckResourceAttr(databaseResourceName, "global_alert.#", "1"), + resource.TestCheckResourceAttr(databaseResourceName, "global_alert.0.name", "dataset-size"), + resource.TestCheckResourceAttr(databaseResourceName, "global_alert.0.value", "60"), // Changes are ignored after creation - resource.TestCheckResourceAttr(resourceName, "global_modules.#", "1"), - resource.TestCheckResourceAttr(resourceName, "global_modules.0", "RedisJSON"), - - resource.TestCheckResourceAttr(resourceName, "override_region.#", "1"), - resource.TestCheckResourceAttr(resourceName, "override_region.0.name", "us-east-1"), - resource.TestCheckResourceAttr(resourceName, "override_region.0.override_global_data_persistence", "none"), - resource.TestCheckResourceAttr(resourceName, "override_region.0.override_global_password", "password-updated"), - resource.TestCheckResourceAttr(resourceName, "override_region.0.override_global_alert.#", "1"), - resource.TestCheckResourceAttr(resourceName, "override_region.0.override_global_alert.0.name", "dataset-size"), - resource.TestCheckResourceAttr(resourceName, "override_region.0.override_global_alert.0.value", "41"), - resource.TestCheckResourceAttr(resourceName, "override_region.0.override_global_source_ips.#", "0"), + resource.TestCheckResourceAttr(databaseResourceName, "global_modules.#", "1"), + resource.TestCheckResourceAttr(databaseResourceName, "global_modules.0", "RedisJSON"), + + resource.TestCheckResourceAttr(databaseResourceName, "override_region.#", "1"), + resource.TestCheckResourceAttr(databaseResourceName, "override_region.0.name", "us-east-1"), + resource.TestCheckResourceAttr(databaseResourceName, "override_region.0.override_global_data_persistence", "none"), + resource.TestCheckResourceAttr(databaseResourceName, "override_region.0.override_global_password", "password-updated"), + resource.TestCheckResourceAttr(databaseResourceName, "override_region.0.override_global_alert.#", "1"), + resource.TestCheckResourceAttr(databaseResourceName, "override_region.0.override_global_alert.0.name", "dataset-size"), + resource.TestCheckResourceAttr(databaseResourceName, "override_region.0.override_global_alert.0.value", "41"), + resource.TestCheckResourceAttr(databaseResourceName, "override_region.0.override_global_source_ips.#", "0"), // Test datasource resource.TestCheckResourceAttr(datasourceName, "dataset_size_in_gb", "1"), @@ -156,28 +164,28 @@ 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, name), + Config: fmt.Sprintf(testAccResourceRedisCloudActiveActiveDatabaseUpdateNoAlerts, subscriptionName, databaseName), Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "dataset_size_in_gb", "1"), - resource.TestCheckResourceAttr(resourceName, "support_oss_cluster_api", "true"), - resource.TestCheckResourceAttr(resourceName, "external_endpoint_for_oss_cluster_api", "true"), - resource.TestCheckResourceAttr(resourceName, "global_data_persistence", "aof-every-1-second"), - resource.TestCheckResourceAttr(resourceName, "global_password", "updated-password"), - resource.TestCheckResourceAttr(resourceName, "global_alert.#", "0"), - resource.TestCheckResourceAttr(resourceName, "global_modules.#", "1"), - resource.TestCheckResourceAttr(resourceName, "global_modules.0", "RedisJSON"), - - resource.TestCheckResourceAttr(resourceName, "override_region.#", "1"), - resource.TestCheckResourceAttr(resourceName, "override_region.0.name", "us-east-1"), - resource.TestCheckResourceAttr(resourceName, "override_region.0.override_global_data_persistence", "none"), - resource.TestCheckResourceAttr(resourceName, "override_region.0.override_global_password", "password-updated"), - resource.TestCheckResourceAttr(resourceName, "override_region.0.override_global_alert.#", "0"), - resource.TestCheckResourceAttr(resourceName, "override_region.0.override_global_source_ips.#", "0"), + resource.TestCheckResourceAttr(databaseResourceName, "dataset_size_in_gb", "1"), + resource.TestCheckResourceAttr(databaseResourceName, "support_oss_cluster_api", "true"), + resource.TestCheckResourceAttr(databaseResourceName, "external_endpoint_for_oss_cluster_api", "true"), + resource.TestCheckResourceAttr(databaseResourceName, "global_data_persistence", "aof-every-1-second"), + resource.TestCheckResourceAttr(databaseResourceName, "global_password", "updated-password"), + resource.TestCheckResourceAttr(databaseResourceName, "global_alert.#", "0"), + resource.TestCheckResourceAttr(databaseResourceName, "global_modules.#", "1"), + resource.TestCheckResourceAttr(databaseResourceName, "global_modules.0", "RedisJSON"), + + resource.TestCheckResourceAttr(databaseResourceName, "override_region.#", "1"), + resource.TestCheckResourceAttr(databaseResourceName, "override_region.0.name", "us-east-1"), + resource.TestCheckResourceAttr(databaseResourceName, "override_region.0.override_global_data_persistence", "none"), + resource.TestCheckResourceAttr(databaseResourceName, "override_region.0.override_global_password", "password-updated"), + resource.TestCheckResourceAttr(databaseResourceName, "override_region.0.override_global_alert.#", "0"), + resource.TestCheckResourceAttr(databaseResourceName, "override_region.0.override_global_source_ips.#", "0"), ), }, // Test that that database is imported successfully { - Config: fmt.Sprintf(testAccResourceRedisCloudActiveActiveDatabaseImport, subscriptionName, name), + Config: fmt.Sprintf(testAccResourceRedisCloudActiveActiveDatabaseImport, subscriptionName, databaseName), ResourceName: "rediscloud_active_active_subscription_database.example", ImportState: true, ImportStateVerify: true, @@ -317,11 +325,15 @@ resource "rediscloud_active_active_subscription_database" "example" { } } - +// data "rediscloud_active_active_subscription_database" "example" { subscription_id = rediscloud_active_active_subscription.example.id name = rediscloud_active_active_subscription_database.example.name } + +data "rediscloud_active_active_subscription_regions" "example" { + subscription_name = rediscloud_active_active_subscription.example.name +} ` // TF config for updating a database diff --git a/provider/rediscloud_active_active_subscription_test.go b/provider/rediscloud_active_active_subscription_test.go index 06d63faf..63c7d701 100644 --- a/provider/rediscloud_active_active_subscription_test.go +++ b/provider/rediscloud_active_active_subscription_test.go @@ -20,14 +20,16 @@ var activeActiveContractFlag = flag.Bool("activeActiveContract", false, var activeActiveMarketplaceFlag = flag.Bool("activeActiveMarketplace", false, "Add this flag '-activeActiveMarketplace' to run tests for marketplace associated accounts") -// Checks CRUDI (CREATE,READ,UPDATE,IMPORT) operations on the subscription resource. +// Checks CRUDI (CREATE, READ, UPDATE, IMPORT) operations on the subscription resource. +// Also checks active-active subscription regions. func TestAccResourceRedisCloudActiveActiveSubscription_CRUDI(t *testing.T) { - testAccRequiresEnvVar(t, "EXECUTE_TESTS") + //testAccRequiresEnvVar(t, "EXECUTE_TESTS") name := acctest.RandomWithPrefix(testResourcePrefix) const resourceName = "rediscloud_active_active_subscription.example" - const datasourceName = "data.rediscloud_active_active_subscription.example" + const datasourceSubscriptionName = "data.rediscloud_active_active_subscription.example" + const datasourceRegionName = "data.rediscloud_active_active_subscription_regions.example" var subId int @@ -37,7 +39,7 @@ func TestAccResourceRedisCloudActiveActiveSubscription_CRUDI(t *testing.T) { CheckDestroy: testAccCheckActiveActiveSubscriptionDestroy, Steps: []resource.TestStep{ { - Config: fmt.Sprintf(testAccResourceRedisCloudActiveActiveSubscription, name), + Config: fmt.Sprintf(testAccResourceRedisCloudActiveActiveSubscription, name, name), Check: resource.ComposeAggregateTestCheckFunc( // Test the resource resource.TestCheckResourceAttr(resourceName, "name", name), @@ -121,45 +123,57 @@ func TestAccResourceRedisCloudActiveActiveSubscription_CRUDI(t *testing.T) { return nil }, - // Test the datasource - resource.TestCheckResourceAttr(datasourceName, "name", name), - resource.TestCheckResourceAttr(datasourceName, "payment_method", "credit-card"), - resource.TestCheckResourceAttrSet(datasourceName, "payment_method_id"), - resource.TestCheckResourceAttr(datasourceName, "cloud_provider", "AWS"), - resource.TestCheckResourceAttr(datasourceName, "number_of_databases", "0"), - resource.TestCheckResourceAttr(datasourceName, "status", "active"), - - resource.TestCheckResourceAttr(datasourceName, "maintenance_windows.0.mode", "manual"), - resource.TestCheckResourceAttr(datasourceName, "maintenance_windows.0.window.#", "2"), - - resource.TestCheckResourceAttr(datasourceName, "maintenance_windows.0.window.0.start_hour", "22"), - resource.TestCheckResourceAttr(datasourceName, "maintenance_windows.0.window.0.duration_in_hours", "8"), - resource.TestCheckResourceAttr(datasourceName, "maintenance_windows.0.window.0.days.#", "2"), - resource.TestCheckResourceAttr(datasourceName, "maintenance_windows.0.window.0.days.0", "Monday"), - resource.TestCheckResourceAttr(datasourceName, "maintenance_windows.0.window.0.days.1", "Thursday"), - - resource.TestCheckResourceAttr(datasourceName, "maintenance_windows.0.window.1.start_hour", "12"), - resource.TestCheckResourceAttr(datasourceName, "maintenance_windows.0.window.1.duration_in_hours", "6"), - resource.TestCheckResourceAttr(datasourceName, "maintenance_windows.0.window.1.days.#", "3"), - resource.TestCheckResourceAttr(datasourceName, "maintenance_windows.0.window.1.days.0", "Friday"), - resource.TestCheckResourceAttr(datasourceName, "maintenance_windows.0.window.1.days.1", "Saturday"), - resource.TestCheckResourceAttr(datasourceName, "maintenance_windows.0.window.1.days.2", "Sunday"), - - resource.TestCheckResourceAttr(datasourceName, "pricing.#", "2"), - - resource.TestCheckResourceAttr(datasourceName, "pricing.0.type", "MinimumPrice"), - resource.TestCheckResourceAttr(datasourceName, "pricing.0.quantity", "1"), - resource.TestCheckResourceAttr(datasourceName, "pricing.0.quantity_measurement", "subscription"), - resource.TestCheckResourceAttrSet(datasourceName, "pricing.0.price_per_unit"), - resource.TestCheckResourceAttr(datasourceName, "pricing.0.price_currency", "USD"), - resource.TestCheckResourceAttr(datasourceName, "pricing.0.price_period", "hour"), - - resource.TestCheckResourceAttr(datasourceName, "pricing.1.type", "MinimumPrice"), - resource.TestCheckResourceAttr(datasourceName, "pricing.1.quantity", "1"), - resource.TestCheckResourceAttr(datasourceName, "pricing.1.quantity_measurement", "subscription"), - resource.TestCheckResourceAttrSet(datasourceName, "pricing.1.price_per_unit"), - resource.TestCheckResourceAttr(datasourceName, "pricing.1.price_currency", "USD"), - resource.TestCheckResourceAttr(datasourceName, "pricing.1.price_period", "hour"), + // Test the subscription datasource + resource.TestCheckResourceAttr(datasourceSubscriptionName, "name", name), + resource.TestCheckResourceAttr(datasourceSubscriptionName, "payment_method", "credit-card"), + resource.TestCheckResourceAttrSet(datasourceSubscriptionName, "payment_method_id"), + resource.TestCheckResourceAttr(datasourceSubscriptionName, "cloud_provider", "AWS"), + resource.TestCheckResourceAttr(datasourceSubscriptionName, "number_of_databases", "0"), + resource.TestCheckResourceAttr(datasourceSubscriptionName, "status", "active"), + + resource.TestCheckResourceAttr(datasourceSubscriptionName, "maintenance_windows.0.mode", "manual"), + resource.TestCheckResourceAttr(datasourceSubscriptionName, "maintenance_windows.0.window.#", "2"), + + resource.TestCheckResourceAttr(datasourceSubscriptionName, "maintenance_windows.0.window.0.start_hour", "22"), + resource.TestCheckResourceAttr(datasourceSubscriptionName, "maintenance_windows.0.window.0.duration_in_hours", "8"), + resource.TestCheckResourceAttr(datasourceSubscriptionName, "maintenance_windows.0.window.0.days.#", "2"), + resource.TestCheckResourceAttr(datasourceSubscriptionName, "maintenance_windows.0.window.0.days.0", "Monday"), + resource.TestCheckResourceAttr(datasourceSubscriptionName, "maintenance_windows.0.window.0.days.1", "Thursday"), + + resource.TestCheckResourceAttr(datasourceSubscriptionName, "maintenance_windows.0.window.1.start_hour", "12"), + resource.TestCheckResourceAttr(datasourceSubscriptionName, "maintenance_windows.0.window.1.duration_in_hours", "6"), + resource.TestCheckResourceAttr(datasourceSubscriptionName, "maintenance_windows.0.window.1.days.#", "3"), + resource.TestCheckResourceAttr(datasourceSubscriptionName, "maintenance_windows.0.window.1.days.0", "Friday"), + resource.TestCheckResourceAttr(datasourceSubscriptionName, "maintenance_windows.0.window.1.days.1", "Saturday"), + resource.TestCheckResourceAttr(datasourceSubscriptionName, "maintenance_windows.0.window.1.days.2", "Sunday"), + + resource.TestCheckResourceAttr(datasourceSubscriptionName, "pricing.#", "2"), + + resource.TestCheckResourceAttr(datasourceSubscriptionName, "pricing.0.type", "MinimumPrice"), + resource.TestCheckResourceAttr(datasourceSubscriptionName, "pricing.0.quantity", "1"), + resource.TestCheckResourceAttr(datasourceSubscriptionName, "pricing.0.quantity_measurement", "subscription"), + resource.TestCheckResourceAttrSet(datasourceSubscriptionName, "pricing.0.price_per_unit"), + resource.TestCheckResourceAttr(datasourceSubscriptionName, "pricing.0.price_currency", "USD"), + resource.TestCheckResourceAttr(datasourceSubscriptionName, "pricing.0.price_period", "hour"), + + resource.TestCheckResourceAttr(datasourceSubscriptionName, "pricing.1.type", "MinimumPrice"), + resource.TestCheckResourceAttr(datasourceSubscriptionName, "pricing.1.quantity", "1"), + resource.TestCheckResourceAttr(datasourceSubscriptionName, "pricing.1.quantity_measurement", "subscription"), + resource.TestCheckResourceAttrSet(datasourceSubscriptionName, "pricing.1.price_per_unit"), + resource.TestCheckResourceAttr(datasourceSubscriptionName, "pricing.1.price_currency", "USD"), + resource.TestCheckResourceAttr(datasourceSubscriptionName, "pricing.1.price_period", "hour"), + + // Test the region datasource + + resource.TestCheckResourceAttr(datasourceRegionName, "subscription_name", name), + //resource.TestCheckResourceAttrSet(datasourceRegionName, "regions.0.regionId"), + resource.TestCheckResourceAttr(datasourceRegionName, "regions.0.region", "us-east-1"), + resource.TestCheckResourceAttr(datasourceRegionName, "regions.0.networking_deployment_cidr", "192.168.0.0/24"), + resource.TestCheckResourceAttrSet(datasourceRegionName, "regions.0.vpc_id"), + //resource.TestCheckResourceAttrSet(datasourceRegionName, "regions.1.regionId"), + 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"), ), }, { @@ -183,8 +197,8 @@ func TestAccResourceRedisCloudActiveActiveSubscription_CRUDI(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "maintenance_windows.0.mode", "automatic"), resource.TestCheckResourceAttr(resourceName, "maintenance_windows.0.window.#", "0"), - resource.TestCheckResourceAttr(datasourceName, "maintenance_windows.0.mode", "automatic"), - resource.TestCheckResourceAttr(datasourceName, "maintenance_windows.0.window.#", "0"), + resource.TestCheckResourceAttr(datasourceSubscriptionName, "maintenance_windows.0.mode", "automatic"), + resource.TestCheckResourceAttr(datasourceSubscriptionName, "maintenance_windows.0.window.#", "0"), ), }, { @@ -335,46 +349,86 @@ data "rediscloud_payment_method" "card" { } resource "rediscloud_active_active_subscription" "example" { - name = "%s" - payment_method_id = data.rediscloud_payment_method.card.id - cloud_provider = "AWS" + 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 - } - } + 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"] - } - } + 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 = ` diff --git a/provider/resource_rediscloud_active_active_subscription_regions_test.go b/provider/resource_rediscloud_active_active_subscription_regions_test.go index ffe7b7a6..fb0138eb 100644 --- a/provider/resource_rediscloud_active_active_subscription_regions_test.go +++ b/provider/resource_rediscloud_active_active_subscription_regions_test.go @@ -20,6 +20,7 @@ func TestAccResourceRedisCloudActiveActiveSubscriptionRegions_CRUDI(t *testing.T dbName := acctest.RandomWithPrefix(testResourcePrefix) + "-regions" + "-db" dbPass := acctest.RandString(20) const resourceName = "rediscloud_active_active_subscription_regions.example" + const datasourceRegionName = "data.rediscloud_active_active_subscription_regions.example" var subId int @@ -39,6 +40,16 @@ func TestAccResourceRedisCloudActiveActiveSubscriptionRegions_CRUDI(t *testing.T resource.TestCheckResourceAttr(resourceName, "region.2.database.0.local_write_operations_per_second", "1500"), resource.TestCheckResourceAttr(resourceName, "region.2.database.0.local_read_operations_per_second", "1500"), + // Test the db regions datasource + resource.TestCheckResourceAttr(datasourceRegionName, "subscription_name", subName), + resource.TestCheckResourceAttrSet(datasourceRegionName, "regions.2.vpc_id"), + resource.TestCheckResourceAttr(datasourceRegionName, "regions.2.region", "us-west-2"), + resource.TestCheckResourceAttr(datasourceRegionName, "regions.2.networking_deployment_cidr", "10.2.0.0/24"), + resource.TestCheckResourceAttrSet(datasourceRegionName, "regions.2.databases.0.database_id"), + resource.TestCheckResourceAttr(datasourceRegionName, "regions.2.databases.0.database_name", dbName), + resource.TestCheckResourceAttr(datasourceRegionName, "regions.2.databases.0.read_operations_per_second", "1500"), + resource.TestCheckResourceAttr(datasourceRegionName, "regions.2.databases.0.write_operations_per_second", "1500"), + func(s *terraform.State) error { r := s.RootModule().Resources[resourceName] @@ -152,6 +163,10 @@ resource "rediscloud_active_active_subscription_database" "example" { } } +data "rediscloud_active_active_subscription_regions" "example" { + subscription_name = rediscloud_active_active_subscription.example.name +} + ` // TF config for provisioning a new region.