From ae54e897fb7a970aad60eb003742279c4236a8fe Mon Sep 17 00:00:00 2001 From: Trent Rosenbaum Date: Fri, 2 May 2025 08:36:14 +0100 Subject: [PATCH 01/27] Updates the service_attachments to reduce from 40 to 1 --- ...discloud_active_active_private_service_connect_endpoint.md | 2 +- docs/resources/rediscloud_private_service_connect_endpoint.md | 4 ++-- ...e_active_private_service_connect_endpoint_accepter_test.go | 2 +- ...oud_active_active_private_service_connect_endpoint_test.go | 2 +- ...discloud_private_service_connect_endpoint_accepter_test.go | 2 +- provider/resource_rediscloud_pro_database_test.go | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/resources/rediscloud_active_active_private_service_connect_endpoint.md b/docs/resources/rediscloud_active_active_private_service_connect_endpoint.md index f0e002f5..8bc2ac19 100644 --- a/docs/resources/rediscloud_active_active_private_service_connect_endpoint.md +++ b/docs/resources/rediscloud_active_active_private_service_connect_endpoint.md @@ -79,7 +79,7 @@ resource "rediscloud_active_active_subscription_regions" "regions" { } locals { - service_attachment_count = 40 # Each rediscloud_active_active_private_service_connect_endpoint will have exactly 40 service attachments + service_attachment_count = 1 # Each rediscloud_active_active_private_service_connect_endpoint will have exactly 1 service attachment region_id = one([for r in rediscloud_active_active_subscription_regions.regions.region : r.region_id if r.region == var.gcp_region]) } diff --git a/docs/resources/rediscloud_private_service_connect_endpoint.md b/docs/resources/rediscloud_private_service_connect_endpoint.md index 9757dc24..3acf6ecd 100644 --- a/docs/resources/rediscloud_private_service_connect_endpoint.md +++ b/docs/resources/rediscloud_private_service_connect_endpoint.md @@ -43,7 +43,7 @@ resource "rediscloud_subscription" "subscription" { } locals { - service_attachment_count = 40 # Each rediscloud_private_service_connect_endpoint will have exactly 40 service attachments + service_attachment_count = 1 # Each rediscloud_private_service_connect_endpoint will have exactly 1 service attachment } resource "rediscloud_private_service_connect" "service" { @@ -195,7 +195,7 @@ module "private_service_connect" { ## Attribute Reference * `private_service_connect_endpoint_id` - The ID of the Private Service Connect Endpoint -* `service_attachments` - The 40 service attachments that are created for the Private Service Connect endpoint, documented below +* `service_attachments` - The service attachment that is created for the Private Service Connect endpoint, documented below The `service_attachments` object has these attributes: diff --git a/provider/rediscloud_active_active_private_service_connect_endpoint_accepter_test.go b/provider/rediscloud_active_active_private_service_connect_endpoint_accepter_test.go index 82a3b9f1..c055c7fa 100644 --- a/provider/rediscloud_active_active_private_service_connect_endpoint_accepter_test.go +++ b/provider/rediscloud_active_active_private_service_connect_endpoint_accepter_test.go @@ -161,7 +161,7 @@ resource "google_compute_subnetwork" "subnet" { } locals { - service_attachment_count = 40 + service_attachment_count = 1 } resource "google_compute_address" "default" { diff --git a/provider/rediscloud_active_active_private_service_connect_endpoint_test.go b/provider/rediscloud_active_active_private_service_connect_endpoint_test.go index 21163a50..8145095d 100644 --- a/provider/rediscloud_active_active_private_service_connect_endpoint_test.go +++ b/provider/rediscloud_active_active_private_service_connect_endpoint_test.go @@ -48,7 +48,7 @@ func TestAccResourceRedisCloudActiveActivePrivateServiceConnectEndpoint_CRUDI(t } return nil }), - resource.TestCheckResourceAttr(datasourceName, "endpoints.0.service_attachments.#", "40"), + resource.TestCheckResourceAttr(datasourceName, "endpoints.0.service_attachments.#", "1"), ), }, { diff --git a/provider/rediscloud_private_service_connect_endpoint_accepter_test.go b/provider/rediscloud_private_service_connect_endpoint_accepter_test.go index 5680269e..a0a1ec86 100644 --- a/provider/rediscloud_private_service_connect_endpoint_accepter_test.go +++ b/provider/rediscloud_private_service_connect_endpoint_accepter_test.go @@ -122,7 +122,7 @@ resource "google_compute_subnetwork" "subnet" { } locals { - service_attachment_count = 40 + service_attachment_count = 1 } resource "google_compute_address" "default" { diff --git a/provider/resource_rediscloud_pro_database_test.go b/provider/resource_rediscloud_pro_database_test.go index e0455b84..ca158889 100644 --- a/provider/resource_rediscloud_pro_database_test.go +++ b/provider/resource_rediscloud_pro_database_test.go @@ -54,7 +54,7 @@ func TestAccResourceRedisCloudProDatabase_CRUDI(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "password", password), resource.TestCheckResourceAttr(resourceName, "alert.#", "1"), resource.TestCheckResourceAttr(resourceName, "alert.0.name", "dataset-size"), - resource.TestCheckResourceAttr(resourceName, "alert.0.value", "40"), + resource.TestCheckResourceAttr(resourceName, "alert.0.value", "1"), resource.TestCheckResourceAttr(resourceName, "modules.#", "1"), resource.TestCheckResourceAttr(resourceName, "modules.0.name", "RedisBloom"), resource.TestCheckResourceAttr(resourceName, "enable_default_user", "true"), From c8637dda3f273534f29484966871f9415323c7e1 Mon Sep 17 00:00:00 2001 From: Matthew Long Date: Tue, 6 May 2025 14:35:04 +0100 Subject: [PATCH 02/27] test: updating tests and docs to reflect fewer provider endpoints --- .../rediscloud_private_service_connect_endpoints.md | 2 +- docs/guides/migration-guide-v1.0.0.md | 4 ++-- .../rediscloud_active_active_subscription_database.md | 4 ++-- docs/resources/rediscloud_subscription_database.md | 4 ++-- provider/datasource_rediscloud_pro_subscription_test.go | 2 +- provider/rediscloud_active_active_database_test.go | 8 ++++---- .../rediscloud_private_service_connect_endpoint_test.go | 2 +- ..._rediscloud_active_active_subscription_regions_test.go | 2 +- provider/resource_rediscloud_pro_database_test.go | 2 +- 9 files changed, 15 insertions(+), 15 deletions(-) diff --git a/docs/data-sources/rediscloud_private_service_connect_endpoints.md b/docs/data-sources/rediscloud_private_service_connect_endpoints.md index c2bbce9c..529110e0 100644 --- a/docs/data-sources/rediscloud_private_service_connect_endpoints.md +++ b/docs/data-sources/rediscloud_private_service_connect_endpoints.md @@ -39,7 +39,7 @@ The `endpoints` object has these attributes: * `gcp_vpc_subnet_name` - The GCP Subnet name * `endpoint_connection_name` - The endpoint connection name * `status` - The endpoint status -* `service_attachments` - The 40 service attachments that are created for the Private Service Connect endpoint, documented below +* `service_attachments` - The service attachments that are created for the Private Service Connect endpoint, documented below The `service_attachments` object has these attributes: diff --git a/docs/guides/migration-guide-v1.0.0.md b/docs/guides/migration-guide-v1.0.0.md index aafe5c98..c2540170 100644 --- a/docs/guides/migration-guide-v1.0.0.md +++ b/docs/guides/migration-guide-v1.0.0.md @@ -70,7 +70,7 @@ resource "rediscloud_subscription" "example" { alert { name = "dataset-size" - value = 40 + value = 1 } } } @@ -132,7 +132,7 @@ To use the latest schema, you need to modify the `rediscloud_subscription` resou alert { name = "dataset-size" - value = 40 + value = 1 } } ``` diff --git a/docs/resources/rediscloud_active_active_subscription_database.md b/docs/resources/rediscloud_active_active_subscription_database.md index fc930a40..204acfdb 100644 --- a/docs/resources/rediscloud_active_active_subscription_database.md +++ b/docs/resources/rediscloud_active_active_subscription_database.md @@ -50,7 +50,7 @@ resource "rediscloud_active_active_subscription_database" "database-resource" { global_source_ips = ["192.168.0.0/16"] global_alert { name = "dataset-size" - value = 40 + value = 1 } global_modules = ["RedisJSON"] @@ -161,4 +161,4 @@ To update an existing configuration for a database which uses the `memory_limit_ $ terraform state rm rediscloud_active_active_subscription_database.database-resource (Update the configuration to use `dataset_size_in_gb` instead of `memory_limit_in_gb`) $ terraform import rediscloud_active_active_subscription_database.database-resource 123456/12345678 -``` \ No newline at end of file +``` diff --git a/docs/resources/rediscloud_subscription_database.md b/docs/resources/rediscloud_subscription_database.md index 6362b915..f4ef95a2 100644 --- a/docs/resources/rediscloud_subscription_database.md +++ b/docs/resources/rediscloud_subscription_database.md @@ -65,7 +65,7 @@ resource "rediscloud_subscription_database" "database-resource" { alert { name = "dataset-size" - value = 40 + value = 1 } tags = { @@ -171,4 +171,4 @@ To update an existing configuration for a database which uses the `memory_limit_ $ terraform state rm rediscloud_subscription_database.database-resource (Update the configuration to use `dataset_size_in_gb` instead of `memory_limit_in_gb`) $ terraform import rediscloud_subscription_database.database-resource 123456/12345678 -``` \ No newline at end of file +``` diff --git a/provider/datasource_rediscloud_pro_subscription_test.go b/provider/datasource_rediscloud_pro_subscription_test.go index f9ba9ffd..147e6f90 100644 --- a/provider/datasource_rediscloud_pro_subscription_test.go +++ b/provider/datasource_rediscloud_pro_subscription_test.go @@ -167,7 +167,7 @@ resource "rediscloud_active_active_subscription_database" "example" { global_source_ips = ["192.168.0.0/16", "192.170.0.0/16"] global_alert { name = "dataset-size" - value = 40 + value = 1 } override_region { name = "us-east-1" diff --git a/provider/rediscloud_active_active_database_test.go b/provider/rediscloud_active_active_database_test.go index 54693057..5802ef68 100644 --- a/provider/rediscloud_active_active_database_test.go +++ b/provider/rediscloud_active_active_database_test.go @@ -48,7 +48,7 @@ func TestAccResourceRedisCloudActiveActiveDatabase_CRUDI(t *testing.T) { 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", "40"), + 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"), @@ -294,7 +294,7 @@ resource "rediscloud_active_active_subscription_database" "example" { global_source_ips = ["192.168.0.0/16", "192.170.0.0/16"] global_alert { name = "dataset-size" - value = 40 + value = 1 } global_modules = ["RedisJSON"] override_region { @@ -433,7 +433,7 @@ resource "rediscloud_active_active_subscription_database" "example" { global_source_ips = ["192.168.0.0/16", "192.170.0.0/16"] global_alert { name = "dataset-size" - value = 40 + value = 1 } override_region { name = "us-east-1" @@ -466,7 +466,7 @@ resource "rediscloud_active_active_subscription_database" "example" { global_source_ips = ["192.168.0.0/16", "192.170.0.0/16"] global_alert { name = "dataset-size" - value = 40 + value = 1 } override_region { name = "us-east-1" diff --git a/provider/rediscloud_private_service_connect_endpoint_test.go b/provider/rediscloud_private_service_connect_endpoint_test.go index 46351f96..848b3db1 100644 --- a/provider/rediscloud_private_service_connect_endpoint_test.go +++ b/provider/rediscloud_private_service_connect_endpoint_test.go @@ -48,7 +48,7 @@ func TestAccResourceRedisCloudPrivateServiceConnectEndpoint_CRUDI(t *testing.T) } return nil }), - resource.TestCheckResourceAttr(datasourceName, "endpoints.0.service_attachments.#", "40"), + resource.TestCheckResourceAttr(datasourceName, "endpoints.0.service_attachments.#", "1"), ), }, { diff --git a/provider/resource_rediscloud_active_active_subscription_regions_test.go b/provider/resource_rediscloud_active_active_subscription_regions_test.go index 69ef3a27..ffe7b7a6 100644 --- a/provider/resource_rediscloud_active_active_subscription_regions_test.go +++ b/provider/resource_rediscloud_active_active_subscription_regions_test.go @@ -148,7 +148,7 @@ resource "rediscloud_active_active_subscription_database" "example" { global_password = "%s" global_alert { name = "dataset-size" - value = 40 + value = 1 } } diff --git a/provider/resource_rediscloud_pro_database_test.go b/provider/resource_rediscloud_pro_database_test.go index ca158889..c284efa4 100644 --- a/provider/resource_rediscloud_pro_database_test.go +++ b/provider/resource_rediscloud_pro_database_test.go @@ -376,7 +376,7 @@ resource "rediscloud_subscription_database" "example" { alert { name = "dataset-size" - value = 40 + value = 1 } modules = [ From bad0b713e16cd24741437bf29ad76bb589b64de3 Mon Sep 17 00:00:00 2001 From: Matthew Long Date: Wed, 19 Mar 2025 16:04:56 +0000 Subject: [PATCH 03/27] feat: adding in support for query performance factors on affected resources --- go.mod | 2 ++ go.sum | 2 -- .../datasource_rediscloud_pro_database.go | 6 +++++ ...datasource_rediscloud_pro_database_test.go | 3 +++ ...iscloud_active_active_subscription_test.go | 3 +++ ...ource_rediscloud_active_active_database.go | 4 +++ ...e_rediscloud_active_active_subscription.go | 12 +++++++-- provider/resource_rediscloud_pro_database.go | 27 ++++++++++++------- .../resource_rediscloud_pro_subscription.go | 20 ++++++++++---- 9 files changed, 61 insertions(+), 18 deletions(-) diff --git a/go.mod b/go.mod index 0a9ba814..70a9a2e3 100644 --- a/go.mod +++ b/go.mod @@ -66,3 +66,5 @@ require ( google.golang.org/protobuf v1.36.3 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) + +replace github.com/RedisLabs/rediscloud-go-api => ../rediscloud-go-api diff --git a/go.sum b/go.sum index 476114d8..48d5c125 100644 --- a/go.sum +++ b/go.sum @@ -4,8 +4,6 @@ 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/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_pro_database.go b/provider/datasource_rediscloud_pro_database.go index 01b20e1b..55a3036c 100644 --- a/provider/datasource_rediscloud_pro_database.go +++ b/provider/datasource_rediscloud_pro_database.go @@ -59,6 +59,12 @@ func dataSourceRedisCloudProDatabase() *schema.Resource { Type: schema.TypeFloat, Computed: true, }, + "query_performance_factor": { + Description: "Query performance factor for this specific database", + Type: schema.TypeString, + Optional: true, + Computed: true, + }, "support_oss_cluster_api": { Description: "Supports the Redis open-source (OSS) Cluster API", Type: schema.TypeBool, diff --git a/provider/datasource_rediscloud_pro_database_test.go b/provider/datasource_rediscloud_pro_database_test.go index 1695cf1b..d28ac3d5 100644 --- a/provider/datasource_rediscloud_pro_database_test.go +++ b/provider/datasource_rediscloud_pro_database_test.go @@ -43,6 +43,7 @@ func TestAccDataSourceRedisCloudProDatabase_basic(t *testing.T) { resource.TestCheckResourceAttrSet(dataSourceById, "public_endpoint"), resource.TestCheckResourceAttrSet(dataSourceById, "private_endpoint"), resource.TestCheckResourceAttr(dataSourceById, "enable_default_user", "true"), + resource.TestCheckResourceAttr(dataSourceById, "query_performance_factor", "4x"), resource.TestCheckResourceAttr(dataSourceByName, "name", "tf-database"), resource.TestCheckResourceAttr(dataSourceByName, "protocol", "redis"), @@ -59,6 +60,7 @@ func TestAccDataSourceRedisCloudProDatabase_basic(t *testing.T) { resource.TestCheckResourceAttrSet(dataSourceByName, "public_endpoint"), resource.TestCheckResourceAttrSet(dataSourceByName, "private_endpoint"), resource.TestCheckResourceAttr(dataSourceByName, "enable_default_user", "true"), + resource.TestCheckResourceAttr(dataSourceByName, "query_performance_factor", "4x"), ), }, }, @@ -108,6 +110,7 @@ resource "rediscloud_subscription_database" "example" { support_oss_cluster_api = true replication = false enable_default_user = true + query_performance_factor = "" } data "rediscloud_database" "example-by-id" { diff --git a/provider/rediscloud_active_active_subscription_test.go b/provider/rediscloud_active_active_subscription_test.go index 06d63faf..27301239 100644 --- a/provider/rediscloud_active_active_subscription_test.go +++ b/provider/rediscloud_active_active_subscription_test.go @@ -45,6 +45,7 @@ func TestAccResourceRedisCloudActiveActiveSubscription_CRUDI(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "cloud_provider", "AWS"), resource.TestCheckResourceAttr(resourceName, "creation_plan.#", "1"), resource.TestCheckResourceAttr(resourceName, "creation_plan.0.memory_limit_in_gb", "1"), + resource.TestCheckResourceAttr(resourceName, "creation_plan.0.query_performance_factor", "4x"), resource.TestCheckResourceAttr(resourceName, "creation_plan.0.quantity", "1"), resource.TestCheckResourceAttr(resourceName, "creation_plan.0.modules.#", "1"), resource.TestCheckResourceAttr(resourceName, "creation_plan.0.modules.0", "RedisJSON"), @@ -170,6 +171,7 @@ func TestAccResourceRedisCloudActiveActiveSubscription_CRUDI(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "cloud_provider", "AWS"), resource.TestCheckResourceAttr(resourceName, "creation_plan.#", "1"), resource.TestCheckResourceAttr(resourceName, "creation_plan.0.memory_limit_in_gb", "1"), + resource.TestCheckResourceAttr(resourceName, "creation_plan.0.query_performance_factor", "4x"), resource.TestCheckResourceAttr(resourceName, "creation_plan.0.quantity", "1"), resource.TestCheckResourceAttr(resourceName, "creation_plan.0.modules.#", "1"), resource.TestCheckResourceAttr(resourceName, "creation_plan.0.modules.0", "RedisJSON"), @@ -341,6 +343,7 @@ resource "rediscloud_active_active_subscription" "example" { creation_plan { memory_limit_in_gb = 1 + query_performance_factor = "2x" modules = ["RedisJSON"] quantity = 1 region { diff --git a/provider/resource_rediscloud_active_active_database.go b/provider/resource_rediscloud_active_active_database.go index 1776278a..a658a3ad 100644 --- a/provider/resource_rediscloud_active_active_database.go +++ b/provider/resource_rediscloud_active_active_database.go @@ -419,6 +419,10 @@ func resourceRedisCloudActiveActiveDatabaseCreate(ctx context.Context, d *schema createDatabase.MemoryLimitInGB = redis.Float64(v.(float64)) } + if v, ok := d.GetOk("query_performance_factor"); ok { + createDatabase.QueryPerformanceFactor = redis.String(v.(string)) + } + if v, ok := d.GetOk("port"); ok { createDatabase.PortNumber = redis.Int(v.(int)) } diff --git a/provider/resource_rediscloud_active_active_subscription.go b/provider/resource_rediscloud_active_active_subscription.go index 731af1e3..615a16b4 100644 --- a/provider/resource_rediscloud_active_active_subscription.go +++ b/provider/resource_rediscloud_active_active_subscription.go @@ -112,6 +112,11 @@ func resourceRedisCloudActiveActiveSubscription() *schema.Resource { Optional: true, ConflictsWith: []string{"creation_plan.0.memory_limit_in_gb"}, }, + "query_performance_factor": { + Description: "Query performance factor for this specific database", + Type: schema.TypeString, + Optional: true, + }, "quantity": { Description: "The planned number of databases", Type: schema.TypeInt, @@ -647,14 +652,16 @@ func buildSubscriptionCreatePlanAADatabases(planMap map[string]interface{}) []*s createModules = append(createModules, createModule) } + queryPerformanceFactor := planMap["queryPerformanceFactor"].(string) + // create the remaining DBs with all other modules - createDatabases = append(createDatabases, createAADatabase(dbName, &idx, localThroughputs, numDatabases, memoryLimitInGB, datasetSizeInGB, createModules)...) + createDatabases = append(createDatabases, createAADatabase(dbName, &idx, localThroughputs, numDatabases, memoryLimitInGB, datasetSizeInGB, createModules, queryPerformanceFactor)...) return createDatabases } // createDatabase returns a CreateDatabase struct with the given parameters -func createAADatabase(dbName string, idx *int, localThroughputs []*subscriptions.CreateLocalThroughput, numDatabases int, memoryLimitInGB float64, datasetSizeInGB float64, modules []*subscriptions.CreateModules) []*subscriptions.CreateDatabase { +func createAADatabase(dbName string, idx *int, localThroughputs []*subscriptions.CreateLocalThroughput, numDatabases int, memoryLimitInGB float64, datasetSizeInGB float64, modules []*subscriptions.CreateModules, queryPerformanceFactor string) []*subscriptions.CreateDatabase { var dbs []*subscriptions.CreateDatabase for i := 0; i < numDatabases; i++ { createDatabase := subscriptions.CreateDatabase{ @@ -663,6 +670,7 @@ func createAADatabase(dbName string, idx *int, localThroughputs []*subscriptions LocalThroughputMeasurement: localThroughputs, Quantity: redis.Int(1), Modules: modules, + QueryPerformanceFactor: redis.String(queryPerformanceFactor), } if datasetSizeInGB > 0 { createDatabase.DatasetSizeInGB = redis.Float64(datasetSizeInGB) diff --git a/provider/resource_rediscloud_pro_database.go b/provider/resource_rediscloud_pro_database.go index b6dfc7d5..aa850e76 100644 --- a/provider/resource_rediscloud_pro_database.go +++ b/provider/resource_rediscloud_pro_database.go @@ -91,6 +91,12 @@ func resourceRedisCloudProDatabase() *schema.Resource { Computed: true, ExactlyOneOf: []string{"memory_limit_in_gb", "dataset_size_in_gb"}, }, + "query_performance_factor": { + Description: "Query performance factor for this specific database", + Type: schema.TypeString, + Optional: true, + Computed: true, + }, "support_oss_cluster_api": { Description: "Support Redis open-source (OSS) Cluster API", Type: schema.TypeBool, @@ -341,6 +347,7 @@ func resourceRedisCloudProDatabaseCreate(ctx context.Context, d *schema.Resource throughputMeasurementBy := d.Get("throughput_measurement_by").(string) throughputMeasurementValue := d.Get("throughput_measurement_value").(int) averageItemSizeInBytes := d.Get("average_item_size_in_bytes").(int) + queryPerformanceFactor := d.Get("query_performance_factor").(string) createModules := make([]*databases.Module, 0) modules := d.Get("modules").(*schema.Set) @@ -383,9 +390,10 @@ func resourceRedisCloudProDatabaseCreate(ctx context.Context, d *schema.Resource By: redis.String(throughputMeasurementBy), Value: redis.Int(throughputMeasurementValue), }, - Modules: createModules, - Alerts: createAlerts, - RemoteBackup: buildBackupPlan(d.Get("remote_backup").([]interface{}), d.Get("periodic_backup_path")), + Modules: createModules, + Alerts: createAlerts, + RemoteBackup: buildBackupPlan(d.Get("remote_backup").([]interface{}), d.Get("periodic_backup_path")), + QueryPerformanceFactor: redis.String(queryPerformanceFactor), } if password != "" { @@ -659,12 +667,13 @@ func resourceRedisCloudProDatabaseUpdate(ctx context.Context, d *schema.Resource By: redis.String(d.Get("throughput_measurement_by").(string)), Value: redis.Int(d.Get("throughput_measurement_value").(int)), }, - DataPersistence: redis.String(d.Get("data_persistence").(string)), - DataEvictionPolicy: redis.String(d.Get("data_eviction").(string)), - SourceIP: setToStringSlice(d.Get("source_ips").(*schema.Set)), - Alerts: &alerts, - RemoteBackup: buildBackupPlan(d.Get("remote_backup").([]interface{}), d.Get("periodic_backup_path")), - EnableDefaultUser: redis.Bool(d.Get("enable_default_user").(bool)), + DataPersistence: redis.String(d.Get("data_persistence").(string)), + DataEvictionPolicy: redis.String(d.Get("data_eviction").(string)), + SourceIP: setToStringSlice(d.Get("source_ips").(*schema.Set)), + Alerts: &alerts, + RemoteBackup: buildBackupPlan(d.Get("remote_backup").([]interface{}), d.Get("periodic_backup_path")), + EnableDefaultUser: redis.Bool(d.Get("enable_default_user").(bool)), + QueryPerformanceFactor: redis.String(d.Get("query_performance_factor").(string)), } // One of the following fields must be set, validation is handled in the schema (ExactlyOneOf) diff --git a/provider/resource_rediscloud_pro_subscription.go b/provider/resource_rediscloud_pro_subscription.go index 922606c4..5fae7ed6 100644 --- a/provider/resource_rediscloud_pro_subscription.go +++ b/provider/resource_rediscloud_pro_subscription.go @@ -798,6 +798,11 @@ func buildSubscriptionCreatePlanDatabases(memoryStorage string, planMap map[stri datasetSizeInGB = v.(float64) } + queryPerformanceFactor := "" + if v, ok := planMap["queryPerformanceFactor"]; ok && v != nil { + queryPerformanceFactor = v.(string) + } + var diags diag.Diagnostics if memoryStorage == databases.MemoryStorageRam && averageItemSizeInBytes != 0 { // TODO This should be changed to an error when releasing 2.0 of the provider @@ -824,7 +829,7 @@ func buildSubscriptionCreatePlanDatabases(memoryStorage string, planMap map[stri for _, v := range planModules { modules = append(modules, &subscriptions.CreateModules{Name: v}) } - createDatabases = append(createDatabases, createDatabase(dbName, &idx, modules, throughputMeasurementBy, throughputMeasurementValue, memoryLimitInGB, datasetSizeInGB, averageItemSizeInBytes, supportOSSClusterAPI, replication, numDatabases)...) + createDatabases = append(createDatabases, createDatabase(dbName, &idx, modules, throughputMeasurementBy, throughputMeasurementValue, memoryLimitInGB, datasetSizeInGB, averageItemSizeInBytes, supportOSSClusterAPI, replication, numDatabases, queryPerformanceFactor)...) } else { // make RedisGraph module the first module, then append the rest of the modules var modules []*subscriptions.CreateModules @@ -835,20 +840,20 @@ func buildSubscriptionCreatePlanDatabases(memoryStorage string, planMap map[stri } } // create a DB with the RedisGraph module - createDatabases = append(createDatabases, createDatabase(dbName, &idx, modules[:1], throughputMeasurementBy, throughputMeasurementValue, memoryLimitInGB, datasetSizeInGB, averageItemSizeInBytes, supportOSSClusterAPI, replication, 1)...) + createDatabases = append(createDatabases, createDatabase(dbName, &idx, modules[:1], throughputMeasurementBy, throughputMeasurementValue, memoryLimitInGB, datasetSizeInGB, averageItemSizeInBytes, supportOSSClusterAPI, replication, 1, queryPerformanceFactor)...) if numDatabases == 1 { // create one extra DB with all other modules - createDatabases = append(createDatabases, createDatabase(dbName, &idx, modules[1:], throughputMeasurementBy, throughputMeasurementValue, memoryLimitInGB, datasetSizeInGB, averageItemSizeInBytes, supportOSSClusterAPI, replication, 1)...) + createDatabases = append(createDatabases, createDatabase(dbName, &idx, modules[1:], throughputMeasurementBy, throughputMeasurementValue, memoryLimitInGB, datasetSizeInGB, averageItemSizeInBytes, supportOSSClusterAPI, replication, 1, queryPerformanceFactor)...) } else if numDatabases > 1 { // create the remaining DBs with all other modules - createDatabases = append(createDatabases, createDatabase(dbName, &idx, modules[1:], throughputMeasurementBy, throughputMeasurementValue, memoryLimitInGB, datasetSizeInGB, averageItemSizeInBytes, supportOSSClusterAPI, replication, numDatabases-1)...) + createDatabases = append(createDatabases, createDatabase(dbName, &idx, modules[1:], throughputMeasurementBy, throughputMeasurementValue, memoryLimitInGB, datasetSizeInGB, averageItemSizeInBytes, supportOSSClusterAPI, replication, numDatabases-1, queryPerformanceFactor)...) } } return createDatabases, diags } // createDatabase returns a CreateDatabase struct with the given parameters -func createDatabase(dbName string, idx *int, modules []*subscriptions.CreateModules, throughputMeasurementBy string, throughputMeasurementValue int, memoryLimitInGB float64, datasetSizeInGB float64, averageItemSizeInBytes int, supportOSSClusterAPI bool, replication bool, numDatabases int) []*subscriptions.CreateDatabase { +func createDatabase(dbName string, idx *int, modules []*subscriptions.CreateModules, throughputMeasurementBy string, throughputMeasurementValue int, memoryLimitInGB float64, datasetSizeInGB float64, averageItemSizeInBytes int, supportOSSClusterAPI bool, replication bool, numDatabases int, queryPerformanceFactor string) []*subscriptions.CreateDatabase { createThroughput := &subscriptions.CreateThroughput{ By: redis.String(throughputMeasurementBy), Value: redis.Int(throughputMeasurementValue), @@ -887,6 +892,11 @@ func createDatabase(dbName string, idx *int, modules []*subscriptions.CreateModu if memoryLimitInGB > 0 { createDatabase.MemoryLimitInGB = redis.Float64(memoryLimitInGB) } + + if queryPerformanceFactor != "" { + createDatabase.QueryPerformanceFactor = redis.String(queryPerformanceFactor) + } + *idx++ dbs = append(dbs, &createDatabase) } From a626de89682f7ae62d02aabe7fc1168d750f3c84 Mon Sep 17 00:00:00 2001 From: Matthew Long Date: Mon, 24 Mar 2025 11:04:30 +0000 Subject: [PATCH 04/27] fix: missing schema for pro sub creation plan --- provider/resource_rediscloud_pro_subscription.go | 5 +++++ provider/resource_rediscloud_pro_subscription_test.go | 11 ++++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/provider/resource_rediscloud_pro_subscription.go b/provider/resource_rediscloud_pro_subscription.go index 5fae7ed6..3c8c2b41 100644 --- a/provider/resource_rediscloud_pro_subscription.go +++ b/provider/resource_rediscloud_pro_subscription.go @@ -255,6 +255,11 @@ func resourceRedisCloudProSubscription() *schema.Resource { Optional: true, ConflictsWith: []string{"creation_plan.0.memory_limit_in_gb"}, }, + "query_performance_factor": { + Description: "Query performance factor for this specific database", + Type: schema.TypeString, + Optional: true, + }, "throughput_measurement_by": { Description: "Throughput measurement method, (either ‘number-of-shards’ or ‘operations-per-second’)", Type: schema.TypeString, diff --git a/provider/resource_rediscloud_pro_subscription_test.go b/provider/resource_rediscloud_pro_subscription_test.go index 6d839cc1..d16e0311 100644 --- a/provider/resource_rediscloud_pro_subscription_test.go +++ b/provider/resource_rediscloud_pro_subscription_test.go @@ -51,9 +51,12 @@ func TestAccResourceRedisCloudProSubscription_CRUDI(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "creation_plan.#", "1"), resource.TestCheckResourceAttr(resourceName, "creation_plan.0.average_item_size_in_bytes", "0"), resource.TestCheckResourceAttr(resourceName, "creation_plan.0.dataset_size_in_gb", "1"), + resource.TestCheckResourceAttr(resourceName, "creation_plan.0.query_performance_factor", "4x"), + resource.TestCheckResourceAttr(resourceName, "creation_plan.0.modules.#", "2"), resource.TestCheckResourceAttr(resourceName, "creation_plan.0.modules.0", "RedisJSON"), resource.TestCheckResourceAttr(resourceName, "creation_plan.0.modules.1", "RedisBloom"), + resource.TestCheckResourceAttr(resourceName, "creation_plan.0.modules.2", "RediSearch"), resource.TestCheckResourceAttr(resourceName, "creation_plan.0.quantity", "1"), resource.TestCheckResourceAttr(resourceName, "creation_plan.0.replication", "false"), resource.TestCheckResourceAttr(resourceName, "creation_plan.0.support_oss_cluster_api", "false"), @@ -756,11 +759,13 @@ resource "rediscloud_subscription" "example" { creation_plan { dataset_size_in_gb = 1 quantity = 1 - replication=false - support_oss_cluster_api=false + replication = false + support_oss_cluster_api = false + query_performance_factor = "4x" + throughput_measurement_by = "operations-per-second" throughput_measurement_value = 10000 - modules = ["RedisJSON", "RedisBloom"] + modules = ["RedisJSON", "RedisBloom", "RediSearch"] } } ` From b55c2d8e99954d1ef9e22e4eae7e3ad33e61fda4 Mon Sep 17 00:00:00 2001 From: Trent Rosenbaum Date: Tue, 25 Mar 2025 09:39:47 +0000 Subject: [PATCH 05/27] Update TestAccDataSourceRedisCloudProDatabase_basic config with RediSearch module and 2x QPF --- provider/datasource_rediscloud_pro_database_test.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/provider/datasource_rediscloud_pro_database_test.go b/provider/datasource_rediscloud_pro_database_test.go index d28ac3d5..d5e1ab09 100644 --- a/provider/datasource_rediscloud_pro_database_test.go +++ b/provider/datasource_rediscloud_pro_database_test.go @@ -96,6 +96,7 @@ resource "rediscloud_subscription" "example" { support_oss_cluster_api=true throughput_measurement_by = "operations-per-second" throughput_measurement_value = 1000 + modules = ["RediSearch"] } } resource "rediscloud_subscription_database" "example" { @@ -110,7 +111,12 @@ resource "rediscloud_subscription_database" "example" { support_oss_cluster_api = true replication = false enable_default_user = true - query_performance_factor = "" + query_performance_factor = "2x" + modules = [ + { + name: "RediSearch" + } + ] } data "rediscloud_database" "example-by-id" { From 13a88a5f79c0d72613c8c5d72b4eee217be671a6 Mon Sep 17 00:00:00 2001 From: Trent Rosenbaum Date: Tue, 25 Mar 2025 13:25:45 +0000 Subject: [PATCH 06/27] Updates datasource_rediscloud_pro_database_test to use a QPF of 2x --- provider/datasource_rediscloud_pro_database_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/provider/datasource_rediscloud_pro_database_test.go b/provider/datasource_rediscloud_pro_database_test.go index d5e1ab09..9b0ecc5a 100644 --- a/provider/datasource_rediscloud_pro_database_test.go +++ b/provider/datasource_rediscloud_pro_database_test.go @@ -43,7 +43,7 @@ func TestAccDataSourceRedisCloudProDatabase_basic(t *testing.T) { resource.TestCheckResourceAttrSet(dataSourceById, "public_endpoint"), resource.TestCheckResourceAttrSet(dataSourceById, "private_endpoint"), resource.TestCheckResourceAttr(dataSourceById, "enable_default_user", "true"), - resource.TestCheckResourceAttr(dataSourceById, "query_performance_factor", "4x"), + resource.TestCheckResourceAttr(dataSourceById, "query_performance_factor", "2x"), resource.TestCheckResourceAttr(dataSourceByName, "name", "tf-database"), resource.TestCheckResourceAttr(dataSourceByName, "protocol", "redis"), @@ -60,7 +60,7 @@ func TestAccDataSourceRedisCloudProDatabase_basic(t *testing.T) { resource.TestCheckResourceAttrSet(dataSourceByName, "public_endpoint"), resource.TestCheckResourceAttrSet(dataSourceByName, "private_endpoint"), resource.TestCheckResourceAttr(dataSourceByName, "enable_default_user", "true"), - resource.TestCheckResourceAttr(dataSourceByName, "query_performance_factor", "4x"), + resource.TestCheckResourceAttr(dataSourceByName, "query_performance_factor", "2x"), ), }, }, From e4d3eec9524a87bb7e62140f6be6e96da7f34982 Mon Sep 17 00:00:00 2001 From: Trent Rosenbaum Date: Tue, 25 Mar 2025 15:34:31 +0000 Subject: [PATCH 07/27] Reverts AA subs to not use query_performance_factor as not supported --- .../rediscloud_active_active_subscription_test.go | 3 --- ...resource_rediscloud_active_active_subscription.go | 12 ++---------- 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/provider/rediscloud_active_active_subscription_test.go b/provider/rediscloud_active_active_subscription_test.go index 27301239..06d63faf 100644 --- a/provider/rediscloud_active_active_subscription_test.go +++ b/provider/rediscloud_active_active_subscription_test.go @@ -45,7 +45,6 @@ func TestAccResourceRedisCloudActiveActiveSubscription_CRUDI(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "cloud_provider", "AWS"), resource.TestCheckResourceAttr(resourceName, "creation_plan.#", "1"), resource.TestCheckResourceAttr(resourceName, "creation_plan.0.memory_limit_in_gb", "1"), - resource.TestCheckResourceAttr(resourceName, "creation_plan.0.query_performance_factor", "4x"), resource.TestCheckResourceAttr(resourceName, "creation_plan.0.quantity", "1"), resource.TestCheckResourceAttr(resourceName, "creation_plan.0.modules.#", "1"), resource.TestCheckResourceAttr(resourceName, "creation_plan.0.modules.0", "RedisJSON"), @@ -171,7 +170,6 @@ func TestAccResourceRedisCloudActiveActiveSubscription_CRUDI(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "cloud_provider", "AWS"), resource.TestCheckResourceAttr(resourceName, "creation_plan.#", "1"), resource.TestCheckResourceAttr(resourceName, "creation_plan.0.memory_limit_in_gb", "1"), - resource.TestCheckResourceAttr(resourceName, "creation_plan.0.query_performance_factor", "4x"), resource.TestCheckResourceAttr(resourceName, "creation_plan.0.quantity", "1"), resource.TestCheckResourceAttr(resourceName, "creation_plan.0.modules.#", "1"), resource.TestCheckResourceAttr(resourceName, "creation_plan.0.modules.0", "RedisJSON"), @@ -343,7 +341,6 @@ resource "rediscloud_active_active_subscription" "example" { creation_plan { memory_limit_in_gb = 1 - query_performance_factor = "2x" modules = ["RedisJSON"] quantity = 1 region { diff --git a/provider/resource_rediscloud_active_active_subscription.go b/provider/resource_rediscloud_active_active_subscription.go index 615a16b4..731af1e3 100644 --- a/provider/resource_rediscloud_active_active_subscription.go +++ b/provider/resource_rediscloud_active_active_subscription.go @@ -112,11 +112,6 @@ func resourceRedisCloudActiveActiveSubscription() *schema.Resource { Optional: true, ConflictsWith: []string{"creation_plan.0.memory_limit_in_gb"}, }, - "query_performance_factor": { - Description: "Query performance factor for this specific database", - Type: schema.TypeString, - Optional: true, - }, "quantity": { Description: "The planned number of databases", Type: schema.TypeInt, @@ -652,16 +647,14 @@ func buildSubscriptionCreatePlanAADatabases(planMap map[string]interface{}) []*s createModules = append(createModules, createModule) } - queryPerformanceFactor := planMap["queryPerformanceFactor"].(string) - // create the remaining DBs with all other modules - createDatabases = append(createDatabases, createAADatabase(dbName, &idx, localThroughputs, numDatabases, memoryLimitInGB, datasetSizeInGB, createModules, queryPerformanceFactor)...) + createDatabases = append(createDatabases, createAADatabase(dbName, &idx, localThroughputs, numDatabases, memoryLimitInGB, datasetSizeInGB, createModules)...) return createDatabases } // createDatabase returns a CreateDatabase struct with the given parameters -func createAADatabase(dbName string, idx *int, localThroughputs []*subscriptions.CreateLocalThroughput, numDatabases int, memoryLimitInGB float64, datasetSizeInGB float64, modules []*subscriptions.CreateModules, queryPerformanceFactor string) []*subscriptions.CreateDatabase { +func createAADatabase(dbName string, idx *int, localThroughputs []*subscriptions.CreateLocalThroughput, numDatabases int, memoryLimitInGB float64, datasetSizeInGB float64, modules []*subscriptions.CreateModules) []*subscriptions.CreateDatabase { var dbs []*subscriptions.CreateDatabase for i := 0; i < numDatabases; i++ { createDatabase := subscriptions.CreateDatabase{ @@ -670,7 +663,6 @@ func createAADatabase(dbName string, idx *int, localThroughputs []*subscriptions LocalThroughputMeasurement: localThroughputs, Quantity: redis.Int(1), Modules: modules, - QueryPerformanceFactor: redis.String(queryPerformanceFactor), } if datasetSizeInGB > 0 { createDatabase.DatasetSizeInGB = redis.Float64(datasetSizeInGB) From 25114651226f9bd35d3dc994851e1e598353d349 Mon Sep 17 00:00:00 2001 From: Trent Rosenbaum Date: Tue, 25 Mar 2025 15:41:46 +0000 Subject: [PATCH 08/27] Reverts AA DB to not use query_performance_factor as not supported --- provider/resource_rediscloud_active_active_database.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/provider/resource_rediscloud_active_active_database.go b/provider/resource_rediscloud_active_active_database.go index a658a3ad..1776278a 100644 --- a/provider/resource_rediscloud_active_active_database.go +++ b/provider/resource_rediscloud_active_active_database.go @@ -419,10 +419,6 @@ func resourceRedisCloudActiveActiveDatabaseCreate(ctx context.Context, d *schema createDatabase.MemoryLimitInGB = redis.Float64(v.(float64)) } - if v, ok := d.GetOk("query_performance_factor"); ok { - createDatabase.QueryPerformanceFactor = redis.String(v.(string)) - } - if v, ok := d.GetOk("port"); ok { createDatabase.PortNumber = redis.Int(v.(int)) } From 141de6f826b40589354660d5711e8bea177788ed Mon Sep 17 00:00:00 2001 From: Trent Rosenbaum Date: Tue, 25 Mar 2025 15:59:43 +0000 Subject: [PATCH 09/27] initial updates for the query_performance_factor --- provider/resource_rediscloud_pro_database_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/provider/resource_rediscloud_pro_database_test.go b/provider/resource_rediscloud_pro_database_test.go index c284efa4..05fb62ca 100644 --- a/provider/resource_rediscloud_pro_database_test.go +++ b/provider/resource_rediscloud_pro_database_test.go @@ -373,6 +373,7 @@ resource "rediscloud_subscription_database" "example" { client_ssl_certificate = "" periodic_backup_path = "" enable_default_user = true + query_performance_factor = "2x" alert { name = "dataset-size" @@ -381,7 +382,7 @@ resource "rediscloud_subscription_database" "example" { modules = [ { - name = "RedisBloom" + name = "RediSearch" } ] From 28ad59cfbcd427f69d90957bf2b3aebaab52878d Mon Sep 17 00:00:00 2001 From: Trent Rosenbaum Date: Thu, 27 Mar 2025 20:26:50 +0000 Subject: [PATCH 10/27] Updates pro sub and DB with QPF CustomDiff validation --- provider/resource_rediscloud_pro_database.go | 79 +++++++++++++++++-- .../resource_rediscloud_pro_database_test.go | 2 +- .../resource_rediscloud_pro_subscription.go | 60 +++++++++++--- 3 files changed, 121 insertions(+), 20 deletions(-) diff --git a/provider/resource_rediscloud_pro_database.go b/provider/resource_rediscloud_pro_database.go index aa850e76..df61a2ae 100644 --- a/provider/resource_rediscloud_pro_database.go +++ b/provider/resource_rediscloud_pro_database.go @@ -49,7 +49,7 @@ func resourceRedisCloudProDatabase() *schema.Resource { Delete: schema.DefaultTimeout(10 * time.Minute), }, - CustomizeDiff: remoteBackupIntervalSetCorrectly("remote_backup"), + CustomizeDiff: customizeDiff(), Schema: map[string]*schema.Schema{ "subscription_id": { @@ -91,12 +91,6 @@ func resourceRedisCloudProDatabase() *schema.Resource { Computed: true, ExactlyOneOf: []string{"memory_limit_in_gb", "dataset_size_in_gb"}, }, - "query_performance_factor": { - Description: "Query performance factor for this specific database", - Type: schema.TypeString, - Optional: true, - Computed: true, - }, "support_oss_cluster_api": { Description: "Support Redis open-source (OSS) Cluster API", Type: schema.TypeBool, @@ -221,6 +215,13 @@ func resourceRedisCloudProDatabase() *schema.Resource { }, }, }, + "query_performance_factor": { + Description: "Query performance factor for this specific database", + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, "modules": { Description: "Modules to be provisioned in the database", Type: schema.TypeSet, @@ -521,6 +522,10 @@ func resourceRedisCloudProDatabaseRead(ctx context.Context, d *schema.ResourceDa return diag.FromErr(err) } + if err := d.Set("query_performance_factor", redis.StringValue(db.QueryPerformanceFactor)); err != nil { + return diag.FromErr(err) + } + if err := d.Set("modules", flattenModules(db.Modules)); err != nil { return diag.FromErr(err) } @@ -593,6 +598,11 @@ func resourceRedisCloudProDatabaseRead(ctx context.Context, d *schema.ResourceDa return diag.FromErr(err) } + ////query_performance_factor + //if err := d.Set("query_performance_factor", redis.String(*db.)); err != nil { + // return diag.FromErr(err) + //} + if err := readTags(ctx, api, subId, dbId, d); err != nil { return diag.FromErr(err) } @@ -882,6 +892,61 @@ func skipDiffIfIntervalIs12And12HourTimeDiff(k, oldValue, newValue string, d *sc return oldTime.Minute() == newTime.Minute() && oldTime.Add(12*time.Hour).Hour() == newTime.Hour() } +func customizeDiff() schema.CustomizeDiffFunc { + return func(ctx context.Context, diff *schema.ResourceDiff, meta interface{}) error { + if err := validateQueryPerformanceFactor()(ctx, diff, meta); err != nil { + return err + } + if err := remoteBackupIntervalSetCorrectly("remote_backup")(ctx, diff, meta); err != nil { + return err + } + return nil + } +} + +func validateQueryPerformanceFactor() schema.CustomizeDiffFunc { + return func(ctx context.Context, diff *schema.ResourceDiff, meta interface{}) error { + // Check if "query_performance_factor" is set + qpf, qpfExists := diff.GetOk("query_performance_factor") + + // Ensure "modules" is explicitly defined in the HCL + _, modulesExists := diff.GetOkExists("modules") + + if qpfExists && qpf.(string) != "" { + if !modulesExists { + return fmt.Errorf(`"query_performance_factor" requires the "modules" key to be explicitly defined in HCL`) + } + + // Retrieve modules as a slice of interfaces + rawModules := diff.Get("modules").(*schema.Set).List() + + // Convert modules to []map[string]interface{} + var modules []map[string]interface{} + for _, rawModule := range rawModules { + if moduleMap, ok := rawModule.(map[string]interface{}); ok { + modules = append(modules, moduleMap) + } + } + + // Check if "RediSearch" exists + if !containsDBModule(modules, "RediSearch") { + return fmt.Errorf(`"query_performance_factor" requires the "modules" list to contain "RediSearch"`) + } + } + return nil + } +} + +// Helper function to check if a module exists +func containsDBModule(modules []map[string]interface{}, moduleName string) bool { + for _, module := range modules { + if name, ok := module["name"].(string); ok && name == moduleName { + return true + } + } + return false +} + func remoteBackupIntervalSetCorrectly(key string) schema.CustomizeDiffFunc { // Validate multiple attributes - https://github.com/hashicorp/terraform-plugin-sdk/issues/233 diff --git a/provider/resource_rediscloud_pro_database_test.go b/provider/resource_rediscloud_pro_database_test.go index 05fb62ca..74770ae9 100644 --- a/provider/resource_rediscloud_pro_database_test.go +++ b/provider/resource_rediscloud_pro_database_test.go @@ -310,7 +310,7 @@ resource "rediscloud_subscription" "example" { quantity = 1 replication=false support_oss_cluster_api=false - modules = [] + modules = ["RediSearch"] } } ` diff --git a/provider/resource_rediscloud_pro_subscription.go b/provider/resource_rediscloud_pro_subscription.go index 3c8c2b41..4dfb29d0 100644 --- a/provider/resource_rediscloud_pro_subscription.go +++ b/provider/resource_rediscloud_pro_subscription.go @@ -21,26 +21,60 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" ) +func containsModule(modules []interface{}, requiredModule string) bool { + for _, m := range modules { + if mod, ok := m.(string); ok && mod == requiredModule { + return true + } + } + return false +} + func resourceRedisCloudProSubscription() *schema.Resource { return &schema.Resource{ - Description: "Creates a Pro Subscription within your Redis Enterprise Cloud Account.", - CreateContext: resourceRedisCloudProSubscriptionCreate, - ReadContext: resourceRedisCloudProSubscriptionRead, - UpdateContext: resourceRedisCloudProSubscriptionUpdate, - DeleteContext: resourceRedisCloudProSubscriptionDelete, - CustomizeDiff: func(ctx context.Context, diff *schema.ResourceDiff, i interface{}) error { - _, cPlanExists := diff.GetOk("creation_plan") - if cPlanExists { + + CustomizeDiff: func(ctx context.Context, diff *schema.ResourceDiff, meta interface{}) error { + + // Ensure the "creation_plan" block exists + _, creationPlanExists := diff.GetOk("creation_plan") + if !creationPlanExists { + if diff.Id() == "" { + return fmt.Errorf(`the "creation_plan" block is required`) + } return nil } - // The resource hasn't been created yet, but the creation plan is missing. - if diff.Id() == "" { - return fmt.Errorf(`the "creation_plan" block is required`) + // Validate "query_performance_factor" dependency on "modules" + creationPlan := diff.Get("creation_plan").([]interface{}) + if len(creationPlan) > 0 { + plan := creationPlan[0].(map[string]interface{}) + + qpf, qpfExists := plan["query_performance_factor"].(string) + + // Ensure "modules" key is explicitly defined in HCL + _, modulesExists := diff.GetOkExists("creation_plan.0.modules") + + if qpfExists && qpf != "" { + if !modulesExists { + return fmt.Errorf(`"query_performance_factor" requires the "modules" key to be explicitly defined in HCL`) + } + + modules, _ := plan["modules"].([]interface{}) + if !containsModule(modules, "RediSearch") { + return fmt.Errorf(`"query_performance_factor" requires the "modules" list to contain "RediSearch"`) + } + } } + return nil }, + Description: "Creates a Pro Subscription within your Redis Enterprise Cloud Account.", + CreateContext: resourceRedisCloudProSubscriptionCreate, + ReadContext: resourceRedisCloudProSubscriptionRead, + UpdateContext: resourceRedisCloudProSubscriptionUpdate, + DeleteContext: resourceRedisCloudProSubscriptionDelete, + Importer: &schema.ResourceImporter{ // Let the READ operation do the heavy lifting for importing values from the API. StateContext: schema.ImportStatePassthroughContext, @@ -259,6 +293,8 @@ func resourceRedisCloudProSubscription() *schema.Resource { Description: "Query performance factor for this specific database", Type: schema.TypeString, Optional: true, + Computed: true, + ForceNew: true, }, "throughput_measurement_by": { Description: "Throughput measurement method, (either ‘number-of-shards’ or ‘operations-per-second’)", @@ -804,7 +840,7 @@ func buildSubscriptionCreatePlanDatabases(memoryStorage string, planMap map[stri } queryPerformanceFactor := "" - if v, ok := planMap["queryPerformanceFactor"]; ok && v != nil { + if v, ok := planMap["query_performance_factor"]; ok && v != nil { queryPerformanceFactor = v.(string) } From 3208bb9ed7ac0a2b6e8ad044110e86e5473a36d1 Mon Sep 17 00:00:00 2001 From: Trent Rosenbaum Date: Tue, 1 Apr 2025 15:08:14 +0100 Subject: [PATCH 11/27] New QPF based test --- ...source_rediscloud_pro_database_qpf_test.go | 189 ++++++++++++++++++ 1 file changed, 189 insertions(+) create mode 100644 provider/resource_rediscloud_pro_database_qpf_test.go diff --git a/provider/resource_rediscloud_pro_database_qpf_test.go b/provider/resource_rediscloud_pro_database_qpf_test.go new file mode 100644 index 00000000..1de508d6 --- /dev/null +++ b/provider/resource_rediscloud_pro_database_qpf_test.go @@ -0,0 +1,189 @@ +package provider + +import ( + "context" + "fmt" + "os" + "regexp" + "strconv" + "testing" + + "github.com/RedisLabs/rediscloud-go-api/redis" + "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" +) + +// Generates the base Terraform config for a Pro Subscription with QPF +func proSubscriptionQPFBoilerplate(name, cloudAccountName string) string { + return fmt.Sprintf(` +data "rediscloud_payment_method" "card" { + card_type = "Visa" +} + +data "rediscloud_cloud_account" "account" { + exclude_internal_account = true + provider_type = "AWS" + name = "%s" +} + +resource "rediscloud_subscription" "example" { + name = "%s" + payment_method_id = data.rediscloud_payment_method.card.id + memory_storage = "ram" + + allowlist { + cidrs = ["192.168.0.0/16"] + security_group_ids = [] + } + + cloud_provider { + provider = data.rediscloud_cloud_account.account.provider_type + cloud_account_id = data.rediscloud_cloud_account.account.id + region { + region = "eu-west-1" + networking_deployment_cidr = "10.0.0.0/24" + preferred_availability_zones = ["eu-west-1a"] + } + } + + creation_plan { + dataset_size_in_gb = 1 + throughput_measurement_by = "operations-per-second" + throughput_measurement_value = 1000 + quantity = 1 + replication = false + support_oss_cluster_api = false + query_performance_factor = "2x" + modules = ["RediSearch"] + } +}`, cloudAccountName, name) +} + +// Generates Terraform configuration for the database +func formatDatabaseConfig(name, cloudAccountName, password string, extraConfig string) string { + return proSubscriptionQPFBoilerplate(name, cloudAccountName) + fmt.Sprintf(` +resource "rediscloud_subscription_database" "example" { + subscription_id = rediscloud_subscription.example.id + name = "example" + protocol = "redis" + dataset_size_in_gb = 3 + data_persistence = "none" + data_eviction = "allkeys-random" + throughput_measurement_by = "operations-per-second" + throughput_measurement_value = 1000 + password = "%s" + support_oss_cluster_api = false + external_endpoint_for_oss_cluster_api = false + replication = false + average_item_size_in_bytes = 0 + client_ssl_certificate = "" + periodic_backup_path = "" + enable_default_user = true + query_performance_factor = "2x" + + alert { + name = "dataset-size" + value = 40 + } + + tags = { + "market" = "emea" + "material" = "cardboard" + } + + %s +}`, password, extraConfig) +} + +// Generic test helper for error cases +func testErrorCase(t *testing.T, config string, expectedError *regexp.Regexp) { + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccAwsPreExistingCloudAccountPreCheck(t) }, + ProviderFactories: providerFactories, + CheckDestroy: testAccCheckProSubscriptionDestroy, + Steps: []resource.TestStep{ + { + Config: config, + ExpectError: expectedError, + }, + }, + }) +} + +func TestAccResourceRedisCloudProDatabase_qpf(t *testing.T) { + name := acctest.RandomWithPrefix(testResourcePrefix) + password := acctest.RandString(20) + testCloudAccountName := os.Getenv("AWS_TEST_CLOUD_ACCOUNT_NAME") + + var subId int + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccAwsPreExistingCloudAccountPreCheck(t) }, + ProviderFactories: providerFactories, + CheckDestroy: testAccCheckProSubscriptionDestroy, + Steps: []resource.TestStep{ + { + Config: formatDatabaseConfig(name, testCloudAccountName, password, `modules = [{ name = "RediSearch" }]`), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("rediscloud_subscription_database.example", "name", "example"), + resource.TestCheckResourceAttr("rediscloud_subscription_database.example", "protocol", "redis"), + resource.TestCheckResourceAttr("rediscloud_subscription_database.example", "dataset_size_in_gb", "3"), + resource.TestCheckResourceAttr("rediscloud_subscription_database.example", "query_performance_factor", "2x"), + resource.TestCheckResourceAttr("rediscloud_subscription_database.example", "tags.market", "emea"), + resource.TestCheckResourceAttr("rediscloud_subscription_database.example", "tags.material", "cardboard"), + + func(s *terraform.State) error { + r := s.RootModule().Resources["rediscloud_subscription.example"] + + var err error + subId, err = strconv.Atoi(r.Primary.ID) + if err != nil { + return fmt.Errorf("couldn't parse the subscription ID: %s", redis.StringValue(&r.Primary.ID)) + } + + client := testProvider.Meta().(*apiClient) + sub, err := client.client.Subscription.Get(context.TODO(), subId) + if err != nil { + return err + } + + if redis.StringValue(sub.Name) != name { + return fmt.Errorf("unexpected name value: %s", redis.StringValue(sub.Name)) + } + + listDb := client.client.Database.List(context.TODO(), subId) + if !listDb.Next() { + return fmt.Errorf("no database found: %s", listDb.Err()) + } + if listDb.Err() != nil { + return listDb.Err() + } + + return nil + }, + ), + }, + }, + }) +} + +func TestAccResourceRedisCloudProDatabase_missingModule(t *testing.T) { + name := acctest.RandomWithPrefix(testResourcePrefix) + password := acctest.RandString(20) + testCloudAccountName := os.Getenv("AWS_TEST_CLOUD_ACCOUNT_NAME") + + config := formatDatabaseConfig(name, testCloudAccountName, password, "") + + testErrorCase(t, config, regexp.MustCompile("query_performance_factor\" requires the \"modules\" key to be explicitly defined in HCL")) +} + +func TestAccResourceRedisCloudProDatabase_missingRediSearchModule(t *testing.T) { + name := acctest.RandomWithPrefix(testResourcePrefix) + password := acctest.RandString(20) + testCloudAccountName := os.Getenv("AWS_TEST_CLOUD_ACCOUNT_NAME") + + config := formatDatabaseConfig(name, testCloudAccountName, password, `modules = [{ name = "RediBloom" }]`) + + testErrorCase(t, config, regexp.MustCompile("query_performance_factor\" requires the \"modules\" list to contain \"RediSearch")) +} From 4c8c2dcaba08951c223088f12ce3b5a3cfe143f9 Mon Sep 17 00:00:00 2001 From: Trent Rosenbaum Date: Tue, 1 Apr 2025 17:43:28 +0100 Subject: [PATCH 12/27] expands qpf test --- ...source_rediscloud_pro_database_qpf_test.go | 66 ++++++------------- 1 file changed, 20 insertions(+), 46 deletions(-) diff --git a/provider/resource_rediscloud_pro_database_qpf_test.go b/provider/resource_rediscloud_pro_database_qpf_test.go index 1de508d6..3505faad 100644 --- a/provider/resource_rediscloud_pro_database_qpf_test.go +++ b/provider/resource_rediscloud_pro_database_qpf_test.go @@ -1,21 +1,17 @@ package provider import ( - "context" "fmt" "os" "regexp" - "strconv" "testing" - "github.com/RedisLabs/rediscloud-go-api/redis" "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" ) // Generates the base Terraform config for a Pro Subscription with QPF -func proSubscriptionQPFBoilerplate(name, cloudAccountName string) string { +func proSubscriptionQPFBoilerplate(name, cloudAccountName, qpf string) string { return fmt.Sprintf(` data "rediscloud_payment_method" "card" { card_type = "Visa" @@ -54,15 +50,15 @@ resource "rediscloud_subscription" "example" { quantity = 1 replication = false support_oss_cluster_api = false - query_performance_factor = "2x" + query_performance_factor = "%s" modules = ["RediSearch"] } -}`, cloudAccountName, name) +}`, cloudAccountName, name, qpf) } // Generates Terraform configuration for the database -func formatDatabaseConfig(name, cloudAccountName, password string, extraConfig string) string { - return proSubscriptionQPFBoilerplate(name, cloudAccountName) + fmt.Sprintf(` +func formatDatabaseConfig(name, cloudAccountName, password, qpf, extraConfig string) string { + return proSubscriptionQPFBoilerplate(name, cloudAccountName, qpf) + fmt.Sprintf(` resource "rediscloud_subscription_database" "example" { subscription_id = rediscloud_subscription.example.id name = "example" @@ -80,7 +76,7 @@ resource "rediscloud_subscription_database" "example" { client_ssl_certificate = "" periodic_backup_path = "" enable_default_user = true - query_performance_factor = "2x" + query_performance_factor = "%s" alert { name = "dataset-size" @@ -93,7 +89,7 @@ resource "rediscloud_subscription_database" "example" { } %s -}`, password, extraConfig) +}`, password, qpf, extraConfig) } // Generic test helper for error cases @@ -116,52 +112,30 @@ func TestAccResourceRedisCloudProDatabase_qpf(t *testing.T) { password := acctest.RandString(20) testCloudAccountName := os.Getenv("AWS_TEST_CLOUD_ACCOUNT_NAME") - var subId int - resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccAwsPreExistingCloudAccountPreCheck(t) }, ProviderFactories: providerFactories, CheckDestroy: testAccCheckProSubscriptionDestroy, Steps: []resource.TestStep{ { - Config: formatDatabaseConfig(name, testCloudAccountName, password, `modules = [{ name = "RediSearch" }]`), + Config: formatDatabaseConfig(name, testCloudAccountName, password, "4x", `modules = [{ name = "RediSearch" }]`), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr("rediscloud_subscription_database.example", "name", "example"), resource.TestCheckResourceAttr("rediscloud_subscription_database.example", "protocol", "redis"), resource.TestCheckResourceAttr("rediscloud_subscription_database.example", "dataset_size_in_gb", "3"), - resource.TestCheckResourceAttr("rediscloud_subscription_database.example", "query_performance_factor", "2x"), + resource.TestCheckResourceAttr("rediscloud_subscription_database.example", "query_performance_factor", "4x"), resource.TestCheckResourceAttr("rediscloud_subscription_database.example", "tags.market", "emea"), resource.TestCheckResourceAttr("rediscloud_subscription_database.example", "tags.material", "cardboard"), + ), + }, - func(s *terraform.State) error { - r := s.RootModule().Resources["rediscloud_subscription.example"] - - var err error - subId, err = strconv.Atoi(r.Primary.ID) - if err != nil { - return fmt.Errorf("couldn't parse the subscription ID: %s", redis.StringValue(&r.Primary.ID)) - } - - client := testProvider.Meta().(*apiClient) - sub, err := client.client.Subscription.Get(context.TODO(), subId) - if err != nil { - return err - } - - if redis.StringValue(sub.Name) != name { - return fmt.Errorf("unexpected name value: %s", redis.StringValue(sub.Name)) - } - - listDb := client.client.Database.List(context.TODO(), subId) - if !listDb.Next() { - return fmt.Errorf("no database found: %s", listDb.Err()) - } - if listDb.Err() != nil { - return listDb.Err() - } - - return nil - }, + // Test plan to ensure query_performance_factor change forces a new resource + { + Config: formatDatabaseConfig(name, testCloudAccountName, password, "2x", `modules = [{ name = "RediSearch" }]`), + PlanOnly: true, // Runs terraform plan without applying + ExpectNonEmptyPlan: true, // Ensures that a change is detected + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("rediscloud_subscription_database.example", "query_performance_factor", "2x"), ), }, }, @@ -173,7 +147,7 @@ func TestAccResourceRedisCloudProDatabase_missingModule(t *testing.T) { password := acctest.RandString(20) testCloudAccountName := os.Getenv("AWS_TEST_CLOUD_ACCOUNT_NAME") - config := formatDatabaseConfig(name, testCloudAccountName, password, "") + config := formatDatabaseConfig(name, testCloudAccountName, password, "4x", "") testErrorCase(t, config, regexp.MustCompile("query_performance_factor\" requires the \"modules\" key to be explicitly defined in HCL")) } @@ -183,7 +157,7 @@ func TestAccResourceRedisCloudProDatabase_missingRediSearchModule(t *testing.T) password := acctest.RandString(20) testCloudAccountName := os.Getenv("AWS_TEST_CLOUD_ACCOUNT_NAME") - config := formatDatabaseConfig(name, testCloudAccountName, password, `modules = [{ name = "RediBloom" }]`) + config := formatDatabaseConfig(name, testCloudAccountName, password, "4x", `modules = [{ name = "RediBloom" }]`) testErrorCase(t, config, regexp.MustCompile("query_performance_factor\" requires the \"modules\" list to contain \"RediSearch")) } From ad66022b8bc8d5de979a906c218898222a7e741c Mon Sep 17 00:00:00 2001 From: Trent Rosenbaum Date: Thu, 3 Apr 2025 09:06:41 +0100 Subject: [PATCH 13/27] Reverts the resource_rediscloud_pro_database_test to focus on non qpf activities --- provider/resource_rediscloud_pro_database_test.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/provider/resource_rediscloud_pro_database_test.go b/provider/resource_rediscloud_pro_database_test.go index 74770ae9..c284efa4 100644 --- a/provider/resource_rediscloud_pro_database_test.go +++ b/provider/resource_rediscloud_pro_database_test.go @@ -310,7 +310,7 @@ resource "rediscloud_subscription" "example" { quantity = 1 replication=false support_oss_cluster_api=false - modules = ["RediSearch"] + modules = [] } } ` @@ -373,7 +373,6 @@ resource "rediscloud_subscription_database" "example" { client_ssl_certificate = "" periodic_backup_path = "" enable_default_user = true - query_performance_factor = "2x" alert { name = "dataset-size" @@ -382,7 +381,7 @@ resource "rediscloud_subscription_database" "example" { modules = [ { - name = "RediSearch" + name = "RedisBloom" } ] From 130204845295155ceb23a86439e4c9b5841a792b Mon Sep 17 00:00:00 2001 From: Trent Rosenbaum Date: Thu, 3 Apr 2025 14:10:19 +0100 Subject: [PATCH 14/27] Updates datasource and resources to handle QPF --- .../datasource_rediscloud_pro_database.go | 5 ++- ...datasource_rediscloud_pro_database_test.go | 1 + provider/resource_rediscloud_pro_database.go | 38 +++++++++++-------- 3 files changed, 27 insertions(+), 17 deletions(-) diff --git a/provider/datasource_rediscloud_pro_database.go b/provider/datasource_rediscloud_pro_database.go index 55a3036c..8b76ce26 100644 --- a/provider/datasource_rediscloud_pro_database.go +++ b/provider/datasource_rediscloud_pro_database.go @@ -62,7 +62,6 @@ func dataSourceRedisCloudProDatabase() *schema.Resource { "query_performance_factor": { Description: "Query performance factor for this specific database", Type: schema.TypeString, - Optional: true, Computed: true, }, "support_oss_cluster_api": { @@ -482,6 +481,10 @@ func dataSourceRedisCloudProDatabaseRead(ctx context.Context, d *schema.Resource return diag.FromErr(err) } + if err := d.Set("query_performance_factor", redis.String(*db.QueryPerformanceFactor)); err != nil { + return diag.FromErr(err) + } + return diags } diff --git a/provider/datasource_rediscloud_pro_database_test.go b/provider/datasource_rediscloud_pro_database_test.go index 9b0ecc5a..9cec9240 100644 --- a/provider/datasource_rediscloud_pro_database_test.go +++ b/provider/datasource_rediscloud_pro_database_test.go @@ -96,6 +96,7 @@ resource "rediscloud_subscription" "example" { support_oss_cluster_api=true throughput_measurement_by = "operations-per-second" throughput_measurement_value = 1000 + query_performance_factor = "2x" modules = ["RediSearch"] } } diff --git a/provider/resource_rediscloud_pro_database.go b/provider/resource_rediscloud_pro_database.go index df61a2ae..43a175de 100644 --- a/provider/resource_rediscloud_pro_database.go +++ b/provider/resource_rediscloud_pro_database.go @@ -391,10 +391,13 @@ func resourceRedisCloudProDatabaseCreate(ctx context.Context, d *schema.Resource By: redis.String(throughputMeasurementBy), Value: redis.Int(throughputMeasurementValue), }, - Modules: createModules, - Alerts: createAlerts, - RemoteBackup: buildBackupPlan(d.Get("remote_backup").([]interface{}), d.Get("periodic_backup_path")), - QueryPerformanceFactor: redis.String(queryPerformanceFactor), + Modules: createModules, + Alerts: createAlerts, + RemoteBackup: buildBackupPlan(d.Get("remote_backup").([]interface{}), d.Get("periodic_backup_path")), + } + + if queryPerformanceFactor != "" { + createDatabase.QueryPerformanceFactor = redis.String(queryPerformanceFactor) } if password != "" { @@ -597,11 +600,10 @@ func resourceRedisCloudProDatabaseRead(ctx context.Context, d *schema.ResourceDa if err := d.Set("remote_backup", flattenBackupPlan(db.Backup, d.Get("remote_backup").([]interface{}), d.Get("periodic_backup_path").(string))); err != nil { return diag.FromErr(err) } - - ////query_performance_factor - //if err := d.Set("query_performance_factor", redis.String(*db.)); err != nil { - // return diag.FromErr(err) - //} + + if err := d.Set("query_performance_factor", redis.String(*db.QueryPerformanceFactor)); err != nil { + return diag.FromErr(err) + } if err := readTags(ctx, api, subId, dbId, d); err != nil { return diag.FromErr(err) @@ -677,13 +679,12 @@ func resourceRedisCloudProDatabaseUpdate(ctx context.Context, d *schema.Resource By: redis.String(d.Get("throughput_measurement_by").(string)), Value: redis.Int(d.Get("throughput_measurement_value").(int)), }, - DataPersistence: redis.String(d.Get("data_persistence").(string)), - DataEvictionPolicy: redis.String(d.Get("data_eviction").(string)), - SourceIP: setToStringSlice(d.Get("source_ips").(*schema.Set)), - Alerts: &alerts, - RemoteBackup: buildBackupPlan(d.Get("remote_backup").([]interface{}), d.Get("periodic_backup_path")), - EnableDefaultUser: redis.Bool(d.Get("enable_default_user").(bool)), - QueryPerformanceFactor: redis.String(d.Get("query_performance_factor").(string)), + DataPersistence: redis.String(d.Get("data_persistence").(string)), + DataEvictionPolicy: redis.String(d.Get("data_eviction").(string)), + SourceIP: setToStringSlice(d.Get("source_ips").(*schema.Set)), + Alerts: &alerts, + RemoteBackup: buildBackupPlan(d.Get("remote_backup").([]interface{}), d.Get("periodic_backup_path")), + EnableDefaultUser: redis.Bool(d.Get("enable_default_user").(bool)), } // One of the following fields must be set, validation is handled in the schema (ExactlyOneOf) @@ -700,6 +701,11 @@ func resourceRedisCloudProDatabaseUpdate(ctx context.Context, d *schema.Resource update.SourceIP = []*string{redis.String("0.0.0.0/0")} } + queryPerformanceFactor := d.Get("query_performance_factor").(string) + if queryPerformanceFactor != "" { + update.QueryPerformanceFactor = redis.String(queryPerformanceFactor) + } + if d.Get("password").(string) != "" { update.Password = redis.String(d.Get("password").(string)) } From ddf24591d48c436f80a0811590bf0a6b1a6bb499 Mon Sep 17 00:00:00 2001 From: Trent Rosenbaum Date: Thu, 3 Apr 2025 14:48:05 +0100 Subject: [PATCH 15/27] Updates to use rediscloud-go-api v0.23.0 --- go.mod | 2 -- go.sum | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 70a9a2e3..0a9ba814 100644 --- a/go.mod +++ b/go.mod @@ -66,5 +66,3 @@ require ( google.golang.org/protobuf v1.36.3 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) - -replace github.com/RedisLabs/rediscloud-go-api => ../rediscloud-go-api diff --git a/go.sum b/go.sum index 48d5c125..476114d8 100644 --- a/go.sum +++ b/go.sum @@ -4,6 +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/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= From f723df50b32c53a42e7c1e66b083d1cb767f983e Mon Sep 17 00:00:00 2001 From: Trent Rosenbaum Date: Fri, 4 Apr 2025 13:05:01 +0100 Subject: [PATCH 16/27] Introduces pro subscription test covering QPF --- .../resource_rediscloud_pro_subscription.go | 1 - ...ce_rediscloud_pro_subscription_qpf_test.go | 129 ++++++++++++++++++ 2 files changed, 129 insertions(+), 1 deletion(-) create mode 100644 provider/resource_rediscloud_pro_subscription_qpf_test.go diff --git a/provider/resource_rediscloud_pro_subscription.go b/provider/resource_rediscloud_pro_subscription.go index 4dfb29d0..64b8e425 100644 --- a/provider/resource_rediscloud_pro_subscription.go +++ b/provider/resource_rediscloud_pro_subscription.go @@ -294,7 +294,6 @@ func resourceRedisCloudProSubscription() *schema.Resource { Type: schema.TypeString, Optional: true, Computed: true, - ForceNew: true, }, "throughput_measurement_by": { Description: "Throughput measurement method, (either ‘number-of-shards’ or ‘operations-per-second’)", diff --git a/provider/resource_rediscloud_pro_subscription_qpf_test.go b/provider/resource_rediscloud_pro_subscription_qpf_test.go new file mode 100644 index 00000000..6ce95ee5 --- /dev/null +++ b/provider/resource_rediscloud_pro_subscription_qpf_test.go @@ -0,0 +1,129 @@ +package provider + +import ( + "fmt" + "os" + "regexp" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +// Generates the base Terraform config for a Pro Subscription with QPF +func formatSubscriptionConfig(name, cloudAccountName, qpf, extraConfig string) string { + return fmt.Sprintf(` +data "rediscloud_payment_method" "card" { + card_type = "Visa" +} + +data "rediscloud_cloud_account" "account" { + exclude_internal_account = true + provider_type = "AWS" + name = "%s" +} + +resource "rediscloud_subscription" "example" { + name = "%s" + payment_method_id = data.rediscloud_payment_method.card.id + memory_storage = "ram" + + allowlist { + cidrs = ["192.168.0.0/16"] + security_group_ids = [] + } + + cloud_provider { + provider = data.rediscloud_cloud_account.account.provider_type + cloud_account_id = data.rediscloud_cloud_account.account.id + region { + region = "eu-west-1" + networking_deployment_cidr = "10.0.0.0/24" + preferred_availability_zones = ["eu-west-1a"] + } + } + + creation_plan { + dataset_size_in_gb = 1 + throughput_measurement_by = "operations-per-second" + throughput_measurement_value = 1000 + quantity = 1 + replication = false + support_oss_cluster_api = false + query_performance_factor = "%s" + + %s + } +}`, cloudAccountName, name, qpf, extraConfig) +} + +// Generic test helper for error cases +func testSubErrorCase(t *testing.T, config string, expectedError *regexp.Regexp) { + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccAwsPreExistingCloudAccountPreCheck(t) }, + ProviderFactories: providerFactories, + CheckDestroy: testAccCheckProSubscriptionDestroy, + Steps: []resource.TestStep{ + { + Config: config, + ExpectError: expectedError, + }, + }, + }) +} + +func TestAccResourceRedisCloudProSubscription_qpf(t *testing.T) { + name := acctest.RandomWithPrefix(testResourcePrefix) + testCloudAccountName := os.Getenv("AWS_TEST_CLOUD_ACCOUNT_NAME") + const resourceName = "rediscloud_subscription.example" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccAwsPreExistingCloudAccountPreCheck(t) }, + ProviderFactories: providerFactories, + CheckDestroy: testAccCheckProSubscriptionDestroy, + Steps: []resource.TestStep{ + { + Config: formatSubscriptionConfig(name, testCloudAccountName, "2x", `modules = ["RediSearch"]`), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "name", name), + resource.TestCheckResourceAttr(resourceName, "payment_method", "credit-card"), + resource.TestCheckResourceAttr(resourceName, "cloud_provider.0.provider", "AWS"), + resource.TestCheckResourceAttr(resourceName, "cloud_provider.0.region.0.preferred_availability_zones.#", "1"), + resource.TestCheckResourceAttrSet(resourceName, "cloud_provider.0.region.0.networks.0.networking_subnet_id"), + resource.TestCheckResourceAttr(resourceName, "creation_plan.#", "1"), + resource.TestCheckResourceAttr(resourceName, "creation_plan.0.average_item_size_in_bytes", "0"), + resource.TestCheckResourceAttr(resourceName, "creation_plan.0.dataset_size_in_gb", "1"), + resource.TestCheckResourceAttr(resourceName, "creation_plan.0.query_performance_factor", "2x"), + + resource.TestCheckResourceAttr(resourceName, "creation_plan.0.modules.#", "1"), + resource.TestCheckResourceAttr(resourceName, "creation_plan.0.modules.0", "RediSearch"), + resource.TestCheckResourceAttr(resourceName, "creation_plan.0.quantity", "1"), + resource.TestCheckResourceAttr(resourceName, "creation_plan.0.replication", "false"), + resource.TestCheckResourceAttr(resourceName, "creation_plan.0.support_oss_cluster_api", "false"), + resource.TestCheckResourceAttr(resourceName, "creation_plan.0.throughput_measurement_by", "operations-per-second"), + resource.TestCheckResourceAttr(resourceName, "creation_plan.0.throughput_measurement_value", "1000"), + ), + }, + }, + }) +} + +func TestAccResourceRedisCloudProSubscription_missingModule(t *testing.T) { + name := acctest.RandomWithPrefix(testResourcePrefix) + password := acctest.RandString(20) + testCloudAccountName := os.Getenv("AWS_TEST_CLOUD_ACCOUNT_NAME") + + config := formatDatabaseConfig(name, testCloudAccountName, password, "4x", "") + + testSubErrorCase(t, config, regexp.MustCompile("query_performance_factor\" requires the \"modules\" key to be explicitly defined in HCL")) +} + +func TestAccResourceRedisCloudProSubscription_missingRediSearchModule(t *testing.T) { + name := acctest.RandomWithPrefix(testResourcePrefix) + password := acctest.RandString(20) + testCloudAccountName := os.Getenv("AWS_TEST_CLOUD_ACCOUNT_NAME") + + config := formatDatabaseConfig(name, testCloudAccountName, password, "4x", `modules = [{ name = "RediBloom" }]`) + + testSubErrorCase(t, config, regexp.MustCompile("query_performance_factor\" requires the \"modules\" list to contain \"RediSearch")) +} From fde66754ac244f689f66930c970f30eb36ee43e7 Mon Sep 17 00:00:00 2001 From: Trent Rosenbaum Date: Fri, 4 Apr 2025 19:26:59 +0100 Subject: [PATCH 17/27] Updates to pro sub and db for tests --- ...rce_rediscloud_active_active_subscription_peering_test.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/provider/resource_rediscloud_active_active_subscription_peering_test.go b/provider/resource_rediscloud_active_active_subscription_peering_test.go index 74b9c219..0928d75b 100644 --- a/provider/resource_rediscloud_active_active_subscription_peering_test.go +++ b/provider/resource_rediscloud_active_active_subscription_peering_test.go @@ -2,12 +2,11 @@ package provider import ( "fmt" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "os" "regexp" "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) func TestAccResourceRedisCloudActiveActiveSubscriptionPeering_aws(t *testing.T) { From 350da73483f561ea884ce044cad0695b4a6508bd Mon Sep 17 00:00:00 2001 From: Trent Rosenbaum Date: Tue, 8 Apr 2025 09:06:46 +0100 Subject: [PATCH 18/27] Reducing the TEST_PARALLELISM from 6 to 2 to locate test failure --- GNUmakefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GNUmakefile b/GNUmakefile index 8a19f929..4373cb08 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -10,7 +10,7 @@ PLUGINS_PATH = ~/.terraform.d/plugins PLUGINS_PROVIDER_PATH=$(PROVIDER_HOSTNAME)/$(PROVIDER_NAMESPACE)/$(PROVIDER_TYPE)/$(PROVIDER_VERSION)/$(PROVIDER_TARGET) # Use a parallelism of 3 by default for tests, overriding whatever GOMAXPROCS is set to. -TEST_PARALLELISM?=6 +TEST_PARALLELISM?=2 TESTARGS?=-short bin: From 7c1eac6e4e77068b52ab1a5ac57fb96c9e62b0f8 Mon Sep 17 00:00:00 2001 From: Trent Rosenbaum Date: Tue, 8 Apr 2025 14:48:04 +0100 Subject: [PATCH 19/27] set TEST_PARALLELISM to 1 --- GNUmakefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GNUmakefile b/GNUmakefile index 4373cb08..8174ef4c 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -10,7 +10,7 @@ PLUGINS_PATH = ~/.terraform.d/plugins PLUGINS_PROVIDER_PATH=$(PROVIDER_HOSTNAME)/$(PROVIDER_NAMESPACE)/$(PROVIDER_TYPE)/$(PROVIDER_VERSION)/$(PROVIDER_TARGET) # Use a parallelism of 3 by default for tests, overriding whatever GOMAXPROCS is set to. -TEST_PARALLELISM?=2 +TEST_PARALLELISM?=1 TESTARGS?=-short bin: From 79bd458c446762db611442c6504ea7d2e2a0458a Mon Sep 17 00:00:00 2001 From: Trent Rosenbaum Date: Wed, 9 Apr 2025 14:53:19 +0100 Subject: [PATCH 20/27] Updates to check that the QPF is within 2x to 16x range --- .../resource_rediscloud_pro_subscription.go | 12 +++++++++++ ...ce_rediscloud_pro_subscription_qpf_test.go | 20 +++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/provider/resource_rediscloud_pro_subscription.go b/provider/resource_rediscloud_pro_subscription.go index 64b8e425..c376f264 100644 --- a/provider/resource_rediscloud_pro_subscription.go +++ b/provider/resource_rediscloud_pro_subscription.go @@ -294,6 +294,18 @@ func resourceRedisCloudProSubscription() *schema.Resource { Type: schema.TypeString, Optional: true, Computed: true, + ValidateFunc: func(val interface{}, key string) (warns []string, errs []error) { + v := val.(string) + matched, err := regexp.MatchString(`^(2|4|6|8|10|12|14|16)x$`, v) + if err != nil { + errs = append(errs, fmt.Errorf("regex match failed: %s", err)) + return + } + if !matched { + errs = append(errs, fmt.Errorf("%q must be an even value between 2x and 16x (inclusive), got: %s", key, v)) + } + return + }, }, "throughput_measurement_by": { Description: "Throughput measurement method, (either ‘number-of-shards’ or ‘operations-per-second’)", diff --git a/provider/resource_rediscloud_pro_subscription_qpf_test.go b/provider/resource_rediscloud_pro_subscription_qpf_test.go index 6ce95ee5..75893d76 100644 --- a/provider/resource_rediscloud_pro_subscription_qpf_test.go +++ b/provider/resource_rediscloud_pro_subscription_qpf_test.go @@ -127,3 +127,23 @@ func TestAccResourceRedisCloudProSubscription_missingRediSearchModule(t *testing testSubErrorCase(t, config, regexp.MustCompile("query_performance_factor\" requires the \"modules\" list to contain \"RediSearch")) } + +func TestAccRedisCloudDatabase_invalidQueryPerformanceFactors(t *testing.T) { + name := acctest.RandomWithPrefix("tf-test") + password := acctest.RandString(20) + testCloudAccountName := os.Getenv("AWS_TEST_CLOUD_ACCOUNT_NAME") + + config := formatDatabaseConfig(name, testCloudAccountName, password, "5x", `modules = [{ name = "RediSearch" }]`) + + testSubErrorCase(t, config, regexp.MustCompile(`"creation_plan\.0\.query_performance_factor" must be an even value between 2x and 16x \(inclusive\), got: 5x`)) +} + +func TestAccRedisCloudDatabase_invalidQueryPerformanceFactors_outOfRange(t *testing.T) { + name := acctest.RandomWithPrefix("tf-test") + password := acctest.RandString(20) + testCloudAccountName := os.Getenv("AWS_TEST_CLOUD_ACCOUNT_NAME") + + config := formatDatabaseConfig(name, testCloudAccountName, password, "30x", `modules = [{ name = "RediSearch" }]`) + + testSubErrorCase(t, config, regexp.MustCompile(`"creation_plan\.0\.query_performance_factor" must be an even value between 2x and 16x \(inclusive\), got: 30x`)) +} From 7de8e74a6e10ae9f150d68a847b8424680201064 Mon Sep 17 00:00:00 2001 From: Trent Rosenbaum Date: Wed, 9 Apr 2025 15:23:22 +0100 Subject: [PATCH 21/27] Udpates to validate QPF range value --- provider/resource_rediscloud_pro_database.go | 13 ++++++++++++ ...source_rediscloud_pro_database_qpf_test.go | 20 +++++++++++++++++++ ...ce_rediscloud_pro_subscription_qpf_test.go | 4 ++-- 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/provider/resource_rediscloud_pro_database.go b/provider/resource_rediscloud_pro_database.go index 43a175de..6899d480 100644 --- a/provider/resource_rediscloud_pro_database.go +++ b/provider/resource_rediscloud_pro_database.go @@ -3,6 +3,7 @@ package provider import ( "context" "fmt" + "regexp" "strconv" "strings" "time" @@ -221,6 +222,18 @@ func resourceRedisCloudProDatabase() *schema.Resource { Optional: true, Computed: true, ForceNew: true, + ValidateFunc: func(val interface{}, key string) (warns []string, errs []error) { + v := val.(string) + matched, err := regexp.MatchString(`^(2|4|6|8|10|12|14|16)x$`, v) + if err != nil { + errs = append(errs, fmt.Errorf("regex match failed: %s", err)) + return + } + if !matched { + errs = append(errs, fmt.Errorf("%q must be an even value between 2x and 16x (inclusive), got: %s", key, v)) + } + return + }, }, "modules": { Description: "Modules to be provisioned in the database", diff --git a/provider/resource_rediscloud_pro_database_qpf_test.go b/provider/resource_rediscloud_pro_database_qpf_test.go index 3505faad..df9ff549 100644 --- a/provider/resource_rediscloud_pro_database_qpf_test.go +++ b/provider/resource_rediscloud_pro_database_qpf_test.go @@ -161,3 +161,23 @@ func TestAccResourceRedisCloudProDatabase_missingRediSearchModule(t *testing.T) testErrorCase(t, config, regexp.MustCompile("query_performance_factor\" requires the \"modules\" list to contain \"RediSearch")) } + +func TestAccResourceRedisCloudProDatabase_invalidQueryPerformanceFactors(t *testing.T) { + name := acctest.RandomWithPrefix("tf-test") + password := acctest.RandString(20) + testCloudAccountName := os.Getenv("AWS_TEST_CLOUD_ACCOUNT_NAME") + + config := formatDatabaseConfig(name, testCloudAccountName, password, "5x", `modules = [{ name = "RediSearch" }]`) + + testSubErrorCase(t, config, regexp.MustCompile(`"creation_plan\.0\.query_performance_factor" must be an even value between 2x and 16x \(inclusive\), got: 5x`)) +} + +func TestAccResourceRedisCloudProDatabase_invalidQueryPerformanceFactors_outOfRange(t *testing.T) { + name := acctest.RandomWithPrefix("tf-test") + password := acctest.RandString(20) + testCloudAccountName := os.Getenv("AWS_TEST_CLOUD_ACCOUNT_NAME") + + config := formatDatabaseConfig(name, testCloudAccountName, password, "30x", `modules = [{ name = "RediSearch" }]`) + + testSubErrorCase(t, config, regexp.MustCompile(`"creation_plan\.0\.query_performance_factor" must be an even value between 2x and 16x \(inclusive\), got: 30x`)) +} diff --git a/provider/resource_rediscloud_pro_subscription_qpf_test.go b/provider/resource_rediscloud_pro_subscription_qpf_test.go index 75893d76..ddf3d6f9 100644 --- a/provider/resource_rediscloud_pro_subscription_qpf_test.go +++ b/provider/resource_rediscloud_pro_subscription_qpf_test.go @@ -128,7 +128,7 @@ func TestAccResourceRedisCloudProSubscription_missingRediSearchModule(t *testing testSubErrorCase(t, config, regexp.MustCompile("query_performance_factor\" requires the \"modules\" list to contain \"RediSearch")) } -func TestAccRedisCloudDatabase_invalidQueryPerformanceFactors(t *testing.T) { +func TestAccResourceRedisCloudProSubscription_invalidQueryPerformanceFactors(t *testing.T) { name := acctest.RandomWithPrefix("tf-test") password := acctest.RandString(20) testCloudAccountName := os.Getenv("AWS_TEST_CLOUD_ACCOUNT_NAME") @@ -138,7 +138,7 @@ func TestAccRedisCloudDatabase_invalidQueryPerformanceFactors(t *testing.T) { testSubErrorCase(t, config, regexp.MustCompile(`"creation_plan\.0\.query_performance_factor" must be an even value between 2x and 16x \(inclusive\), got: 5x`)) } -func TestAccRedisCloudDatabase_invalidQueryPerformanceFactors_outOfRange(t *testing.T) { +func TestAccResourceRedisCloudProSubscription_invalidQueryPerformanceFactors_outOfRange(t *testing.T) { name := acctest.RandomWithPrefix("tf-test") password := acctest.RandString(20) testCloudAccountName := os.Getenv("AWS_TEST_CLOUD_ACCOUNT_NAME") From ef2c0f1f1bbf5221773f9221fe7c0ad215f89b0d Mon Sep 17 00:00:00 2001 From: Trent Rosenbaum Date: Wed, 9 Apr 2025 16:03:06 +0100 Subject: [PATCH 22/27] Refined the QPF range to be 2x - 8x to match swagger api response --- provider/resource_rediscloud_pro_database.go | 4 ++-- provider/resource_rediscloud_pro_database_qpf_test.go | 4 ++-- provider/resource_rediscloud_pro_subscription.go | 4 ++-- provider/resource_rediscloud_pro_subscription_qpf_test.go | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/provider/resource_rediscloud_pro_database.go b/provider/resource_rediscloud_pro_database.go index 6899d480..4b66f91b 100644 --- a/provider/resource_rediscloud_pro_database.go +++ b/provider/resource_rediscloud_pro_database.go @@ -224,13 +224,13 @@ func resourceRedisCloudProDatabase() *schema.Resource { ForceNew: true, ValidateFunc: func(val interface{}, key string) (warns []string, errs []error) { v := val.(string) - matched, err := regexp.MatchString(`^(2|4|6|8|10|12|14|16)x$`, v) + matched, err := regexp.MatchString(`^([2468])x$`, v) if err != nil { errs = append(errs, fmt.Errorf("regex match failed: %s", err)) return } if !matched { - errs = append(errs, fmt.Errorf("%q must be an even value between 2x and 16x (inclusive), got: %s", key, v)) + errs = append(errs, fmt.Errorf("%q must be an even value between 2x and 8x (inclusive), got: %s", key, v)) } return }, diff --git a/provider/resource_rediscloud_pro_database_qpf_test.go b/provider/resource_rediscloud_pro_database_qpf_test.go index df9ff549..4c47a8c3 100644 --- a/provider/resource_rediscloud_pro_database_qpf_test.go +++ b/provider/resource_rediscloud_pro_database_qpf_test.go @@ -169,7 +169,7 @@ func TestAccResourceRedisCloudProDatabase_invalidQueryPerformanceFactors(t *test config := formatDatabaseConfig(name, testCloudAccountName, password, "5x", `modules = [{ name = "RediSearch" }]`) - testSubErrorCase(t, config, regexp.MustCompile(`"creation_plan\.0\.query_performance_factor" must be an even value between 2x and 16x \(inclusive\), got: 5x`)) + testSubErrorCase(t, config, regexp.MustCompile(`"creation_plan\.0\.query_performance_factor" must be an even value between 2x and 8x \(inclusive\), got: 5x`)) } func TestAccResourceRedisCloudProDatabase_invalidQueryPerformanceFactors_outOfRange(t *testing.T) { @@ -179,5 +179,5 @@ func TestAccResourceRedisCloudProDatabase_invalidQueryPerformanceFactors_outOfRa config := formatDatabaseConfig(name, testCloudAccountName, password, "30x", `modules = [{ name = "RediSearch" }]`) - testSubErrorCase(t, config, regexp.MustCompile(`"creation_plan\.0\.query_performance_factor" must be an even value between 2x and 16x \(inclusive\), got: 30x`)) + testSubErrorCase(t, config, regexp.MustCompile(`"creation_plan\.0\.query_performance_factor" must be an even value between 2x and 8x \(inclusive\), got: 30x`)) } diff --git a/provider/resource_rediscloud_pro_subscription.go b/provider/resource_rediscloud_pro_subscription.go index c376f264..1d2e8e03 100644 --- a/provider/resource_rediscloud_pro_subscription.go +++ b/provider/resource_rediscloud_pro_subscription.go @@ -296,13 +296,13 @@ func resourceRedisCloudProSubscription() *schema.Resource { Computed: true, ValidateFunc: func(val interface{}, key string) (warns []string, errs []error) { v := val.(string) - matched, err := regexp.MatchString(`^(2|4|6|8|10|12|14|16)x$`, v) + matched, err := regexp.MatchString(`^([2468])x$`, v) if err != nil { errs = append(errs, fmt.Errorf("regex match failed: %s", err)) return } if !matched { - errs = append(errs, fmt.Errorf("%q must be an even value between 2x and 16x (inclusive), got: %s", key, v)) + errs = append(errs, fmt.Errorf("%q must be an even value between 2x and 8x (inclusive), got: %s", key, v)) } return }, diff --git a/provider/resource_rediscloud_pro_subscription_qpf_test.go b/provider/resource_rediscloud_pro_subscription_qpf_test.go index ddf3d6f9..9c97b8bb 100644 --- a/provider/resource_rediscloud_pro_subscription_qpf_test.go +++ b/provider/resource_rediscloud_pro_subscription_qpf_test.go @@ -135,7 +135,7 @@ func TestAccResourceRedisCloudProSubscription_invalidQueryPerformanceFactors(t * config := formatDatabaseConfig(name, testCloudAccountName, password, "5x", `modules = [{ name = "RediSearch" }]`) - testSubErrorCase(t, config, regexp.MustCompile(`"creation_plan\.0\.query_performance_factor" must be an even value between 2x and 16x \(inclusive\), got: 5x`)) + testSubErrorCase(t, config, regexp.MustCompile(`"creation_plan\.0\.query_performance_factor" must be an even value between 2x and 8x \(inclusive\), got: 5x`)) } func TestAccResourceRedisCloudProSubscription_invalidQueryPerformanceFactors_outOfRange(t *testing.T) { @@ -145,5 +145,5 @@ func TestAccResourceRedisCloudProSubscription_invalidQueryPerformanceFactors_out config := formatDatabaseConfig(name, testCloudAccountName, password, "30x", `modules = [{ name = "RediSearch" }]`) - testSubErrorCase(t, config, regexp.MustCompile(`"creation_plan\.0\.query_performance_factor" must be an even value between 2x and 16x \(inclusive\), got: 30x`)) + testSubErrorCase(t, config, regexp.MustCompile(`"creation_plan\.0\.query_performance_factor" must be an even value between 2x and 8x \(inclusive\), got: 30x`)) } From 694367efa3fb5c5429a0b8ec687555c31bb2050d Mon Sep 17 00:00:00 2001 From: Trent Rosenbaum Date: Tue, 29 Apr 2025 09:10:16 +0100 Subject: [PATCH 23/27] Restores the TEST_PARALLELISM to a value of 6 --- GNUmakefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GNUmakefile b/GNUmakefile index 8174ef4c..8a19f929 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -10,7 +10,7 @@ PLUGINS_PATH = ~/.terraform.d/plugins PLUGINS_PROVIDER_PATH=$(PROVIDER_HOSTNAME)/$(PROVIDER_NAMESPACE)/$(PROVIDER_TYPE)/$(PROVIDER_VERSION)/$(PROVIDER_TARGET) # Use a parallelism of 3 by default for tests, overriding whatever GOMAXPROCS is set to. -TEST_PARALLELISM?=1 +TEST_PARALLELISM?=6 TESTARGS?=-short bin: From 99d584abc95125f25a2ce7739bd1bd9c2a1c8dac Mon Sep 17 00:00:00 2001 From: Matthew Long Date: Thu, 15 May 2025 16:11:04 +0100 Subject: [PATCH 24/27] test: renaming qpf tests so that smoke tests can pick out qpf --- provider/resource_rediscloud_pro_database_qpf_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/provider/resource_rediscloud_pro_database_qpf_test.go b/provider/resource_rediscloud_pro_database_qpf_test.go index 4c47a8c3..24cb2496 100644 --- a/provider/resource_rediscloud_pro_database_qpf_test.go +++ b/provider/resource_rediscloud_pro_database_qpf_test.go @@ -142,7 +142,7 @@ func TestAccResourceRedisCloudProDatabase_qpf(t *testing.T) { }) } -func TestAccResourceRedisCloudProDatabase_missingModule(t *testing.T) { +func TestAccResourceRedisCloudProDatabase_qpf_missingModule(t *testing.T) { name := acctest.RandomWithPrefix(testResourcePrefix) password := acctest.RandString(20) testCloudAccountName := os.Getenv("AWS_TEST_CLOUD_ACCOUNT_NAME") @@ -152,7 +152,7 @@ func TestAccResourceRedisCloudProDatabase_missingModule(t *testing.T) { testErrorCase(t, config, regexp.MustCompile("query_performance_factor\" requires the \"modules\" key to be explicitly defined in HCL")) } -func TestAccResourceRedisCloudProDatabase_missingRediSearchModule(t *testing.T) { +func TestAccResourceRedisCloudProDatabase_qpf_missingRediSearchModule(t *testing.T) { name := acctest.RandomWithPrefix(testResourcePrefix) password := acctest.RandString(20) testCloudAccountName := os.Getenv("AWS_TEST_CLOUD_ACCOUNT_NAME") @@ -162,7 +162,7 @@ func TestAccResourceRedisCloudProDatabase_missingRediSearchModule(t *testing.T) testErrorCase(t, config, regexp.MustCompile("query_performance_factor\" requires the \"modules\" list to contain \"RediSearch")) } -func TestAccResourceRedisCloudProDatabase_invalidQueryPerformanceFactors(t *testing.T) { +func TestAccResourceRedisCloudProDatabase_qpf_invalidQueryPerformanceFactors(t *testing.T) { name := acctest.RandomWithPrefix("tf-test") password := acctest.RandString(20) testCloudAccountName := os.Getenv("AWS_TEST_CLOUD_ACCOUNT_NAME") @@ -172,7 +172,7 @@ func TestAccResourceRedisCloudProDatabase_invalidQueryPerformanceFactors(t *test testSubErrorCase(t, config, regexp.MustCompile(`"creation_plan\.0\.query_performance_factor" must be an even value between 2x and 8x \(inclusive\), got: 5x`)) } -func TestAccResourceRedisCloudProDatabase_invalidQueryPerformanceFactors_outOfRange(t *testing.T) { +func TestAccResourceRedisCloudProDatabase_qpf_invalidQueryPerformanceFactors_outOfRange(t *testing.T) { name := acctest.RandomWithPrefix("tf-test") password := acctest.RandString(20) testCloudAccountName := os.Getenv("AWS_TEST_CLOUD_ACCOUNT_NAME") From 5b65d5d2122416775d6fea8477517cb951265b04 Mon Sep 17 00:00:00 2001 From: Matthew Long Date: Thu, 15 May 2025 16:30:56 +0100 Subject: [PATCH 25/27] chore: changing pr workflow to include qpf tests --- .github/workflows/terraform_provider_pr.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.github/workflows/terraform_provider_pr.yml b/.github/workflows/terraform_provider_pr.yml index 309d801e..9f087313 100644 --- a/.github/workflows/terraform_provider_pr.yml +++ b/.github/workflows/terraform_provider_pr.yml @@ -149,6 +149,19 @@ 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 ] + 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_.*"' + tfproviderlint: name: tfproviderlint needs: [go_build] From 2bd68a64e0ce5e79d60e3c611b0ff39dda098575 Mon Sep 17 00:00:00 2001 From: Matthew Long Date: Thu, 15 May 2025 16:53:51 +0100 Subject: [PATCH 26/27] fix: regex for qpf workflow is wrong --- .github/workflows/terraform_provider_pr.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/terraform_provider_pr.yml b/.github/workflows/terraform_provider_pr.yml index 9f087313..cf80a88c 100644 --- a/.github/workflows/terraform_provider_pr.yml +++ b/.github/workflows/terraform_provider_pr.yml @@ -160,7 +160,7 @@ jobs: - 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="TestAccResourceRedisCloudProDatabase_qpf.*"' tfproviderlint: name: tfproviderlint From 3c69143cba0e03048a2b9493a351891cb4be2923 Mon Sep 17 00:00:00 2001 From: Matthew Long Date: Fri, 16 May 2025 09:58:54 +0100 Subject: [PATCH 27/27] fix: nil check on query performance factor --- provider/resource_rediscloud_pro_database.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/provider/resource_rediscloud_pro_database.go b/provider/resource_rediscloud_pro_database.go index 4b66f91b..a6d959ad 100644 --- a/provider/resource_rediscloud_pro_database.go +++ b/provider/resource_rediscloud_pro_database.go @@ -613,9 +613,11 @@ func resourceRedisCloudProDatabaseRead(ctx context.Context, d *schema.ResourceDa if err := d.Set("remote_backup", flattenBackupPlan(db.Backup, d.Get("remote_backup").([]interface{}), d.Get("periodic_backup_path").(string))); err != nil { return diag.FromErr(err) } - - if err := d.Set("query_performance_factor", redis.String(*db.QueryPerformanceFactor)); err != nil { - return diag.FromErr(err) + + if db.QueryPerformanceFactor != nil { + if err := d.Set("query_performance_factor", redis.String(*db.QueryPerformanceFactor)); err != nil { + return diag.FromErr(err) + } } if err := readTags(ctx, api, subId, dbId, d); err != nil {