diff --git a/.github/mergify.yml b/.github/mergify.yml index b010656..ef15545 100644 --- a/.github/mergify.yml +++ b/.github/mergify.yml @@ -56,3 +56,10 @@ pull_request_rules: changes_requested: true approved: true message: "This Pull Request has been updated, so we're dismissing all reviews." + +- name: "close Pull Requests without files changed" + conditions: + - "#files=0" + actions: + close: + message: "This pull request has been automatically closed by Mergify because there are no longer any changes." diff --git a/README.md b/README.md index 04ba071..9dea01c 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ Terraform module that loads and processes an opinionated ["stack" configuration](#examples) from YAML sources using the [`terraform-provider-utils`](https://github.com/cloudposse/terraform-provider-utils) Terraform provider. -It supports deep-merged variables, backend config, and remote state outputs for Terraform and helmfile components. +It supports deep-merged variables, settings, ENV variables, backend config, and remote state outputs for Terraform and helmfile components. --- @@ -66,9 +66,11 @@ We literally have [*hundreds of terraform modules*][terraform_modules] that are ## Introduction -The module is composed of three sub-modules: +The module is composed of the following sub-modules: - [vars](modules/vars) - accepts stack configuration and returns deep-merged variables for a Terraform or helmfile component. + - [settings](modules/settings) - accepts stack configuration and returns deep-merged settings for a Terraform or helmfile component. + - [env](modules/env) - accepts stack configuration and returns deep-merged ENV variables for a Terraform or helmfile component. - [backend](modules/backend) - accepts stack configuration and returns backend config for a Terraform component. - [remote-state](modules/remote-state) - accepts stack configuration and returns remote state outputs for a Terraform component. The module supports `s3` and `remote` (Terraform Cloud) backends. @@ -114,7 +116,7 @@ see [test](test). For an example on how to configure remote state for Terraform components in YAML config files and then read the components outputs from the remote state, see [examples/remote-state](examples/remote-state). -For an example on how to process `vars` and `backend` configurations for all Terraform and helmfile components for a list of stacks, +For an example on how to process `vars`, `settings`, `env` and `backend` configurations for all Terraform and helmfile components for a list of stacks, see [examples/stacks](examples/stacks). @@ -184,60 +186,107 @@ and returns variables and backend config for the Terraform component `my-vpc` fr context = module.this.context } + + module "settings" { + source = "cloudposse/stack-config/yaml//modules/settings" + # version = "x.x.x" + + stack_config_local_path = "./stacks" + stack = "my-stack" + component_type = "terraform" + component = "my-vpc" + + context = module.this.context + } + + module "env" { + source = "cloudposse/stack-config/yaml//modules/env" + # version = "x.x.x" + + stack_config_local_path = "./stacks" + stack = "my-stack" + component_type = "terraform" + component = "my-vpc" + + context = module.this.context + } + ``` -The example returns the following `vars` and `backend` configurations for the `my-vpc` Terraform component: +The example returns the following deep-merged `vars`, `settings`, `env`, and `backend` configurations for the `my-vpc` Terraform component: ```hcl - vars = { - "availability_zones" = [ - "us-east-2a", - "us-east-2b", - "us-east-2c", +backend = { + "acl" = "bucket-owner-full-control" + "bucket" = "eg-ue2-root-tfstate" + "dynamodb_table" = "eg-ue2-root-tfstate-lock" + "encrypt" = true + "key" = "terraform.tfstate" + "region" = "us-east-2" + "role_arn" = "arn:aws:iam::xxxxxxxxxxxx:role/eg-gbl-root-terraform" + "workspace_key_prefix" = "vpc" +} + +backend_type = "s3" +base_component = "vpc" + +env = { + "ENV_TEST_1" = "test1_override" + "ENV_TEST_2" = "test2_override" + "ENV_TEST_3" = "test3" + "ENV_TEST_4" = "test4" +} + +settings = { + "spacelift" = { + "autodeploy" = true + "branch" = "test" + "triggers" = [ + "1", + "2", ] - "cidr_block" = "10.132.0.0/18" - "environment" = "ue2" - "level" = 3 - "namespace" = "eg" - "param" = "param4" - "region" = "us-east-2" - "stage" = "prod" - "subnet_type_tag_key" = "example/subnet/type" - "test_map" = { - "a" = "a_override_2" - "b" = "b_override" - "c" = [ - 1, - 2, - 3, + "workspace_enabled" = true + } + "version" = 1 +} + +vars = { + "availability_zones" = [ + "us-east-2a", + "us-east-2b", + "us-east-2c", + ] + "cidr_block" = "10.132.0.0/18" + "environment" = "ue2" + "level" = 3 + "namespace" = "eg" + "param" = "param4" + "region" = "us-east-2" + "stage" = "prod" + "subnet_type_tag_key" = "example/subnet/type" + "test_map" = { + "a" = "a_override_2" + "b" = "b_override" + "c" = [ + 1, + 2, + 3, + ] + "map2" = { + "atr1" = 1 + "atr2" = 2 + "atr3" = [ + "3a", + "3b", + "3c", ] - "map2" = { - "atr1" = 1 - "atr2" = 2 - "atr3" = [ - "3a", - "3b", - "3c", - ] - } } - "var_1" = "1_override" - "var_2" = "2_override" - "var_3" = "3a" } + "var_1" = "1_override" + "var_2" = "2_override" + "var_3" = "3a" +} - backend_type = s3 - - backend = { - "acl" = "bucket-owner-full-control" - "bucket" = "eg-ue2-root-tfstate" - "dynamodb_table" = "eg-ue2-root-tfstate-lock" - "encrypt" = true - "key" = "terraform.tfstate" - "region" = "us-east-2" - "role_arn" = "arn:aws:iam::xxxxxxxxxxxx:role/eg-gbl-root-terraform" - "workspace_key_prefix" = "vpc" - } ``` See [examples/complete](examples/complete) for more details. @@ -252,7 +301,7 @@ __NOTE:__ The backend type (`s3`) and backend configuration for the components a ```hcl module "remote_state_my_vpc" { - source = "cloudposse/stack-config/yaml" + source = "cloudposse/stack-config/yaml//modules/remote-state" # Cloud Posse recommends pinning every module to a specific version # version = "x.x.x" @@ -262,7 +311,7 @@ __NOTE:__ The backend type (`s3`) and backend configuration for the components a } module "remote_state_eks" { - source = "cloudposse/stack-config/yaml" + source = "cloudposse/stack-config/yaml//modules/remote-state" # Cloud Posse recommends pinning every module to a specific version # version = "x.x.x" @@ -297,13 +346,13 @@ Available targets: | external | >= 2.0 | | local | >= 1.3 | | template | >= 2.2 | -| utils | >= 0.2.1 | +| utils | >= 0.3.0 | ## Providers | Name | Version | |------|---------| -| utils | >= 0.2.1 | +| utils | >= 0.3.0 | ## Modules @@ -315,7 +364,7 @@ Available targets: | Name | |------| -| [utils_stack_config_yaml](https://registry.terraform.io/providers/cloudposse/utils/0.2.1/docs/data-sources/stack_config_yaml) | +| [utils_stack_config_yaml](https://registry.terraform.io/providers/cloudposse/utils/0.3.0/docs/data-sources/stack_config_yaml) | ## Inputs diff --git a/README.yaml b/README.yaml index 6637427..a3007ca 100644 --- a/README.yaml +++ b/README.yaml @@ -99,14 +99,16 @@ description: |- Terraform module that loads and processes an opinionated ["stack" configuration](#examples) from YAML sources using the [`terraform-provider-utils`](https://github.com/cloudposse/terraform-provider-utils) Terraform provider. - It supports deep-merged variables, backend config, and remote state outputs for Terraform and helmfile components. + It supports deep-merged variables, settings, ENV variables, backend config, and remote state outputs for Terraform and helmfile components. # Introduction to the project introduction: |- - The module is composed of three sub-modules: + The module is composed of the following sub-modules: - [vars](modules/vars) - accepts stack configuration and returns deep-merged variables for a Terraform or helmfile component. + - [settings](modules/settings) - accepts stack configuration and returns deep-merged settings for a Terraform or helmfile component. + - [env](modules/env) - accepts stack configuration and returns deep-merged ENV variables for a Terraform or helmfile component. - [backend](modules/backend) - accepts stack configuration and returns backend config for a Terraform component. - [remote-state](modules/remote-state) - accepts stack configuration and returns remote state outputs for a Terraform component. The module supports `s3` and `remote` (Terraform Cloud) backends. @@ -121,7 +123,7 @@ usage: |- For an example on how to configure remote state for Terraform components in YAML config files and then read the components outputs from the remote state, see [examples/remote-state](examples/remote-state). - For an example on how to process `vars` and `backend` configurations for all Terraform and helmfile components for a list of stacks, + For an example on how to process `vars`, `settings`, `env` and `backend` configurations for all Terraform and helmfile components for a list of stacks, see [examples/stacks](examples/stacks). @@ -189,60 +191,107 @@ examples: |- context = module.this.context } + + module "settings" { + source = "cloudposse/stack-config/yaml//modules/settings" + # version = "x.x.x" + + stack_config_local_path = "./stacks" + stack = "my-stack" + component_type = "terraform" + component = "my-vpc" + + context = module.this.context + } + + module "env" { + source = "cloudposse/stack-config/yaml//modules/env" + # version = "x.x.x" + + stack_config_local_path = "./stacks" + stack = "my-stack" + component_type = "terraform" + component = "my-vpc" + + context = module.this.context + } + ``` - The example returns the following `vars` and `backend` configurations for the `my-vpc` Terraform component: + The example returns the following deep-merged `vars`, `settings`, `env`, and `backend` configurations for the `my-vpc` Terraform component: ```hcl - vars = { - "availability_zones" = [ - "us-east-2a", - "us-east-2b", - "us-east-2c", + backend = { + "acl" = "bucket-owner-full-control" + "bucket" = "eg-ue2-root-tfstate" + "dynamodb_table" = "eg-ue2-root-tfstate-lock" + "encrypt" = true + "key" = "terraform.tfstate" + "region" = "us-east-2" + "role_arn" = "arn:aws:iam::xxxxxxxxxxxx:role/eg-gbl-root-terraform" + "workspace_key_prefix" = "vpc" + } + + backend_type = "s3" + base_component = "vpc" + + env = { + "ENV_TEST_1" = "test1_override" + "ENV_TEST_2" = "test2_override" + "ENV_TEST_3" = "test3" + "ENV_TEST_4" = "test4" + } + + settings = { + "spacelift" = { + "autodeploy" = true + "branch" = "test" + "triggers" = [ + "1", + "2", ] - "cidr_block" = "10.132.0.0/18" - "environment" = "ue2" - "level" = 3 - "namespace" = "eg" - "param" = "param4" - "region" = "us-east-2" - "stage" = "prod" - "subnet_type_tag_key" = "example/subnet/type" - "test_map" = { - "a" = "a_override_2" - "b" = "b_override" - "c" = [ - 1, - 2, - 3, + "workspace_enabled" = true + } + "version" = 1 + } + + vars = { + "availability_zones" = [ + "us-east-2a", + "us-east-2b", + "us-east-2c", + ] + "cidr_block" = "10.132.0.0/18" + "environment" = "ue2" + "level" = 3 + "namespace" = "eg" + "param" = "param4" + "region" = "us-east-2" + "stage" = "prod" + "subnet_type_tag_key" = "example/subnet/type" + "test_map" = { + "a" = "a_override_2" + "b" = "b_override" + "c" = [ + 1, + 2, + 3, + ] + "map2" = { + "atr1" = 1 + "atr2" = 2 + "atr3" = [ + "3a", + "3b", + "3c", ] - "map2" = { - "atr1" = 1 - "atr2" = 2 - "atr3" = [ - "3a", - "3b", - "3c", - ] - } } - "var_1" = "1_override" - "var_2" = "2_override" - "var_3" = "3a" } + "var_1" = "1_override" + "var_2" = "2_override" + "var_3" = "3a" + } - backend_type = s3 - - backend = { - "acl" = "bucket-owner-full-control" - "bucket" = "eg-ue2-root-tfstate" - "dynamodb_table" = "eg-ue2-root-tfstate-lock" - "encrypt" = true - "key" = "terraform.tfstate" - "region" = "us-east-2" - "role_arn" = "arn:aws:iam::xxxxxxxxxxxx:role/eg-gbl-root-terraform" - "workspace_key_prefix" = "vpc" - } ``` See [examples/complete](examples/complete) for more details. @@ -257,7 +306,7 @@ examples: |- ```hcl module "remote_state_my_vpc" { - source = "cloudposse/stack-config/yaml" + source = "cloudposse/stack-config/yaml//modules/remote-state" # Cloud Posse recommends pinning every module to a specific version # version = "x.x.x" @@ -267,7 +316,7 @@ examples: |- } module "remote_state_eks" { - source = "cloudposse/stack-config/yaml" + source = "cloudposse/stack-config/yaml//modules/remote-state" # Cloud Posse recommends pinning every module to a specific version # version = "x.x.x" diff --git a/docs/terraform.md b/docs/terraform.md index 4319972..02149a6 100644 --- a/docs/terraform.md +++ b/docs/terraform.md @@ -7,13 +7,13 @@ | external | >= 2.0 | | local | >= 1.3 | | template | >= 2.2 | -| utils | >= 0.2.1 | +| utils | >= 0.3.0 | ## Providers | Name | Version | |------|---------| -| utils | >= 0.2.1 | +| utils | >= 0.3.0 | ## Modules @@ -25,7 +25,7 @@ | Name | |------| -| [utils_stack_config_yaml](https://registry.terraform.io/providers/cloudposse/utils/0.2.1/docs/data-sources/stack_config_yaml) | +| [utils_stack_config_yaml](https://registry.terraform.io/providers/cloudposse/utils/0.3.0/docs/data-sources/stack_config_yaml) | ## Inputs diff --git a/examples/complete/main.tf b/examples/complete/main.tf index 869a71e..70011e2 100644 --- a/examples/complete/main.tf +++ b/examples/complete/main.tf @@ -19,3 +19,26 @@ module "backend" { context = module.this.context } + +module "settings" { + source = "../../modules/settings" + + stack_config_local_path = var.stack_config_local_path + stack = var.stack + component_type = var.component_type + component = var.component + + context = module.this.context +} + +module "env" { + source = "../../modules/env" + + stack_config_local_path = var.stack_config_local_path + stack = var.stack + component_type = var.component_type + component = var.component + + context = module.this.context +} + diff --git a/examples/complete/outputs.tf b/examples/complete/outputs.tf index b1a5918..5687f5a 100644 --- a/examples/complete/outputs.tf +++ b/examples/complete/outputs.tf @@ -1,6 +1,6 @@ output "vars" { value = module.vars.vars - description = "Vars configuration for the component" + description = "vars for the component" } output "backend_type" { @@ -17,3 +17,13 @@ output "base_component" { value = module.backend.base_component description = "Base component name" } + +output "settings" { + value = module.settings.settings + description = "settings for the component" +} + +output "env" { + value = module.env.env + description = "ENV variables for the component" +} diff --git a/examples/complete/stacks/imports-level-3.yaml b/examples/complete/stacks/imports-level-3.yaml index ef760fd..b07bbcb 100644 --- a/examples/complete/stacks/imports-level-3.yaml +++ b/examples/complete/stacks/imports-level-3.yaml @@ -8,6 +8,14 @@ terraform: vars: var_1: 1 var_3: 3 + settings: + version: 1 + spacelift: + workspace_enabled: false + autodeploy: false + env: + ENV_TEST_1: test1 + ENV_TEST_2: test2 helmfile: vars: {} diff --git a/examples/complete/stacks/my-stack.yaml b/examples/complete/stacks/my-stack.yaml index 6357b42..5595dd0 100644 --- a/examples/complete/stacks/my-stack.yaml +++ b/examples/complete/stacks/my-stack.yaml @@ -25,6 +25,16 @@ components: - 3a - 3b - 3c + settings: + spacelift: + workspace_enabled: true + autodeploy: true + branch: "test" + triggers: ["1", "2"] + env: + ENV_TEST_1: test1_override + ENV_TEST_2: test2_override + ENV_TEST_4: test4 vpc: vars: @@ -36,6 +46,9 @@ components: - 1 - 2 - 3 + env: + ENV_TEST_3: test3 + eks: vars: {} diff --git a/examples/complete/versions.tf b/examples/complete/versions.tf index 6bf7201..0077d8a 100644 --- a/examples/complete/versions.tf +++ b/examples/complete/versions.tf @@ -16,7 +16,7 @@ terraform { } utils = { source = "cloudposse/utils" - version = ">= 0.2.1" + version = ">= 0.3.0" } } } diff --git a/examples/remote-state/versions.tf b/examples/remote-state/versions.tf index 6bf7201..0077d8a 100644 --- a/examples/remote-state/versions.tf +++ b/examples/remote-state/versions.tf @@ -16,7 +16,7 @@ terraform { } utils = { source = "cloudposse/utils" - version = ">= 0.2.1" + version = ">= 0.3.0" } } } diff --git a/examples/stacks/README.md b/examples/stacks/README.md index 4181a7e..7c0940a 100644 --- a/examples/stacks/README.md +++ b/examples/stacks/README.md @@ -29,6 +29,8 @@ The module returns `vars` and `backend` configurations for all Terraform and hel "components" = { "helmfile" = { "alb-controller" = { + "env" = {} + "settings" = {} "vars" = { "account_number" = "1234567890" "chart_values" = { @@ -43,6 +45,8 @@ The module returns `vars` and `backend` configurations for all Terraform and hel } } "cert-manager" = { + "env" = {} + "settings" = {} "vars" = { "account_number" = "1234567890" "environment" = "uw2" @@ -53,6 +57,40 @@ The module returns `vars` and `backend` configurations for all Terraform and hel "stage" = "dev" } } + "datadog" = { + "env" = { + "ENV_DD_TEST_1" = "dd1" + "ENV_DD_TEST_2" = "dd2" + "ENV_DD_TEST_3" = "dd3" + } + "settings" = {} + "vars" = { + "account_number" = "1234567890" + "apm" = { + "enabled" = true + } + "clusterAgent" = { + "enabled" = true + } + "datadogTags" = [ + "env:uw2-dev", + "region:us-west-2", + "stage:dev", + ] + "environment" = "uw2" + "installed" = true + "namespace" = "eg" + "processAgent" = { + "enabled" = true + } + "region" = "us-west-2" + "ssm_region" = "us-west-2" + "stage" = "dev" + "systemProbe" = { + "enabled" = true + } + } + } } "terraform" = { "account" = { @@ -67,6 +105,18 @@ The module returns `vars` and `backend` configurations for all Terraform and hel "workspace_key_prefix" = "account" } "backend_type" = "s3" + "env" = { + "ENV_TEST_1" = "test1" + "ENV_TEST_2" = "test2" + "ENV_TEST_3" = "test3" + } + "settings" = { + "spacelift" = { + "autodeploy" = false + "workspace_enabled" = false + } + "version" = 0 + } "vars" = { "environment" = "uw2" "namespace" = "eg" @@ -86,6 +136,22 @@ The module returns `vars` and `backend` configurations for all Terraform and hel "workspace_key_prefix" = "aurora-postgres" } "backend_type" = "s3" + "env" = { + "ENV_TEST_1" = "test1" + "ENV_TEST_2" = "test2" + "ENV_TEST_3" = "test3" + "ENV_TEST_4" = "test4" + "ENV_TEST_5" = "test5" + "ENV_TEST_6" = "test6" + "ENV_TEST_7" = "test7" + } + "settings" = { + "spacelift" = { + "autodeploy" = false + "workspace_enabled" = false + } + "version" = 0 + } "vars" = { "cluster_size" = 1 "environment" = "uw2" @@ -107,67 +173,30 @@ The module returns `vars` and `backend` configurations for all Terraform and hel "workspace_key_prefix" = "aurora-postgres" } "backend_type" = "s3" - "vars" = { - "cluster_size" = 1 - "environment" = "uw2" - "instance_type" = "db.r4.xlarge" - "namespace" = "eg" - "region" = "us-west-2" - "stage" = "dev" - } - } - "efs" = { - "backend" = { - "acl" = "bucket-owner-full-control" - "bucket" = "eg-uw2-root-tfstate" - "dynamodb_table" = "eg-uw2-root-tfstate-lock" - "encrypt" = true - "key" = "terraform.tfstate" - "region" = "us-west-2" - "role_arn" = "arn:aws:iam::XXXXXXXXXXXX:role/eg-gbl-root-terraform" - "workspace_key_prefix" = "efs" + "component" = "aurora-postgres" + "env" = { + "ENV_TEST_1" = "test1_override2" + "ENV_TEST_2" = "test2_override2" + "ENV_TEST_3" = "test3" + "ENV_TEST_4" = "test4" + "ENV_TEST_5" = "test5" + "ENV_TEST_6" = "test6" + "ENV_TEST_7" = "test7" + "ENV_TEST_8" = "test8" } - "backend_type" = "s3" - "vars" = { - "environment" = "uw2" - "namespace" = "eg" - "region" = "us-west-2" - "stage" = "dev" - } - } - "sso" = { - "backend" = { - "acl" = "bucket-owner-full-control" - "bucket" = "eg-uw2-root-tfstate" - "dynamodb_table" = "eg-uw2-root-tfstate-lock" - "encrypt" = true - "key" = "terraform.tfstate" - "region" = "us-west-2" - "role_arn" = null - "workspace_key_prefix" = "sso" - } - "backend_type" = "s3" - "vars" = { - "environment" = "uw2" - "namespace" = "eg" - "region" = "us-west-2" - "stage" = "dev" - } - } - "tfstate-backend" = { - "backend" = { - "acl" = "bucket-owner-full-control" - "bucket" = "eg-uw2-root-tfstate" - "dynamodb_table" = "eg-uw2-root-tfstate-lock" - "encrypt" = true - "key" = "terraform.tfstate" - "region" = "us-west-2" - "role_arn" = null - "workspace_key_prefix" = "tfstate-backend" + "settings" = { + "spacelift" = { + "autodeploy" = true + "branch" = "dev" + "triggers" = [] + "workspace_enabled" = true + } + "version" = 0 } - "backend_type" = "s3" "vars" = { + "cluster_size" = 1 "environment" = "uw2" + "instance_type" = "db.r4.xlarge" "namespace" = "eg" "region" = "us-west-2" "stage" = "dev" @@ -185,6 +214,20 @@ The module returns `vars` and `backend` configurations for all Terraform and hel "workspace_key_prefix" = "vpc" } "backend_type" = "s3" + "env" = { + "ENV_TEST_1" = "test1" + "ENV_TEST_2" = "test2" + "ENV_TEST_3" = "test3" + } + "settings" = { + "spacelift" = { + "autodeploy" = true + "branch" = "" + "triggers" = [] + "workspace_enabled" = true + } + "version" = 0 + } "vars" = { "availability_zones" = [ "us-west-2b", @@ -203,7 +246,7 @@ The module returns `vars` and `backend` configurations for all Terraform and hel "vpc_flow_logs_traffic_type" = "ALL" } } - "vpc-flow-logs-bucket" = { + "eks" = { "backend" = { "acl" = "bucket-owner-full-control" "bucket" = "eg-uw2-root-tfstate" @@ -212,13 +255,48 @@ The module returns `vars` and `backend` configurations for all Terraform and hel "key" = "terraform.tfstate" "region" = "us-west-2" "role_arn" = "arn:aws:iam::XXXXXXXXXXXX:role/eg-gbl-root-terraform" - "workspace_key_prefix" = "vpc-flow-logs-bucket" + "workspace_key_prefix" = "eks" } "backend_type" = "s3" + "env" = { + "ENV_TEST_1" = "test1_override" + "ENV_TEST_2" = "test2_override" + "ENV_TEST_3" = "test3" + "ENV_TEST_4" = "test4" + } + "settings" = { + "spacelift" = { + "autodeploy" = true + "branch" = "test" + "triggers" = [] + "workspace_enabled" = true + } + "version" = 0 + } "vars" = { "environment" = "uw2" "namespace" = "eg" "region" = "us-west-2" + "region_availability_zones" = [ + "us-west-2b", + "us-west-2c", + "us-west-2d", + ] + "spotinst_instance_profile" = "eg-gbl-dev-spotinst-worker" + "spotinst_oceans" = { + "main" = { + "ami_release_version" = null + "ami_type" = "AL2_x86_64" + "attributes" = null + "desired_group_size" = 1 + "disk_size" = 100 + "instance_types" = null + "kubernetes_version" = null + "max_group_size" = 3 + "min_group_size" = 1 + "tags" = null + } + } "stage" = "dev" } } diff --git a/examples/stacks/stacks/uw2-dev.yaml b/examples/stacks/stacks/uw2-dev.yaml index 113e291..97fdb6c 100644 --- a/examples/stacks/stacks/uw2-dev.yaml +++ b/examples/stacks/stacks/uw2-dev.yaml @@ -21,6 +21,12 @@ components: zone_config: - subdomain: dev zone_name: uw2.example.com + settings: + spacelift: + workspace_enabled: true + autodeploy: false + branch: "" + triggers: [] eks: vars: @@ -37,20 +43,51 @@ components: instance_types: null ami_type: "AL2_x86_64" tags: null + settings: + spacelift: + workspace_enabled: true + autodeploy: true + branch: "test" + triggers: [] + env: + ENV_TEST_1: test1_override + ENV_TEST_2: test2_override + ENV_TEST_4: test4 vpc: vars: cidr_block: "10.114.0.0/18" + settings: + spacelift: + workspace_enabled: true + autodeploy: true + branch: "" + triggers: [] aurora-postgres: vars: instance_type: db.r4.large cluster_size: 1 + env: + ENV_TEST_4: test4 + ENV_TEST_5: test5 + ENV_TEST_6: test6 + ENV_TEST_7: test7 aurora-postgres-2: component: aurora-postgres vars: instance_type: db.r4.xlarge + settings: + spacelift: + workspace_enabled: true + autodeploy: true + branch: "dev" + triggers: [] + env: + ENV_TEST_1: test1_override2 + ENV_TEST_2: test2_override2 + ENV_TEST_8: test8 helmfile: @@ -61,3 +98,7 @@ components: - "env:uw2-dev" - "region:us-west-2" - "stage:dev" + env: + ENV_DD_TEST_1: dd1 + ENV_DD_TEST_2: dd2 + ENV_DD_TEST_3: dd3 diff --git a/examples/stacks/stacks/uw2-globals.yaml b/examples/stacks/stacks/uw2-globals.yaml index 35bdb1b..84f7b49 100644 --- a/examples/stacks/stacks/uw2-globals.yaml +++ b/examples/stacks/stacks/uw2-globals.yaml @@ -7,6 +7,15 @@ vars: terraform: vars: {} + settings: + version: 0 + spacelift: + workspace_enabled: false + autodeploy: false + env: + ENV_TEST_1: test1 + ENV_TEST_2: test2 + ENV_TEST_3: test3 helmfile: vars: diff --git a/examples/stacks/stacks/uw2-prod.yaml b/examples/stacks/stacks/uw2-prod.yaml index c2252c0..54d8869 100644 --- a/examples/stacks/stacks/uw2-prod.yaml +++ b/examples/stacks/stacks/uw2-prod.yaml @@ -21,6 +21,12 @@ components: zone_config: - subdomain: prod zone_name: uw2.example.com + settings: + spacelift: + workspace_enabled: true + autodeploy: false + branch: "" + triggers: [] eks: vars: @@ -37,20 +43,51 @@ components: instance_types: null ami_type: "AL2_x86_64" tags: null + settings: + spacelift: + workspace_enabled: true + autodeploy: true + branch: "" + triggers: [] + env: + ENV_TEST_1: test1_override + ENV_TEST_2: test2_override + ENV_TEST_4: test4 vpc: vars: cidr_block: "10.116.0.0/18" + settings: + spacelift: + workspace_enabled: true + autodeploy: false + branch: "" + triggers: [] aurora-postgres: vars: instance_type: db.r4.large cluster_size: 3 + env: + ENV_TEST_4: test4 + ENV_TEST_5: test5 + ENV_TEST_6: test6 + ENV_TEST_7: test7 aurora-postgres-2: component: aurora-postgres vars: instance_type: db.r4.xlarge + settings: + spacelift: + workspace_enabled: true + autodeploy: true + branch: "" + triggers: [] + env: + ENV_TEST_1: test1_override2 + ENV_TEST_2: test2_override2 + ENV_TEST_8: test8 helmfile: @@ -61,3 +98,7 @@ components: - "env:uw2-prod" - "region:us-west-2" - "stage:prod" + env: + ENV_DD_TEST_1: dd1 + ENV_DD_TEST_2: dd2 + ENV_DD_TEST_3: dd3 diff --git a/examples/stacks/stacks/uw2-staging.yaml b/examples/stacks/stacks/uw2-staging.yaml index fd81b10..011ea9a 100644 --- a/examples/stacks/stacks/uw2-staging.yaml +++ b/examples/stacks/stacks/uw2-staging.yaml @@ -21,6 +21,12 @@ components: zone_config: - subdomain: staging zone_name: uw2.example.com + settings: + spacelift: + workspace_enabled: true + autodeploy: false + branch: "" + triggers: [] eks: vars: @@ -37,20 +43,51 @@ components: instance_types: null ami_type: "AL2_x86_64" tags: null + settings: + spacelift: + workspace_enabled: true + autodeploy: true + branch: "" + triggers: [] + env: + ENV_TEST_1: test1_override + ENV_TEST_2: test2_override + ENV_TEST_4: test4 vpc: vars: cidr_block: "10.118.0.0/18" + settings: + spacelift: + workspace_enabled: true + autodeploy: false + branch: "" + triggers: [] aurora-postgres: vars: instance_type: db.r4.large cluster_size: 2 + env: + ENV_TEST_4: test4 + ENV_TEST_5: test5 + ENV_TEST_6: test6 + ENV_TEST_7: test7 aurora-postgres-2: component: aurora-postgres vars: instance_type: db.r4.xlarge + settings: + spacelift: + workspace_enabled: true + autodeploy: true + branch: "" + triggers: [] + env: + ENV_TEST_1: test1_override2 + ENV_TEST_2: test2_override2 + ENV_TEST_8: test8 helmfile: @@ -61,3 +98,7 @@ components: - "env:uw2-staging" - "region:us-west-2" - "stage:staging" + env: + ENV_DD_TEST_1: dd1 + ENV_DD_TEST_2: dd2 + ENV_DD_TEST_3: dd3 diff --git a/examples/stacks/stacks/uw2-uat.yaml b/examples/stacks/stacks/uw2-uat.yaml index 6b569fc..8e48e2e 100644 --- a/examples/stacks/stacks/uw2-uat.yaml +++ b/examples/stacks/stacks/uw2-uat.yaml @@ -21,6 +21,12 @@ components: zone_config: - subdomain: uat zone_name: uw2.example.com + settings: + spacelift: + workspace_enabled: true + autodeploy: false + branch: "" + triggers: [] eks: vars: @@ -37,21 +43,60 @@ components: instance_types: null ami_type: "AL2_x86_64" tags: null + settings: + spacelift: + workspace_enabled: true + autodeploy: false + branch: "main" + triggers: [] + env: + ENV_TEST_1: test1_override + ENV_TEST_2: test2_override + ENV_TEST_4: test4 vpc: vars: cidr_block: "10.120.0.0/18" + settings: + spacelift: + workspace_enabled: true + autodeploy: false + branch: "main" + triggers: [] aurora-postgres: vars: instance_type: db.r4.large cluster_size: 2 + settings: + version: 1 + spacelift: + workspace_enabled: false + autodeploy: false + branch: "test3" + triggers: ["4", "5", "6"] + env: + ENV_TEST_4: test4 + ENV_TEST_5: test5 + ENV_TEST_6: test6 + ENV_TEST_7: test7 aurora-postgres-2: component: aurora-postgres vars: cluster_size: 3 instance_type: db.r4.xlarge + settings: + version: 2 + spacelift: + workspace_enabled: true + autodeploy: true + branch: "test4" + triggers: ["7", "8", "9"] + env: + ENV_TEST_1: test1_override2 + ENV_TEST_2: test2_override2 + ENV_TEST_8: test8 helmfile: @@ -62,3 +107,7 @@ components: - "env:uw2-uat" - "region:us-west-2" - "stage:uat" + env: + ENV_DD_TEST_1: dd1 + ENV_DD_TEST_2: dd2 + ENV_DD_TEST_3: dd3 diff --git a/examples/stacks/versions.tf b/examples/stacks/versions.tf index 6bf7201..0077d8a 100644 --- a/examples/stacks/versions.tf +++ b/examples/stacks/versions.tf @@ -16,7 +16,7 @@ terraform { } utils = { source = "cloudposse/utils" - version = ">= 0.2.1" + version = ">= 0.3.0" } } } diff --git a/modules/backend/README.md b/modules/backend/README.md index 55044b9..87fe889 100644 --- a/modules/backend/README.md +++ b/modules/backend/README.md @@ -5,7 +5,7 @@ Terraform module that accepts stack configuration and returns backend config for ## Usage The following example loads the stack config `my-stack` (which in turn imports other YAML config dependencies) -and returns variables and backend config for stack `my-stack` and Terraform component `my-vpc`. +and returns variables and backend config for Terraform component `my-vpc`. ```hcl module "vars" { diff --git a/modules/backend/main.tf b/modules/backend/main.tf index fb8b973..3a947ec 100644 --- a/modules/backend/main.tf +++ b/modules/backend/main.tf @@ -7,7 +7,8 @@ data "utils_stack_config_yaml" "config" { } locals { - backend_type = yamldecode(data.utils_stack_config_yaml.config.output[0])["components"][var.component_type][var.component]["backend_type"] - backend = yamldecode(data.utils_stack_config_yaml.config.output[0])["components"][var.component_type][var.component]["backend"] - base_component = try(yamldecode(data.utils_stack_config_yaml.config.output[0])["components"][var.component_type][var.component]["component"], "") + config = yamldecode(data.utils_stack_config_yaml.config.output[0]) + backend_type = local.config["components"][var.component_type][var.component]["backend_type"] + backend = local.config["components"][var.component_type][var.component]["backend"] + base_component = try(local.config["components"][var.component_type][var.component]["component"], "") } diff --git a/modules/backend/versions.tf b/modules/backend/versions.tf index 6bf7201..0077d8a 100644 --- a/modules/backend/versions.tf +++ b/modules/backend/versions.tf @@ -16,7 +16,7 @@ terraform { } utils = { source = "cloudposse/utils" - version = ">= 0.2.1" + version = ">= 0.3.0" } } } diff --git a/modules/env/README.md b/modules/env/README.md new file mode 100644 index 0000000..d37b449 --- /dev/null +++ b/modules/env/README.md @@ -0,0 +1,24 @@ +# env + +Terraform module that accepts stack configuration and returns deep-merged ENV variables for a Terraform or helmfile component. + +## Usage + +The following example loads the stack config `my-stack` (which in turn imports other YAML config dependencies) +and returns ENV variables for Terraform component `my-vpc`. + + ```hcl + module "vars" { + source = "cloudposse/stack-config/yaml//modules/env" + # version = "x.x.x" + + stack_config_local_path = "./stacks" + stack = "my-stack" + component_type = "terraform" + component = "my-vpc" + + context = module.this.context + } +``` + +See [examples/complete](../../examples/complete) for more details. diff --git a/modules/env/context.tf b/modules/env/context.tf new file mode 100644 index 0000000..81f99b4 --- /dev/null +++ b/modules/env/context.tf @@ -0,0 +1,202 @@ +# +# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label +# All other instances of this file should be a copy of that one +# +# +# Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf +# and then place it in your Terraform module to automatically get +# Cloud Posse's standard configuration inputs suitable for passing +# to Cloud Posse modules. +# +# Modules should access the whole context as `module.this.context` +# to get the input variables with nulls for defaults, +# for example `context = module.this.context`, +# and access individual variables as `module.this.`, +# with final values filled in. +# +# For example, when using defaults, `module.this.context.delimiter` +# will be null, and `module.this.delimiter` will be `-` (hyphen). +# + +module "this" { + source = "cloudposse/label/null" + version = "0.24.1" # requires Terraform >= 0.13.0 + + enabled = var.enabled + namespace = var.namespace + environment = var.environment + stage = var.stage + name = var.name + delimiter = var.delimiter + attributes = var.attributes + tags = var.tags + additional_tag_map = var.additional_tag_map + label_order = var.label_order + regex_replace_chars = var.regex_replace_chars + id_length_limit = var.id_length_limit + label_key_case = var.label_key_case + label_value_case = var.label_value_case + + context = var.context +} + +# Copy contents of cloudposse/terraform-null-label/variables.tf here + +variable "context" { + type = any + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = lookup(var.context, "label_key_case", null) == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = lookup(var.context, "label_value_case", null) == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters (minimum 6). + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT + validation { + condition = var.id_length_limit == null ? true : var.id_length_limit >= 6 || var.id_length_limit == 0 + error_message = "The id_length_limit must be >= 6 if supplied (not null), or 0 for unlimited length." + } +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} +#### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/modules/env/main.tf b/modules/env/main.tf new file mode 100644 index 0000000..c3fe25f --- /dev/null +++ b/modules/env/main.tf @@ -0,0 +1,13 @@ +locals { + stack = var.stack != null ? var.stack : format("%s-%s", module.this.environment, module.this.stage) +} + +data "utils_stack_config_yaml" "config" { + input = [format("%s/%s.yaml", var.stack_config_local_path, local.stack)] +} + +locals { + config = yamldecode(data.utils_stack_config_yaml.config.output[0]) + env = local.config["components"][var.component_type][var.component]["env"] + base_component = try(local.config["components"][var.component_type][var.component]["component"], "") +} diff --git a/modules/env/outputs.tf b/modules/env/outputs.tf new file mode 100644 index 0000000..41026d2 --- /dev/null +++ b/modules/env/outputs.tf @@ -0,0 +1,9 @@ +output "env" { + value = local.env + description = "ENV variables for the component" +} + +output "base_component" { + value = local.base_component + description = "Base component name" +} diff --git a/modules/env/variables.tf b/modules/env/variables.tf new file mode 100644 index 0000000..2136a8e --- /dev/null +++ b/modules/env/variables.tf @@ -0,0 +1,21 @@ +variable "stack_config_local_path" { + type = string + description = "Path to local stack configs" +} + +variable "stack" { + type = string + description = "Stack name" + default = null +} + +variable "component_type" { + type = string + description = "Component type (terraform or helmfile)" + default = "terraform" +} + +variable "component" { + type = string + description = "Component" +} diff --git a/modules/env/versions.tf b/modules/env/versions.tf new file mode 100644 index 0000000..0077d8a --- /dev/null +++ b/modules/env/versions.tf @@ -0,0 +1,22 @@ +terraform { + required_version = ">= 0.13.0" + + required_providers { + local = { + source = "hashicorp/local" + version = ">= 1.3" + } + template = { + source = "hashicorp/template" + version = ">= 2.2" + } + external = { + source = "hashicorp/external" + version = ">= 2.0" + } + utils = { + source = "cloudposse/utils" + version = ">= 0.3.0" + } + } +} diff --git a/modules/remote-state/versions.tf b/modules/remote-state/versions.tf index 6bf7201..0077d8a 100644 --- a/modules/remote-state/versions.tf +++ b/modules/remote-state/versions.tf @@ -16,7 +16,7 @@ terraform { } utils = { source = "cloudposse/utils" - version = ">= 0.2.1" + version = ">= 0.3.0" } } } diff --git a/modules/settings/README.md b/modules/settings/README.md new file mode 100644 index 0000000..d9e1e5b --- /dev/null +++ b/modules/settings/README.md @@ -0,0 +1,24 @@ +# settings + +Terraform module that accepts stack configuration and returns deep-merged settings for a Terraform or helmfile component. + +## Usage + +The following example loads the stack config `my-stack` (which in turn imports other YAML config dependencies) +and returns settings for Terraform component `my-vpc`. + + ```hcl + module "vars" { + source = "cloudposse/stack-config/yaml//modules/settings" + # version = "x.x.x" + + stack_config_local_path = "./stacks" + stack = "my-stack" + component_type = "terraform" + component = "my-vpc" + + context = module.this.context + } +``` + +See [examples/complete](../../examples/complete) for more details. diff --git a/modules/settings/context.tf b/modules/settings/context.tf new file mode 100644 index 0000000..81f99b4 --- /dev/null +++ b/modules/settings/context.tf @@ -0,0 +1,202 @@ +# +# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label +# All other instances of this file should be a copy of that one +# +# +# Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf +# and then place it in your Terraform module to automatically get +# Cloud Posse's standard configuration inputs suitable for passing +# to Cloud Posse modules. +# +# Modules should access the whole context as `module.this.context` +# to get the input variables with nulls for defaults, +# for example `context = module.this.context`, +# and access individual variables as `module.this.`, +# with final values filled in. +# +# For example, when using defaults, `module.this.context.delimiter` +# will be null, and `module.this.delimiter` will be `-` (hyphen). +# + +module "this" { + source = "cloudposse/label/null" + version = "0.24.1" # requires Terraform >= 0.13.0 + + enabled = var.enabled + namespace = var.namespace + environment = var.environment + stage = var.stage + name = var.name + delimiter = var.delimiter + attributes = var.attributes + tags = var.tags + additional_tag_map = var.additional_tag_map + label_order = var.label_order + regex_replace_chars = var.regex_replace_chars + id_length_limit = var.id_length_limit + label_key_case = var.label_key_case + label_value_case = var.label_value_case + + context = var.context +} + +# Copy contents of cloudposse/terraform-null-label/variables.tf here + +variable "context" { + type = any + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = lookup(var.context, "label_key_case", null) == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = lookup(var.context, "label_value_case", null) == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters (minimum 6). + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT + validation { + condition = var.id_length_limit == null ? true : var.id_length_limit >= 6 || var.id_length_limit == 0 + error_message = "The id_length_limit must be >= 6 if supplied (not null), or 0 for unlimited length." + } +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} +#### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/modules/settings/main.tf b/modules/settings/main.tf new file mode 100644 index 0000000..b2361de --- /dev/null +++ b/modules/settings/main.tf @@ -0,0 +1,13 @@ +locals { + stack = var.stack != null ? var.stack : format("%s-%s", module.this.environment, module.this.stage) +} + +data "utils_stack_config_yaml" "config" { + input = [format("%s/%s.yaml", var.stack_config_local_path, local.stack)] +} + +locals { + config = yamldecode(data.utils_stack_config_yaml.config.output[0]) + settings = local.config["components"][var.component_type][var.component]["settings"] + base_component = try(local.config["components"][var.component_type][var.component]["component"], "") +} diff --git a/modules/settings/outputs.tf b/modules/settings/outputs.tf new file mode 100644 index 0000000..1afca5b --- /dev/null +++ b/modules/settings/outputs.tf @@ -0,0 +1,9 @@ +output "settings" { + value = local.settings + description = "settings for the component" +} + +output "base_component" { + value = local.base_component + description = "Base component name" +} diff --git a/modules/settings/variables.tf b/modules/settings/variables.tf new file mode 100644 index 0000000..2136a8e --- /dev/null +++ b/modules/settings/variables.tf @@ -0,0 +1,21 @@ +variable "stack_config_local_path" { + type = string + description = "Path to local stack configs" +} + +variable "stack" { + type = string + description = "Stack name" + default = null +} + +variable "component_type" { + type = string + description = "Component type (terraform or helmfile)" + default = "terraform" +} + +variable "component" { + type = string + description = "Component" +} diff --git a/modules/settings/versions.tf b/modules/settings/versions.tf new file mode 100644 index 0000000..0077d8a --- /dev/null +++ b/modules/settings/versions.tf @@ -0,0 +1,22 @@ +terraform { + required_version = ">= 0.13.0" + + required_providers { + local = { + source = "hashicorp/local" + version = ">= 1.3" + } + template = { + source = "hashicorp/template" + version = ">= 2.2" + } + external = { + source = "hashicorp/external" + version = ">= 2.0" + } + utils = { + source = "cloudposse/utils" + version = ">= 0.3.0" + } + } +} diff --git a/modules/vars/README.md b/modules/vars/README.md index d2bccce..13dae36 100644 --- a/modules/vars/README.md +++ b/modules/vars/README.md @@ -5,7 +5,7 @@ Terraform module that accepts stack configuration and returns deep-merged variab ## Usage The following example loads the stack config `my-stack` (which in turn imports other YAML config dependencies) -and returns variables and backend config for stack `my-stack` and Terraform component `my-vpc`. +and returns variables and backend config for Terraform component `my-vpc`. ```hcl module "vars" { diff --git a/modules/vars/main.tf b/modules/vars/main.tf index 69d1abe..3f94cbe 100644 --- a/modules/vars/main.tf +++ b/modules/vars/main.tf @@ -7,5 +7,7 @@ data "utils_stack_config_yaml" "config" { } locals { - vars = yamldecode(data.utils_stack_config_yaml.config.output[0])["components"][var.component_type][var.component]["vars"] + config = yamldecode(data.utils_stack_config_yaml.config.output[0]) + vars = local.config["components"][var.component_type][var.component]["vars"] + base_component = try(local.config["components"][var.component_type][var.component]["component"], "") } diff --git a/modules/vars/outputs.tf b/modules/vars/outputs.tf index 3643517..0f8b475 100644 --- a/modules/vars/outputs.tf +++ b/modules/vars/outputs.tf @@ -2,3 +2,8 @@ output "vars" { value = local.vars description = "Vars configuration for the component" } + +output "base_component" { + value = local.base_component + description = "Base component name" +} diff --git a/modules/vars/versions.tf b/modules/vars/versions.tf index 6bf7201..0077d8a 100644 --- a/modules/vars/versions.tf +++ b/modules/vars/versions.tf @@ -16,7 +16,7 @@ terraform { } utils = { source = "cloudposse/utils" - version = ">= 0.2.1" + version = ">= 0.3.0" } } } diff --git a/test/src/examples_complete_test.go b/test/src/examples_complete_test.go index 45d2b54..47d5fa8 100644 --- a/test/src/examples_complete_test.go +++ b/test/src/examples_complete_test.go @@ -38,4 +38,14 @@ func TestExamplesComplete(t *testing.T) { backend := terraform.OutputMap(t, terraformOptions, "backend") // Verify we're getting back the outputs we expect assert.Greater(t, len(backend), 0) + + // Run `terraform output` to get the value of an output variable + settings := terraform.OutputMap(t, terraformOptions, "settings") + // Verify we're getting back the outputs we expect + assert.Greater(t, len(settings), 0) + + // Run `terraform output` to get the value of an output variable + env := terraform.OutputMap(t, terraformOptions, "env") + // Verify we're getting back the outputs we expect + assert.Greater(t, len(env), 0) } diff --git a/versions.tf b/versions.tf index 6bf7201..0077d8a 100644 --- a/versions.tf +++ b/versions.tf @@ -16,7 +16,7 @@ terraform { } utils = { source = "cloudposse/utils" - version = ">= 0.2.1" + version = ">= 0.3.0" } } }