From da3cb650afa3cfd5140405b91961b8ba4891d8a1 Mon Sep 17 00:00:00 2001 From: "Luis M. Gallardo D" Date: Wed, 16 Jul 2025 15:40:34 +0200 Subject: [PATCH 1/3] fix: Resolve conditions variable type error in backup selections MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix conditions variable type from optional(map(any)) to proper nested object structure - Update selection_by_conditions example to use conditions instead of selection_tags - Add comprehensive test case for conditions variable validation - Resolves issue #169 where conditions caused "attribute types must all match" error The conditions variable now properly supports the AWS Backup API structure: - string_equals: map of key-value pairs for exact matches - string_not_equals: map of key-value pairs for exclusions - string_like: map of key-value pairs for pattern matching - string_not_like: map of key-value pairs for pattern exclusions 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- examples/selection_by_conditions/main.tf | 17 +++----- test/examples_test.go | 29 ++++++++++++++ test/fixtures/terraform/conditions/main.tf | 40 +++++++++++++++++++ test/fixtures/terraform/conditions/outputs.tf | 14 +++++++ .../terraform/conditions/variables.tf | 17 ++++++++ .../fixtures/terraform/conditions/versions.tf | 9 +++++ variables.tf | 7 +++- 7 files changed, 120 insertions(+), 13 deletions(-) create mode 100644 test/fixtures/terraform/conditions/main.tf create mode 100644 test/fixtures/terraform/conditions/outputs.tf create mode 100644 test/fixtures/terraform/conditions/variables.tf create mode 100644 test/fixtures/terraform/conditions/versions.tf diff --git a/examples/selection_by_conditions/main.tf b/examples/selection_by_conditions/main.tf index 5115c21..6f7f4a0 100644 --- a/examples/selection_by_conditions/main.tf +++ b/examples/selection_by_conditions/main.tf @@ -38,19 +38,12 @@ module "aws_backup_example" { # Selection configuration using conditions selections = { selection_by_conditions = { - name = "selection_by_conditions" - selection_tags = [ - { - type = "STRINGEQUALS" - key = "Environment" - value = "prod" - }, - { - type = "STRINGEQUALS" - key = "Service" - value = "web" + conditions = { + string_equals = { + "aws:ResourceTag/Environment" = "prod" + "aws:ResourceTag/Service" = "web" } - ] + } } } diff --git a/test/examples_test.go b/test/examples_test.go index b36d977..9b33a35 100644 --- a/test/examples_test.go +++ b/test/examples_test.go @@ -150,6 +150,35 @@ func TestExamplesWithCustomVariables(t *testing.T) { } } +func TestConditionsVariableTypes(t *testing.T) { + t.Parallel() + + // Test that the conditions variable accepts the proper structure + terraformOptions := &terraform.Options{ + TerraformDir: "./fixtures/terraform/conditions", + NoColor: true, + PlanFilePath: "tfplan-conditions", + } + + // Clean up plan file after test + defer func() { + planFile := filepath.Join("./fixtures/terraform/conditions", "tfplan-conditions") + if _, err := os.Stat(planFile); err == nil { + os.Remove(planFile) + } + }() + + // Init and validate + RetryableInit(t, terraformOptions) + + // Run terraform plan to validate the conditions structure works + RetryablePlan(t, terraformOptions) + + // Validate that plan was created successfully + planFile := filepath.Join("./fixtures/terraform/conditions", "tfplan-conditions") + assert.FileExists(t, planFile, "Plan file should be created for conditions test") +} + func TestExampleTerraformFiles(t *testing.T) { t.Parallel() diff --git a/test/fixtures/terraform/conditions/main.tf b/test/fixtures/terraform/conditions/main.tf new file mode 100644 index 0000000..672da25 --- /dev/null +++ b/test/fixtures/terraform/conditions/main.tf @@ -0,0 +1,40 @@ +module "aws_backup_conditions" { + source = "../../../.." + + # Basic configuration + plan_name = "conditions-backup-plan" + vault_name = "conditions-backup-vault" + + rules = [ + { + name = "conditions-backup-rule" + target_vault_name = "conditions-backup-vault" + schedule = "cron(0 5 ? * * *)" + start_window = 480 + completion_window = 600 + lifecycle = { + delete_after = 30 + } + } + ] + + # Test the conditions functionality + selections = { + conditions_test = { + conditions = { + string_equals = { + "aws:ResourceTag/Environment" = "dev" + "aws:ResourceTag/BackupEnabled" = "true" + } + string_not_equals = { + "aws:ResourceTag/SkipBackup" = "true" + } + } + } + } + + tags = { + Environment = "dev" + TestCase = "conditions" + } +} \ No newline at end of file diff --git a/test/fixtures/terraform/conditions/outputs.tf b/test/fixtures/terraform/conditions/outputs.tf new file mode 100644 index 0000000..dfc7c96 --- /dev/null +++ b/test/fixtures/terraform/conditions/outputs.tf @@ -0,0 +1,14 @@ +output "plan_arn" { + description = "Backup plan ARN" + value = module.aws_backup_conditions.plan_arn +} + +output "vault_arn" { + description = "Backup vault ARN" + value = module.aws_backup_conditions.vault_arn +} + +output "plan_id" { + description = "Backup plan ID" + value = module.aws_backup_conditions.plan_id +} \ No newline at end of file diff --git a/test/fixtures/terraform/conditions/variables.tf b/test/fixtures/terraform/conditions/variables.tf new file mode 100644 index 0000000..b39ba83 --- /dev/null +++ b/test/fixtures/terraform/conditions/variables.tf @@ -0,0 +1,17 @@ +variable "region" { + description = "AWS Region" + type = string + default = "us-east-1" +} + +variable "plan_name" { + description = "Plan name" + type = string + default = "conditions-backup-plan" +} + +variable "vault_name" { + description = "Vault name" + type = string + default = "conditions-backup-vault" +} \ No newline at end of file diff --git a/test/fixtures/terraform/conditions/versions.tf b/test/fixtures/terraform/conditions/versions.tf new file mode 100644 index 0000000..4c65a71 --- /dev/null +++ b/test/fixtures/terraform/conditions/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_version = ">= 1.0" + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 5.0" + } + } +} \ No newline at end of file diff --git a/variables.tf b/variables.tf index 88e7158..977bdf7 100644 --- a/variables.tf +++ b/variables.tf @@ -119,7 +119,12 @@ variable "plans" { selections = optional(map(object({ resources = optional(list(string)) not_resources = optional(list(string)) - conditions = optional(map(any)) + conditions = optional(object({ + string_equals = optional(map(string)) + string_not_equals = optional(map(string)) + string_like = optional(map(string)) + string_not_like = optional(map(string)) + })) selection_tags = optional(list(object({ type = string key = string From 9a2711c5039bef4ccb7e3ba16469656dfe75c05a Mon Sep 17 00:00:00 2001 From: "Luis M. Gallardo D" Date: Wed, 16 Jul 2025 17:53:49 +0200 Subject: [PATCH 2/3] fix: Add missing newlines to fix terraform fmt check --- test/fixtures/terraform/conditions/main.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/fixtures/terraform/conditions/main.tf b/test/fixtures/terraform/conditions/main.tf index 672da25..08c7453 100644 --- a/test/fixtures/terraform/conditions/main.tf +++ b/test/fixtures/terraform/conditions/main.tf @@ -23,7 +23,7 @@ module "aws_backup_conditions" { conditions_test = { conditions = { string_equals = { - "aws:ResourceTag/Environment" = "dev" + "aws:ResourceTag/Environment" = "dev" "aws:ResourceTag/BackupEnabled" = "true" } string_not_equals = { From d9b8e1426530e51d2656b80938c81892f7f5a797 Mon Sep 17 00:00:00 2001 From: "Luis M. Gallardo D" Date: Wed, 16 Jul 2025 18:29:47 +0200 Subject: [PATCH 3/3] fix: Make conditions variable types consistent across all variables - Update selection_conditions variable to use structured object type - Update backup_selections.conditions to use structured object type - Ensures consistent type definition across all conditions variables - Addresses PR review feedback about type inconsistency --- variables.tf | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/variables.tf b/variables.tf index 977bdf7..72d132f 100644 --- a/variables.tf +++ b/variables.tf @@ -333,8 +333,13 @@ variable "selection_not_resources" { variable "selection_conditions" { description = "A map of conditions that you define to assign resources to your backup plans using tags." - type = map(any) - default = {} + type = object({ + string_equals = optional(map(string)) + string_not_equals = optional(map(string)) + string_like = optional(map(string)) + string_not_like = optional(map(string)) + }) + default = {} } variable "selection_tags" { @@ -548,8 +553,13 @@ variable "backup_selections" { type = map(object({ resources = optional(list(string)) not_resources = optional(list(string)) - conditions = optional(map(any)) - tags = optional(map(string)) + conditions = optional(object({ + string_equals = optional(map(string)) + string_not_equals = optional(map(string)) + string_like = optional(map(string)) + string_not_like = optional(map(string)) + })) + tags = optional(map(string)) })) default = {}