├── .editorconfig ├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── bug_report.yml │ ├── config.yml │ ├── feature_request.md │ ├── feature_request.yml │ └── question.md ├── PULL_REQUEST_TEMPLATE.md ├── banner.png ├── mergify.yml ├── renovate.json ├── settings.yml └── workflows │ ├── branch.yml │ ├── chatops.yml │ ├── release.yml │ └── scheduled.yml ├── .gitignore ├── LICENSE ├── README.md ├── README.yaml ├── atmos.yaml ├── context.tf ├── examples ├── backend │ ├── atmos.yaml │ ├── context.tf │ ├── fixtures.tfvars │ ├── main.tf │ ├── outputs.tf │ ├── stacks │ │ ├── catalog │ │ │ ├── helmfile │ │ │ │ ├── echo-server.yaml │ │ │ │ └── infra-server.yaml │ │ │ └── terraform │ │ │ │ ├── services │ │ │ │ ├── service-1-override.yaml │ │ │ │ ├── service-1.yaml │ │ │ │ ├── service-2-override.yaml │ │ │ │ ├── service-2.yaml │ │ │ │ ├── top-level-service-1.yaml │ │ │ │ └── top-level-service-2.yaml │ │ │ │ ├── tenant1-ue2-dev.yaml │ │ │ │ ├── test-component-override.yaml │ │ │ │ ├── test-component.yaml │ │ │ │ ├── top-level-component1.yaml │ │ │ │ └── vpc.yaml │ │ ├── globals │ │ │ ├── globals.yaml │ │ │ ├── tenant1-globals.yaml │ │ │ ├── tenant2-globals.yaml │ │ │ └── ue2-globals.yaml │ │ ├── tenant1 │ │ │ └── ue2 │ │ │ │ ├── dev.yaml │ │ │ │ ├── prod.yaml │ │ │ │ └── staging.yaml │ │ └── tenant2 │ │ │ └── ue2 │ │ │ ├── dev.yaml │ │ │ ├── prod.yaml │ │ │ └── staging.yaml │ ├── variables.tf │ └── versions.tf ├── complete │ ├── atmos.yaml │ ├── context.tf │ ├── fixtures.tfvars │ ├── main.tf │ ├── outputs.tf │ ├── stacks │ │ ├── imports-level-2.yaml │ │ ├── imports-level-3.yaml │ │ ├── imports-level-3a.yaml │ │ ├── imports-level-4.yaml │ │ └── my-stack.yaml │ ├── variables.tf │ └── versions.tf ├── remote-state │ ├── atmos.yaml │ ├── context.tf │ ├── fixtures.tfvars │ ├── main.tf │ ├── outputs.tf │ ├── stacks │ │ ├── catalog │ │ │ ├── helmfile │ │ │ │ ├── echo-server.yaml │ │ │ │ └── infra-server.yaml │ │ │ └── terraform │ │ │ │ ├── services │ │ │ │ ├── service-1-override.yaml │ │ │ │ ├── service-1.yaml │ │ │ │ ├── service-2-override.yaml │ │ │ │ ├── service-2.yaml │ │ │ │ ├── top-level-service-1.yaml │ │ │ │ └── top-level-service-2.yaml │ │ │ │ ├── tenant1-ue2-dev.yaml │ │ │ │ ├── test-component-override.yaml │ │ │ │ ├── test-component.yaml │ │ │ │ ├── top-level-component1.yaml │ │ │ │ └── vpc.yaml │ │ ├── globals │ │ │ ├── globals.yaml │ │ │ ├── tenant1-globals.yaml │ │ │ ├── tenant2-globals.yaml │ │ │ └── ue2-globals.yaml │ │ ├── tenant1 │ │ │ └── ue2 │ │ │ │ ├── dev.yaml │ │ │ │ ├── prod.yaml │ │ │ │ └── staging.yaml │ │ └── tenant2 │ │ │ └── ue2 │ │ │ ├── dev.yaml │ │ │ ├── prod.yaml │ │ │ └── staging.yaml │ ├── variables.tf │ └── versions.tf ├── spacelift │ ├── atmos.yaml │ ├── context.tf │ ├── fixtures.tfvars │ ├── main.tf │ ├── outputs.tf │ ├── stacks │ │ ├── catalog │ │ │ ├── helmfile │ │ │ │ ├── echo-server.yaml │ │ │ │ ├── infra-server-override.yaml │ │ │ │ └── infra-server.yaml │ │ │ └── terraform │ │ │ │ ├── mixins │ │ │ │ ├── test-1.yaml │ │ │ │ └── test-2.yaml │ │ │ │ ├── services │ │ │ │ ├── service-1-override-2.yaml │ │ │ │ ├── service-1-override.yaml │ │ │ │ ├── service-1.yaml │ │ │ │ ├── service-2-override-2.yaml │ │ │ │ ├── service-2-override.yaml │ │ │ │ ├── service-2.yaml │ │ │ │ ├── top-level-service-1.yaml │ │ │ │ └── top-level-service-2.yaml │ │ │ │ ├── tenant1-ue2-dev.yaml │ │ │ │ ├── test-component-override-2.yaml │ │ │ │ ├── test-component-override-3.yaml │ │ │ │ ├── test-component-override.yaml │ │ │ │ ├── test-component.yaml │ │ │ │ ├── top-level-component1.yaml │ │ │ │ └── vpc.yaml │ │ ├── globals │ │ │ ├── globals.yaml │ │ │ ├── tenant1-globals.yaml │ │ │ ├── tenant2-globals.yaml │ │ │ └── ue2-globals.yaml │ │ ├── tenant1 │ │ │ └── ue2 │ │ │ │ ├── dev.yaml │ │ │ │ ├── prod.yaml │ │ │ │ └── staging.yaml │ │ └── tenant2 │ │ │ └── ue2 │ │ │ ├── dev.yaml │ │ │ ├── prod.yaml │ │ │ └── staging.yaml │ ├── variables.tf │ └── versions.tf ├── stack │ ├── context.tf │ ├── fixtures.tfvars │ ├── main.tf │ ├── outputs.tf │ ├── variables.tf │ └── versions.tf └── stacks │ ├── README.md │ ├── atmos.yaml │ ├── context.tf │ ├── fixtures.tfvars │ ├── main.tf │ ├── outputs.tf │ ├── stacks │ ├── eks │ │ └── eks-defaults.yaml │ ├── globals.yaml │ ├── uw2-dev.yaml │ ├── uw2-globals.yaml │ ├── uw2-prod.yaml │ ├── uw2-staging.yaml │ └── uw2-uat.yaml │ ├── variables.tf │ └── versions.tf ├── main.tf ├── modules ├── backend │ ├── README.md │ ├── context-always.tf │ ├── main.tf │ ├── outputs.tf │ ├── variables.tf │ └── versions.tf ├── env │ ├── README.md │ ├── context-always.tf │ ├── main.tf │ ├── outputs.tf │ ├── variables.tf │ └── versions.tf ├── remote-state │ ├── README.md │ ├── context-always.tf │ ├── data-source.tf │ ├── dummy-remote-state.json │ ├── main.tf │ ├── outputs.tf │ ├── variables.tf │ └── versions.tf ├── settings │ ├── README.md │ ├── context-always.tf │ ├── main.tf │ ├── outputs.tf │ ├── variables.tf │ └── versions.tf ├── spacelift │ ├── README.md │ ├── context-always.tf │ ├── main.tf │ ├── outputs.tf │ ├── variables.tf │ └── versions.tf ├── stack │ ├── README.md │ ├── context-always.tf │ ├── main.tf │ ├── outputs.tf │ ├── variables.tf │ └── versions.tf └── vars │ ├── README.md │ ├── context-always.tf │ ├── main.tf │ ├── outputs.tf │ ├── variables.tf │ └── versions.tf ├── outputs.tf ├── test ├── .gitignore ├── Makefile ├── Makefile.alpine └── src │ ├── .gitignore │ ├── Makefile │ ├── examples_backend_test.go │ ├── examples_complete_test.go │ ├── examples_remote_state_test.go │ ├── examples_spacelift_test.go │ ├── examples_stack_test.go │ ├── examples_stacks_test.go │ ├── go.mod │ └── go.sum ├── variables.tf └── versions.tf /.editorconfig: -------------------------------------------------------------------------------- 1 | # Unix-style newlines with a newline ending every file 2 | [*] 3 | charset = utf-8 4 | end_of_line = lf 5 | indent_size = 2 6 | indent_style = space 7 | insert_final_newline = true 8 | trim_trailing_whitespace = true 9 | 10 | [*.{tf,tfvars}] 11 | indent_size = 2 12 | indent_style = space 13 | 14 | [*.md] 15 | max_line_length = 0 16 | trim_trailing_whitespace = false 17 | 18 | # Override for Makefile 19 | [{Makefile, makefile, GNUmakefile, Makefile.*}] 20 | tab_width = 2 21 | indent_style = tab 22 | indent_size = 4 23 | 24 | [COMMIT_EDITMSG] 25 | max_line_length = 0 26 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Use this file to define individuals or teams that are responsible for code in a repository. 2 | # Read more: 3 | # 4 | # Order is important: the last matching pattern has the highest precedence 5 | 6 | # These owners will be the default owners for everything 7 | * @cloudposse/engineering @cloudposse/contributors 8 | 9 | # Cloud Posse must review any changes to Makefiles 10 | **/Makefile @cloudposse/engineering 11 | **/Makefile.* @cloudposse/engineering 12 | 13 | # Cloud Posse must review any changes to GitHub actions 14 | .github/* @cloudposse/engineering 15 | 16 | # Cloud Posse must review any changes to standard context definition, 17 | # but some changes can be rubber-stamped. 18 | **/*.tf @cloudposse/engineering @cloudposse/contributors @cloudposse/approvers 19 | README.yaml @cloudposse/engineering @cloudposse/contributors @cloudposse/approvers 20 | README.md @cloudposse/engineering @cloudposse/contributors @cloudposse/approvers 21 | docs/*.md @cloudposse/engineering @cloudposse/contributors @cloudposse/approvers 22 | 23 | # Cloud Posse Admins must review all changes to CODEOWNERS or the mergify configuration 24 | .github/mergify.yml @cloudposse/admins 25 | .github/CODEOWNERS @cloudposse/admins 26 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: 'bug' 6 | assignees: '' 7 | 8 | --- 9 | 10 | Found a bug? Maybe our [Slack Community](https://slack.cloudposse.com) can help. 11 | 12 | [![Slack Community](https://slack.cloudposse.com/badge.svg)](https://slack.cloudposse.com) 13 | 14 | ## Describe the Bug 15 | A clear and concise description of what the bug is. 16 | 17 | ## Expected Behavior 18 | A clear and concise description of what you expected to happen. 19 | 20 | ## Steps to Reproduce 21 | Steps to reproduce the behavior: 22 | 1. Go to '...' 23 | 2. Run '....' 24 | 3. Enter '....' 25 | 4. See error 26 | 27 | ## Screenshots 28 | If applicable, add screenshots or logs to help explain your problem. 29 | 30 | ## Environment (please complete the following information): 31 | 32 | Anything that will help us triage the bug will help. Here are some ideas: 33 | - OS: [e.g. Linux, OSX, WSL, etc] 34 | - Version [e.g. 10.15] 35 | 36 | ## Additional Context 37 | Add any other context about the problem here. -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | description: Create a report to help us improve 4 | labels: ["bug"] 5 | assignees: [""] 6 | body: 7 | - type: markdown 8 | attributes: 9 | value: | 10 | Found a bug? 11 | 12 | Please checkout our [Slack Community](https://slack.cloudposse.com) 13 | or visit our [Slack Archive](https://archive.sweetops.com/). 14 | 15 | [![Slack Community](https://slack.cloudposse.com/badge.svg)](https://slack.cloudposse.com) 16 | 17 | - type: textarea 18 | id: concise-description 19 | attributes: 20 | label: Describe the Bug 21 | description: A clear and concise description of what the bug is. 22 | placeholder: What is the bug about? 23 | validations: 24 | required: true 25 | 26 | - type: textarea 27 | id: expected 28 | attributes: 29 | label: Expected Behavior 30 | description: A clear and concise description of what you expected. 31 | placeholder: What happened? 32 | validations: 33 | required: true 34 | 35 | - type: textarea 36 | id: reproduction-steps 37 | attributes: 38 | label: Steps to Reproduce 39 | description: Steps to reproduce the behavior. 40 | placeholder: How do we reproduce it? 41 | validations: 42 | required: true 43 | 44 | - type: textarea 45 | id: screenshots 46 | attributes: 47 | label: Screenshots 48 | description: If applicable, add screenshots or logs to help explain. 49 | validations: 50 | required: false 51 | 52 | - type: textarea 53 | id: environment 54 | attributes: 55 | label: Environment 56 | description: Anything that will help us triage the bug. 57 | placeholder: | 58 | - OS: [e.g. Linux, OSX, WSL, etc] 59 | - Version [e.g. 10.15] 60 | - Module version 61 | - Terraform version 62 | validations: 63 | required: false 64 | 65 | - type: textarea 66 | id: additional 67 | attributes: 68 | label: Additional Context 69 | description: | 70 | Add any other context about the problem here. 71 | validations: 72 | required: false 73 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | 3 | contact_links: 4 | 5 | - name: Community Slack Team 6 | url: https://cloudposse.com/slack/ 7 | about: |- 8 | Please ask and answer questions here. 9 | 10 | - name: Office Hours 11 | url: https://cloudposse.com/office-hours/ 12 | about: |- 13 | Join us every Wednesday for FREE Office Hours (lunch & learn). 14 | 15 | - name: DevOps Accelerator Program 16 | url: https://cloudposse.com/accelerate/ 17 | about: |- 18 | Own your infrastructure in record time. We build it. You drive it. 19 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature Request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: 'feature request' 6 | assignees: '' 7 | 8 | --- 9 | 10 | Have a question? Please checkout our [Slack Community](https://slack.cloudposse.com) or visit our [Slack Archive](https://archive.sweetops.com/). 11 | 12 | [![Slack Community](https://slack.cloudposse.com/badge.svg)](https://slack.cloudposse.com) 13 | 14 | ## Describe the Feature 15 | 16 | A clear and concise description of what the bug is. 17 | 18 | ## Expected Behavior 19 | 20 | A clear and concise description of what you expected to happen. 21 | 22 | ## Use Case 23 | 24 | Is your feature request related to a problem/challenge you are trying to solve? Please provide some additional context of why this feature or capability will be valuable. 25 | 26 | ## Describe Ideal Solution 27 | 28 | A clear and concise description of what you want to happen. If you don't know, that's okay. 29 | 30 | ## Alternatives Considered 31 | 32 | Explain what alternative solutions or features you've considered. 33 | 34 | ## Additional Context 35 | 36 | Add any other context or screenshots about the feature request here. 37 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature Request 3 | description: Suggest an idea for this project 4 | labels: ["feature request"] 5 | assignees: [""] 6 | body: 7 | - type: markdown 8 | attributes: 9 | value: | 10 | Have a question? 11 | 12 | Please checkout our [Slack Community](https://slack.cloudposse.com) 13 | or visit our [Slack Archive](https://archive.sweetops.com/). 14 | 15 | [![Slack Community](https://slack.cloudposse.com/badge.svg)](https://slack.cloudposse.com) 16 | 17 | - type: textarea 18 | id: concise-description 19 | attributes: 20 | label: Describe the Feature 21 | description: A clear and concise description of what the feature is. 22 | placeholder: What is the feature about? 23 | validations: 24 | required: true 25 | 26 | - type: textarea 27 | id: expected 28 | attributes: 29 | label: Expected Behavior 30 | description: A clear and concise description of what you expected. 31 | placeholder: What happened? 32 | validations: 33 | required: true 34 | 35 | - type: textarea 36 | id: use-case 37 | attributes: 38 | label: Use Case 39 | description: | 40 | Is your feature request related to a problem/challenge you are trying 41 | to solve? 42 | 43 | Please provide some additional context of why this feature or 44 | capability will be valuable. 45 | validations: 46 | required: true 47 | 48 | - type: textarea 49 | id: ideal-solution 50 | attributes: 51 | label: Describe Ideal Solution 52 | description: A clear and concise description of what you want to happen. 53 | validations: 54 | required: true 55 | 56 | - type: textarea 57 | id: alternatives-considered 58 | attributes: 59 | label: Alternatives Considered 60 | description: Explain alternative solutions or features considered. 61 | validations: 62 | required: false 63 | 64 | - type: textarea 65 | id: additional 66 | attributes: 67 | label: Additional Context 68 | description: | 69 | Add any other context about the problem here. 70 | validations: 71 | required: false 72 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/question.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudposse/terraform-yaml-stack-config/d5c8b4ab026c86825c07a115fbb537092443ace1/.github/ISSUE_TEMPLATE/question.md -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## what 2 | 3 | 7 | 8 | ## why 9 | 10 | 15 | 16 | ## references 17 | 18 | 22 | -------------------------------------------------------------------------------- /.github/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudposse/terraform-yaml-stack-config/d5c8b4ab026c86825c07a115fbb537092443ace1/.github/banner.png -------------------------------------------------------------------------------- /.github/mergify.yml: -------------------------------------------------------------------------------- 1 | extends: .github 2 | -------------------------------------------------------------------------------- /.github/renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "config:base", 4 | ":preserveSemverRanges" 5 | ], 6 | "baseBranches": ["main", "master", "/^release\\/v\\d{1,2}$/"], 7 | "labels": ["auto-update"], 8 | "dependencyDashboardAutoclose": true, 9 | "enabledManagers": ["terraform"], 10 | "terraform": { 11 | "ignorePaths": ["**/context.tf", "examples/**"] 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /.github/settings.yml: -------------------------------------------------------------------------------- 1 | # Upstream changes from _extends are only recognized when modifications are made to this file in the default branch. 2 | _extends: .github 3 | repository: 4 | name: terraform-yaml-stack-config 5 | description: Terraform module that loads an opinionated 'stack' configuration from local or remote YAML sources. It supports deep-merged variables, settings, ENV variables, backend config, and remote state outputs for Terraform and helmfile components. 6 | homepage: https://cloudposse.com/accelerate 7 | topics: yaml, configuration, config, configuration-management, terraform, terraform-module, helm, helmfile, configuration-files, configs, yaml-configuration, stack, stacks 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /.github/workflows/branch.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Branch 3 | on: 4 | pull_request: 5 | branches: 6 | - main 7 | - release/** 8 | types: [opened, synchronize, reopened, labeled, unlabeled] 9 | push: 10 | branches: 11 | - main 12 | - release/v* 13 | paths-ignore: 14 | - '.github/**' 15 | - 'docs/**' 16 | - 'examples/**' 17 | - 'test/**' 18 | - 'README.md' 19 | 20 | permissions: {} 21 | 22 | jobs: 23 | terraform-module: 24 | uses: cloudposse/.github/.github/workflows/shared-terraform-module.yml@main 25 | secrets: inherit 26 | -------------------------------------------------------------------------------- /.github/workflows/chatops.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: chatops 3 | on: 4 | issue_comment: 5 | types: [created] 6 | 7 | permissions: 8 | pull-requests: write 9 | id-token: write 10 | contents: write 11 | statuses: write 12 | 13 | jobs: 14 | test: 15 | uses: cloudposse/.github/.github/workflows/shared-terraform-chatops.yml@main 16 | if: ${{ github.event.issue.pull_request && contains(github.event.comment.body, '/terratest') }} 17 | secrets: inherit 18 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: release 3 | on: 4 | release: 5 | types: 6 | - published 7 | 8 | permissions: 9 | id-token: write 10 | contents: write 11 | pull-requests: write 12 | 13 | jobs: 14 | terraform-module: 15 | uses: cloudposse/.github/.github/workflows/shared-release-branches.yml@main 16 | secrets: inherit 17 | -------------------------------------------------------------------------------- /.github/workflows/scheduled.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: scheduled 3 | on: 4 | workflow_dispatch: { } # Allows manually trigger this workflow 5 | schedule: 6 | - cron: "0 3 * * *" 7 | 8 | permissions: 9 | pull-requests: write 10 | id-token: write 11 | contents: write 12 | 13 | jobs: 14 | scheduled: 15 | uses: cloudposse/.github/.github/workflows/shared-terraform-scheduled.yml@main 16 | secrets: inherit 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Local .terraform directories 2 | **/.terraform/* 3 | 4 | # .tfstate files 5 | *.tfstate 6 | *.tfstate.* 7 | .terraform 8 | .terraform.tfstate.lock.info 9 | **/.terraform.lock.hcl 10 | 11 | **/.idea 12 | **/*.iml 13 | 14 | # Cloud Posse Build Harness https://github.com/cloudposse/build-harness 15 | **/.build-harness 16 | **/build-harness 17 | 18 | # Crash log files 19 | crash.log 20 | test.log 21 | -------------------------------------------------------------------------------- /atmos.yaml: -------------------------------------------------------------------------------- 1 | # Atmos Configuration — powered by https://atmos.tools 2 | # 3 | # This configuration enables centralized, DRY, and consistent project scaffolding using Atmos. 4 | # 5 | # Included features: 6 | # - Organizational custom commands: https://atmos.tools/core-concepts/custom-commands 7 | # - Automated README generation: https://atmos.tools/cli/commands/docs/generate 8 | # 9 | 10 | # Import shared configuration used by all modules 11 | import: 12 | - https://raw.githubusercontent.com/cloudposse/.github/refs/heads/main/.github/atmos/terraform-module.yaml 13 | -------------------------------------------------------------------------------- /context.tf: -------------------------------------------------------------------------------- 1 | # 2 | # ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label 3 | # All other instances of this file should be a copy of that one 4 | # 5 | # 6 | # Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf 7 | # and then place it in your Terraform module to automatically get 8 | # Cloud Posse's standard configuration inputs suitable for passing 9 | # to Cloud Posse modules. 10 | # 11 | # curl -sL https://raw.githubusercontent.com/cloudposse/terraform-null-label/master/exports/context.tf -o context.tf 12 | # 13 | # Modules should access the whole context as `module.this.context` 14 | # to get the input variables with nulls for defaults, 15 | # for example `context = module.this.context`, 16 | # and access individual variables as `module.this.`, 17 | # with final values filled in. 18 | # 19 | # For example, when using defaults, `module.this.context.delimiter` 20 | # will be null, and `module.this.delimiter` will be `-` (hyphen). 21 | # 22 | 23 | module "this" { 24 | source = "cloudposse/label/null" 25 | version = "0.25.0" # requires Terraform >= 0.13.0 26 | 27 | enabled = var.enabled 28 | namespace = var.namespace 29 | tenant = var.tenant 30 | environment = var.environment 31 | stage = var.stage 32 | name = var.name 33 | delimiter = var.delimiter 34 | attributes = var.attributes 35 | tags = var.tags 36 | additional_tag_map = var.additional_tag_map 37 | label_order = var.label_order 38 | regex_replace_chars = var.regex_replace_chars 39 | id_length_limit = var.id_length_limit 40 | label_key_case = var.label_key_case 41 | label_value_case = var.label_value_case 42 | descriptor_formats = var.descriptor_formats 43 | labels_as_tags = var.labels_as_tags 44 | 45 | context = var.context 46 | } 47 | 48 | # Copy contents of cloudposse/terraform-null-label/variables.tf here 49 | 50 | variable "context" { 51 | type = any 52 | default = { 53 | enabled = true 54 | namespace = null 55 | tenant = null 56 | environment = null 57 | stage = null 58 | name = null 59 | delimiter = null 60 | attributes = [] 61 | tags = {} 62 | additional_tag_map = {} 63 | regex_replace_chars = null 64 | label_order = [] 65 | id_length_limit = null 66 | label_key_case = null 67 | label_value_case = null 68 | descriptor_formats = {} 69 | # Note: we have to use [] instead of null for unset lists due to 70 | # https://github.com/hashicorp/terraform/issues/28137 71 | # which was not fixed until Terraform 1.0.0, 72 | # but we want the default to be all the labels in `label_order` 73 | # and we want users to be able to prevent all tag generation 74 | # by setting `labels_as_tags` to `[]`, so we need 75 | # a different sentinel to indicate "default" 76 | labels_as_tags = ["unset"] 77 | } 78 | description = <<-EOT 79 | Single object for setting entire context at once. 80 | See description of individual variables for details. 81 | Leave string and numeric variables as `null` to use default value. 82 | Individual variable settings (non-null) override settings in context object, 83 | except for attributes, tags, and additional_tag_map, which are merged. 84 | EOT 85 | 86 | validation { 87 | condition = lookup(var.context, "label_key_case", null) == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) 88 | error_message = "Allowed values: `lower`, `title`, `upper`." 89 | } 90 | 91 | validation { 92 | condition = lookup(var.context, "label_value_case", null) == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) 93 | error_message = "Allowed values: `lower`, `title`, `upper`, `none`." 94 | } 95 | } 96 | 97 | variable "enabled" { 98 | type = bool 99 | default = null 100 | description = "Set to false to prevent the module from creating any resources" 101 | } 102 | 103 | variable "namespace" { 104 | type = string 105 | default = null 106 | description = "ID element. Usually an abbreviation of your organization name, e.g. 'eg' or 'cp', to help ensure generated IDs are globally unique" 107 | } 108 | 109 | variable "tenant" { 110 | type = string 111 | default = null 112 | description = "ID element _(Rarely used, not included by default)_. A customer identifier, indicating who this instance of a resource is for" 113 | } 114 | 115 | variable "environment" { 116 | type = string 117 | default = null 118 | description = "ID element. Usually used for region e.g. 'uw2', 'us-west-2', OR role 'prod', 'staging', 'dev', 'UAT'" 119 | } 120 | 121 | variable "stage" { 122 | type = string 123 | default = null 124 | description = "ID element. Usually used to indicate role, e.g. 'prod', 'staging', 'source', 'build', 'test', 'deploy', 'release'" 125 | } 126 | 127 | variable "name" { 128 | type = string 129 | default = null 130 | description = <<-EOT 131 | ID element. Usually the component or solution name, e.g. 'app' or 'jenkins'. 132 | This is the only ID element not also included as a `tag`. 133 | The "name" tag is set to the full `id` string. There is no tag with the value of the `name` input. 134 | EOT 135 | } 136 | 137 | variable "delimiter" { 138 | type = string 139 | default = null 140 | description = <<-EOT 141 | Delimiter to be used between ID elements. 142 | Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. 143 | EOT 144 | } 145 | 146 | variable "attributes" { 147 | type = list(string) 148 | default = [] 149 | description = <<-EOT 150 | ID element. Additional attributes (e.g. `workers` or `cluster`) to add to `id`, 151 | in the order they appear in the list. New attributes are appended to the 152 | end of the list. The elements of the list are joined by the `delimiter` 153 | and treated as a single ID element. 154 | EOT 155 | } 156 | 157 | variable "labels_as_tags" { 158 | type = set(string) 159 | default = ["default"] 160 | description = <<-EOT 161 | Set of labels (ID elements) to include as tags in the `tags` output. 162 | Default is to include all labels. 163 | Tags with empty values will not be included in the `tags` output. 164 | Set to `[]` to suppress all generated tags. 165 | **Notes:** 166 | The value of the `name` tag, if included, will be the `id`, not the `name`. 167 | Unlike other `null-label` inputs, the initial setting of `labels_as_tags` cannot be 168 | changed in later chained modules. Attempts to change it will be silently ignored. 169 | EOT 170 | } 171 | 172 | variable "tags" { 173 | type = map(string) 174 | default = {} 175 | description = <<-EOT 176 | Additional tags (e.g. `{'BusinessUnit': 'XYZ'}`). 177 | Neither the tag keys nor the tag values will be modified by this module. 178 | EOT 179 | } 180 | 181 | variable "additional_tag_map" { 182 | type = map(string) 183 | default = {} 184 | description = <<-EOT 185 | Additional key-value pairs to add to each map in `tags_as_list_of_maps`. Not added to `tags` or `id`. 186 | This is for some rare cases where resources want additional configuration of tags 187 | and therefore take a list of maps with tag key, value, and additional configuration. 188 | EOT 189 | } 190 | 191 | variable "label_order" { 192 | type = list(string) 193 | default = null 194 | description = <<-EOT 195 | The order in which the labels (ID elements) appear in the `id`. 196 | Defaults to ["namespace", "environment", "stage", "name", "attributes"]. 197 | You can omit any of the 6 labels ("tenant" is the 6th), but at least one must be present. 198 | EOT 199 | } 200 | 201 | variable "regex_replace_chars" { 202 | type = string 203 | default = null 204 | description = <<-EOT 205 | Terraform regular expression (regex) string. 206 | Characters matching the regex will be removed from the ID elements. 207 | If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. 208 | EOT 209 | } 210 | 211 | variable "id_length_limit" { 212 | type = number 213 | default = null 214 | description = <<-EOT 215 | Limit `id` to this many characters (minimum 6). 216 | Set to `0` for unlimited length. 217 | Set to `null` for keep the existing setting, which defaults to `0`. 218 | Does not affect `id_full`. 219 | EOT 220 | validation { 221 | condition = var.id_length_limit == null ? true : var.id_length_limit >= 6 || var.id_length_limit == 0 222 | error_message = "The id_length_limit must be >= 6 if supplied (not null), or 0 for unlimited length." 223 | } 224 | } 225 | 226 | variable "label_key_case" { 227 | type = string 228 | default = null 229 | description = <<-EOT 230 | Controls the letter case of the `tags` keys (label names) for tags generated by this module. 231 | Does not affect keys of tags passed in via the `tags` input. 232 | Possible values: `lower`, `title`, `upper`. 233 | Default value: `title`. 234 | EOT 235 | 236 | validation { 237 | condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) 238 | error_message = "Allowed values: `lower`, `title`, `upper`." 239 | } 240 | } 241 | 242 | variable "label_value_case" { 243 | type = string 244 | default = null 245 | description = <<-EOT 246 | Controls the letter case of ID elements (labels) as included in `id`, 247 | set as tag values, and output by this module individually. 248 | Does not affect values of tags passed in via the `tags` input. 249 | Possible values: `lower`, `title`, `upper` and `none` (no transformation). 250 | Set this to `title` and set `delimiter` to `""` to yield Pascal Case IDs. 251 | Default value: `lower`. 252 | EOT 253 | 254 | validation { 255 | condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) 256 | error_message = "Allowed values: `lower`, `title`, `upper`, `none`." 257 | } 258 | } 259 | 260 | variable "descriptor_formats" { 261 | type = any 262 | default = {} 263 | description = <<-EOT 264 | Describe additional descriptors to be output in the `descriptors` output map. 265 | Map of maps. Keys are names of descriptors. Values are maps of the form 266 | `{ 267 | format = string 268 | labels = list(string) 269 | }` 270 | (Type is `any` so the map values can later be enhanced to provide additional options.) 271 | `format` is a Terraform format string to be passed to the `format()` function. 272 | `labels` is a list of labels, in order, to pass to `format()` function. 273 | Label values will be normalized before being passed to `format()` so they will be 274 | identical to how they appear in `id`. 275 | Default is `{}` (`descriptors` output will be empty). 276 | EOT 277 | } 278 | 279 | #### End of copy of cloudposse/terraform-null-label/variables.tf 280 | -------------------------------------------------------------------------------- /examples/backend/atmos.yaml: -------------------------------------------------------------------------------- 1 | # CLI config is loaded from the following locations (from lowest to highest priority): 2 | # system dir (`/usr/local/etc/atmos` on Linux, `%LOCALAPPDATA%/atmos` on Windows) 3 | # home dir (~/.atmos) 4 | # current directory 5 | # ENV vars 6 | # Command-line arguments 7 | # 8 | # It supports POSIX-style Globs for file names/paths (double-star `**` is supported) 9 | # https://en.wikipedia.org/wiki/Glob_(programming) 10 | 11 | # Base path for components, stacks and workflows configurations. 12 | # Can also be set using `ATMOS_BASE_PATH` ENV var, or `--base-path` command-line argument. 13 | # Supports both absolute and relative paths. 14 | # If not provided or is an empty string, `components.terraform.base_path`, `components.helmfile.base_path`, `stacks.base_path` and `workflows.base_path` 15 | # are independent settings (supporting both absolute and relative paths). 16 | # If `base_path` is provided, `components.terraform.base_path`, `components.helmfile.base_path`, `stacks.base_path` and `workflows.base_path` 17 | # are considered paths relative to `base_path`. 18 | base_path: "." 19 | 20 | components: 21 | terraform: 22 | # Can also be set using `ATMOS_COMPONENTS_TERRAFORM_BASE_PATH` ENV var, or `--terraform-dir` command-line argument 23 | # Supports both absolute and relative paths 24 | base_path: "components/terraform" 25 | # Can also be set using `ATMOS_COMPONENTS_TERRAFORM_APPLY_AUTO_APPROVE` ENV var 26 | apply_auto_approve: false 27 | # Can also be set using `ATMOS_COMPONENTS_TERRAFORM_DEPLOY_RUN_INIT` ENV var, or `--deploy-run-init` command-line argument 28 | deploy_run_init: true 29 | # Can also be set using `ATMOS_COMPONENTS_TERRAFORM_INIT_RUN_RECONFIGURE` ENV var, or `--init-run-reconfigure` command-line argument 30 | init_run_reconfigure: true 31 | # Can also be set using `ATMOS_COMPONENTS_TERRAFORM_AUTO_GENERATE_BACKEND_FILE` ENV var, or `--auto-generate-backend-file` command-line argument 32 | auto_generate_backend_file: false 33 | helmfile: 34 | # Can also be set using `ATMOS_COMPONENTS_HELMFILE_BASE_PATH` ENV var, or `--helmfile-dir` command-line argument 35 | # Supports both absolute and relative paths 36 | base_path: "components/helmfile" 37 | # Can also be set using `ATMOS_COMPONENTS_HELMFILE_KUBECONFIG_PATH` ENV var 38 | kubeconfig_path: "/dev/shm" 39 | # Can also be set using `ATMOS_COMPONENTS_HELMFILE_HELM_AWS_PROFILE_PATTERN` ENV var 40 | helm_aws_profile_pattern: "{namespace}-{tenant}-gbl-{stage}-helm" 41 | # Can also be set using `ATMOS_COMPONENTS_HELMFILE_CLUSTER_NAME_PATTERN` ENV var 42 | cluster_name_pattern: "{namespace}-{tenant}-{environment}-{stage}-eks-cluster" 43 | 44 | stacks: 45 | # Can also be set using `ATMOS_STACKS_BASE_PATH` ENV var, or `--config-dir` and `--stacks-dir` command-line arguments 46 | # Supports both absolute and relative paths 47 | base_path: "stacks" 48 | # Can also be set using `ATMOS_STACKS_INCLUDED_PATHS` ENV var (comma-separated values string) 49 | included_paths: 50 | - "**/*" 51 | # Can also be set using `ATMOS_STACKS_EXCLUDED_PATHS` ENV var (comma-separated values string) 52 | excluded_paths: 53 | - "globals/**/*" 54 | - "catalog/**/*" 55 | - "**/*globals*" 56 | # Can also be set using `ATMOS_STACKS_NAME_PATTERN` ENV var 57 | name_pattern: "{tenant}-{environment}-{stage}" 58 | 59 | workflows: 60 | # Can also be set using `ATMOS_WORKFLOWS_BASE_PATH` ENV var, or `--workflows-dir` command-line arguments 61 | # Supports both absolute and relative paths 62 | base_path: "workflows" 63 | 64 | logs: 65 | file: "/dev/stdout" 66 | # Supported log levels: Trace, Debug, Info, Warning, Off 67 | level: Info 68 | -------------------------------------------------------------------------------- /examples/backend/fixtures.tfvars: -------------------------------------------------------------------------------- 1 | enabled = true 2 | 3 | component = "test/test-component-override" 4 | 5 | tenant = "tenant1" 6 | 7 | environment = "ue2" 8 | 9 | stage = "dev" 10 | -------------------------------------------------------------------------------- /examples/backend/main.tf: -------------------------------------------------------------------------------- 1 | module "backend" { 2 | source = "../../modules/backend" 3 | 4 | stack = var.stack 5 | component = var.component 6 | ignore_errors = var.ignore_errors 7 | env = var.env 8 | atmos_cli_config_path = var.atmos_cli_config_path 9 | atmos_base_path = var.atmos_base_path 10 | 11 | context = module.this.context 12 | } 13 | -------------------------------------------------------------------------------- /examples/backend/outputs.tf: -------------------------------------------------------------------------------- 1 | output "backend_type" { 2 | value = module.backend.backend_type 3 | description = "Backend type" 4 | } 5 | 6 | output "backend" { 7 | value = module.backend.backend 8 | description = "Backend configuration for the component" 9 | } 10 | -------------------------------------------------------------------------------- /examples/backend/stacks/catalog/helmfile/echo-server.yaml: -------------------------------------------------------------------------------- 1 | components: 2 | helmfile: 3 | echo-server: 4 | vars: 5 | installed: true 6 | -------------------------------------------------------------------------------- /examples/backend/stacks/catalog/helmfile/infra-server.yaml: -------------------------------------------------------------------------------- 1 | components: 2 | helmfile: 3 | "infra/infra-server": 4 | vars: 5 | installed: true 6 | -------------------------------------------------------------------------------- /examples/backend/stacks/catalog/terraform/services/service-1-override.yaml: -------------------------------------------------------------------------------- 1 | components: 2 | terraform: 3 | "test/test-component-override": 4 | vars: 5 | service_1_name: "service-1-override" 6 | service_1_map: 7 | a: 1 8 | b: 2 9 | c: 3 10 | service_1_list: 11 | - 1 12 | - 2 13 | - 3 14 | -------------------------------------------------------------------------------- /examples/backend/stacks/catalog/terraform/services/service-1.yaml: -------------------------------------------------------------------------------- 1 | components: 2 | terraform: 3 | "test/test-component": 4 | vars: 5 | service_1_name: "service-1" 6 | -------------------------------------------------------------------------------- /examples/backend/stacks/catalog/terraform/services/service-2-override.yaml: -------------------------------------------------------------------------------- 1 | components: 2 | terraform: 3 | "test/test-component-override": 4 | vars: 5 | service_2_name: "service-2-override" 6 | service_2_map: 7 | a: 1 8 | b: 2 9 | c: 3 10 | service_2_list: 11 | - 1 12 | - 2 13 | - 3 14 | -------------------------------------------------------------------------------- /examples/backend/stacks/catalog/terraform/services/service-2.yaml: -------------------------------------------------------------------------------- 1 | components: 2 | terraform: 3 | "test/test-component": 4 | vars: 5 | service_2_name: "service-2" 6 | -------------------------------------------------------------------------------- /examples/backend/stacks/catalog/terraform/services/top-level-service-1.yaml: -------------------------------------------------------------------------------- 1 | components: 2 | terraform: 3 | top-level-component1: 4 | vars: 5 | service_1_name: "top-level-service-1" 6 | -------------------------------------------------------------------------------- /examples/backend/stacks/catalog/terraform/services/top-level-service-2.yaml: -------------------------------------------------------------------------------- 1 | components: 2 | terraform: 3 | top-level-component1: 4 | vars: 5 | service_2_name: "top-level-service-2" 6 | -------------------------------------------------------------------------------- /examples/backend/stacks/catalog/terraform/tenant1-ue2-dev.yaml: -------------------------------------------------------------------------------- 1 | components: 2 | terraform: 3 | "test/test-component-override": 4 | vars: 5 | service_1_name: "service-1-override-2" 6 | -------------------------------------------------------------------------------- /examples/backend/stacks/catalog/terraform/test-component-override.yaml: -------------------------------------------------------------------------------- 1 | # `import` supports POSIX-style Globs for file names/paths (double-star `**` is supported) 2 | # https://en.wikipedia.org/wiki/Glob_(programming) 3 | # https://pkg.go.dev/gopkg.in/godo.v2/glob 4 | # https://github.com/bmatcuk/doublestar 5 | # File extensions are optional (if not specified, `.yaml` is used by default) 6 | import: 7 | - catalog/terraform/services/service-?-override.* 8 | 9 | components: 10 | terraform: 11 | "test/test-component-override": 12 | # Specify terraform binary to run 13 | command: "/usr/local/bin/terraform" 14 | # By using `component` attribute, `test-component-override` inherits from `test-component` and can override its variables 15 | # In this example, variables for each service are overridden in `catalog/services/service-?-override.*` 16 | component: "test/test-component" 17 | # Other variables can be overridden here 18 | vars: {} 19 | env: 20 | TEST_ENV_VAR1: "val1-override" 21 | TEST_ENV_VAR3: "val3-override" 22 | TEST_ENV_VAR4: "val4" 23 | # Override remote state backend for this component 24 | remote_state_backend_type: static # s3, remote, vault, static, etc. 25 | remote_state_backend: 26 | static: 27 | val1: true 28 | val2: "2" 29 | val3: 3 30 | val4: null 31 | -------------------------------------------------------------------------------- /examples/backend/stacks/catalog/terraform/test-component.yaml: -------------------------------------------------------------------------------- 1 | # `import` supports POSIX-style Globs for file names/paths (double-star `**` is supported) 2 | # https://en.wikipedia.org/wiki/Glob_(programming) 3 | # https://pkg.go.dev/gopkg.in/godo.v2/glob 4 | # https://github.com/bmatcuk/doublestar 5 | # File extensions are optional (if not specified, `.yaml` is used by default) 6 | import: 7 | - catalog/terraform/services/service-?.* 8 | 9 | components: 10 | terraform: 11 | "test/test-component": 12 | settings: 13 | spacelift: 14 | workspace_enabled: true 15 | vars: 16 | enabled: true 17 | env: 18 | TEST_ENV_VAR1: "val1" 19 | TEST_ENV_VAR2: "val2" 20 | TEST_ENV_VAR3: "val3" 21 | -------------------------------------------------------------------------------- /examples/backend/stacks/catalog/terraform/top-level-component1.yaml: -------------------------------------------------------------------------------- 1 | # `import` supports POSIX-style Globs for file names/paths (double-star `**` is supported) 2 | # https://en.wikipedia.org/wiki/Glob_(programming) 3 | # https://pkg.go.dev/gopkg.in/godo.v2/glob 4 | # https://github.com/bmatcuk/doublestar 5 | # File extensions are optional (if not specified, `.yaml` is used by default) 6 | import: 7 | - catalog/terraform/services/top-level-service-?.* 8 | 9 | components: 10 | terraform: 11 | top-level-component1: 12 | settings: 13 | spacelift: 14 | workspace_enabled: true 15 | vars: 16 | enabled: true 17 | -------------------------------------------------------------------------------- /examples/backend/stacks/catalog/terraform/vpc.yaml: -------------------------------------------------------------------------------- 1 | components: 2 | terraform: 3 | "infra/vpc": 4 | backend: 5 | s3: 6 | workspace_key_prefix: infra-vpc 7 | settings: 8 | spacelift: 9 | workspace_enabled: true 10 | vars: 11 | enabled: true 12 | name: "common" 13 | subnet_type_tag_key: eg.io/subnet/type 14 | nat_gateway_enabled: true 15 | nat_instance_enabled: false 16 | max_subnet_count: 3 17 | -------------------------------------------------------------------------------- /examples/backend/stacks/globals/globals.yaml: -------------------------------------------------------------------------------- 1 | vars: 2 | namespace: eg 3 | 4 | terraform: 5 | vars: {} 6 | 7 | backend_type: s3 # s3, remote, vault, static, etc. 8 | backend: 9 | s3: 10 | encrypt: true 11 | bucket: "eg-ue2-root-tfstate" 12 | key: "terraform.tfstate" 13 | dynamodb_table: "eg-ue2-root-tfstate-lock" 14 | acl: "bucket-owner-full-control" 15 | region: "us-east-2" 16 | role_arn: null 17 | remote: 18 | vault: 19 | 20 | remote_state_backend: 21 | s3: 22 | role_arn: "arn:aws:iam::123456789012:role/eg-gbl-root-terraform" 23 | 24 | helmfile: 25 | vars: {} 26 | 27 | components: 28 | terraform: {} 29 | helmfile: {} 30 | -------------------------------------------------------------------------------- /examples/backend/stacks/globals/tenant1-globals.yaml: -------------------------------------------------------------------------------- 1 | vars: 2 | tenant: tenant1 3 | -------------------------------------------------------------------------------- /examples/backend/stacks/globals/tenant2-globals.yaml: -------------------------------------------------------------------------------- 1 | vars: 2 | tenant: tenant2 3 | -------------------------------------------------------------------------------- /examples/backend/stacks/globals/ue2-globals.yaml: -------------------------------------------------------------------------------- 1 | import: 2 | - globals/globals 3 | 4 | vars: 5 | region: us-east-2 6 | environment: ue2 7 | 8 | helmfile: 9 | vars: {} 10 | 11 | components: 12 | terraform: 13 | "infra/vpc": 14 | vars: 15 | availability_zones: ["us-east-2a", "us-east-2b", "us-east-2c"] 16 | -------------------------------------------------------------------------------- /examples/backend/stacks/tenant1/ue2/dev.yaml: -------------------------------------------------------------------------------- 1 | import: 2 | - globals/tenant1-globals 3 | - globals/ue2-globals 4 | - catalog/terraform/top-level-component1 5 | - catalog/terraform/test-component 6 | - catalog/terraform/test-component-override 7 | - catalog/terraform/vpc 8 | - catalog/terraform/tenant1-ue2-dev 9 | - catalog/helmfile/echo-server 10 | - catalog/helmfile/infra-server 11 | 12 | vars: 13 | stage: dev 14 | 15 | terraform: 16 | vars: {} 17 | 18 | helmfile: 19 | vars: {} 20 | 21 | components: 22 | terraform: 23 | "infra/vpc": 24 | vars: 25 | cidr_block: 10.10.0.0/18 26 | -------------------------------------------------------------------------------- /examples/backend/stacks/tenant1/ue2/prod.yaml: -------------------------------------------------------------------------------- 1 | import: 2 | - globals/tenant1-globals 3 | - globals/ue2-globals 4 | - catalog/terraform/top-level-component1 5 | - catalog/terraform/test-component 6 | - catalog/terraform/test-component-override 7 | - catalog/terraform/vpc 8 | - catalog/helmfile/echo-server 9 | - catalog/helmfile/infra-server 10 | 11 | vars: 12 | stage: prod 13 | 14 | terraform: 15 | vars: {} 16 | 17 | helmfile: 18 | vars: {} 19 | 20 | components: 21 | terraform: 22 | "infra/vpc": 23 | vars: 24 | cidr_block: 10.8.0.0/18 25 | -------------------------------------------------------------------------------- /examples/backend/stacks/tenant1/ue2/staging.yaml: -------------------------------------------------------------------------------- 1 | import: 2 | - globals/tenant1-globals 3 | - globals/ue2-globals 4 | - catalog/terraform/top-level-component1 5 | - catalog/terraform/test-component 6 | - catalog/terraform/test-component-override 7 | - catalog/terraform/vpc 8 | - catalog/helmfile/echo-server 9 | - catalog/helmfile/infra-server 10 | 11 | vars: 12 | stage: staging 13 | 14 | terraform: 15 | vars: {} 16 | 17 | helmfile: 18 | vars: {} 19 | 20 | components: 21 | terraform: 22 | "infra/vpc": 23 | vars: 24 | cidr_block: 10.9.0.0/18 25 | -------------------------------------------------------------------------------- /examples/backend/stacks/tenant2/ue2/dev.yaml: -------------------------------------------------------------------------------- 1 | import: 2 | - globals/tenant2-globals 3 | - globals/ue2-globals 4 | - catalog/terraform/top-level-component1 5 | - catalog/terraform/test-component 6 | - catalog/terraform/test-component-override 7 | - catalog/terraform/vpc 8 | - catalog/helmfile/echo-server 9 | - catalog/helmfile/infra-server 10 | 11 | vars: 12 | stage: dev 13 | 14 | terraform: 15 | vars: {} 16 | 17 | helmfile: 18 | vars: {} 19 | 20 | components: 21 | terraform: 22 | "infra/vpc": 23 | vars: 24 | cidr_block: 10.10.0.0/18 25 | -------------------------------------------------------------------------------- /examples/backend/stacks/tenant2/ue2/prod.yaml: -------------------------------------------------------------------------------- 1 | import: 2 | - globals/tenant2-globals 3 | - globals/ue2-globals 4 | - catalog/terraform/top-level-component1 5 | - catalog/terraform/test-component 6 | - catalog/terraform/test-component-override 7 | - catalog/terraform/vpc 8 | - catalog/helmfile/echo-server 9 | - catalog/helmfile/infra-server 10 | 11 | vars: 12 | stage: prod 13 | 14 | terraform: 15 | vars: {} 16 | 17 | helmfile: 18 | vars: {} 19 | 20 | components: 21 | terraform: 22 | "infra/vpc": 23 | vars: 24 | cidr_block: 10.8.0.0/18 25 | -------------------------------------------------------------------------------- /examples/backend/stacks/tenant2/ue2/staging.yaml: -------------------------------------------------------------------------------- 1 | import: 2 | - globals/tenant2-globals 3 | - globals/ue2-globals 4 | - catalog/terraform/top-level-component1 5 | - catalog/terraform/test-component 6 | - catalog/terraform/test-component-override 7 | - catalog/terraform/vpc 8 | - catalog/helmfile/echo-server 9 | - catalog/helmfile/infra-server 10 | 11 | vars: 12 | stage: staging 13 | 14 | terraform: 15 | vars: {} 16 | 17 | helmfile: 18 | vars: {} 19 | 20 | components: 21 | terraform: 22 | "infra/vpc": 23 | vars: 24 | cidr_block: 10.9.0.0/18 25 | -------------------------------------------------------------------------------- /examples/backend/variables.tf: -------------------------------------------------------------------------------- 1 | variable "stack" { 2 | type = string 3 | description = "Stack name" 4 | default = null 5 | } 6 | 7 | variable "component" { 8 | type = string 9 | description = "Component" 10 | } 11 | 12 | variable "ignore_errors" { 13 | type = bool 14 | description = "Set to true to ignore errors from the 'utils' provider (if the component is not found in the stack)" 15 | default = false 16 | } 17 | 18 | variable "env" { 19 | type = map(string) 20 | description = "Map of ENV vars in the format `key=value`. These ENV vars will be set in the `utils` provider before executing the data source" 21 | default = null 22 | } 23 | 24 | variable "atmos_cli_config_path" { 25 | type = string 26 | description = "atmos CLI config path" 27 | default = null 28 | } 29 | 30 | variable "atmos_base_path" { 31 | type = string 32 | description = "atmos base path to components and stacks" 33 | default = null 34 | } 35 | -------------------------------------------------------------------------------- /examples/backend/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 0.14.0" 3 | 4 | required_providers { 5 | local = { 6 | source = "hashicorp/local" 7 | version = ">= 1.3" 8 | } 9 | external = { 10 | source = "hashicorp/external" 11 | version = ">= 2.0" 12 | } 13 | utils = { 14 | source = "cloudposse/utils" 15 | version = ">= 1.8.0" 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /examples/complete/atmos.yaml: -------------------------------------------------------------------------------- 1 | # CLI config is loaded from the following locations (from lowest to highest priority): 2 | # system dir (`/usr/local/etc/atmos` on Linux, `%LOCALAPPDATA%/atmos` on Windows) 3 | # home dir (~/.atmos) 4 | # current directory 5 | # ENV vars 6 | # Command-line arguments 7 | # 8 | # It supports POSIX-style Globs for file names/paths (double-star `**` is supported) 9 | # https://en.wikipedia.org/wiki/Glob_(programming) 10 | 11 | # Base path for components, stacks and workflows configurations. 12 | # Can also be set using `ATMOS_BASE_PATH` ENV var, or `--base-path` command-line argument. 13 | # Supports both absolute and relative paths. 14 | # If not provided or is an empty string, `components.terraform.base_path`, `components.helmfile.base_path`, `stacks.base_path` and `workflows.base_path` 15 | # are independent settings (supporting both absolute and relative paths). 16 | # If `base_path` is provided, `components.terraform.base_path`, `components.helmfile.base_path`, `stacks.base_path` and `workflows.base_path` 17 | # are considered paths relative to `base_path`. 18 | base_path: "." 19 | 20 | components: 21 | terraform: 22 | # Can also be set using `ATMOS_COMPONENTS_TERRAFORM_BASE_PATH` ENV var, or `--terraform-dir` command-line argument 23 | # Supports both absolute and relative paths 24 | base_path: "components/terraform" 25 | # Can also be set using `ATMOS_COMPONENTS_TERRAFORM_APPLY_AUTO_APPROVE` ENV var 26 | apply_auto_approve: false 27 | # Can also be set using `ATMOS_COMPONENTS_TERRAFORM_DEPLOY_RUN_INIT` ENV var, or `--deploy-run-init` command-line argument 28 | deploy_run_init: true 29 | # Can also be set using `ATMOS_COMPONENTS_TERRAFORM_INIT_RUN_RECONFIGURE` ENV var, or `--init-run-reconfigure` command-line argument 30 | init_run_reconfigure: true 31 | # Can also be set using `ATMOS_COMPONENTS_TERRAFORM_AUTO_GENERATE_BACKEND_FILE` ENV var, or `--auto-generate-backend-file` command-line argument 32 | auto_generate_backend_file: false 33 | helmfile: 34 | # Can also be set using `ATMOS_COMPONENTS_HELMFILE_BASE_PATH` ENV var, or `--helmfile-dir` command-line argument 35 | # Supports both absolute and relative paths 36 | base_path: "components/helmfile" 37 | # Can also be set using `ATMOS_COMPONENTS_HELMFILE_KUBECONFIG_PATH` ENV var 38 | kubeconfig_path: "/dev/shm" 39 | # Can also be set using `ATMOS_COMPONENTS_HELMFILE_HELM_AWS_PROFILE_PATTERN` ENV var 40 | helm_aws_profile_pattern: "{namespace}-{tenant}-gbl-{stage}-helm" 41 | # Can also be set using `ATMOS_COMPONENTS_HELMFILE_CLUSTER_NAME_PATTERN` ENV var 42 | cluster_name_pattern: "{namespace}-{tenant}-{environment}-{stage}-eks-cluster" 43 | 44 | stacks: 45 | # Can also be set using `ATMOS_STACKS_BASE_PATH` ENV var, or `--config-dir` and `--stacks-dir` command-line arguments 46 | # Supports both absolute and relative paths 47 | base_path: "stacks" 48 | # Can also be set using `ATMOS_STACKS_INCLUDED_PATHS` ENV var (comma-separated values string) 49 | included_paths: 50 | - "**/*" 51 | # Can also be set using `ATMOS_STACKS_EXCLUDED_PATHS` ENV var (comma-separated values string) 52 | excluded_paths: 53 | - "globals/**/*" 54 | - "catalog/**/*" 55 | - "**/*globals*" 56 | # Can also be set using `ATMOS_STACKS_NAME_PATTERN` ENV var 57 | name_pattern: "{tenant}-{environment}-{stage}" 58 | 59 | workflows: 60 | # Can also be set using `ATMOS_WORKFLOWS_BASE_PATH` ENV var, or `--workflows-dir` command-line arguments 61 | # Supports both absolute and relative paths 62 | base_path: "workflows" 63 | 64 | logs: 65 | file: "/dev/stdout" 66 | # Supported log levels: Trace, Debug, Info, Warning, Off 67 | level: Info 68 | -------------------------------------------------------------------------------- /examples/complete/fixtures.tfvars: -------------------------------------------------------------------------------- 1 | enabled = true 2 | 3 | stack_config_local_path = "./stacks" 4 | 5 | stack = "my-stack" 6 | 7 | component_type = "terraform" 8 | 9 | component = "my-vpc" 10 | -------------------------------------------------------------------------------- /examples/complete/main.tf: -------------------------------------------------------------------------------- 1 | module "vars" { 2 | source = "../../modules/vars" 3 | 4 | stack_config_local_path = var.stack_config_local_path 5 | stack = var.stack 6 | component_type = var.component_type 7 | component = var.component 8 | 9 | context = module.this.context 10 | } 11 | 12 | module "settings" { 13 | source = "../../modules/settings" 14 | 15 | stack_config_local_path = var.stack_config_local_path 16 | stack = var.stack 17 | component_type = var.component_type 18 | component = var.component 19 | 20 | context = module.this.context 21 | } 22 | 23 | module "env" { 24 | source = "../../modules/env" 25 | 26 | stack_config_local_path = var.stack_config_local_path 27 | stack = var.stack 28 | component_type = var.component_type 29 | component = var.component 30 | 31 | context = module.this.context 32 | } 33 | 34 | module "stack" { 35 | source = "../../modules/stack" 36 | 37 | stack = var.stack 38 | context = module.this.context 39 | } 40 | -------------------------------------------------------------------------------- /examples/complete/outputs.tf: -------------------------------------------------------------------------------- 1 | output "vars" { 2 | value = module.vars.vars 3 | description = "vars for the component" 4 | } 5 | 6 | output "settings" { 7 | value = module.settings.settings 8 | description = "Settings for the component" 9 | } 10 | 11 | output "env" { 12 | value = module.env.env 13 | description = "ENV variables for the component" 14 | } 15 | 16 | output "stack_name" { 17 | value = module.stack.stack_name 18 | description = "Stack name" 19 | } 20 | -------------------------------------------------------------------------------- /examples/complete/stacks/imports-level-2.yaml: -------------------------------------------------------------------------------- 1 | import: 2 | - imports-level-3 3 | - imports-level-3a 4 | 5 | vars: 6 | region: us-east-2 7 | environment: ue2 8 | 9 | terraform: 10 | vars: 11 | var_1: 1_override 12 | var_2: 2_override 13 | 14 | helmfile: 15 | vars: 16 | var_1: 1 17 | var_2: 2 18 | -------------------------------------------------------------------------------- /examples/complete/stacks/imports-level-3.yaml: -------------------------------------------------------------------------------- 1 | import: 2 | - imports-level-4 3 | 4 | vars: 5 | namespace: eg 6 | 7 | terraform: 8 | vars: 9 | var_1: 1 10 | var_3: 3 11 | settings: 12 | version: 1 13 | spacelift: 14 | workspace_enabled: false 15 | autodeploy: false 16 | env: 17 | ENV_TEST_1: test1 18 | ENV_TEST_2: test2 19 | 20 | helmfile: 21 | vars: {} 22 | 23 | components: 24 | terraform: 25 | vpc: 26 | vars: 27 | test_map: 28 | a: a 29 | b: b 30 | c: 31 | - 5 32 | - 6 33 | - 7 34 | backend: 35 | s3: 36 | workspace_key_prefix: "vpc" 37 | eks: 38 | backend: 39 | s3: 40 | workspace_key_prefix: "eks" 41 | vars: 42 | cluster_kubernetes_version: "1.18" 43 | -------------------------------------------------------------------------------- /examples/complete/stacks/imports-level-3a.yaml: -------------------------------------------------------------------------------- 1 | vars: 2 | level: 3 3 | 4 | terraform: 5 | vars: 6 | var_1: 1a 7 | var_2: 2a 8 | var_3: 3a 9 | 10 | backend_type: s3 # s3, remote, vault, etc. 11 | 12 | backend: 13 | s3: 14 | encrypt: true 15 | dynamodb_table: "eg-ue2-root-tfstate-lock" 16 | role_arn: "arn:aws:iam::xxxxxxxxxxxx:role/eg-gbl-root-terraform" 17 | acl: "bucket-owner-full-control" 18 | bucket: "eg-ue2-root-tfstate" 19 | key: "terraform.tfstate" 20 | region: "us-east-2" 21 | remote: 22 | organization: company 23 | workspace: ws1 24 | vault: {} 25 | 26 | components: 27 | terraform: 28 | vpc: 29 | vars: 30 | availability_zones: ["us-east-2a", "us-east-2b", "us-east-2c"] 31 | 32 | helmfile: 33 | vars: {} 34 | -------------------------------------------------------------------------------- /examples/complete/stacks/imports-level-4.yaml: -------------------------------------------------------------------------------- 1 | vars: 2 | level: 4 3 | param: param4 4 | 5 | terraform: 6 | vars: {} 7 | 8 | helmfile: 9 | vars: {} 10 | 11 | components: 12 | terraform: 13 | vpc: 14 | vars: 15 | subnet_type_tag_key: "example/subnet/type" 16 | backend: 17 | s3: 18 | workspace_key_prefix: "vpc" 19 | -------------------------------------------------------------------------------- /examples/complete/stacks/my-stack.yaml: -------------------------------------------------------------------------------- 1 | import: 2 | - imports-level-2 3 | 4 | vars: 5 | stage: prod 6 | 7 | terraform: 8 | vars: {} 9 | 10 | helmfile: 11 | vars: {} 12 | 13 | components: 14 | terraform: 15 | my-vpc: 16 | component: vpc 17 | vars: 18 | cidr_block: "10.132.0.0/18" 19 | test_map: 20 | a: a_override_2 21 | map2: 22 | atr1: 1 23 | atr2: 2 24 | atr3: 25 | - 3a 26 | - 3b 27 | - 3c 28 | settings: 29 | spacelift: 30 | workspace_enabled: true 31 | autodeploy: true 32 | branch: "test" 33 | triggers: ["1", "2"] 34 | env: 35 | ENV_TEST_1: test1_override 36 | ENV_TEST_2: test2_override 37 | ENV_TEST_4: test4 38 | 39 | vpc: 40 | vars: 41 | cidr_block: "10.102.0.0/18" 42 | test_map: 43 | a: a_override 44 | b: b_override 45 | c: 46 | - 1 47 | - 2 48 | - 3 49 | env: 50 | ENV_TEST_3: test3 51 | 52 | eks: 53 | vars: {} 54 | 55 | helmfile: 56 | nginx-ingress: 57 | vars: 58 | installed: true 59 | -------------------------------------------------------------------------------- /examples/complete/variables.tf: -------------------------------------------------------------------------------- 1 | variable "stack_config_local_path" { 2 | type = string 3 | description = "Path to local stack configs" 4 | } 5 | 6 | variable "stack" { 7 | type = string 8 | description = "Stack name" 9 | } 10 | 11 | variable "component_type" { 12 | type = string 13 | description = "Component type" 14 | } 15 | 16 | variable "component" { 17 | type = string 18 | description = "Component" 19 | } 20 | -------------------------------------------------------------------------------- /examples/complete/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 1.1.0" 3 | 4 | required_providers { 5 | local = { 6 | source = "hashicorp/local" 7 | version = ">= 1.3" 8 | } 9 | external = { 10 | source = "hashicorp/external" 11 | version = ">= 2.0" 12 | } 13 | utils = { 14 | source = "cloudposse/utils" 15 | version = ">= 1.8.0" 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /examples/remote-state/atmos.yaml: -------------------------------------------------------------------------------- 1 | # CLI config is loaded from the following locations (from lowest to highest priority): 2 | # system dir (`/usr/local/etc/atmos` on Linux, `%LOCALAPPDATA%/atmos` on Windows) 3 | # home dir (~/.atmos) 4 | # current directory 5 | # ENV vars 6 | # Command-line arguments 7 | # 8 | # It supports POSIX-style Globs for file names/paths (double-star `**` is supported) 9 | # https://en.wikipedia.org/wiki/Glob_(programming) 10 | 11 | # Base path for components, stacks and workflows configurations. 12 | # Can also be set using `ATMOS_BASE_PATH` ENV var, or `--base-path` command-line argument. 13 | # Supports both absolute and relative paths. 14 | # If not provided or is an empty string, `components.terraform.base_path`, `components.helmfile.base_path`, `stacks.base_path` and `workflows.base_path` 15 | # are independent settings (supporting both absolute and relative paths). 16 | # If `base_path` is provided, `components.terraform.base_path`, `components.helmfile.base_path`, `stacks.base_path` and `workflows.base_path` 17 | # are considered paths relative to `base_path`. 18 | base_path: "." 19 | 20 | components: 21 | terraform: 22 | # Can also be set using `ATMOS_COMPONENTS_TERRAFORM_BASE_PATH` ENV var, or `--terraform-dir` command-line argument 23 | # Supports both absolute and relative paths 24 | base_path: "components/terraform" 25 | # Can also be set using `ATMOS_COMPONENTS_TERRAFORM_APPLY_AUTO_APPROVE` ENV var 26 | apply_auto_approve: false 27 | # Can also be set using `ATMOS_COMPONENTS_TERRAFORM_DEPLOY_RUN_INIT` ENV var, or `--deploy-run-init` command-line argument 28 | deploy_run_init: true 29 | # Can also be set using `ATMOS_COMPONENTS_TERRAFORM_INIT_RUN_RECONFIGURE` ENV var, or `--init-run-reconfigure` command-line argument 30 | init_run_reconfigure: true 31 | # Can also be set using `ATMOS_COMPONENTS_TERRAFORM_AUTO_GENERATE_BACKEND_FILE` ENV var, or `--auto-generate-backend-file` command-line argument 32 | auto_generate_backend_file: false 33 | helmfile: 34 | # Can also be set using `ATMOS_COMPONENTS_HELMFILE_BASE_PATH` ENV var, or `--helmfile-dir` command-line argument 35 | # Supports both absolute and relative paths 36 | base_path: "components/helmfile" 37 | # Can also be set using `ATMOS_COMPONENTS_HELMFILE_KUBECONFIG_PATH` ENV var 38 | kubeconfig_path: "/dev/shm" 39 | # Can also be set using `ATMOS_COMPONENTS_HELMFILE_HELM_AWS_PROFILE_PATTERN` ENV var 40 | helm_aws_profile_pattern: "{namespace}-{tenant}-gbl-{stage}-helm" 41 | # Can also be set using `ATMOS_COMPONENTS_HELMFILE_CLUSTER_NAME_PATTERN` ENV var 42 | cluster_name_pattern: "{namespace}-{tenant}-{environment}-{stage}-eks-cluster" 43 | 44 | stacks: 45 | # Can also be set using `ATMOS_STACKS_BASE_PATH` ENV var, or `--config-dir` and `--stacks-dir` command-line arguments 46 | # Supports both absolute and relative paths 47 | base_path: "stacks" 48 | # Can also be set using `ATMOS_STACKS_INCLUDED_PATHS` ENV var (comma-separated values string) 49 | included_paths: 50 | - "**/*" 51 | # Can also be set using `ATMOS_STACKS_EXCLUDED_PATHS` ENV var (comma-separated values string) 52 | excluded_paths: 53 | - "globals/**/*" 54 | - "catalog/**/*" 55 | - "**/*globals*" 56 | # Can also be set using `ATMOS_STACKS_NAME_PATTERN` ENV var 57 | name_pattern: "{tenant}-{environment}-{stage}" 58 | 59 | workflows: 60 | # Can also be set using `ATMOS_WORKFLOWS_BASE_PATH` ENV var, or `--workflows-dir` command-line arguments 61 | # Supports both absolute and relative paths 62 | base_path: "workflows" 63 | 64 | logs: 65 | file: "/dev/stdout" 66 | # Supported log levels: Trace, Debug, Info, Warning, Off 67 | level: Info 68 | -------------------------------------------------------------------------------- /examples/remote-state/fixtures.tfvars: -------------------------------------------------------------------------------- 1 | enabled = true 2 | -------------------------------------------------------------------------------- /examples/remote-state/main.tf: -------------------------------------------------------------------------------- 1 | module "remote_state_using_stack" { 2 | source = "../../modules/remote-state" 3 | 4 | component = "test/test-component-override" 5 | stack = "tenant1-ue2-dev" 6 | 7 | # Verify that a default output not matching the real output does not cause a Terraform error 8 | defaults = { 9 | val1 = ["default-list"] 10 | val2 = "default-value" 11 | } 12 | 13 | env = { 14 | ATMOS_CLI_CONFIG_PATH = path.module 15 | } 16 | 17 | atmos_cli_config_path = var.atmos_cli_config_path 18 | atmos_base_path = var.atmos_base_path 19 | 20 | context = module.this.context 21 | } 22 | 23 | module "remote_state_using_context" { 24 | source = "../../modules/remote-state" 25 | 26 | component = "test/test-component-override" 27 | namespace = "" 28 | tenant = "tenant1" 29 | environment = "ue2" 30 | stage = "dev" 31 | 32 | env = { 33 | ATMOS_CLI_CONFIG_PATH = path.module 34 | } 35 | 36 | atmos_cli_config_path = var.atmos_cli_config_path 37 | atmos_base_path = var.atmos_base_path 38 | 39 | context = module.this.context 40 | } 41 | 42 | module "remote_state_using_context_ignore_errors" { 43 | source = "../../modules/remote-state" 44 | 45 | # Use a wrong component for testing 46 | # If `ignore_errors = false`, the `utils` provider will throw the error: Could not find config for the component 'test/test-component-override-wrong' in the stack 'tenant1-ue2-dev' 47 | # Note that terraform `try()` does not catch errors from providers, so `try(module.remote_state_using_context_ignore_errors.outputs, {})` will not work 48 | ignore_errors = true 49 | component = "test/test-component-override-wrong" 50 | namespace = "" 51 | tenant = "tenant1" 52 | environment = "ue2" 53 | stage = "dev" 54 | 55 | defaults = { 56 | default_output = "default-value" 57 | } 58 | 59 | env = { 60 | ATMOS_CLI_CONFIG_PATH = path.module 61 | } 62 | 63 | atmos_cli_config_path = var.atmos_cli_config_path 64 | atmos_base_path = var.atmos_base_path 65 | 66 | context = module.this.context 67 | } 68 | 69 | module "remote_state_with_bypass" { 70 | source = "../../modules/remote-state" 71 | 72 | bypass = true 73 | 74 | defaults = { 75 | default_output = "default-value" 76 | } 77 | 78 | component = "test/test-component-override" 79 | namespace = "" 80 | tenant = "tenant1" 81 | environment = "ue2" 82 | stage = "dev" 83 | 84 | atmos_cli_config_path = var.atmos_cli_config_path 85 | atmos_base_path = var.atmos_base_path 86 | 87 | context = module.this.context 88 | } 89 | -------------------------------------------------------------------------------- /examples/remote-state/outputs.tf: -------------------------------------------------------------------------------- 1 | output "remote_state_using_stack" { 2 | value = module.remote_state_using_stack.outputs 3 | description = "Component remote state using the provided stack name" 4 | } 5 | 6 | output "remote_state_using_context" { 7 | value = module.remote_state_using_context.outputs 8 | description = "Component remote state using the provided context" 9 | } 10 | 11 | output "remote_state_using_context_ignore_errors" { 12 | value = module.remote_state_using_context_ignore_errors.outputs 13 | description = "Component remote state using wrong component. Errors are ignored in the 'utils' provider" 14 | } 15 | 16 | output "remote_state_with_bypass" { 17 | value = module.remote_state_with_bypass.outputs 18 | description = "Component remote state with 'bypass' set to 'true'" 19 | } 20 | -------------------------------------------------------------------------------- /examples/remote-state/stacks/catalog/helmfile/echo-server.yaml: -------------------------------------------------------------------------------- 1 | components: 2 | helmfile: 3 | echo-server: 4 | vars: 5 | installed: true 6 | -------------------------------------------------------------------------------- /examples/remote-state/stacks/catalog/helmfile/infra-server.yaml: -------------------------------------------------------------------------------- 1 | components: 2 | helmfile: 3 | "infra/infra-server": 4 | vars: 5 | installed: true 6 | -------------------------------------------------------------------------------- /examples/remote-state/stacks/catalog/terraform/services/service-1-override.yaml: -------------------------------------------------------------------------------- 1 | components: 2 | terraform: 3 | "test/test-component-override": 4 | vars: 5 | service_1_name: "service-1-override" 6 | service_1_map: 7 | a: 1 8 | b: 2 9 | c: 3 10 | service_1_list: 11 | - 1 12 | - 2 13 | - 3 14 | -------------------------------------------------------------------------------- /examples/remote-state/stacks/catalog/terraform/services/service-1.yaml: -------------------------------------------------------------------------------- 1 | components: 2 | terraform: 3 | "test/test-component": 4 | vars: 5 | service_1_name: "service-1" 6 | -------------------------------------------------------------------------------- /examples/remote-state/stacks/catalog/terraform/services/service-2-override.yaml: -------------------------------------------------------------------------------- 1 | components: 2 | terraform: 3 | "test/test-component-override": 4 | vars: 5 | service_2_name: "service-2-override" 6 | service_2_map: 7 | a: 1 8 | b: 2 9 | c: 3 10 | service_2_list: 11 | - 1 12 | - 2 13 | - 3 14 | -------------------------------------------------------------------------------- /examples/remote-state/stacks/catalog/terraform/services/service-2.yaml: -------------------------------------------------------------------------------- 1 | components: 2 | terraform: 3 | "test/test-component": 4 | vars: 5 | service_2_name: "service-2" 6 | -------------------------------------------------------------------------------- /examples/remote-state/stacks/catalog/terraform/services/top-level-service-1.yaml: -------------------------------------------------------------------------------- 1 | components: 2 | terraform: 3 | top-level-component1: 4 | vars: 5 | service_1_name: "top-level-service-1" 6 | -------------------------------------------------------------------------------- /examples/remote-state/stacks/catalog/terraform/services/top-level-service-2.yaml: -------------------------------------------------------------------------------- 1 | components: 2 | terraform: 3 | top-level-component1: 4 | vars: 5 | service_2_name: "top-level-service-2" 6 | -------------------------------------------------------------------------------- /examples/remote-state/stacks/catalog/terraform/tenant1-ue2-dev.yaml: -------------------------------------------------------------------------------- 1 | components: 2 | terraform: 3 | "test/test-component-override": 4 | vars: 5 | service_1_name: "service-1-override-2" 6 | -------------------------------------------------------------------------------- /examples/remote-state/stacks/catalog/terraform/test-component-override.yaml: -------------------------------------------------------------------------------- 1 | # `import` supports POSIX-style Globs for file names/paths (double-star `**` is supported) 2 | # https://en.wikipedia.org/wiki/Glob_(programming) 3 | # https://pkg.go.dev/gopkg.in/godo.v2/glob 4 | # https://github.com/bmatcuk/doublestar 5 | # File extensions are optional (if not specified, `.yaml` is used by default) 6 | import: 7 | - catalog/terraform/services/service-?-override.* 8 | 9 | components: 10 | terraform: 11 | "test/test-component-override": 12 | # Specify terraform binary to run 13 | command: "/usr/local/bin/terraform" 14 | # By using `component` attribute, `test-component-override` inherits from `test-component` and can override its variables 15 | # In this example, variables for each service are overridden in `catalog/services/service-?-override.*` 16 | component: "test/test-component" 17 | # Other variables can be overridden here 18 | vars: {} 19 | env: 20 | TEST_ENV_VAR1: "val1-override" 21 | TEST_ENV_VAR3: "val3-override" 22 | TEST_ENV_VAR4: "val4" 23 | # Override remote state backend for this component 24 | remote_state_backend_type: static # s3, remote, vault, static, etc. 25 | remote_state_backend: 26 | static: 27 | val1: true 28 | val2: "2" 29 | val3: 3 30 | val4: null 31 | -------------------------------------------------------------------------------- /examples/remote-state/stacks/catalog/terraform/test-component.yaml: -------------------------------------------------------------------------------- 1 | # `import` supports POSIX-style Globs for file names/paths (double-star `**` is supported) 2 | # https://en.wikipedia.org/wiki/Glob_(programming) 3 | # https://pkg.go.dev/gopkg.in/godo.v2/glob 4 | # https://github.com/bmatcuk/doublestar 5 | # File extensions are optional (if not specified, `.yaml` is used by default) 6 | import: 7 | - catalog/terraform/services/service-?.* 8 | 9 | components: 10 | terraform: 11 | "test/test-component": 12 | settings: 13 | spacelift: 14 | workspace_enabled: true 15 | vars: 16 | enabled: true 17 | env: 18 | TEST_ENV_VAR1: "val1" 19 | TEST_ENV_VAR2: "val2" 20 | TEST_ENV_VAR3: "val3" 21 | -------------------------------------------------------------------------------- /examples/remote-state/stacks/catalog/terraform/top-level-component1.yaml: -------------------------------------------------------------------------------- 1 | # `import` supports POSIX-style Globs for file names/paths (double-star `**` is supported) 2 | # https://en.wikipedia.org/wiki/Glob_(programming) 3 | # https://pkg.go.dev/gopkg.in/godo.v2/glob 4 | # https://github.com/bmatcuk/doublestar 5 | # File extensions are optional (if not specified, `.yaml` is used by default) 6 | import: 7 | - catalog/terraform/services/top-level-service-?.* 8 | 9 | components: 10 | terraform: 11 | top-level-component1: 12 | settings: 13 | spacelift: 14 | workspace_enabled: true 15 | vars: 16 | enabled: true 17 | -------------------------------------------------------------------------------- /examples/remote-state/stacks/catalog/terraform/vpc.yaml: -------------------------------------------------------------------------------- 1 | components: 2 | terraform: 3 | "infra/vpc": 4 | backend: 5 | s3: 6 | workspace_key_prefix: infra-vpc 7 | settings: 8 | spacelift: 9 | workspace_enabled: true 10 | vars: 11 | enabled: true 12 | name: "common" 13 | subnet_type_tag_key: eg.io/subnet/type 14 | nat_gateway_enabled: true 15 | nat_instance_enabled: false 16 | max_subnet_count: 3 17 | -------------------------------------------------------------------------------- /examples/remote-state/stacks/globals/globals.yaml: -------------------------------------------------------------------------------- 1 | vars: 2 | namespace: eg 3 | 4 | terraform: 5 | vars: {} 6 | 7 | backend_type: s3 # s3, remote, vault, static, etc. 8 | backend: 9 | s3: 10 | encrypt: true 11 | bucket: "eg-ue2-root-tfstate" 12 | key: "terraform.tfstate" 13 | dynamodb_table: "eg-ue2-root-tfstate-lock" 14 | acl: "bucket-owner-full-control" 15 | region: "us-east-2" 16 | role_arn: null 17 | remote: 18 | vault: 19 | 20 | remote_state_backend: 21 | s3: 22 | role_arn: "arn:aws:iam::123456789012:role/eg-gbl-root-terraform" 23 | 24 | helmfile: 25 | vars: {} 26 | 27 | components: 28 | terraform: {} 29 | helmfile: {} 30 | -------------------------------------------------------------------------------- /examples/remote-state/stacks/globals/tenant1-globals.yaml: -------------------------------------------------------------------------------- 1 | vars: 2 | tenant: tenant1 3 | -------------------------------------------------------------------------------- /examples/remote-state/stacks/globals/tenant2-globals.yaml: -------------------------------------------------------------------------------- 1 | vars: 2 | tenant: tenant2 3 | -------------------------------------------------------------------------------- /examples/remote-state/stacks/globals/ue2-globals.yaml: -------------------------------------------------------------------------------- 1 | import: 2 | - globals/globals 3 | 4 | vars: 5 | region: us-east-2 6 | environment: ue2 7 | 8 | helmfile: 9 | vars: {} 10 | 11 | components: 12 | terraform: 13 | "infra/vpc": 14 | vars: 15 | availability_zones: ["us-east-2a", "us-east-2b", "us-east-2c"] 16 | -------------------------------------------------------------------------------- /examples/remote-state/stacks/tenant1/ue2/dev.yaml: -------------------------------------------------------------------------------- 1 | import: 2 | - globals/tenant1-globals 3 | - globals/ue2-globals 4 | - catalog/terraform/top-level-component1 5 | - catalog/terraform/test-component 6 | - catalog/terraform/test-component-override 7 | - catalog/terraform/vpc 8 | - catalog/terraform/tenant1-ue2-dev 9 | - catalog/helmfile/echo-server 10 | - catalog/helmfile/infra-server 11 | 12 | vars: 13 | stage: dev 14 | 15 | terraform: 16 | vars: {} 17 | 18 | helmfile: 19 | vars: {} 20 | 21 | components: 22 | terraform: 23 | "infra/vpc": 24 | vars: 25 | cidr_block: 10.10.0.0/18 26 | -------------------------------------------------------------------------------- /examples/remote-state/stacks/tenant1/ue2/prod.yaml: -------------------------------------------------------------------------------- 1 | import: 2 | - globals/tenant1-globals 3 | - globals/ue2-globals 4 | - catalog/terraform/top-level-component1 5 | - catalog/terraform/test-component 6 | - catalog/terraform/test-component-override 7 | - catalog/terraform/vpc 8 | - catalog/helmfile/echo-server 9 | - catalog/helmfile/infra-server 10 | 11 | vars: 12 | stage: prod 13 | 14 | terraform: 15 | vars: {} 16 | 17 | helmfile: 18 | vars: {} 19 | 20 | components: 21 | terraform: 22 | "infra/vpc": 23 | vars: 24 | cidr_block: 10.8.0.0/18 25 | -------------------------------------------------------------------------------- /examples/remote-state/stacks/tenant1/ue2/staging.yaml: -------------------------------------------------------------------------------- 1 | import: 2 | - globals/tenant1-globals 3 | - globals/ue2-globals 4 | - catalog/terraform/top-level-component1 5 | - catalog/terraform/test-component 6 | - catalog/terraform/test-component-override 7 | - catalog/terraform/vpc 8 | - catalog/helmfile/echo-server 9 | - catalog/helmfile/infra-server 10 | 11 | vars: 12 | stage: staging 13 | 14 | terraform: 15 | vars: {} 16 | 17 | helmfile: 18 | vars: {} 19 | 20 | components: 21 | terraform: 22 | "infra/vpc": 23 | vars: 24 | cidr_block: 10.9.0.0/18 25 | -------------------------------------------------------------------------------- /examples/remote-state/stacks/tenant2/ue2/dev.yaml: -------------------------------------------------------------------------------- 1 | import: 2 | - globals/tenant2-globals 3 | - globals/ue2-globals 4 | - catalog/terraform/top-level-component1 5 | - catalog/terraform/test-component 6 | - catalog/terraform/test-component-override 7 | - catalog/terraform/vpc 8 | - catalog/helmfile/echo-server 9 | - catalog/helmfile/infra-server 10 | 11 | vars: 12 | stage: dev 13 | 14 | terraform: 15 | vars: {} 16 | 17 | helmfile: 18 | vars: {} 19 | 20 | components: 21 | terraform: 22 | "infra/vpc": 23 | vars: 24 | cidr_block: 10.10.0.0/18 25 | -------------------------------------------------------------------------------- /examples/remote-state/stacks/tenant2/ue2/prod.yaml: -------------------------------------------------------------------------------- 1 | import: 2 | - globals/tenant2-globals 3 | - globals/ue2-globals 4 | - catalog/terraform/top-level-component1 5 | - catalog/terraform/test-component 6 | - catalog/terraform/test-component-override 7 | - catalog/terraform/vpc 8 | - catalog/helmfile/echo-server 9 | - catalog/helmfile/infra-server 10 | 11 | vars: 12 | stage: prod 13 | 14 | terraform: 15 | vars: {} 16 | 17 | helmfile: 18 | vars: {} 19 | 20 | components: 21 | terraform: 22 | "infra/vpc": 23 | vars: 24 | cidr_block: 10.8.0.0/18 25 | -------------------------------------------------------------------------------- /examples/remote-state/stacks/tenant2/ue2/staging.yaml: -------------------------------------------------------------------------------- 1 | import: 2 | - globals/tenant2-globals 3 | - globals/ue2-globals 4 | - catalog/terraform/top-level-component1 5 | - catalog/terraform/test-component 6 | - catalog/terraform/test-component-override 7 | - catalog/terraform/vpc 8 | - catalog/helmfile/echo-server 9 | - catalog/helmfile/infra-server 10 | 11 | vars: 12 | stage: staging 13 | 14 | terraform: 15 | vars: {} 16 | 17 | helmfile: 18 | vars: {} 19 | 20 | components: 21 | terraform: 22 | "infra/vpc": 23 | vars: 24 | cidr_block: 10.9.0.0/18 25 | -------------------------------------------------------------------------------- /examples/remote-state/variables.tf: -------------------------------------------------------------------------------- 1 | variable "atmos_cli_config_path" { 2 | type = string 3 | description = "atmos CLI config path" 4 | default = null 5 | } 6 | 7 | variable "atmos_base_path" { 8 | type = string 9 | description = "atmos base path to components and stacks" 10 | default = null 11 | } 12 | -------------------------------------------------------------------------------- /examples/remote-state/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 1.1.0" 3 | 4 | required_providers { 5 | local = { 6 | source = "hashicorp/local" 7 | version = ">= 1.3" 8 | } 9 | external = { 10 | source = "hashicorp/external" 11 | version = ">= 2.0" 12 | } 13 | utils = { 14 | source = "cloudposse/utils" 15 | version = ">= 1.8.0" 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /examples/spacelift/atmos.yaml: -------------------------------------------------------------------------------- 1 | # CLI config is loaded from the following locations (from lowest to highest priority): 2 | # system dir (`/usr/local/etc/atmos` on Linux, `%LOCALAPPDATA%/atmos` on Windows) 3 | # home dir (~/.atmos) 4 | # current directory 5 | # ENV vars 6 | # Command-line arguments 7 | # 8 | # It supports POSIX-style Globs for file names/paths (double-star `**` is supported) 9 | # https://en.wikipedia.org/wiki/Glob_(programming) 10 | 11 | # Base path for components, stacks and workflows configurations. 12 | # Can also be set using `ATMOS_BASE_PATH` ENV var, or `--base-path` command-line argument. 13 | # Supports both absolute and relative paths. 14 | # If not provided or is an empty string, `components.terraform.base_path`, `components.helmfile.base_path`, `stacks.base_path` and `workflows.base_path` 15 | # are independent settings (supporting both absolute and relative paths). 16 | # If `base_path` is provided, `components.terraform.base_path`, `components.helmfile.base_path`, `stacks.base_path` and `workflows.base_path` 17 | # are considered paths relative to `base_path`. 18 | base_path: "." 19 | 20 | components: 21 | terraform: 22 | # Can also be set using `ATMOS_COMPONENTS_TERRAFORM_BASE_PATH` ENV var, or `--terraform-dir` command-line argument 23 | # Supports both absolute and relative paths 24 | base_path: "components/terraform" 25 | # Can also be set using `ATMOS_COMPONENTS_TERRAFORM_APPLY_AUTO_APPROVE` ENV var 26 | apply_auto_approve: false 27 | # Can also be set using `ATMOS_COMPONENTS_TERRAFORM_DEPLOY_RUN_INIT` ENV var, or `--deploy-run-init` command-line argument 28 | deploy_run_init: true 29 | # Can also be set using `ATMOS_COMPONENTS_TERRAFORM_INIT_RUN_RECONFIGURE` ENV var, or `--init-run-reconfigure` command-line argument 30 | init_run_reconfigure: true 31 | # Can also be set using `ATMOS_COMPONENTS_TERRAFORM_AUTO_GENERATE_BACKEND_FILE` ENV var, or `--auto-generate-backend-file` command-line argument 32 | auto_generate_backend_file: false 33 | helmfile: 34 | # Can also be set using `ATMOS_COMPONENTS_HELMFILE_BASE_PATH` ENV var, or `--helmfile-dir` command-line argument 35 | # Supports both absolute and relative paths 36 | base_path: "components/helmfile" 37 | # Can also be set using `ATMOS_COMPONENTS_HELMFILE_KUBECONFIG_PATH` ENV var 38 | kubeconfig_path: "/dev/shm" 39 | # Can also be set using `ATMOS_COMPONENTS_HELMFILE_HELM_AWS_PROFILE_PATTERN` ENV var 40 | helm_aws_profile_pattern: "{namespace}-{tenant}-gbl-{stage}-helm" 41 | # Can also be set using `ATMOS_COMPONENTS_HELMFILE_CLUSTER_NAME_PATTERN` ENV var 42 | cluster_name_pattern: "{namespace}-{tenant}-{environment}-{stage}-eks-cluster" 43 | 44 | stacks: 45 | # Can also be set using `ATMOS_STACKS_BASE_PATH` ENV var, or `--config-dir` and `--stacks-dir` command-line arguments 46 | # Supports both absolute and relative paths 47 | base_path: "stacks" 48 | # Can also be set using `ATMOS_STACKS_INCLUDED_PATHS` ENV var (comma-separated values string) 49 | included_paths: 50 | - "**/*" 51 | # Can also be set using `ATMOS_STACKS_EXCLUDED_PATHS` ENV var (comma-separated values string) 52 | excluded_paths: 53 | - "globals/**/*" 54 | - "catalog/**/*" 55 | - "**/*globals*" 56 | # Can also be set using `ATMOS_STACKS_NAME_PATTERN` ENV var 57 | name_pattern: "{tenant}-{environment}-{stage}" 58 | 59 | workflows: 60 | # Can also be set using `ATMOS_WORKFLOWS_BASE_PATH` ENV var, or `--workflows-dir` command-line arguments 61 | # Supports both absolute and relative paths 62 | base_path: "workflows" 63 | 64 | logs: 65 | file: "/dev/stdout" 66 | # Supported log levels: Trace, Debug, Info, Warning, Off 67 | level: Info 68 | -------------------------------------------------------------------------------- /examples/spacelift/fixtures.tfvars: -------------------------------------------------------------------------------- 1 | enabled = true 2 | 3 | stack_config_path_template = "stacks/%s.yaml" 4 | 5 | stack_deps_processing_enabled = true 6 | 7 | component_deps_processing_enabled = true 8 | 9 | imports_processing_enabled = true 10 | -------------------------------------------------------------------------------- /examples/spacelift/main.tf: -------------------------------------------------------------------------------- 1 | module "spacelift" { 2 | source = "../../modules/spacelift" 3 | 4 | stack_config_path_template = var.stack_config_path_template 5 | stack_deps_processing_enabled = var.stack_deps_processing_enabled 6 | component_deps_processing_enabled = var.component_deps_processing_enabled 7 | imports_processing_enabled = var.imports_processing_enabled 8 | 9 | env = var.env 10 | 11 | context = module.this.context 12 | } 13 | -------------------------------------------------------------------------------- /examples/spacelift/outputs.tf: -------------------------------------------------------------------------------- 1 | output "spacelift_stacks" { 2 | value = module.spacelift.spacelift_stacks 3 | description = "Spacelift stacks" 4 | } 5 | -------------------------------------------------------------------------------- /examples/spacelift/stacks/catalog/helmfile/echo-server.yaml: -------------------------------------------------------------------------------- 1 | components: 2 | helmfile: 3 | echo-server: 4 | vars: 5 | installed: true 6 | -------------------------------------------------------------------------------- /examples/spacelift/stacks/catalog/helmfile/infra-server-override.yaml: -------------------------------------------------------------------------------- 1 | components: 2 | helmfile: 3 | "infra/infra-server-override": 4 | component: "infra/infra-server" 5 | vars: 6 | installed: true 7 | a: "1_override" 8 | -------------------------------------------------------------------------------- /examples/spacelift/stacks/catalog/helmfile/infra-server.yaml: -------------------------------------------------------------------------------- 1 | components: 2 | helmfile: 3 | "infra/infra-server": 4 | vars: 5 | installed: true 6 | a: "1" 7 | -------------------------------------------------------------------------------- /examples/spacelift/stacks/catalog/terraform/mixins/test-1.yaml: -------------------------------------------------------------------------------- 1 | components: 2 | terraform: 3 | "mixin/test-1": 4 | vars: 5 | service_1_name: "mixin-1" 6 | metadata: 7 | type: abstract 8 | -------------------------------------------------------------------------------- /examples/spacelift/stacks/catalog/terraform/mixins/test-2.yaml: -------------------------------------------------------------------------------- 1 | components: 2 | terraform: 3 | "mixin/test-2": 4 | vars: 5 | service_1_name: "mixin-2" 6 | metadata: 7 | type: abstract 8 | -------------------------------------------------------------------------------- /examples/spacelift/stacks/catalog/terraform/services/service-1-override-2.yaml: -------------------------------------------------------------------------------- 1 | components: 2 | terraform: 3 | "test/test-component-override-2": 4 | vars: 5 | service_1_name: "service-1-override-2" 6 | service_1_map: 7 | b: 6 8 | c: 7 9 | d: 8 10 | service_1_list: 11 | - 5 12 | - 6 13 | - 7 14 | -------------------------------------------------------------------------------- /examples/spacelift/stacks/catalog/terraform/services/service-1-override.yaml: -------------------------------------------------------------------------------- 1 | components: 2 | terraform: 3 | "test/test-component-override": 4 | vars: 5 | service_1_name: "service-1-override" 6 | service_1_map: 7 | a: 1 8 | b: 2 9 | c: 3 10 | service_1_list: 11 | - 1 12 | - 2 13 | - 3 14 | -------------------------------------------------------------------------------- /examples/spacelift/stacks/catalog/terraform/services/service-1.yaml: -------------------------------------------------------------------------------- 1 | components: 2 | terraform: 3 | "test/test-component": 4 | vars: 5 | service_1_name: "service-1" 6 | -------------------------------------------------------------------------------- /examples/spacelift/stacks/catalog/terraform/services/service-2-override-2.yaml: -------------------------------------------------------------------------------- 1 | components: 2 | terraform: 3 | "test/test-component-override-2": 4 | vars: 5 | service_2_name: "service-2-override-2" 6 | service_2_map: 7 | a: 4 8 | b: 5 9 | c: 6 10 | service_2_list: 11 | - 4 12 | - 5 13 | - 6 14 | -------------------------------------------------------------------------------- /examples/spacelift/stacks/catalog/terraform/services/service-2-override.yaml: -------------------------------------------------------------------------------- 1 | components: 2 | terraform: 3 | "test/test-component-override": 4 | vars: 5 | service_2_name: "service-2-override" 6 | service_2_map: 7 | a: 1 8 | b: 2 9 | c: 3 10 | service_2_list: 11 | - 1 12 | - 2 13 | - 3 14 | -------------------------------------------------------------------------------- /examples/spacelift/stacks/catalog/terraform/services/service-2.yaml: -------------------------------------------------------------------------------- 1 | components: 2 | terraform: 3 | "test/test-component": 4 | vars: 5 | service_2_name: "service-2" 6 | -------------------------------------------------------------------------------- /examples/spacelift/stacks/catalog/terraform/services/top-level-service-1.yaml: -------------------------------------------------------------------------------- 1 | components: 2 | terraform: 3 | top-level-component1: 4 | vars: 5 | service_1_name: "top-level-service-1" 6 | -------------------------------------------------------------------------------- /examples/spacelift/stacks/catalog/terraform/services/top-level-service-2.yaml: -------------------------------------------------------------------------------- 1 | components: 2 | terraform: 3 | top-level-component1: 4 | vars: 5 | service_2_name: "top-level-service-2" 6 | -------------------------------------------------------------------------------- /examples/spacelift/stacks/catalog/terraform/tenant1-ue2-dev.yaml: -------------------------------------------------------------------------------- 1 | components: 2 | terraform: 3 | "test/test-component-override": 4 | vars: 5 | service_1_name: "service-1-override-2" 6 | -------------------------------------------------------------------------------- /examples/spacelift/stacks/catalog/terraform/test-component-override-2.yaml: -------------------------------------------------------------------------------- 1 | # `import` supports POSIX-style Globs for file names/paths (double-star `**` is supported) 2 | # https://en.wikipedia.org/wiki/Glob_(programming) 3 | # https://pkg.go.dev/gopkg.in/godo.v2/glob 4 | # https://github.com/bmatcuk/doublestar 5 | # File extensions are optional (if not specified, `.yaml` is used by default) 6 | import: 7 | - catalog/terraform/services/service-?-override-2.* 8 | 9 | components: 10 | terraform: 11 | "test/test-component-override-2": 12 | # Specify terraform binary to run 13 | command: "/usr/local/bin/terraform" 14 | # The `component` attribute specifies that `test-component-override-2` inherits from the `test-component-override` base component, 15 | # which in turn inherits from `test-component` (inheritance chain). 16 | # `test-component-override-2` can override all the variables and other settings of all its base components (except the `metadata` section). 17 | # In this example, variables for each service are overridden in `catalog/services/service-?-override-2.*` 18 | component: "test/test-component-override" 19 | # Other variables can be overridden here 20 | vars: {} 21 | # Other ENV vars can be overridden here 22 | env: 23 | TEST_ENV_VAR1: "val1-override-2" 24 | TEST_ENV_VAR2: "val2-override-2" 25 | TEST_ENV_VAR4: "val4-override-2" 26 | # Override remote state backend for this component 27 | remote_state_backend_type: static # s3, remote, vault, static, etc. 28 | remote_state_backend: 29 | static: 30 | val1: true 31 | val2: "5" 32 | val3: 7 33 | val4: null 34 | -------------------------------------------------------------------------------- /examples/spacelift/stacks/catalog/terraform/test-component-override-3.yaml: -------------------------------------------------------------------------------- 1 | # `import` supports POSIX-style Globs for file names/paths (double-star `**` is supported) 2 | # https://en.wikipedia.org/wiki/Glob_(programming) 3 | # https://pkg.go.dev/gopkg.in/godo.v2/glob 4 | # https://github.com/bmatcuk/doublestar 5 | # File extensions are optional (if not specified, `.yaml` is used by default) 6 | import: 7 | - catalog/terraform/mixins/test-*.* 8 | 9 | components: 10 | terraform: 11 | "test/test-component-override-3": 12 | settings: 13 | spacelift: 14 | workspace_enabled: false 15 | vars: {} 16 | env: 17 | TEST_ENV_VAR1: "val1-override-3" 18 | TEST_ENV_VAR2: "val2-override-3" 19 | TEST_ENV_VAR3: "val3-override-3" 20 | TEST_ENV_VAR4: "val4-override-3" 21 | metadata: 22 | # `real` is implicit, you don't need to specify it; `abstract` makes the component protected from being deployed 23 | type: real 24 | # Terraform component. Must exist in `components/terraform` folder. 25 | # If not specified, it's assumed that this component `test/test-component-override-3` is also a Terraform component 26 | # in `components/terraform/test/test-component-override-3` folder 27 | component: "test/test-component" 28 | # Multiple inheritance. It's a down-top/left-right matrix (similar to Method Resolution Order (MRO), which is how Python supports multiple inheritance). 29 | # All base components and mixins are processed and deep-merged in the order they are specified in the `inherits` list: 30 | # 1. `test/test-component-override-2` overrides `test/test-component-override` and its base components (all the way up its inheritance chain). 31 | # 2. `mixin/test-1` overrides `test/test-component-override-2` and its base components (all the way up its inheritance chain). 32 | # 3. `mixin/test-2` overrides `mixin/test-1` and its base components (all the way up its inheritance chain). 33 | # 4. This `test/test-component-override-3` component overrides `mixin/test-2` and its base components (all the way up its inheritance chain). 34 | # Inheritance: test/test-component-override-3 -> mixin/test-2 -> mixin/test-1 -> test/test-component-override-2 -> test/test-component-override -> test/test-component 35 | inherits: 36 | - "test/test-component-override" 37 | - "test/test-component-override-2" 38 | - "mixin/test-1" 39 | - "mixin/test-2" 40 | # Override Terraform workspace 41 | # Note that by default, Terraform workspace is generated from the context, e.g. `-` 42 | terraform_workspace: test-component-override-3-workspace 43 | -------------------------------------------------------------------------------- /examples/spacelift/stacks/catalog/terraform/test-component-override.yaml: -------------------------------------------------------------------------------- 1 | # `import` supports POSIX-style Globs for file names/paths (double-star `**` is supported) 2 | # https://en.wikipedia.org/wiki/Glob_(programming) 3 | # https://pkg.go.dev/gopkg.in/godo.v2/glob 4 | # https://github.com/bmatcuk/doublestar 5 | # File extensions are optional (if not specified, `.yaml` is used by default) 6 | import: 7 | - catalog/terraform/services/service-?-override.* 8 | 9 | components: 10 | terraform: 11 | "test/test-component-override": 12 | # Specify terraform binary to run 13 | command: "/usr/local/bin/terraform" 14 | # The `component` attribute specifies that `test-component-override` inherits from the `test-component` base component. 15 | # `test-component-override` can override all the variables and other settings of the base component (except the `metadata` section). 16 | # In this example, variables for each service are overridden in `catalog/services/service-?-override.*` 17 | component: "test/test-component" 18 | # Other variables can be overridden here 19 | vars: {} 20 | # Other ENV vars can be overridden here 21 | env: 22 | TEST_ENV_VAR1: "val1-override" 23 | TEST_ENV_VAR3: "val3-override" 24 | TEST_ENV_VAR4: "val4" 25 | # Override remote state backend for this component 26 | remote_state_backend_type: static # s3, remote, vault, static, etc. 27 | remote_state_backend: 28 | static: 29 | val1: true 30 | val2: "2" 31 | val3: 3 32 | val4: null 33 | metadata: 34 | # Override Terraform workspace 35 | # Note that by default, Terraform workspace is generated from the context, e.g. `-` 36 | terraform_workspace: test-component-override-workspace-override 37 | -------------------------------------------------------------------------------- /examples/spacelift/stacks/catalog/terraform/test-component.yaml: -------------------------------------------------------------------------------- 1 | # `import` supports POSIX-style Globs for file names/paths (double-star `**` is supported) 2 | # https://en.wikipedia.org/wiki/Glob_(programming) 3 | # https://pkg.go.dev/gopkg.in/godo.v2/glob 4 | # https://github.com/bmatcuk/doublestar 5 | # File extensions are optional (if not specified, `.yaml` is used by default) 6 | import: 7 | - catalog/terraform/services/service-?.* 8 | 9 | components: 10 | terraform: 11 | "test/test-component": 12 | component: "test/test-component" 13 | settings: 14 | spacelift: 15 | workspace_enabled: true 16 | # Setting `metadata.type: abstract` makes the component `abstract` (similar to OOP abstract classes, which can't be instantiated), 17 | # explicitly prohibiting the component from being deployed, 18 | # and a Spacelift stack from being created for the component (even if `settings.spacelift.workspace_enabled: true`). 19 | # `terraform apply` and `terraform deploy` will fail with an error that the component cannot be provisioned. 20 | # All other terraform commands on this component will succeed. 21 | # If `metadata.type` attribute is not specified, it defaults to `real` (which means the component can be provisioned). 22 | metadata: 23 | type: real # `real` is implicit, you don't need to specify it; `abstract` makes the component protected from being deployed 24 | vars: 25 | enabled: true 26 | env: 27 | TEST_ENV_VAR1: "val1" 28 | TEST_ENV_VAR2: "val2" 29 | TEST_ENV_VAR3: "val3" 30 | -------------------------------------------------------------------------------- /examples/spacelift/stacks/catalog/terraform/top-level-component1.yaml: -------------------------------------------------------------------------------- 1 | # `import` supports POSIX-style Globs for file names/paths (double-star `**` is supported) 2 | # https://en.wikipedia.org/wiki/Glob_(programming) 3 | # https://pkg.go.dev/gopkg.in/godo.v2/glob 4 | # https://github.com/bmatcuk/doublestar 5 | # File extensions are optional (if not specified, `.yaml` is used by default) 6 | import: 7 | - catalog/terraform/services/top-level-service-?.* 8 | 9 | components: 10 | terraform: 11 | top-level-component1: 12 | settings: 13 | spacelift: 14 | workspace_enabled: true 15 | vars: 16 | enabled: true 17 | -------------------------------------------------------------------------------- /examples/spacelift/stacks/catalog/terraform/vpc.yaml: -------------------------------------------------------------------------------- 1 | components: 2 | terraform: 3 | "infra/vpc": 4 | backend: 5 | s3: 6 | workspace_key_prefix: infra-vpc 7 | settings: 8 | spacelift: 9 | workspace_enabled: true 10 | vars: 11 | enabled: true 12 | name: "common" 13 | subnet_type_tag_key: eg.io/subnet/type 14 | nat_gateway_enabled: true 15 | nat_instance_enabled: false 16 | max_subnet_count: 3 17 | -------------------------------------------------------------------------------- /examples/spacelift/stacks/globals/globals.yaml: -------------------------------------------------------------------------------- 1 | vars: 2 | namespace: eg 3 | 4 | terraform: 5 | vars: {} 6 | 7 | backend_type: s3 # s3, remote, vault, static, azurerm, etc. 8 | backend: 9 | s3: 10 | encrypt: true 11 | bucket: "eg-ue2-root-tfstate" 12 | key: "terraform.tfstate" 13 | dynamodb_table: "eg-ue2-root-tfstate-lock" 14 | acl: "bucket-owner-full-control" 15 | region: "us-east-2" 16 | role_arn: null 17 | azurerm: 18 | subscription_id: 88888-8888-8888-8888-8888888888 19 | resource_group_name: rg-terraform-state 20 | storage_account_name: staterraformstate 21 | container_name: dev-tfstate 22 | key: dev.atmos 23 | remote: 24 | vault: 25 | 26 | remote_state_backend: 27 | s3: 28 | role_arn: "arn:aws:iam::123456789012:role/eg-gbl-root-terraform" 29 | 30 | helmfile: 31 | vars: {} 32 | 33 | components: 34 | terraform: {} 35 | helmfile: {} 36 | -------------------------------------------------------------------------------- /examples/spacelift/stacks/globals/tenant1-globals.yaml: -------------------------------------------------------------------------------- 1 | vars: 2 | tenant: tenant1 3 | -------------------------------------------------------------------------------- /examples/spacelift/stacks/globals/tenant2-globals.yaml: -------------------------------------------------------------------------------- 1 | vars: 2 | tenant: tenant2 3 | -------------------------------------------------------------------------------- /examples/spacelift/stacks/globals/ue2-globals.yaml: -------------------------------------------------------------------------------- 1 | import: 2 | - globals/globals 3 | 4 | vars: 5 | region: us-east-2 6 | environment: ue2 7 | 8 | helmfile: 9 | vars: {} 10 | 11 | components: 12 | terraform: 13 | "infra/vpc": 14 | vars: 15 | availability_zones: ["us-east-2a", "us-east-2b", "us-east-2c"] 16 | -------------------------------------------------------------------------------- /examples/spacelift/stacks/tenant1/ue2/dev.yaml: -------------------------------------------------------------------------------- 1 | import: 2 | - globals/tenant1-globals 3 | - globals/ue2-globals 4 | - catalog/terraform/top-level-component1 5 | - catalog/terraform/test-component 6 | - catalog/terraform/test-component-override 7 | - catalog/terraform/test-component-override-2 8 | - catalog/terraform/test-component-override-3 9 | - catalog/terraform/vpc 10 | - catalog/terraform/tenant1-ue2-dev 11 | - catalog/helmfile/echo-server 12 | - catalog/helmfile/infra-server 13 | - catalog/helmfile/infra-server-override 14 | 15 | vars: 16 | stage: dev 17 | 18 | terraform: 19 | vars: {} 20 | 21 | helmfile: 22 | vars: {} 23 | 24 | components: 25 | terraform: 26 | "infra/vpc": 27 | vars: 28 | cidr_block: 10.10.0.0/18 29 | -------------------------------------------------------------------------------- /examples/spacelift/stacks/tenant1/ue2/prod.yaml: -------------------------------------------------------------------------------- 1 | import: 2 | - globals/tenant1-globals 3 | - globals/ue2-globals 4 | - catalog/terraform/top-level-component1 5 | - catalog/terraform/test-component 6 | - catalog/terraform/test-component-override 7 | - catalog/terraform/test-component-override-2 8 | - catalog/terraform/test-component-override-3 9 | - catalog/terraform/vpc 10 | - catalog/helmfile/echo-server 11 | - catalog/helmfile/infra-server 12 | - catalog/helmfile/infra-server-override 13 | 14 | vars: 15 | stage: prod 16 | 17 | terraform: 18 | vars: {} 19 | 20 | helmfile: 21 | vars: {} 22 | 23 | components: 24 | terraform: 25 | "infra/vpc": 26 | vars: 27 | cidr_block: 10.8.0.0/18 28 | -------------------------------------------------------------------------------- /examples/spacelift/stacks/tenant1/ue2/staging.yaml: -------------------------------------------------------------------------------- 1 | import: 2 | - globals/tenant1-globals 3 | - globals/ue2-globals 4 | - catalog/terraform/top-level-component1 5 | - catalog/terraform/test-component 6 | - catalog/terraform/test-component-override 7 | - catalog/terraform/test-component-override-2 8 | - catalog/terraform/test-component-override-3 9 | - catalog/terraform/vpc 10 | - catalog/helmfile/echo-server 11 | - catalog/helmfile/infra-server 12 | - catalog/helmfile/infra-server-override 13 | 14 | vars: 15 | stage: staging 16 | 17 | terraform: 18 | vars: {} 19 | 20 | helmfile: 21 | vars: {} 22 | 23 | components: 24 | terraform: 25 | "infra/vpc": 26 | vars: 27 | cidr_block: 10.9.0.0/18 28 | -------------------------------------------------------------------------------- /examples/spacelift/stacks/tenant2/ue2/dev.yaml: -------------------------------------------------------------------------------- 1 | import: 2 | - globals/tenant2-globals 3 | - globals/ue2-globals 4 | - catalog/terraform/top-level-component1 5 | - catalog/terraform/test-component 6 | - catalog/terraform/test-component-override 7 | - catalog/terraform/test-component-override-2 8 | - catalog/terraform/test-component-override-3 9 | - catalog/terraform/vpc 10 | - catalog/helmfile/echo-server 11 | - catalog/helmfile/infra-server 12 | - catalog/helmfile/infra-server-override 13 | 14 | vars: 15 | stage: dev 16 | 17 | terraform: 18 | vars: {} 19 | 20 | helmfile: 21 | vars: {} 22 | 23 | components: 24 | terraform: 25 | "infra/vpc": 26 | vars: 27 | cidr_block: 10.10.0.0/18 28 | -------------------------------------------------------------------------------- /examples/spacelift/stacks/tenant2/ue2/prod.yaml: -------------------------------------------------------------------------------- 1 | import: 2 | - globals/tenant2-globals 3 | - globals/ue2-globals 4 | - catalog/terraform/top-level-component1 5 | - catalog/terraform/test-component 6 | - catalog/terraform/test-component-override 7 | - catalog/terraform/test-component-override-2 8 | - catalog/terraform/test-component-override-3 9 | - catalog/terraform/vpc 10 | - catalog/helmfile/echo-server 11 | - catalog/helmfile/infra-server 12 | - catalog/helmfile/infra-server-override 13 | 14 | vars: 15 | stage: prod 16 | 17 | terraform: 18 | vars: {} 19 | 20 | helmfile: 21 | vars: {} 22 | 23 | components: 24 | terraform: 25 | "infra/vpc": 26 | vars: 27 | cidr_block: 10.8.0.0/18 28 | -------------------------------------------------------------------------------- /examples/spacelift/stacks/tenant2/ue2/staging.yaml: -------------------------------------------------------------------------------- 1 | import: 2 | - globals/tenant2-globals 3 | - globals/ue2-globals 4 | - catalog/terraform/top-level-component1 5 | - catalog/terraform/test-component 6 | - catalog/terraform/test-component-override 7 | - catalog/terraform/test-component-override-2 8 | - catalog/terraform/test-component-override-3 9 | - catalog/terraform/vpc 10 | - catalog/helmfile/echo-server 11 | - catalog/helmfile/infra-server 12 | - catalog/helmfile/infra-server-override 13 | 14 | vars: 15 | stage: staging 16 | 17 | terraform: 18 | vars: {} 19 | 20 | helmfile: 21 | vars: {} 22 | 23 | components: 24 | terraform: 25 | "infra/vpc": 26 | vars: 27 | cidr_block: 10.9.0.0/18 28 | -------------------------------------------------------------------------------- /examples/spacelift/variables.tf: -------------------------------------------------------------------------------- 1 | variable "stack_deps_processing_enabled" { 2 | type = bool 3 | description = "Boolean flag to enable/disable processing all stack dependencies in the provided stack" 4 | default = false 5 | } 6 | 7 | variable "component_deps_processing_enabled" { 8 | type = bool 9 | description = "Boolean flag to enable/disable processing stack config dependencies for the components in the provided stack" 10 | default = true 11 | } 12 | 13 | variable "imports_processing_enabled" { 14 | type = bool 15 | description = "Enable/disable processing stack imports" 16 | default = false 17 | } 18 | 19 | variable "stack_config_path_template" { 20 | type = string 21 | description = "Stack config path template" 22 | default = "stacks/%s.yaml" 23 | } 24 | 25 | variable "env" { 26 | type = map(string) 27 | description = "Map of ENV vars in the format `key=value`. These ENV vars will be set in the `utils` provider before executing the data source" 28 | default = null 29 | } 30 | -------------------------------------------------------------------------------- /examples/spacelift/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 0.14.0" 3 | 4 | required_providers { 5 | local = { 6 | source = "hashicorp/local" 7 | version = ">= 1.3" 8 | } 9 | external = { 10 | source = "hashicorp/external" 11 | version = ">= 2.0" 12 | } 13 | utils = { 14 | source = "cloudposse/utils" 15 | version = ">= 1.8.0" 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /examples/stack/context.tf: -------------------------------------------------------------------------------- 1 | # 2 | # ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label 3 | # All other instances of this file should be a copy of that one 4 | # 5 | # 6 | # Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf 7 | # and then place it in your Terraform module to automatically get 8 | # Cloud Posse's standard configuration inputs suitable for passing 9 | # to Cloud Posse modules. 10 | # 11 | # curl -sL https://raw.githubusercontent.com/cloudposse/terraform-null-label/master/exports/context.tf -o context.tf 12 | # 13 | # Modules should access the whole context as `module.this.context` 14 | # to get the input variables with nulls for defaults, 15 | # for example `context = module.this.context`, 16 | # and access individual variables as `module.this.`, 17 | # with final values filled in. 18 | # 19 | # For example, when using defaults, `module.this.context.delimiter` 20 | # will be null, and `module.this.delimiter` will be `-` (hyphen). 21 | # 22 | 23 | module "this" { 24 | source = "cloudposse/label/null" 25 | version = "0.25.0" # requires Terraform >= 0.13.0 26 | 27 | enabled = var.enabled 28 | namespace = var.namespace 29 | tenant = var.tenant 30 | environment = var.environment 31 | stage = var.stage 32 | name = var.name 33 | delimiter = var.delimiter 34 | attributes = var.attributes 35 | tags = var.tags 36 | additional_tag_map = var.additional_tag_map 37 | label_order = var.label_order 38 | regex_replace_chars = var.regex_replace_chars 39 | id_length_limit = var.id_length_limit 40 | label_key_case = var.label_key_case 41 | label_value_case = var.label_value_case 42 | descriptor_formats = var.descriptor_formats 43 | labels_as_tags = var.labels_as_tags 44 | 45 | context = var.context 46 | } 47 | 48 | # Copy contents of cloudposse/terraform-null-label/variables.tf here 49 | 50 | variable "context" { 51 | type = any 52 | default = { 53 | enabled = true 54 | namespace = null 55 | tenant = null 56 | environment = null 57 | stage = null 58 | name = null 59 | delimiter = null 60 | attributes = [] 61 | tags = {} 62 | additional_tag_map = {} 63 | regex_replace_chars = null 64 | label_order = [] 65 | id_length_limit = null 66 | label_key_case = null 67 | label_value_case = null 68 | descriptor_formats = {} 69 | # Note: we have to use [] instead of null for unset lists due to 70 | # https://github.com/hashicorp/terraform/issues/28137 71 | # which was not fixed until Terraform 1.0.0, 72 | # but we want the default to be all the labels in `label_order` 73 | # and we want users to be able to prevent all tag generation 74 | # by setting `labels_as_tags` to `[]`, so we need 75 | # a different sentinel to indicate "default" 76 | labels_as_tags = ["unset"] 77 | } 78 | description = <<-EOT 79 | Single object for setting entire context at once. 80 | See description of individual variables for details. 81 | Leave string and numeric variables as `null` to use default value. 82 | Individual variable settings (non-null) override settings in context object, 83 | except for attributes, tags, and additional_tag_map, which are merged. 84 | EOT 85 | 86 | validation { 87 | condition = lookup(var.context, "label_key_case", null) == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) 88 | error_message = "Allowed values: `lower`, `title`, `upper`." 89 | } 90 | 91 | validation { 92 | condition = lookup(var.context, "label_value_case", null) == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) 93 | error_message = "Allowed values: `lower`, `title`, `upper`, `none`." 94 | } 95 | } 96 | 97 | variable "enabled" { 98 | type = bool 99 | default = null 100 | description = "Set to false to prevent the module from creating any resources" 101 | } 102 | 103 | variable "namespace" { 104 | type = string 105 | default = null 106 | description = "ID element. Usually an abbreviation of your organization name, e.g. 'eg' or 'cp', to help ensure generated IDs are globally unique" 107 | } 108 | 109 | variable "tenant" { 110 | type = string 111 | default = null 112 | description = "ID element _(Rarely used, not included by default)_. A customer identifier, indicating who this instance of a resource is for" 113 | } 114 | 115 | variable "environment" { 116 | type = string 117 | default = null 118 | description = "ID element. Usually used for region e.g. 'uw2', 'us-west-2', OR role 'prod', 'staging', 'dev', 'UAT'" 119 | } 120 | 121 | variable "stage" { 122 | type = string 123 | default = null 124 | description = "ID element. Usually used to indicate role, e.g. 'prod', 'staging', 'source', 'build', 'test', 'deploy', 'release'" 125 | } 126 | 127 | variable "name" { 128 | type = string 129 | default = null 130 | description = <<-EOT 131 | ID element. Usually the component or solution name, e.g. 'app' or 'jenkins'. 132 | This is the only ID element not also included as a `tag`. 133 | The "name" tag is set to the full `id` string. There is no tag with the value of the `name` input. 134 | EOT 135 | } 136 | 137 | variable "delimiter" { 138 | type = string 139 | default = null 140 | description = <<-EOT 141 | Delimiter to be used between ID elements. 142 | Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. 143 | EOT 144 | } 145 | 146 | variable "attributes" { 147 | type = list(string) 148 | default = [] 149 | description = <<-EOT 150 | ID element. Additional attributes (e.g. `workers` or `cluster`) to add to `id`, 151 | in the order they appear in the list. New attributes are appended to the 152 | end of the list. The elements of the list are joined by the `delimiter` 153 | and treated as a single ID element. 154 | EOT 155 | } 156 | 157 | variable "labels_as_tags" { 158 | type = set(string) 159 | default = ["default"] 160 | description = <<-EOT 161 | Set of labels (ID elements) to include as tags in the `tags` output. 162 | Default is to include all labels. 163 | Tags with empty values will not be included in the `tags` output. 164 | Set to `[]` to suppress all generated tags. 165 | **Notes:** 166 | The value of the `name` tag, if included, will be the `id`, not the `name`. 167 | Unlike other `null-label` inputs, the initial setting of `labels_as_tags` cannot be 168 | changed in later chained modules. Attempts to change it will be silently ignored. 169 | EOT 170 | } 171 | 172 | variable "tags" { 173 | type = map(string) 174 | default = {} 175 | description = <<-EOT 176 | Additional tags (e.g. `{'BusinessUnit': 'XYZ'}`). 177 | Neither the tag keys nor the tag values will be modified by this module. 178 | EOT 179 | } 180 | 181 | variable "additional_tag_map" { 182 | type = map(string) 183 | default = {} 184 | description = <<-EOT 185 | Additional key-value pairs to add to each map in `tags_as_list_of_maps`. Not added to `tags` or `id`. 186 | This is for some rare cases where resources want additional configuration of tags 187 | and therefore take a list of maps with tag key, value, and additional configuration. 188 | EOT 189 | } 190 | 191 | variable "label_order" { 192 | type = list(string) 193 | default = null 194 | description = <<-EOT 195 | The order in which the labels (ID elements) appear in the `id`. 196 | Defaults to ["namespace", "environment", "stage", "name", "attributes"]. 197 | You can omit any of the 6 labels ("tenant" is the 6th), but at least one must be present. 198 | EOT 199 | } 200 | 201 | variable "regex_replace_chars" { 202 | type = string 203 | default = null 204 | description = <<-EOT 205 | Terraform regular expression (regex) string. 206 | Characters matching the regex will be removed from the ID elements. 207 | If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. 208 | EOT 209 | } 210 | 211 | variable "id_length_limit" { 212 | type = number 213 | default = null 214 | description = <<-EOT 215 | Limit `id` to this many characters (minimum 6). 216 | Set to `0` for unlimited length. 217 | Set to `null` for keep the existing setting, which defaults to `0`. 218 | Does not affect `id_full`. 219 | EOT 220 | validation { 221 | condition = var.id_length_limit == null ? true : var.id_length_limit >= 6 || var.id_length_limit == 0 222 | error_message = "The id_length_limit must be >= 6 if supplied (not null), or 0 for unlimited length." 223 | } 224 | } 225 | 226 | variable "label_key_case" { 227 | type = string 228 | default = null 229 | description = <<-EOT 230 | Controls the letter case of the `tags` keys (label names) for tags generated by this module. 231 | Does not affect keys of tags passed in via the `tags` input. 232 | Possible values: `lower`, `title`, `upper`. 233 | Default value: `title`. 234 | EOT 235 | 236 | validation { 237 | condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) 238 | error_message = "Allowed values: `lower`, `title`, `upper`." 239 | } 240 | } 241 | 242 | variable "label_value_case" { 243 | type = string 244 | default = null 245 | description = <<-EOT 246 | Controls the letter case of ID elements (labels) as included in `id`, 247 | set as tag values, and output by this module individually. 248 | Does not affect values of tags passed in via the `tags` input. 249 | Possible values: `lower`, `title`, `upper` and `none` (no transformation). 250 | Set this to `title` and set `delimiter` to `""` to yield Pascal Case IDs. 251 | Default value: `lower`. 252 | EOT 253 | 254 | validation { 255 | condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) 256 | error_message = "Allowed values: `lower`, `title`, `upper`, `none`." 257 | } 258 | } 259 | 260 | variable "descriptor_formats" { 261 | type = any 262 | default = {} 263 | description = <<-EOT 264 | Describe additional descriptors to be output in the `descriptors` output map. 265 | Map of maps. Keys are names of descriptors. Values are maps of the form 266 | `{ 267 | format = string 268 | labels = list(string) 269 | }` 270 | (Type is `any` so the map values can later be enhanced to provide additional options.) 271 | `format` is a Terraform format string to be passed to the `format()` function. 272 | `labels` is a list of labels, in order, to pass to `format()` function. 273 | Label values will be normalized before being passed to `format()` so they will be 274 | identical to how they appear in `id`. 275 | Default is `{}` (`descriptors` output will be empty). 276 | EOT 277 | } 278 | 279 | #### End of copy of cloudposse/terraform-null-label/variables.tf 280 | -------------------------------------------------------------------------------- /examples/stack/fixtures.tfvars: -------------------------------------------------------------------------------- 1 | enabled = true 2 | 3 | stack = "my-stack" 4 | -------------------------------------------------------------------------------- /examples/stack/main.tf: -------------------------------------------------------------------------------- 1 | # Since `var.stack` is provided, the module should just return it 2 | module "stack_1" { 3 | source = "../../modules/stack" 4 | 5 | stack = var.stack 6 | 7 | context = module.this.context 8 | } 9 | 10 | # Since `var.stack` is provided, the module should just return it regardless of all other settings 11 | module "stack_2" { 12 | source = "../../modules/stack" 13 | 14 | stack = var.stack 15 | environment = "uw2" 16 | stage = "dev" 17 | 18 | context = module.this.context 19 | } 20 | 21 | # Since `var.stack` and `var.descriptor_formats` are not provided, the module creates the stack name from the provided context 22 | module "stack_3" { 23 | source = "../../modules/stack" 24 | 25 | environment = "uw2" 26 | stage = "dev" 27 | 28 | context = module.this.context 29 | } 30 | 31 | # Since `var.stack` and `var.descriptor_formats` are not provided, the module creates the stack name from the provided context 32 | module "stack_4" { 33 | source = "../../modules/stack" 34 | 35 | tenant = "acme" 36 | environment = "uw2" 37 | stage = "dev" 38 | 39 | context = module.this.context 40 | } 41 | 42 | # Test `descriptor_formats` 43 | module "stack_5" { 44 | source = "../../modules/stack" 45 | 46 | tenant = "acme" 47 | environment = "uw2" 48 | stage = "dev" 49 | 50 | descriptor_formats = { 51 | stack = { 52 | labels = ["tenant", "environment", "stage"] 53 | format = "%v-%v-%v" 54 | } 55 | } 56 | 57 | context = module.this.context 58 | } 59 | 60 | # Test `descriptor_formats` 61 | module "stack_6" { 62 | source = "../../modules/stack" 63 | 64 | tenant = "acme" 65 | environment = "uw2" 66 | stage = "dev" 67 | 68 | descriptor_formats = { 69 | stack = { 70 | labels = ["stage", "environment", "tenant"] 71 | format = "%v-%v-%v" 72 | } 73 | } 74 | 75 | context = module.this.context 76 | } 77 | 78 | # Test `descriptor_formats` 79 | module "stack_7" { 80 | source = "../../modules/stack" 81 | 82 | tenant = "acme" 83 | environment = "uw2" 84 | stage = "dev" 85 | 86 | descriptor_formats = { 87 | stack = { 88 | labels = ["environment", "tenant", "stage"] 89 | format = "%v-%v-%v" 90 | } 91 | } 92 | 93 | context = module.this.context 94 | } 95 | 96 | # Test `descriptor_formats` 97 | module "stack_8" { 98 | source = "../../modules/stack" 99 | 100 | tenant = "acme" 101 | environment = "uw2" 102 | stage = "dev" 103 | 104 | descriptor_formats = { 105 | stack = { 106 | labels = ["stage", "tenant", "environment"] 107 | format = "%v-%v-%v" 108 | } 109 | } 110 | 111 | context = module.this.context 112 | } 113 | 114 | # Since `var.stack` is provided, the module should just return it regardless of all other settings (don't use `var.stack` and `var.descriptor_formats) 115 | module "stack_9" { 116 | source = "../../modules/stack" 117 | 118 | stack = var.stack 119 | tenant = "acme" 120 | environment = "uw2" 121 | stage = "dev" 122 | 123 | descriptor_formats = { 124 | stack = { 125 | labels = ["tenant", "environment", "stage"] 126 | format = "%v-%v-%v" 127 | } 128 | } 129 | 130 | context = module.this.context 131 | } 132 | -------------------------------------------------------------------------------- /examples/stack/outputs.tf: -------------------------------------------------------------------------------- 1 | output "stack_1_name" { 2 | value = module.stack_1.stack_name 3 | description = "Name of stack 1" 4 | } 5 | 6 | output "stack_2_name" { 7 | value = module.stack_2.stack_name 8 | description = "Name of stack 2" 9 | } 10 | 11 | output "stack_3_name" { 12 | value = module.stack_3.stack_name 13 | description = "Name of stack 3" 14 | } 15 | 16 | output "stack_4_name" { 17 | value = module.stack_4.stack_name 18 | description = "Name of stack 4" 19 | } 20 | 21 | output "stack_5_name" { 22 | value = module.stack_5.stack_name 23 | description = "Name of stack 5" 24 | } 25 | 26 | output "stack_6_name" { 27 | value = module.stack_6.stack_name 28 | description = "Name of stack 6" 29 | } 30 | 31 | output "stack_7_name" { 32 | value = module.stack_7.stack_name 33 | description = "Name of stack 7" 34 | } 35 | 36 | output "stack_8_name" { 37 | value = module.stack_8.stack_name 38 | description = "Name of stack 8" 39 | } 40 | 41 | output "stack_9_name" { 42 | value = module.stack_9.stack_name 43 | description = "Name of stack 9" 44 | } 45 | -------------------------------------------------------------------------------- /examples/stack/variables.tf: -------------------------------------------------------------------------------- 1 | variable "stack" { 2 | type = string 3 | description = "Stack name" 4 | } 5 | -------------------------------------------------------------------------------- /examples/stack/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 0.14.0" 3 | 4 | required_providers { 5 | local = { 6 | source = "hashicorp/local" 7 | version = ">= 1.3" 8 | } 9 | external = { 10 | source = "hashicorp/external" 11 | version = ">= 2.0" 12 | } 13 | utils = { 14 | source = "cloudposse/utils" 15 | version = ">= 1.8.0" 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /examples/stacks/atmos.yaml: -------------------------------------------------------------------------------- 1 | # CLI config is loaded from the following locations (from lowest to highest priority): 2 | # system dir (`/usr/local/etc/atmos` on Linux, `%LOCALAPPDATA%/atmos` on Windows) 3 | # home dir (~/.atmos) 4 | # current directory 5 | # ENV vars 6 | # Command-line arguments 7 | # 8 | # It supports POSIX-style Globs for file names/paths (double-star `**` is supported) 9 | # https://en.wikipedia.org/wiki/Glob_(programming) 10 | 11 | # Base path for components, stacks and workflows configurations. 12 | # Can also be set using `ATMOS_BASE_PATH` ENV var, or `--base-path` command-line argument. 13 | # Supports both absolute and relative paths. 14 | # If not provided or is an empty string, `components.terraform.base_path`, `components.helmfile.base_path`, `stacks.base_path` and `workflows.base_path` 15 | # are independent settings (supporting both absolute and relative paths). 16 | # If `base_path` is provided, `components.terraform.base_path`, `components.helmfile.base_path`, `stacks.base_path` and `workflows.base_path` 17 | # are considered paths relative to `base_path`. 18 | base_path: "." 19 | 20 | components: 21 | terraform: 22 | # Can also be set using `ATMOS_COMPONENTS_TERRAFORM_BASE_PATH` ENV var, or `--terraform-dir` command-line argument 23 | # Supports both absolute and relative paths 24 | base_path: "components/terraform" 25 | # Can also be set using `ATMOS_COMPONENTS_TERRAFORM_APPLY_AUTO_APPROVE` ENV var 26 | apply_auto_approve: false 27 | # Can also be set using `ATMOS_COMPONENTS_TERRAFORM_DEPLOY_RUN_INIT` ENV var, or `--deploy-run-init` command-line argument 28 | deploy_run_init: true 29 | # Can also be set using `ATMOS_COMPONENTS_TERRAFORM_INIT_RUN_RECONFIGURE` ENV var, or `--init-run-reconfigure` command-line argument 30 | init_run_reconfigure: true 31 | # Can also be set using `ATMOS_COMPONENTS_TERRAFORM_AUTO_GENERATE_BACKEND_FILE` ENV var, or `--auto-generate-backend-file` command-line argument 32 | auto_generate_backend_file: false 33 | helmfile: 34 | # Can also be set using `ATMOS_COMPONENTS_HELMFILE_BASE_PATH` ENV var, or `--helmfile-dir` command-line argument 35 | # Supports both absolute and relative paths 36 | base_path: "components/helmfile" 37 | # Can also be set using `ATMOS_COMPONENTS_HELMFILE_KUBECONFIG_PATH` ENV var 38 | kubeconfig_path: "/dev/shm" 39 | # Can also be set using `ATMOS_COMPONENTS_HELMFILE_HELM_AWS_PROFILE_PATTERN` ENV var 40 | helm_aws_profile_pattern: "{namespace}-{tenant}-gbl-{stage}-helm" 41 | # Can also be set using `ATMOS_COMPONENTS_HELMFILE_CLUSTER_NAME_PATTERN` ENV var 42 | cluster_name_pattern: "{namespace}-{tenant}-{environment}-{stage}-eks-cluster" 43 | 44 | stacks: 45 | # Can also be set using `ATMOS_STACKS_BASE_PATH` ENV var, or `--config-dir` and `--stacks-dir` command-line arguments 46 | # Supports both absolute and relative paths 47 | base_path: "stacks" 48 | # Can also be set using `ATMOS_STACKS_INCLUDED_PATHS` ENV var (comma-separated values string) 49 | included_paths: 50 | - "**/*" 51 | # Can also be set using `ATMOS_STACKS_EXCLUDED_PATHS` ENV var (comma-separated values string) 52 | excluded_paths: 53 | - "globals/**/*" 54 | - "catalog/**/*" 55 | - "**/*globals*" 56 | # Can also be set using `ATMOS_STACKS_NAME_PATTERN` ENV var 57 | name_pattern: "{tenant}-{environment}-{stage}" 58 | 59 | workflows: 60 | # Can also be set using `ATMOS_WORKFLOWS_BASE_PATH` ENV var, or `--workflows-dir` command-line arguments 61 | # Supports both absolute and relative paths 62 | base_path: "workflows" 63 | 64 | logs: 65 | file: "/dev/stdout" 66 | # Supported log levels: Trace, Debug, Info, Warning, Off 67 | level: Info 68 | -------------------------------------------------------------------------------- /examples/stacks/context.tf: -------------------------------------------------------------------------------- 1 | # 2 | # ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label 3 | # All other instances of this file should be a copy of that one 4 | # 5 | # 6 | # Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf 7 | # and then place it in your Terraform module to automatically get 8 | # Cloud Posse's standard configuration inputs suitable for passing 9 | # to Cloud Posse modules. 10 | # 11 | # curl -sL https://raw.githubusercontent.com/cloudposse/terraform-null-label/master/exports/context.tf -o context.tf 12 | # 13 | # Modules should access the whole context as `module.this.context` 14 | # to get the input variables with nulls for defaults, 15 | # for example `context = module.this.context`, 16 | # and access individual variables as `module.this.`, 17 | # with final values filled in. 18 | # 19 | # For example, when using defaults, `module.this.context.delimiter` 20 | # will be null, and `module.this.delimiter` will be `-` (hyphen). 21 | # 22 | 23 | module "this" { 24 | source = "cloudposse/label/null" 25 | version = "0.25.0" # requires Terraform >= 0.13.0 26 | 27 | enabled = var.enabled 28 | namespace = var.namespace 29 | tenant = var.tenant 30 | environment = var.environment 31 | stage = var.stage 32 | name = var.name 33 | delimiter = var.delimiter 34 | attributes = var.attributes 35 | tags = var.tags 36 | additional_tag_map = var.additional_tag_map 37 | label_order = var.label_order 38 | regex_replace_chars = var.regex_replace_chars 39 | id_length_limit = var.id_length_limit 40 | label_key_case = var.label_key_case 41 | label_value_case = var.label_value_case 42 | descriptor_formats = var.descriptor_formats 43 | labels_as_tags = var.labels_as_tags 44 | 45 | context = var.context 46 | } 47 | 48 | # Copy contents of cloudposse/terraform-null-label/variables.tf here 49 | 50 | variable "context" { 51 | type = any 52 | default = { 53 | enabled = true 54 | namespace = null 55 | tenant = null 56 | environment = null 57 | stage = null 58 | name = null 59 | delimiter = null 60 | attributes = [] 61 | tags = {} 62 | additional_tag_map = {} 63 | regex_replace_chars = null 64 | label_order = [] 65 | id_length_limit = null 66 | label_key_case = null 67 | label_value_case = null 68 | descriptor_formats = {} 69 | # Note: we have to use [] instead of null for unset lists due to 70 | # https://github.com/hashicorp/terraform/issues/28137 71 | # which was not fixed until Terraform 1.0.0, 72 | # but we want the default to be all the labels in `label_order` 73 | # and we want users to be able to prevent all tag generation 74 | # by setting `labels_as_tags` to `[]`, so we need 75 | # a different sentinel to indicate "default" 76 | labels_as_tags = ["unset"] 77 | } 78 | description = <<-EOT 79 | Single object for setting entire context at once. 80 | See description of individual variables for details. 81 | Leave string and numeric variables as `null` to use default value. 82 | Individual variable settings (non-null) override settings in context object, 83 | except for attributes, tags, and additional_tag_map, which are merged. 84 | EOT 85 | 86 | validation { 87 | condition = lookup(var.context, "label_key_case", null) == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) 88 | error_message = "Allowed values: `lower`, `title`, `upper`." 89 | } 90 | 91 | validation { 92 | condition = lookup(var.context, "label_value_case", null) == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) 93 | error_message = "Allowed values: `lower`, `title`, `upper`, `none`." 94 | } 95 | } 96 | 97 | variable "enabled" { 98 | type = bool 99 | default = null 100 | description = "Set to false to prevent the module from creating any resources" 101 | } 102 | 103 | variable "namespace" { 104 | type = string 105 | default = null 106 | description = "ID element. Usually an abbreviation of your organization name, e.g. 'eg' or 'cp', to help ensure generated IDs are globally unique" 107 | } 108 | 109 | variable "tenant" { 110 | type = string 111 | default = null 112 | description = "ID element _(Rarely used, not included by default)_. A customer identifier, indicating who this instance of a resource is for" 113 | } 114 | 115 | variable "environment" { 116 | type = string 117 | default = null 118 | description = "ID element. Usually used for region e.g. 'uw2', 'us-west-2', OR role 'prod', 'staging', 'dev', 'UAT'" 119 | } 120 | 121 | variable "stage" { 122 | type = string 123 | default = null 124 | description = "ID element. Usually used to indicate role, e.g. 'prod', 'staging', 'source', 'build', 'test', 'deploy', 'release'" 125 | } 126 | 127 | variable "name" { 128 | type = string 129 | default = null 130 | description = <<-EOT 131 | ID element. Usually the component or solution name, e.g. 'app' or 'jenkins'. 132 | This is the only ID element not also included as a `tag`. 133 | The "name" tag is set to the full `id` string. There is no tag with the value of the `name` input. 134 | EOT 135 | } 136 | 137 | variable "delimiter" { 138 | type = string 139 | default = null 140 | description = <<-EOT 141 | Delimiter to be used between ID elements. 142 | Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. 143 | EOT 144 | } 145 | 146 | variable "attributes" { 147 | type = list(string) 148 | default = [] 149 | description = <<-EOT 150 | ID element. Additional attributes (e.g. `workers` or `cluster`) to add to `id`, 151 | in the order they appear in the list. New attributes are appended to the 152 | end of the list. The elements of the list are joined by the `delimiter` 153 | and treated as a single ID element. 154 | EOT 155 | } 156 | 157 | variable "labels_as_tags" { 158 | type = set(string) 159 | default = ["default"] 160 | description = <<-EOT 161 | Set of labels (ID elements) to include as tags in the `tags` output. 162 | Default is to include all labels. 163 | Tags with empty values will not be included in the `tags` output. 164 | Set to `[]` to suppress all generated tags. 165 | **Notes:** 166 | The value of the `name` tag, if included, will be the `id`, not the `name`. 167 | Unlike other `null-label` inputs, the initial setting of `labels_as_tags` cannot be 168 | changed in later chained modules. Attempts to change it will be silently ignored. 169 | EOT 170 | } 171 | 172 | variable "tags" { 173 | type = map(string) 174 | default = {} 175 | description = <<-EOT 176 | Additional tags (e.g. `{'BusinessUnit': 'XYZ'}`). 177 | Neither the tag keys nor the tag values will be modified by this module. 178 | EOT 179 | } 180 | 181 | variable "additional_tag_map" { 182 | type = map(string) 183 | default = {} 184 | description = <<-EOT 185 | Additional key-value pairs to add to each map in `tags_as_list_of_maps`. Not added to `tags` or `id`. 186 | This is for some rare cases where resources want additional configuration of tags 187 | and therefore take a list of maps with tag key, value, and additional configuration. 188 | EOT 189 | } 190 | 191 | variable "label_order" { 192 | type = list(string) 193 | default = null 194 | description = <<-EOT 195 | The order in which the labels (ID elements) appear in the `id`. 196 | Defaults to ["namespace", "environment", "stage", "name", "attributes"]. 197 | You can omit any of the 6 labels ("tenant" is the 6th), but at least one must be present. 198 | EOT 199 | } 200 | 201 | variable "regex_replace_chars" { 202 | type = string 203 | default = null 204 | description = <<-EOT 205 | Terraform regular expression (regex) string. 206 | Characters matching the regex will be removed from the ID elements. 207 | If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. 208 | EOT 209 | } 210 | 211 | variable "id_length_limit" { 212 | type = number 213 | default = null 214 | description = <<-EOT 215 | Limit `id` to this many characters (minimum 6). 216 | Set to `0` for unlimited length. 217 | Set to `null` for keep the existing setting, which defaults to `0`. 218 | Does not affect `id_full`. 219 | EOT 220 | validation { 221 | condition = var.id_length_limit == null ? true : var.id_length_limit >= 6 || var.id_length_limit == 0 222 | error_message = "The id_length_limit must be >= 6 if supplied (not null), or 0 for unlimited length." 223 | } 224 | } 225 | 226 | variable "label_key_case" { 227 | type = string 228 | default = null 229 | description = <<-EOT 230 | Controls the letter case of the `tags` keys (label names) for tags generated by this module. 231 | Does not affect keys of tags passed in via the `tags` input. 232 | Possible values: `lower`, `title`, `upper`. 233 | Default value: `title`. 234 | EOT 235 | 236 | validation { 237 | condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) 238 | error_message = "Allowed values: `lower`, `title`, `upper`." 239 | } 240 | } 241 | 242 | variable "label_value_case" { 243 | type = string 244 | default = null 245 | description = <<-EOT 246 | Controls the letter case of ID elements (labels) as included in `id`, 247 | set as tag values, and output by this module individually. 248 | Does not affect values of tags passed in via the `tags` input. 249 | Possible values: `lower`, `title`, `upper` and `none` (no transformation). 250 | Set this to `title` and set `delimiter` to `""` to yield Pascal Case IDs. 251 | Default value: `lower`. 252 | EOT 253 | 254 | validation { 255 | condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) 256 | error_message = "Allowed values: `lower`, `title`, `upper`, `none`." 257 | } 258 | } 259 | 260 | variable "descriptor_formats" { 261 | type = any 262 | default = {} 263 | description = <<-EOT 264 | Describe additional descriptors to be output in the `descriptors` output map. 265 | Map of maps. Keys are names of descriptors. Values are maps of the form 266 | `{ 267 | format = string 268 | labels = list(string) 269 | }` 270 | (Type is `any` so the map values can later be enhanced to provide additional options.) 271 | `format` is a Terraform format string to be passed to the `format()` function. 272 | `labels` is a list of labels, in order, to pass to `format()` function. 273 | Label values will be normalized before being passed to `format()` so they will be 274 | identical to how they appear in `id`. 275 | Default is `{}` (`descriptors` output will be empty). 276 | EOT 277 | } 278 | 279 | #### End of copy of cloudposse/terraform-null-label/variables.tf 280 | -------------------------------------------------------------------------------- /examples/stacks/fixtures.tfvars: -------------------------------------------------------------------------------- 1 | enabled = true 2 | 3 | stacks = [ 4 | "uw2-dev", 5 | "uw2-prod", 6 | "uw2-staging", 7 | "uw2-uat" 8 | ] 9 | 10 | stack_deps_processing_enabled = true 11 | 12 | component_deps_processing_enabled = true 13 | -------------------------------------------------------------------------------- /examples/stacks/main.tf: -------------------------------------------------------------------------------- 1 | module "stacks" { 2 | source = "../../" 3 | 4 | stack_config_local_path = "${path.cwd}/stacks" 5 | stacks = var.stacks 6 | stack_deps_processing_enabled = var.stack_deps_processing_enabled 7 | component_deps_processing_enabled = var.component_deps_processing_enabled 8 | 9 | context = module.this.context 10 | } 11 | -------------------------------------------------------------------------------- /examples/stacks/outputs.tf: -------------------------------------------------------------------------------- 1 | output "config" { 2 | value = module.stacks.config 3 | description = "Stack configurations" 4 | } 5 | -------------------------------------------------------------------------------- /examples/stacks/stacks/eks/eks-defaults.yaml: -------------------------------------------------------------------------------- 1 | components: 2 | terraform: 3 | 4 | efs: 5 | vars: {} 6 | 7 | eks-iam: 8 | vars: {} 9 | 10 | helmfile: 11 | 12 | alb-controller: 13 | vars: 14 | installed: true 15 | chart_values: 16 | enableCertManager: true 17 | 18 | codefresh-account: 19 | vars: 20 | installed: true 21 | unlimited_staging_enabled: false 22 | 23 | echo-server: 24 | vars: 25 | installed: true 26 | 27 | efs-provisioner: 28 | vars: 29 | installed: true 30 | 31 | external-dns: 32 | vars: 33 | installed: true 34 | 35 | idp-roles: 36 | vars: 37 | installed: true 38 | 39 | metrics-server: 40 | vars: 41 | installed: true 42 | 43 | cert-manager: 44 | vars: 45 | installed: true 46 | 47 | ocean-controller: 48 | vars: 49 | installed: true 50 | 51 | reloader: 52 | vars: 53 | installed: true 54 | -------------------------------------------------------------------------------- /examples/stacks/stacks/globals.yaml: -------------------------------------------------------------------------------- 1 | vars: 2 | namespace: eg 3 | 4 | terraform: 5 | vars: {} 6 | 7 | backend_type: s3 # s3, remote, vault, etc. 8 | backend: 9 | s3: 10 | encrypt: true 11 | bucket: "eg-uw2-root-tfstate" 12 | key: "terraform.tfstate" 13 | dynamodb_table: "eg-uw2-root-tfstate-lock" 14 | role_arn: "arn:aws:iam::XXXXXXXXXXXX:role/eg-gbl-root-terraform" 15 | acl: "bucket-owner-full-control" 16 | region: "us-west-2" 17 | remote: {} 18 | vault: {} 19 | 20 | helmfile: 21 | vars: {} 22 | 23 | components: 24 | terraform: 25 | tfstate-backend: 26 | backend: 27 | s3: 28 | workspace_key_prefix: "tfstate-backend" 29 | role_arn: null 30 | 31 | account: 32 | backend: 33 | s3: 34 | workspace_key_prefix: "account" 35 | role_arn: null 36 | 37 | account-map: 38 | backend: 39 | s3: 40 | workspace_key_prefix: "account-map" 41 | role_arn: null 42 | 43 | account-settings: 44 | backend: 45 | s3: 46 | workspace_key_prefix: "account-settings" 47 | role_arn: null 48 | 49 | dns-delegated: 50 | backend: 51 | s3: 52 | workspace_key_prefix: "dns-delegated" 53 | 54 | dns-primary: 55 | backend: 56 | s3: 57 | workspace_key_prefix: "dns-primary" 58 | 59 | eks: 60 | backend: 61 | s3: 62 | workspace_key_prefix: "eks" 63 | 64 | eks-iam: 65 | backend: 66 | s3: 67 | workspace_key_prefix: "eks-iam" 68 | 69 | iam-delegated-roles: 70 | backend: 71 | s3: 72 | workspace_key_prefix: "iam-delegated-roles" 73 | role_arn: null 74 | 75 | iam-primary-roles: 76 | backend: 77 | s3: 78 | workspace_key_prefix: "iam-primary-roles" 79 | role_arn: null 80 | 81 | spotinst-integration: 82 | backend: 83 | s3: 84 | workspace_key_prefix: "spotinst-integration" 85 | 86 | sso: 87 | backend: 88 | s3: 89 | workspace_key_prefix: "sso" 90 | role_arn: null 91 | 92 | config-bucket: 93 | backend: 94 | s3: 95 | workspace_key_prefix: "config-bucket" 96 | 97 | cloudtrail-bucket: 98 | backend: 99 | s3: 100 | workspace_key_prefix: "cloudtrail-bucket" 101 | 102 | cloudtrail: 103 | vars: 104 | cloudtrail_bucket_environment_name: "uw2" 105 | cloudtrail_bucket_stage_name: "audit" 106 | backend: 107 | s3: 108 | workspace_key_prefix: "cloudtrail" 109 | 110 | transit-gateway: 111 | backend: 112 | s3: 113 | workspace_key_prefix: "transit-gateway" 114 | 115 | vpc-flow-logs-bucket: 116 | backend: 117 | s3: 118 | workspace_key_prefix: "vpc-flow-logs-bucket" 119 | 120 | vpc: 121 | vars: 122 | subnet_type_tag_key: "eg.com/subnet/type" 123 | vpc_flow_logs_enabled: true 124 | vpc_flow_logs_bucket_environment_name: "uw2" 125 | vpc_flow_logs_bucket_stage_name: "audit" 126 | vpc_flow_logs_traffic_type: "ALL" 127 | backend: 128 | s3: 129 | workspace_key_prefix: "vpc" 130 | 131 | ecr: 132 | backend: 133 | s3: 134 | workspace_key_prefix: "ecr" 135 | 136 | datadog-integration: 137 | backend: 138 | s3: 139 | workspace_key_prefix: "datadog-integration" 140 | 141 | datadog-monitor: 142 | backend: 143 | s3: 144 | workspace_key_prefix: "datadog-monitor" 145 | 146 | aurora-postgres: 147 | backend: 148 | s3: 149 | workspace_key_prefix: "aurora-postgres" 150 | 151 | efs: 152 | backend: 153 | s3: 154 | workspace_key_prefix: "efs" 155 | 156 | mq-broker: 157 | backend: 158 | s3: 159 | workspace_key_prefix: "mq-broker" 160 | 161 | ses: 162 | backend: 163 | s3: 164 | workspace_key_prefix: "ses" 165 | -------------------------------------------------------------------------------- /examples/stacks/stacks/uw2-dev.yaml: -------------------------------------------------------------------------------- 1 | import: 2 | - uw2-globals 3 | - eks/eks-defaults 4 | 5 | vars: 6 | stage: dev 7 | 8 | terraform: 9 | vars: {} 10 | 11 | helmfile: 12 | vars: 13 | account_number: "1234567890" 14 | 15 | components: 16 | terraform: 17 | 18 | dns-delegated: 19 | vars: 20 | request_acm_certificate: true 21 | zone_config: 22 | - subdomain: dev 23 | zone_name: uw2.example.com 24 | settings: 25 | spacelift: 26 | workspace_enabled: true 27 | autodeploy: false 28 | branch: "" 29 | triggers: [] 30 | 31 | eks: 32 | vars: 33 | spotinst_instance_profile: eg-gbl-dev-spotinst-worker 34 | spotinst_oceans: 35 | main: 36 | desired_group_size: 1 37 | max_group_size: 3 38 | min_group_size: 1 39 | kubernetes_version: null 40 | ami_release_version: null 41 | attributes: null 42 | disk_size: 100 43 | instance_types: null 44 | ami_type: "AL2_x86_64" 45 | tags: null 46 | settings: 47 | spacelift: 48 | workspace_enabled: true 49 | autodeploy: true 50 | branch: "test" 51 | triggers: [] 52 | env: 53 | ENV_TEST_1: test1_override 54 | ENV_TEST_2: test2_override 55 | ENV_TEST_4: test4 56 | 57 | vpc: 58 | vars: 59 | cidr_block: "10.114.0.0/18" 60 | settings: 61 | spacelift: 62 | workspace_enabled: true 63 | autodeploy: true 64 | branch: "" 65 | triggers: [] 66 | 67 | aurora-postgres: 68 | vars: 69 | instance_type: db.r4.large 70 | cluster_size: 1 71 | env: 72 | ENV_TEST_4: test4 73 | ENV_TEST_5: test5 74 | ENV_TEST_6: test6 75 | ENV_TEST_7: test7 76 | 77 | aurora-postgres-2: 78 | component: aurora-postgres 79 | vars: 80 | instance_type: db.r4.xlarge 81 | settings: 82 | spacelift: 83 | workspace_enabled: true 84 | autodeploy: true 85 | branch: "dev" 86 | triggers: [] 87 | env: 88 | ENV_TEST_1: test1_override2 89 | ENV_TEST_2: test2_override2 90 | ENV_TEST_8: test8 91 | 92 | helmfile: 93 | 94 | datadog: 95 | vars: 96 | installed: true 97 | datadogTags: 98 | - "env:uw2-dev" 99 | - "region:us-west-2" 100 | - "stage:dev" 101 | env: 102 | ENV_DD_TEST_1: dd1 103 | ENV_DD_TEST_2: dd2 104 | ENV_DD_TEST_3: dd3 105 | -------------------------------------------------------------------------------- /examples/stacks/stacks/uw2-globals.yaml: -------------------------------------------------------------------------------- 1 | import: 2 | - globals 3 | 4 | vars: 5 | region: us-west-2 6 | environment: uw2 7 | 8 | terraform: 9 | vars: {} 10 | settings: 11 | version: 0 12 | spacelift: 13 | workspace_enabled: false 14 | autodeploy: false 15 | env: 16 | ENV_TEST_1: test1 17 | ENV_TEST_2: test2 18 | ENV_TEST_3: test3 19 | 20 | helmfile: 21 | vars: 22 | ssm_region: us-west-2 23 | 24 | components: 25 | terraform: 26 | vpc: 27 | vars: 28 | availability_zones: ["us-west-2b", "us-west-2c", "us-west-2d"] 29 | 30 | eks: 31 | vars: 32 | region_availability_zones: ["us-west-2b", "us-west-2c", "us-west-2d"] 33 | 34 | helmfile: 35 | datadog: 36 | vars: 37 | apm: 38 | enabled: true 39 | processAgent: 40 | enabled: true 41 | systemProbe: 42 | enabled: true 43 | clusterAgent: 44 | enabled: true 45 | -------------------------------------------------------------------------------- /examples/stacks/stacks/uw2-prod.yaml: -------------------------------------------------------------------------------- 1 | import: 2 | - uw2-globals 3 | - eks/eks-defaults 4 | 5 | vars: 6 | stage: prod 7 | 8 | terraform: 9 | vars: {} 10 | 11 | helmfile: 12 | vars: 13 | account_number: "1234567891" 14 | 15 | components: 16 | terraform: 17 | 18 | dns-delegated: 19 | vars: 20 | request_acm_certificate: true 21 | zone_config: 22 | - subdomain: prod 23 | zone_name: uw2.example.com 24 | settings: 25 | spacelift: 26 | workspace_enabled: true 27 | autodeploy: false 28 | branch: "" 29 | triggers: [] 30 | 31 | eks: 32 | vars: 33 | spotinst_instance_profile: eg-gbl-prod-spotinst-worker 34 | spotinst_oceans: 35 | main: 36 | desired_group_size: 1 37 | max_group_size: 10 38 | min_group_size: 1 39 | kubernetes_version: null 40 | ami_release_version: null 41 | attributes: null 42 | disk_size: 100 43 | instance_types: null 44 | ami_type: "AL2_x86_64" 45 | tags: null 46 | settings: 47 | spacelift: 48 | workspace_enabled: true 49 | autodeploy: true 50 | branch: "" 51 | triggers: [] 52 | env: 53 | ENV_TEST_1: test1_override 54 | ENV_TEST_2: test2_override 55 | ENV_TEST_4: test4 56 | 57 | vpc: 58 | vars: 59 | cidr_block: "10.116.0.0/18" 60 | settings: 61 | spacelift: 62 | workspace_enabled: true 63 | autodeploy: false 64 | branch: "" 65 | triggers: [] 66 | 67 | aurora-postgres: 68 | vars: 69 | instance_type: db.r4.large 70 | cluster_size: 3 71 | env: 72 | ENV_TEST_4: test4 73 | ENV_TEST_5: test5 74 | ENV_TEST_6: test6 75 | ENV_TEST_7: test7 76 | 77 | aurora-postgres-2: 78 | component: aurora-postgres 79 | vars: 80 | instance_type: db.r4.xlarge 81 | settings: 82 | spacelift: 83 | workspace_enabled: true 84 | autodeploy: true 85 | branch: "" 86 | triggers: [] 87 | env: 88 | ENV_TEST_1: test1_override2 89 | ENV_TEST_2: test2_override2 90 | ENV_TEST_8: test8 91 | 92 | helmfile: 93 | 94 | datadog: 95 | vars: 96 | installed: true 97 | datadogTags: 98 | - "env:uw2-prod" 99 | - "region:us-west-2" 100 | - "stage:prod" 101 | env: 102 | ENV_DD_TEST_1: dd1 103 | ENV_DD_TEST_2: dd2 104 | ENV_DD_TEST_3: dd3 105 | -------------------------------------------------------------------------------- /examples/stacks/stacks/uw2-staging.yaml: -------------------------------------------------------------------------------- 1 | import: 2 | - uw2-globals 3 | - eks/eks-defaults 4 | 5 | vars: 6 | stage: staging 7 | 8 | terraform: 9 | vars: {} 10 | 11 | helmfile: 12 | vars: 13 | account_number: "1234567892" 14 | 15 | components: 16 | terraform: 17 | 18 | dns-delegated: 19 | vars: 20 | request_acm_certificate: true 21 | zone_config: 22 | - subdomain: staging 23 | zone_name: uw2.example.com 24 | settings: 25 | spacelift: 26 | workspace_enabled: true 27 | autodeploy: false 28 | branch: "" 29 | triggers: [] 30 | 31 | eks: 32 | vars: 33 | spotinst_instance_profile: eg-gbl-staging-spotinst-worker 34 | spotinst_oceans: 35 | main: 36 | desired_group_size: 1 37 | max_group_size: 5 38 | min_group_size: 1 39 | kubernetes_version: null 40 | ami_release_version: null 41 | attributes: null 42 | disk_size: 100 43 | instance_types: null 44 | ami_type: "AL2_x86_64" 45 | tags: null 46 | settings: 47 | spacelift: 48 | workspace_enabled: true 49 | autodeploy: true 50 | branch: "" 51 | triggers: [] 52 | env: 53 | ENV_TEST_1: test1_override 54 | ENV_TEST_2: test2_override 55 | ENV_TEST_4: test4 56 | 57 | vpc: 58 | vars: 59 | cidr_block: "10.118.0.0/18" 60 | settings: 61 | spacelift: 62 | workspace_enabled: true 63 | autodeploy: false 64 | branch: "" 65 | triggers: [] 66 | 67 | aurora-postgres: 68 | vars: 69 | instance_type: db.r4.large 70 | cluster_size: 2 71 | env: 72 | ENV_TEST_4: test4 73 | ENV_TEST_5: test5 74 | ENV_TEST_6: test6 75 | ENV_TEST_7: test7 76 | 77 | aurora-postgres-2: 78 | component: aurora-postgres 79 | vars: 80 | instance_type: db.r4.xlarge 81 | settings: 82 | spacelift: 83 | workspace_enabled: true 84 | autodeploy: true 85 | branch: "" 86 | triggers: [] 87 | env: 88 | ENV_TEST_1: test1_override2 89 | ENV_TEST_2: test2_override2 90 | ENV_TEST_8: test8 91 | 92 | helmfile: 93 | 94 | datadog: 95 | vars: 96 | installed: true 97 | datadogTags: 98 | - "env:uw2-staging" 99 | - "region:us-west-2" 100 | - "stage:staging" 101 | env: 102 | ENV_DD_TEST_1: dd1 103 | ENV_DD_TEST_2: dd2 104 | ENV_DD_TEST_3: dd3 105 | -------------------------------------------------------------------------------- /examples/stacks/stacks/uw2-uat.yaml: -------------------------------------------------------------------------------- 1 | import: 2 | - uw2-globals 3 | - eks/eks-defaults 4 | 5 | vars: 6 | stage: uat 7 | 8 | terraform: 9 | vars: {} 10 | 11 | helmfile: 12 | vars: 13 | account_number: "1234567893" 14 | 15 | components: 16 | terraform: 17 | 18 | dns-delegated: 19 | vars: 20 | request_acm_certificate: true 21 | zone_config: 22 | - subdomain: uat 23 | zone_name: uw2.example.com 24 | settings: 25 | spacelift: 26 | workspace_enabled: true 27 | autodeploy: false 28 | branch: "" 29 | triggers: [] 30 | 31 | eks: 32 | vars: 33 | spotinst_instance_profile: eg-gbl-uat-spotinst-worker 34 | spotinst_oceans: 35 | main: 36 | desired_group_size: 1 37 | max_group_size: 3 38 | min_group_size: 1 39 | kubernetes_version: null 40 | ami_release_version: null 41 | attributes: null 42 | disk_size: 100 43 | instance_types: null 44 | ami_type: "AL2_x86_64" 45 | tags: null 46 | settings: 47 | spacelift: 48 | workspace_enabled: true 49 | autodeploy: false 50 | branch: "main" 51 | triggers: [] 52 | env: 53 | ENV_TEST_1: test1_override 54 | ENV_TEST_2: test2_override 55 | ENV_TEST_4: test4 56 | 57 | vpc: 58 | vars: 59 | cidr_block: "10.120.0.0/18" 60 | settings: 61 | spacelift: 62 | workspace_enabled: true 63 | autodeploy: false 64 | branch: "main" 65 | triggers: [] 66 | 67 | aurora-postgres: 68 | vars: 69 | instance_type: db.r4.large 70 | cluster_size: 2 71 | settings: 72 | version: 1 73 | spacelift: 74 | workspace_enabled: false 75 | autodeploy: false 76 | branch: "test3" 77 | triggers: ["4", "5", "6"] 78 | env: 79 | ENV_TEST_4: test4 80 | ENV_TEST_5: test5 81 | ENV_TEST_6: test6 82 | ENV_TEST_7: test7 83 | 84 | aurora-postgres-2: 85 | component: aurora-postgres 86 | vars: 87 | cluster_size: 3 88 | instance_type: db.r4.xlarge 89 | settings: 90 | version: 2 91 | spacelift: 92 | workspace_enabled: true 93 | autodeploy: true 94 | branch: "test4" 95 | triggers: ["7", "8", "9"] 96 | env: 97 | ENV_TEST_1: test1_override2 98 | ENV_TEST_2: test2_override2 99 | ENV_TEST_8: test8 100 | 101 | helmfile: 102 | 103 | datadog: 104 | vars: 105 | installed: true 106 | datadogTags: 107 | - "env:uw2-uat" 108 | - "region:us-west-2" 109 | - "stage:uat" 110 | env: 111 | ENV_DD_TEST_1: dd1 112 | ENV_DD_TEST_2: dd2 113 | ENV_DD_TEST_3: dd3 114 | -------------------------------------------------------------------------------- /examples/stacks/variables.tf: -------------------------------------------------------------------------------- 1 | variable "stack_config_local_path" { 2 | type = string 3 | description = "Path to local stack configs" 4 | default = "./stacks" 5 | } 6 | 7 | variable "stacks" { 8 | type = list(string) 9 | description = "A list of stack names" 10 | } 11 | 12 | variable "stack_deps_processing_enabled" { 13 | type = bool 14 | description = "Boolean flag to enable/disable processing all stack dependencies in the provided stack" 15 | default = false 16 | } 17 | 18 | variable "component_deps_processing_enabled" { 19 | type = bool 20 | description = "Boolean flag to enable/disable processing stack config dependencies for the components in the provided stack" 21 | default = false 22 | } 23 | -------------------------------------------------------------------------------- /examples/stacks/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 0.14.0" 3 | 4 | required_providers { 5 | local = { 6 | source = "hashicorp/local" 7 | version = ">= 1.3" 8 | } 9 | external = { 10 | source = "hashicorp/external" 11 | version = ">= 2.0" 12 | } 13 | utils = { 14 | source = "cloudposse/utils" 15 | version = ">= 1.8.0" 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /main.tf: -------------------------------------------------------------------------------- 1 | data "utils_stack_config_yaml" "config" { 2 | input = [for stack in var.stacks : format("%s/%s.yaml", var.stack_config_local_path, stack)] 3 | process_stack_deps = var.stack_deps_processing_enabled 4 | process_component_deps = var.component_deps_processing_enabled 5 | } 6 | 7 | locals { 8 | decoded = [for i in data.utils_stack_config_yaml.config.output : yamldecode(i)] 9 | 10 | config = [ 11 | for stack in local.decoded : { 12 | imports = stack.imports, 13 | components = { 14 | helmfile = stack.components.helmfile, 15 | terraform = stack.components.terraform 16 | } 17 | } 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /modules/backend/README.md: -------------------------------------------------------------------------------- 1 | # backend 2 | 3 | Terraform module that accepts stack configuration and returns backend config for a component. 4 | 5 | ## Usage 6 | 7 | The following example loads the stack config `my-stack` (which in turn imports other YAML config dependencies) 8 | and returns the backend config for the component `my-vpc`. 9 | 10 | ```hcl 11 | module "backend" { 12 | source = "cloudposse/stack-config/yaml//modules/backend" 13 | # version = "x.x.x" 14 | 15 | stack = "my-stack" 16 | component = "my-vpc" 17 | 18 | context = module.this.context 19 | } 20 | ``` 21 | 22 | The example returns the following `backend` configuration: 23 | 24 | ```hcl 25 | backend_type = s3 26 | 27 | backend = { 28 | "acl" = "bucket-owner-full-control" 29 | "bucket" = "eg-ue2-root-tfstate" 30 | "dynamodb_table" = "eg-ue2-root-tfstate-lock" 31 | "encrypt" = true 32 | "key" = "terraform.tfstate" 33 | "region" = "us-east-2" 34 | "role_arn" = "arn:aws:iam::xxxxxxxxxxxx:role/eg-gbl-root-terraform" 35 | "workspace_key_prefix" = "vpc" 36 | } 37 | ``` 38 | 39 | See [examples/complete](../../examples/complete) for more details. 40 | -------------------------------------------------------------------------------- /modules/backend/main.tf: -------------------------------------------------------------------------------- 1 | data "utils_component_config" "config" { 2 | component = var.component 3 | stack = var.stack 4 | namespace = module.always.namespace 5 | tenant = module.always.tenant 6 | environment = module.always.environment 7 | stage = module.always.stage 8 | ignore_errors = var.ignore_errors 9 | env = var.env 10 | atmos_cli_config_path = var.atmos_cli_config_path 11 | atmos_base_path = var.atmos_base_path 12 | } 13 | 14 | locals { 15 | config = yamldecode(data.utils_component_config.config.output) 16 | backend_type = local.config.backend_type 17 | backend = local.config.backend 18 | } 19 | -------------------------------------------------------------------------------- /modules/backend/outputs.tf: -------------------------------------------------------------------------------- 1 | output "backend_type" { 2 | value = local.backend_type 3 | description = "Backend type for the component" 4 | } 5 | 6 | output "backend" { 7 | value = local.backend 8 | description = "Backend configuration for the component" 9 | } 10 | -------------------------------------------------------------------------------- /modules/backend/variables.tf: -------------------------------------------------------------------------------- 1 | variable "stack" { 2 | type = string 3 | description = "Stack name" 4 | default = null 5 | } 6 | 7 | variable "component" { 8 | type = string 9 | description = "Component" 10 | } 11 | 12 | variable "ignore_errors" { 13 | type = bool 14 | description = "Set to true to ignore errors from the 'utils' provider (if the component is not found in the stack)" 15 | default = false 16 | } 17 | 18 | variable "env" { 19 | type = map(string) 20 | description = "Map of ENV vars in the format `key=value`. These ENV vars will be set in the `utils` provider before executing the data source" 21 | default = null 22 | } 23 | 24 | variable "atmos_cli_config_path" { 25 | type = string 26 | description = "atmos CLI config path" 27 | default = null 28 | } 29 | 30 | variable "atmos_base_path" { 31 | type = string 32 | description = "atmos base path to components and stacks" 33 | default = null 34 | } 35 | -------------------------------------------------------------------------------- /modules/backend/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 0.14.0" 3 | 4 | required_providers { 5 | local = { 6 | source = "hashicorp/local" 7 | version = ">= 1.3" 8 | } 9 | external = { 10 | source = "hashicorp/external" 11 | version = ">= 2.0" 12 | } 13 | utils = { 14 | source = "cloudposse/utils" 15 | version = ">= 1.7.1" 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /modules/env/README.md: -------------------------------------------------------------------------------- 1 | # env 2 | 3 | Terraform module that accepts stack configuration and returns deep-merged ENV variables for a Terraform or helmfile component. 4 | 5 | ## Usage 6 | 7 | The following example loads the stack config `my-stack` (which in turn imports other YAML config dependencies) 8 | and returns ENV variables for Terraform component `my-vpc`. 9 | 10 | ```hcl 11 | module "vars" { 12 | source = "cloudposse/stack-config/yaml//modules/env" 13 | # version = "x.x.x" 14 | 15 | stack_config_local_path = "./stacks" 16 | stack = "my-stack" 17 | component_type = "terraform" 18 | component = "my-vpc" 19 | 20 | context = module.this.context 21 | } 22 | ``` 23 | 24 | See [examples/complete](../../examples/complete) for more details. 25 | -------------------------------------------------------------------------------- /modules/env/main.tf: -------------------------------------------------------------------------------- 1 | module "stack" { 2 | source = "../stack" 3 | 4 | stack = var.stack 5 | context = module.always.context 6 | } 7 | 8 | data "utils_stack_config_yaml" "config" { 9 | base_path = var.stack_config_local_path 10 | input = [format("%s/%s.yaml", var.stack_config_local_path, module.stack.stack_name)] 11 | } 12 | 13 | locals { 14 | config = yamldecode(data.utils_stack_config_yaml.config.output[0]) 15 | env = local.config["components"][var.component_type][var.component]["env"] 16 | base_component = try(local.config["components"][var.component_type][var.component]["component"], "") 17 | } 18 | -------------------------------------------------------------------------------- /modules/env/outputs.tf: -------------------------------------------------------------------------------- 1 | output "env" { 2 | value = local.env 3 | description = "ENV variables for the component" 4 | } 5 | 6 | output "base_component" { 7 | value = local.base_component 8 | description = "Base component name" 9 | } 10 | -------------------------------------------------------------------------------- /modules/env/variables.tf: -------------------------------------------------------------------------------- 1 | variable "stack_config_local_path" { 2 | type = string 3 | description = "Path to local stack configs" 4 | } 5 | 6 | variable "stack" { 7 | type = string 8 | description = "Stack name" 9 | default = null 10 | } 11 | 12 | variable "component_type" { 13 | type = string 14 | description = "Component type (terraform or helmfile)" 15 | default = "terraform" 16 | } 17 | 18 | variable "component" { 19 | type = string 20 | description = "Component" 21 | } 22 | -------------------------------------------------------------------------------- /modules/env/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 0.14.0" 3 | 4 | required_providers { 5 | local = { 6 | source = "hashicorp/local" 7 | version = ">= 1.3" 8 | } 9 | external = { 10 | source = "hashicorp/external" 11 | version = ">= 2.0" 12 | } 13 | utils = { 14 | source = "cloudposse/utils" 15 | version = ">= 1.7.1" 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /modules/remote-state/README.md: -------------------------------------------------------------------------------- 1 | # remote-state 2 | 3 | Terraform module that accepts a component and a stack name and returns remote state outputs for the component. 4 | 5 | The module supports all backends supported by Terraform and OpenTofu, plus the Atmos-specific `static` backend. 6 | 7 | 8 | ### Errors 9 | 10 | > [!NOTE] 11 | > 12 | > If you experience an error from the `terraform_remote_state` data source, 13 | > this is most likely not an error in this module, but rather an error in the 14 | > `remote_state` configuration in the referenced stack. This module performs 15 | > no validation on the remote state configuration, and only modifies the configuration 16 | > for the `remote` backend (to set the workspace name) and, 17 | > _only when `var.privileged` is set to `true`_, the `s3` configuration (to remove 18 | > settings for assuming a role). If `var.privileged` is left at the default value of `false` 19 | > and you are not using the `remote` backend, then this module will not modify the backend 20 | > configuration in any way. 21 | 22 | ### "Local" Backend 23 | 24 | > [!IMPORTANT] 25 | > 26 | > If the local backend has a relative path, it will be resolved 27 | > relative to the current working directory, which is usually a root module 28 | > referencing the remote state. However, when the local backend is created, 29 | > the current working directory is the directory where the target root module 30 | > is defined. This can cause the lookup to fail if the source is not reachable 31 | > from the client directory as `../source`. 32 | 33 | For example, if your directory structure looks like this: 34 | 35 | ```text 36 | project 37 | ├── components 38 | │   ├── client 39 | │   │   └── main.tf 40 | │   └── complex 41 | │   └── source 42 | │   └── main.tf 43 | └── local-state 44 | └── complex 45 | └── source 46 | └── terraform.tfstate 47 | ``` 48 | 49 | Terraform code in `project/components/complex/source` can create its local state 50 | file (`terraform.tfstate`) in the `local-state/complex/source` 51 | directory using `path = "../../../local-state/complex/source/terraform.tfstate"`. 52 | However, Terraform code in `project/components/client` that references the same 53 | local state using the same backend configuration will fail because the current 54 | working directory is `project/components/client` and the relative path will not 55 | resolve correctly. 56 | 57 | 58 | ## Usage 59 | 60 | The following example accepts a stack config `my-stack` (which in turn imports other YAML config dependencies) 61 | and returns remote state outputs from the `s3` backend for `my-vpc` and `eks` Terraform components. 62 | 63 | __NOTE:__ The backend type (`s3`) and backend configuration for the components are defined in the stack YAML config files. 64 | 65 | ```hcl 66 | module "remote_state_my_vpc" { 67 | source = "cloudposse/stack-config/yaml//modules/remote-state" 68 | # Cloud Posse recommends pinning every module to a specific version 69 | # version = "x.x.x" 70 | 71 | stack = "my-stack" 72 | component = "my-vpc" 73 | } 74 | 75 | module "remote_state_eks" { 76 | source = "cloudposse/stack-config/yaml//modules/remote-state" 77 | # Cloud Posse recommends pinning every module to a specific version 78 | # version = "x.x.x" 79 | 80 | stack = "my-stack" 81 | component = "eks" 82 | } 83 | ``` 84 | 85 | See [examples/remote-state](../../examples/remote-state) for more details. 86 | -------------------------------------------------------------------------------- /modules/remote-state/data-source.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | custom_backends = ["none", "bypass", "static"] 3 | is_data_source_backend = !contains(local.custom_backends, local.backend_type) 4 | 5 | remote_workspace = var.workspace != null ? var.workspace : local.workspace 6 | ds_backend = local.is_data_source_backend ? local.backend_type : "none" 7 | ds_workspace = local.ds_backend == "none" ? null : local.remote_workspace 8 | 9 | # The `privileged` flag is no longer used in the Cloud Posse reference architecture, but is maintained for compatibility. 10 | # This was and is only supported for the S3 backend. 11 | # 12 | # When the `privileged` flag is set to `true`, the user running Terraform is considered privileged and therefore 13 | # does not need to assume a different role to access the S3 backend. 14 | # 15 | # This is accomplished by removing any profile or role ARN settings from the configuration. 16 | s3_privileged_backend = { for k, v in local.backend : k => v if !contains(["profile", "role_arn", "assume_role", "assume_role_with_web_identity"], k) } 17 | 18 | # Workaround for the fact that the 2 different backends can be different types, 19 | # but both results of a conditional must be the same type. 20 | s3_backend = { 21 | # normal, not privileged 22 | false = local.backend 23 | # privileged 24 | true = local.s3_privileged_backend 25 | } 26 | 27 | # Customize certain configurations. Otherwise we will just use whatever was configured in the stack. 28 | ds_configurations = { 29 | # If no valid configuration is found for the backend datasource, provide a dummy one. 30 | none = { 31 | path = "${path.module}/dummy-remote-state.json" 32 | } 33 | 34 | remote = merge(local.backend, { 35 | workspaces = { 36 | name = local.remote_workspace 37 | } 38 | }) 39 | 40 | s3 = local.s3_backend[var.privileged] 41 | } # ds_configurations 42 | 43 | } 44 | 45 | data "terraform_remote_state" "data_source" { 46 | count = var.bypass ? 0 : 1 47 | 48 | # Use a dummy local backend when the real backend is not supported by the data source 49 | backend = local.ds_backend == "none" ? "local" : local.ds_backend 50 | workspace = local.ds_workspace 51 | # If nothing needs to be customized, just use whatever was configured in the stack 52 | config = lookup(local.ds_configurations, local.ds_backend, local.backend) 53 | defaults = var.defaults 54 | } 55 | -------------------------------------------------------------------------------- /modules/remote-state/dummy-remote-state.json: -------------------------------------------------------------------------------- 1 | {"version": 1} 2 | -------------------------------------------------------------------------------- /modules/remote-state/main.tf: -------------------------------------------------------------------------------- 1 | data "utils_component_config" "config" { 2 | count = var.bypass ? 0 : 1 3 | 4 | component = var.component 5 | stack = var.stack 6 | namespace = module.always.namespace 7 | tenant = module.always.tenant 8 | environment = module.always.environment 9 | stage = module.always.stage 10 | ignore_errors = var.ignore_errors 11 | env = var.env 12 | atmos_cli_config_path = var.atmos_cli_config_path 13 | atmos_base_path = var.atmos_base_path 14 | } 15 | 16 | locals { 17 | config = try(yamldecode(data.utils_component_config.config[0].output), {}) 18 | 19 | remote_state_backend_type = try(local.config.remote_state_backend_type, "") 20 | backend_type = try(coalesce(local.remote_state_backend_type, local.config.backend_type), "none") 21 | 22 | # If `config.remote_state_backend` is not declared in YAML config, the default value will be an empty map `{}` 23 | backend_config_key = try(local.config.remote_state_backend, null) != null && try(length(local.config.remote_state_backend), 0) > 0 ? "remote_state_backend" : "backend" 24 | 25 | # This is used because the `?` operator in some instances (depending on the condition) changes the types of all items of the map to all `strings` 26 | backend_configs = { 27 | backend = lookup(local.config, "backend", {}) 28 | remote_state_backend = lookup(local.config, "remote_state_backend", {}) 29 | } 30 | 31 | backend = local.backend_configs[local.backend_config_key] 32 | 33 | workspace = lookup(local.config, "workspace", "") 34 | # workspace_key_prefix = lookup(local.backend, "workspace_key_prefix", null) 35 | 36 | remote_states = { 37 | data_source = try(data.terraform_remote_state.data_source[0].outputs, var.defaults) 38 | bypass = var.defaults 39 | static = local.backend 40 | } 41 | 42 | remote_state_backend_key = var.bypass ? "bypass" : local.is_data_source_backend ? "data_source" : local.backend_type 43 | computed_remote_state_backend_key = try(length(local.remote_states[local.remote_state_backend_key]), 0) > 0 ? local.remote_state_backend_key : "bypass" 44 | 45 | outputs = local.remote_states[local.computed_remote_state_backend_key] 46 | } 47 | -------------------------------------------------------------------------------- /modules/remote-state/outputs.tf: -------------------------------------------------------------------------------- 1 | output "backend_type" { 2 | value = local.backend_type 3 | description = "Backend type" 4 | } 5 | 6 | output "backend" { 7 | value = local.backend 8 | description = "Backend configuration for the component" 9 | } 10 | 11 | output "s3_workspace_name" { 12 | value = local.ds_backend == "s3" ? local.remote_workspace : null 13 | description = "(DEPRECATED: use `workspace_name` instead): Terraform workspace name for the component s3 backend" 14 | } 15 | 16 | output "remote_workspace_name" { 17 | value = local.ds_backend == "remote" ? local.remote_workspace : null 18 | description = "(DEPRECATED: use `workspace_name` instead): Terraform workspace name for the component remote backend" 19 | } 20 | 21 | output "workspace_name" { 22 | value = local.remote_workspace 23 | description = "Terraform workspace name from which to retrieve the Terraform state" 24 | } 25 | 26 | output "outputs" { 27 | value = local.outputs 28 | description = "Remote state" 29 | } 30 | -------------------------------------------------------------------------------- /modules/remote-state/variables.tf: -------------------------------------------------------------------------------- 1 | variable "stack" { 2 | type = string 3 | description = "Stack name" 4 | default = null 5 | } 6 | 7 | variable "component" { 8 | type = string 9 | description = "Component" 10 | } 11 | 12 | variable "privileged" { 13 | type = bool 14 | description = "True if the caller already has access to the backend without assuming roles" 15 | default = false 16 | } 17 | 18 | variable "defaults" { 19 | type = any 20 | description = "Default values if the data source is empty" 21 | default = null 22 | } 23 | 24 | variable "workspace" { 25 | type = string 26 | description = "Workspace (this overrides the workspace calculated from the context)" 27 | default = null 28 | } 29 | 30 | variable "bypass" { 31 | type = bool 32 | description = "Set to true to skip looking up the remote state and just return the defaults" 33 | default = false 34 | } 35 | 36 | variable "ignore_errors" { 37 | type = bool 38 | description = "Set to true to ignore errors from the 'utils' provider (if the component is not found in the stack)" 39 | default = false 40 | } 41 | 42 | variable "env" { 43 | type = map(string) 44 | description = "Map of ENV vars in the format `key=value`. These ENV vars will be set in the `utils` provider before executing the data source" 45 | default = null 46 | } 47 | 48 | variable "atmos_cli_config_path" { 49 | type = string 50 | description = "atmos CLI config path" 51 | default = null 52 | } 53 | 54 | variable "atmos_base_path" { 55 | type = string 56 | description = "atmos base path to components and stacks" 57 | default = null 58 | } 59 | -------------------------------------------------------------------------------- /modules/remote-state/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 1.1.0" 3 | 4 | required_providers { 5 | local = { 6 | source = "hashicorp/local" 7 | version = ">= 1.3" 8 | } 9 | external = { 10 | source = "hashicorp/external" 11 | version = ">= 2.0" 12 | } 13 | utils = { 14 | source = "cloudposse/utils" 15 | # We were previously pinning this to <=1.8.0, but changing this each time we had a new version was a pain. As 16 | # a compromise, we'll pin to a minimum version, but allow any patch version below 2.0.0 and we will make sure 17 | # that if we make any major/breaking changes in cloudposse/utils, we'll increment to 2.0.0. 18 | version = ">= 1.7.1, < 2.0.0" 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /modules/settings/README.md: -------------------------------------------------------------------------------- 1 | # settings 2 | 3 | Terraform module that accepts stack configuration and returns deep-merged settings for a Terraform or helmfile component. 4 | 5 | ## Usage 6 | 7 | The following example loads the stack config `my-stack` (which in turn imports other YAML config dependencies) 8 | and returns settings for Terraform component `my-vpc`. 9 | 10 | ```hcl 11 | module "vars" { 12 | source = "cloudposse/stack-config/yaml//modules/settings" 13 | # version = "x.x.x" 14 | 15 | stack_config_local_path = "./stacks" 16 | stack = "my-stack" 17 | component_type = "terraform" 18 | component = "my-vpc" 19 | 20 | context = module.this.context 21 | } 22 | ``` 23 | 24 | See [examples/complete](../../examples/complete) for more details. 25 | -------------------------------------------------------------------------------- /modules/settings/main.tf: -------------------------------------------------------------------------------- 1 | module "stack" { 2 | source = "../stack" 3 | 4 | stack = var.stack 5 | context = module.always.context 6 | } 7 | 8 | data "utils_stack_config_yaml" "config" { 9 | base_path = var.stack_config_local_path 10 | input = [format("%s/%s.yaml", var.stack_config_local_path, module.stack.stack_name)] 11 | } 12 | 13 | locals { 14 | config = yamldecode(data.utils_stack_config_yaml.config.output[0]) 15 | settings = local.config["components"][var.component_type][var.component]["settings"] 16 | base_component = try(local.config["components"][var.component_type][var.component]["component"], "") 17 | } 18 | -------------------------------------------------------------------------------- /modules/settings/outputs.tf: -------------------------------------------------------------------------------- 1 | output "settings" { 2 | value = local.settings 3 | description = "settings for the component" 4 | } 5 | 6 | output "base_component" { 7 | value = local.base_component 8 | description = "Base component name" 9 | } 10 | -------------------------------------------------------------------------------- /modules/settings/variables.tf: -------------------------------------------------------------------------------- 1 | variable "stack_config_local_path" { 2 | type = string 3 | description = "Path to local stack configs" 4 | } 5 | 6 | variable "stack" { 7 | type = string 8 | description = "Stack name" 9 | default = null 10 | } 11 | 12 | variable "component_type" { 13 | type = string 14 | description = "Component type (terraform or helmfile)" 15 | default = "terraform" 16 | } 17 | 18 | variable "component" { 19 | type = string 20 | description = "Component" 21 | } 22 | -------------------------------------------------------------------------------- /modules/settings/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 0.14.0" 3 | 4 | required_providers { 5 | local = { 6 | source = "hashicorp/local" 7 | version = ">= 1.3" 8 | } 9 | external = { 10 | source = "hashicorp/external" 11 | version = ">= 2.0" 12 | } 13 | utils = { 14 | source = "cloudposse/utils" 15 | version = ">= 1.7.1" 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /modules/spacelift/README.md: -------------------------------------------------------------------------------- 1 | # spacelift 2 | 3 | Terraform module that accepts infrastructure stack configurations and transforms it into Spacelift stacks. 4 | 5 | ## Usage 6 | 7 | The following example loads the infrastructure YAML stack configs and returns Spacelift stack configurations: 8 | 9 | 10 | ```hcl 11 | module "spacelift" { 12 | source = "../../modules/spacelift" 13 | 14 | stack_config_path_template = "stacks/%s.yaml" 15 | component_deps_processing_enabled = true 16 | 17 | context = module.this.context 18 | } 19 | ``` 20 | 21 | See [examples/spacelift](../../examples/spacelift) for more details. 22 | -------------------------------------------------------------------------------- /modules/spacelift/main.tf: -------------------------------------------------------------------------------- 1 | data "utils_spacelift_stack_config" "spacelift_stacks" { 2 | process_stack_deps = var.stack_deps_processing_enabled 3 | process_component_deps = var.component_deps_processing_enabled 4 | process_imports = var.imports_processing_enabled 5 | stack_config_path_template = var.stack_config_path_template 6 | env = var.env 7 | } 8 | 9 | locals { 10 | spacelift_stacks = yamldecode(data.utils_spacelift_stack_config.spacelift_stacks.output) 11 | } 12 | -------------------------------------------------------------------------------- /modules/spacelift/outputs.tf: -------------------------------------------------------------------------------- 1 | output "spacelift_stacks" { 2 | value = local.spacelift_stacks 3 | description = "Spacelift stacks" 4 | } 5 | -------------------------------------------------------------------------------- /modules/spacelift/variables.tf: -------------------------------------------------------------------------------- 1 | variable "stack_deps_processing_enabled" { 2 | type = bool 3 | description = "Boolean flag to enable/disable processing all stack dependencies in the provided stack" 4 | default = false 5 | } 6 | 7 | variable "component_deps_processing_enabled" { 8 | type = bool 9 | description = "Boolean flag to enable/disable processing stack config dependencies for the components in the provided stack" 10 | default = true 11 | } 12 | 13 | variable "imports_processing_enabled" { 14 | type = bool 15 | description = "Enable/disable processing stack imports" 16 | default = false 17 | } 18 | 19 | variable "stack_config_path_template" { 20 | type = string 21 | description = "Stack config path template" 22 | default = "stacks/%s.yaml" 23 | } 24 | 25 | variable "env" { 26 | type = map(string) 27 | description = "Map of ENV vars in the format `key=value`. These ENV vars will be set in the `utils` provider before executing the data source" 28 | default = null 29 | } 30 | -------------------------------------------------------------------------------- /modules/spacelift/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 0.14.0" 3 | 4 | required_providers { 5 | local = { 6 | source = "hashicorp/local" 7 | version = ">= 1.3" 8 | } 9 | external = { 10 | source = "hashicorp/external" 11 | version = ">= 2.0" 12 | } 13 | utils = { 14 | source = "cloudposse/utils" 15 | version = ">= 1.7.1" 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /modules/stack/README.md: -------------------------------------------------------------------------------- 1 | # stack 2 | 3 | Terraform module that constructs stack names. 4 | 5 | If `var.stack` is specified, will be returned as is. 6 | 7 | If not specified, the output will be calculated using the provided `context`. 8 | -------------------------------------------------------------------------------- /modules/stack/main.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | descriptor_stack = lookup(module.always.descriptors, "stack", null) 3 | 4 | # If `var.stack` is provided, return it. 5 | # Else, if `descriptors["stack"]` is specified, use it. 6 | # Otherwise, construct the stack name from the provided `context`. 7 | stack_name = var.stack != null ? var.stack : ( 8 | local.descriptor_stack != null ? local.descriptor_stack : ( 9 | module.always.tenant != null && module.always.tenant != "" ? format("%s-%s-%s", module.always.tenant, module.always.environment, module.always.stage) : ( 10 | # Default stack name from `environment` and `stage` 11 | format("%s-%s", module.always.environment, module.always.stage) 12 | ) 13 | ) 14 | ) 15 | } 16 | -------------------------------------------------------------------------------- /modules/stack/outputs.tf: -------------------------------------------------------------------------------- 1 | output "stack_name" { 2 | value = local.stack_name 3 | description = "Stack name" 4 | } 5 | -------------------------------------------------------------------------------- /modules/stack/variables.tf: -------------------------------------------------------------------------------- 1 | variable "stack" { 2 | type = string 3 | description = "Stack name. If specified, will be returned as is. If not specified, will be calculated using the provided `context`" 4 | default = null 5 | } 6 | -------------------------------------------------------------------------------- /modules/stack/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 0.14.0" 3 | 4 | required_providers { 5 | local = { 6 | source = "hashicorp/local" 7 | version = ">= 1.3" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /modules/vars/README.md: -------------------------------------------------------------------------------- 1 | # vars 2 | 3 | Terraform module that accepts stack configuration and returns deep-merged variables for a Terraform or helmfile component. 4 | 5 | ## Usage 6 | 7 | The following example loads the stack config `my-stack` (which in turn imports other YAML config dependencies) 8 | and returns variables and backend config for Terraform component `my-vpc`. 9 | 10 | ```hcl 11 | module "vars" { 12 | source = "cloudposse/stack-config/yaml//modules/vars" 13 | # version = "x.x.x" 14 | 15 | stack_config_local_path = "./stacks" 16 | stack = "my-stack" 17 | component_type = "terraform" 18 | component = "my-vpc" 19 | 20 | context = module.this.context 21 | } 22 | 23 | module "backend" { 24 | source = "cloudposse/stack-config/yaml//modules/backend" 25 | # version = "x.x.x" 26 | 27 | stack_config_local_path = "./stacks" 28 | stack = "my-stack" 29 | component_type = "terraform" 30 | component = "my-vpc" 31 | 32 | context = module.this.context 33 | } 34 | ``` 35 | 36 | The example returns the following `vars` and `backend` configurations for `my-stack` stack and `my-vpc` Terraform component: 37 | 38 | ```hcl 39 | vars = { 40 | "availability_zones" = [ 41 | "us-east-2a", 42 | "us-east-2b", 43 | "us-east-2c", 44 | ] 45 | "cidr_block" = "10.132.0.0/18" 46 | "environment" = "ue2" 47 | "level" = 3 48 | "namespace" = "eg" 49 | "param" = "param4" 50 | "region" = "us-east-2" 51 | "stage" = "prod" 52 | "subnet_type_tag_key" = "example/subnet/type" 53 | "test_map" = { 54 | "a" = "a_override_2" 55 | "b" = "b_override" 56 | "c" = [ 57 | 1, 58 | 2, 59 | 3, 60 | ] 61 | "map2" = { 62 | "atr1" = 1 63 | "atr2" = 2 64 | "atr3" = [ 65 | "3a", 66 | "3b", 67 | "3c", 68 | ] 69 | } 70 | } 71 | "var_1" = "1_override" 72 | "var_2" = "2_override" 73 | "var_3" = "3a" 74 | } 75 | 76 | backend_type = s3 77 | 78 | backend = { 79 | "acl" = "bucket-owner-full-control" 80 | "bucket" = "eg-ue2-root-tfstate" 81 | "dynamodb_table" = "eg-ue2-root-tfstate-lock" 82 | "encrypt" = true 83 | "key" = "terraform.tfstate" 84 | "region" = "us-east-2" 85 | "role_arn" = "arn:aws:iam::xxxxxxxxxxxx:role/eg-gbl-root-terraform" 86 | "workspace_key_prefix" = "vpc" 87 | } 88 | ``` 89 | 90 | See [examples/complete](../../examples/complete) for more details. 91 | -------------------------------------------------------------------------------- /modules/vars/main.tf: -------------------------------------------------------------------------------- 1 | module "stack" { 2 | source = "../stack" 3 | 4 | stack = var.stack 5 | context = module.always.context 6 | } 7 | 8 | data "utils_stack_config_yaml" "config" { 9 | base_path = var.stack_config_local_path 10 | input = [format("%s/%s.yaml", var.stack_config_local_path, module.stack.stack_name)] 11 | } 12 | 13 | locals { 14 | config = yamldecode(data.utils_stack_config_yaml.config.output[0]) 15 | vars = local.config["components"][var.component_type][var.component]["vars"] 16 | base_component = try(local.config["components"][var.component_type][var.component]["component"], "") 17 | } 18 | -------------------------------------------------------------------------------- /modules/vars/outputs.tf: -------------------------------------------------------------------------------- 1 | output "vars" { 2 | value = local.vars 3 | description = "Vars configuration for the component" 4 | } 5 | 6 | output "base_component" { 7 | value = local.base_component 8 | description = "Base component name" 9 | } 10 | -------------------------------------------------------------------------------- /modules/vars/variables.tf: -------------------------------------------------------------------------------- 1 | variable "stack_config_local_path" { 2 | type = string 3 | description = "Path to local stack configs" 4 | } 5 | 6 | variable "stack" { 7 | type = string 8 | description = "Stack name" 9 | default = null 10 | } 11 | 12 | variable "component_type" { 13 | type = string 14 | description = "Component type (terraform or helmfile)" 15 | default = "terraform" 16 | } 17 | 18 | variable "component" { 19 | type = string 20 | description = "Component" 21 | } 22 | -------------------------------------------------------------------------------- /modules/vars/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 0.14.0" 3 | 4 | required_providers { 5 | local = { 6 | source = "hashicorp/local" 7 | version = ">= 1.3" 8 | } 9 | external = { 10 | source = "hashicorp/external" 11 | version = ">= 2.0" 12 | } 13 | utils = { 14 | source = "cloudposse/utils" 15 | version = ">= 1.7.1" 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /outputs.tf: -------------------------------------------------------------------------------- 1 | output "config" { 2 | value = local.config 3 | description = "Stack configurations" 4 | } 5 | -------------------------------------------------------------------------------- /test/.gitignore: -------------------------------------------------------------------------------- 1 | .test-harness 2 | .envrc 3 | -------------------------------------------------------------------------------- /test/Makefile: -------------------------------------------------------------------------------- 1 | TEST_HARNESS ?= https://github.com/cloudposse/test-harness.git 2 | TEST_HARNESS_BRANCH ?= master 3 | TEST_HARNESS_PATH = $(realpath .test-harness) 4 | BATS_ARGS ?= --tap 5 | BATS_LOG ?= test.log 6 | 7 | # Define a macro to run the tests 8 | define RUN_TESTS 9 | @echo "Running tests in $(1)" 10 | @cd $(1) && bats $(BATS_ARGS) $(addsuffix .bats,$(addprefix $(TEST_HARNESS_PATH)/test/terraform/,$(TESTS))) 11 | endef 12 | 13 | default: all 14 | 15 | -include Makefile.* 16 | 17 | ## Provision the test-harnesss 18 | .test-harness: 19 | [ -d $@ ] || git clone --depth=1 -b $(TEST_HARNESS_BRANCH) $(TEST_HARNESS) $@ 20 | 21 | ## Initialize the tests 22 | init: .test-harness 23 | 24 | ## Install all dependencies (OS specific) 25 | deps:: 26 | @exit 0 27 | 28 | ## Clean up the test harness 29 | clean: 30 | [ "$(TEST_HARNESS_PATH)" == "/" ] || rm -rf $(TEST_HARNESS_PATH) 31 | 32 | ## Run all tests 33 | all: module examples/complete 34 | 35 | ## Run basic sanity checks against the module itself 36 | module: export TESTS ?= installed lint module-pinning provider-pinning validate terraform-docs input-descriptions output-descriptions 37 | module: deps 38 | $(call RUN_TESTS, ../) 39 | 40 | ## Run tests against example 41 | examples/complete: export TESTS ?= installed lint validate 42 | examples/complete: deps 43 | $(call RUN_TESTS, ../$@) 44 | -------------------------------------------------------------------------------- /test/Makefile.alpine: -------------------------------------------------------------------------------- 1 | ifneq (,$(wildcard /sbin/apk)) 2 | ## Install all dependencies for alpine 3 | deps:: init 4 | @apk add --update terraform-docs@cloudposse json2hcl@cloudposse 5 | endif 6 | -------------------------------------------------------------------------------- /test/src/.gitignore: -------------------------------------------------------------------------------- 1 | .gopath 2 | vendor/ 3 | -------------------------------------------------------------------------------- /test/src/Makefile: -------------------------------------------------------------------------------- 1 | export TERRAFORM_VERSION ?= $(shell curl -s https://checkpoint-api.hashicorp.com/v1/check/terraform | jq -r -M '.current_version' | cut -d. -f1) 2 | 3 | .DEFAULT_GOAL : all 4 | 5 | .PHONY: all 6 | ## Default target 7 | all: test 8 | 9 | .PHONY : init 10 | ## Initialize tests 11 | init: 12 | @exit 0 13 | 14 | .PHONY : test 15 | ## Run tests 16 | test: init 17 | go mod download 18 | go test -v -timeout 3m -run TestExamplesComplete 19 | go test -v -timeout 3m -run TestExamplesStacks 20 | go test -v -timeout 3m -run TestExamplesSpacelift # NOTE: Test is skipped because the test itself is broken 21 | go test -v -timeout 3m -run TestExamplesStack 22 | go test -v -timeout 3m -run TestExamplesRemoteState 23 | go test -v -timeout 3m -run TestExamplesBackend 24 | 25 | ## Run tests in docker container 26 | docker/test: 27 | docker run --name terratest --rm -it -e AWS_ACCESS_KEY_ID -e AWS_SECRET_ACCESS_KEY -e AWS_SESSION_TOKEN -e GITHUB_TOKEN \ 28 | -e PATH="/usr/local/terraform/$(TERRAFORM_VERSION)/bin:/go/bin:/usr/local/go/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" \ 29 | -v $(CURDIR)/../../:/module/ cloudposse/test-harness:latest -C /module/test/src test 30 | 31 | .PHONY : clean 32 | ## Clean up files 33 | clean: 34 | rm -rf ../../examples/complete/*.tfstate* 35 | rm -rf ../../examples/stacks/*.tfstate* 36 | rm -rf ../../examples/spacelift/*.tfstate* 37 | rm -rf ../../examples/stack/*.tfstate* 38 | rm -rf ../../examples/remote-state/*.tfstate* 39 | rm -rf ../../examples/backend/*.tfstate* 40 | -------------------------------------------------------------------------------- /test/src/examples_backend_test.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "github.com/gruntwork-io/terratest/modules/terraform" 5 | "github.com/stretchr/testify/assert" 6 | "testing" 7 | ) 8 | 9 | // Test the Terraform module in examples/backend using Terratest. 10 | func TestExamplesBackend(t *testing.T) { 11 | 12 | terraformOptions := &terraform.Options{ 13 | // The path to where our Terraform code is located 14 | TerraformDir: "../../examples/backend", 15 | Upgrade: true, 16 | // Variables to pass to our Terraform code using -var-file options 17 | VarFiles: []string{"fixtures.tfvars"}, 18 | } 19 | 20 | // At the end of the test, run `terraform destroy` to clean up any resources that were created 21 | defer terraform.Destroy(t, terraformOptions) 22 | 23 | // This will run `terraform init` and `terraform apply` and fail the test if there are any errors 24 | terraform.InitAndApply(t, terraformOptions) 25 | 26 | // Run `terraform output` to get the value of an output variable 27 | backendType := terraform.Output(t, terraformOptions, "backend_type") 28 | // Verify we're getting back the outputs we expect 29 | assert.Equal(t, "s3", backendType) 30 | 31 | // Run `terraform output` to get the value of an output variable 32 | backend := terraform.OutputMap(t, terraformOptions, "backend") 33 | // Verify we're getting back the outputs we expect 34 | assert.Greater(t, len(backend), 0) 35 | } 36 | -------------------------------------------------------------------------------- /test/src/examples_complete_test.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "github.com/gruntwork-io/terratest/modules/terraform" 5 | "github.com/stretchr/testify/assert" 6 | "testing" 7 | ) 8 | 9 | // Test the Terraform module in examples/complete using Terratest. 10 | func TestExamplesComplete(t *testing.T) { 11 | 12 | terraformOptions := &terraform.Options{ 13 | // The path to where our Terraform code is located 14 | TerraformDir: "../../examples/complete", 15 | Upgrade: true, 16 | // Variables to pass to our Terraform code using -var-file options 17 | VarFiles: []string{"fixtures.tfvars"}, 18 | } 19 | 20 | // At the end of the test, run `terraform destroy` to clean up any resources that were created 21 | defer terraform.Destroy(t, terraformOptions) 22 | 23 | // This will run `terraform init` and `terraform apply` and fail the test if there are any errors 24 | terraform.InitAndApply(t, terraformOptions) 25 | 26 | // Run `terraform output` to get the value of an output variable 27 | vars := terraform.OutputMap(t, terraformOptions, "vars") 28 | // Verify we're getting back the outputs we expect 29 | assert.Greater(t, len(vars), 0) 30 | 31 | // Run `terraform output` to get the value of an output variable 32 | settings := terraform.OutputMap(t, terraformOptions, "settings") 33 | // Verify we're getting back the outputs we expect 34 | assert.Greater(t, len(settings), 0) 35 | 36 | // Run `terraform output` to get the value of an output variable 37 | env := terraform.OutputMap(t, terraformOptions, "env") 38 | // Verify we're getting back the outputs we expect 39 | assert.Greater(t, len(env), 0) 40 | 41 | // Run `terraform output` to get the value of an output variable 42 | stackName := terraform.Output(t, terraformOptions, "stack_name") 43 | // Verify we're getting back the outputs we expect 44 | assert.Equal(t, "my-stack", stackName) 45 | } 46 | -------------------------------------------------------------------------------- /test/src/examples_remote_state_test.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "github.com/gruntwork-io/terratest/modules/terraform" 5 | "github.com/stretchr/testify/assert" 6 | "testing" 7 | ) 8 | 9 | // Test the Terraform module in examples/remote-state using Terratest. 10 | func TestExamplesRemoteState(t *testing.T) { 11 | 12 | terraformOptions := &terraform.Options{ 13 | // The path to where our Terraform code is located 14 | TerraformDir: "../../examples/remote-state", 15 | Upgrade: true, 16 | // Variables to pass to our Terraform code using -var-file options 17 | VarFiles: []string{"fixtures.tfvars"}, 18 | } 19 | 20 | // At the end of the test, run `terraform destroy` to clean up any resources that were created 21 | defer terraform.Destroy(t, terraformOptions) 22 | 23 | // This will run `terraform init` and `terraform apply` and fail the test if there are any errors 24 | terraform.InitAndApply(t, terraformOptions) 25 | 26 | // Run `terraform output` to get the value of an output variable 27 | var output any 28 | 29 | terraform.OutputStruct(t, terraformOptions, "remote_state_using_stack", &output) 30 | remoteStateUsingStack := output.(map[string]any) 31 | // Verify we're getting back the outputs we expect 32 | assert.NotNilf(t, remoteStateUsingStack, "remote state is empty") 33 | assert.Equal(t, true, remoteStateUsingStack["val1"]) 34 | assert.Equal(t, "2", remoteStateUsingStack["val2"]) 35 | assert.Equal(t, float64(3), remoteStateUsingStack["val3"]) 36 | assert.Equal(t, nil, remoteStateUsingStack["val4"]) 37 | 38 | terraform.OutputStruct(t, terraformOptions, "remote_state_using_context", &output) 39 | remoteStateUsingContext := output.(map[string]any) 40 | // Verify we're getting back the outputs we expect 41 | assert.NotNilf(t, remoteStateUsingContext, "remote state is empty") 42 | assert.Equal(t, true, remoteStateUsingContext["val1"]) 43 | assert.Equal(t, "2", remoteStateUsingContext["val2"]) 44 | assert.Equal(t, float64(3), remoteStateUsingContext["val3"]) 45 | assert.Equal(t, nil, remoteStateUsingContext["val4"]) 46 | 47 | terraform.OutputStruct(t, terraformOptions, "remote_state_using_context_ignore_errors", &output) 48 | remoteStateUsingContextIgnoreErrors := output.(map[string]any) 49 | // Verify we're getting back the outputs we expect 50 | assert.NotNilf(t, remoteStateUsingContextIgnoreErrors, "remote state is empty") 51 | assert.Equal(t, "default-value", remoteStateUsingContextIgnoreErrors["default_output"]) 52 | 53 | terraform.OutputStruct(t, terraformOptions, "remote_state_with_bypass", &output) 54 | remoteStateWithBypass := output.(map[string]any) 55 | // Verify we're getting back the outputs we expect 56 | assert.NotNilf(t, remoteStateWithBypass, "remote state is empty") 57 | assert.Equal(t, "default-value", remoteStateWithBypass["default_output"]) 58 | } 59 | -------------------------------------------------------------------------------- /test/src/examples_spacelift_test.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "github.com/gruntwork-io/terratest/modules/terraform" 5 | "github.com/stretchr/testify/assert" 6 | "testing" 7 | ) 8 | 9 | // Test the Terraform module in examples/spacelift using Terratest. 10 | func TestExamplesSpacelift(t *testing.T) { 11 | 12 | t.Skip("Skipping test because the test itself is broken with the addition of *-override-2* stacks") 13 | 14 | terraformOptions := &terraform.Options{ 15 | // The path to where our Terraform code is located 16 | TerraformDir: "../../examples/spacelift", 17 | Upgrade: true, 18 | // Variables to pass to our Terraform code using -var-file options 19 | VarFiles: []string{"fixtures.tfvars"}, 20 | } 21 | 22 | // At the end of the test, run `terraform destroy` to clean up any resources that were created 23 | defer terraform.Destroy(t, terraformOptions) 24 | 25 | // This will run `terraform init` and `terraform apply` and fail the test if there are any errors 26 | terraform.InitAndApply(t, terraformOptions) 27 | 28 | // Run `terraform output` to get the value of an output variable 29 | var output any 30 | terraform.OutputStruct(t, terraformOptions, "spacelift_stacks", &output) 31 | spaceliftStacks := output.(map[string]any) 32 | 33 | // Verify we're getting back the outputs we expect 34 | assert.Equal(t, 30, len(spaceliftStacks)) 35 | 36 | tenant1Ue2DevInfraVpcStack := spaceliftStacks["tenant1-ue2-dev-infra-vpc"].(map[string]any) 37 | tenant1Ue2DevInfraVpcStackInfrastructureStackName := tenant1Ue2DevInfraVpcStack["stack"].(string) 38 | tenant1Ue2DevInfraVpcStackBackend := tenant1Ue2DevInfraVpcStack["backend"].(map[string]any) 39 | tenant1Ue2DevInfraVpcStackBackendWorkspaceKeyPrefix := tenant1Ue2DevInfraVpcStackBackend["workspace_key_prefix"].(string) 40 | assert.Equal(t, "tenant1-ue2-dev", tenant1Ue2DevInfraVpcStackInfrastructureStackName) 41 | assert.Equal(t, "infra-vpc", tenant1Ue2DevInfraVpcStackBackendWorkspaceKeyPrefix) 42 | 43 | tenant1Ue2DevTestTestComponentOverrideComponent := spaceliftStacks["tenant1-ue2-dev-test-test-component-override"].(map[string]any) 44 | tenant1Ue2DevTestTestComponentOverrideComponentInfrastructureStackName := tenant1Ue2DevTestTestComponentOverrideComponent["stack"].(string) 45 | tenant1Ue2DevTestTestComponentOverrideComponentBackend := tenant1Ue2DevTestTestComponentOverrideComponent["backend"].(map[string]any) 46 | tenant1Ue2DevTestTestComponentOverrideComponentBaseComponent := tenant1Ue2DevTestTestComponentOverrideComponent["base_component"].(string) 47 | tenant1Ue2DevTestTestComponentOverrideComponentBackendWorkspaceKeyPrefix := tenant1Ue2DevTestTestComponentOverrideComponentBackend["workspace_key_prefix"].(string) 48 | tenant1Ue2DevTestTestComponentOverrideComponentDeps := tenant1Ue2DevTestTestComponentOverrideComponent["deps"].([]any) 49 | tenant1Ue2DevTestTestComponentOverrideComponentLabels := tenant1Ue2DevTestTestComponentOverrideComponent["labels"].([]any) 50 | tenant1Ue2DevTestTestComponentOverrideTerraformWorkspace := tenant1Ue2DevTestTestComponentOverrideComponent["workspace"] 51 | assert.Equal(t, "tenant1-ue2-dev", tenant1Ue2DevTestTestComponentOverrideComponentInfrastructureStackName) 52 | assert.Equal(t, "test-test-component", tenant1Ue2DevTestTestComponentOverrideComponentBackendWorkspaceKeyPrefix) 53 | assert.Equal(t, "test/test-component", tenant1Ue2DevTestTestComponentOverrideComponentBaseComponent) 54 | assert.Equal(t, 10, len(tenant1Ue2DevTestTestComponentOverrideComponentDeps)) 55 | assert.Equal(t, "catalog/terraform/services/service-1", tenant1Ue2DevTestTestComponentOverrideComponentDeps[0]) 56 | assert.Equal(t, "catalog/terraform/services/service-1-override", tenant1Ue2DevTestTestComponentOverrideComponentDeps[1]) 57 | assert.Equal(t, "catalog/terraform/services/service-2", tenant1Ue2DevTestTestComponentOverrideComponentDeps[2]) 58 | assert.Equal(t, "catalog/terraform/services/service-2-override", tenant1Ue2DevTestTestComponentOverrideComponentDeps[3]) 59 | assert.Equal(t, "catalog/terraform/tenant1-ue2-dev", tenant1Ue2DevTestTestComponentOverrideComponentDeps[4]) 60 | assert.Equal(t, "catalog/terraform/test-component-override", tenant1Ue2DevTestTestComponentOverrideComponentDeps[5]) 61 | assert.Equal(t, "globals/globals", tenant1Ue2DevTestTestComponentOverrideComponentDeps[6]) 62 | assert.Equal(t, "globals/tenant1-globals", tenant1Ue2DevTestTestComponentOverrideComponentDeps[7]) 63 | assert.Equal(t, "globals/ue2-globals", tenant1Ue2DevTestTestComponentOverrideComponentDeps[8]) 64 | assert.Equal(t, 35, len(tenant1Ue2DevTestTestComponentOverrideComponentLabels)) 65 | assert.Equal(t, "deps:stacks/catalog/terraform/services/service-2.yaml", tenant1Ue2DevTestTestComponentOverrideComponentLabels[25]) 66 | assert.Equal(t, "deps:stacks/catalog/terraform/services/service-2-override.yaml", tenant1Ue2DevTestTestComponentOverrideComponentLabels[26]) 67 | assert.Equal(t, "deps:stacks/catalog/terraform/tenant1-ue2-dev.yaml", tenant1Ue2DevTestTestComponentOverrideComponentLabels[27]) 68 | assert.Equal(t, "deps:stacks/catalog/terraform/test-component-override.yaml", tenant1Ue2DevTestTestComponentOverrideComponentLabels[28]) 69 | assert.Equal(t, "deps:stacks/globals/globals.yaml", tenant1Ue2DevTestTestComponentOverrideComponentLabels[29]) 70 | assert.Equal(t, "deps:stacks/globals/tenant1-globals.yaml", tenant1Ue2DevTestTestComponentOverrideComponentLabels[30]) 71 | assert.Equal(t, "deps:stacks/globals/ue2-globals.yaml", tenant1Ue2DevTestTestComponentOverrideComponentLabels[31]) 72 | assert.Equal(t, "deps:stacks/tenant1/ue2/dev.yaml", tenant1Ue2DevTestTestComponentOverrideComponentLabels[32]) 73 | assert.Equal(t, "folder:component/test/test-component-override", tenant1Ue2DevTestTestComponentOverrideComponentLabels[33]) 74 | assert.Equal(t, "test-component-override-workspace-override", tenant1Ue2DevTestTestComponentOverrideTerraformWorkspace) 75 | } 76 | -------------------------------------------------------------------------------- /test/src/examples_stack_test.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "github.com/gruntwork-io/terratest/modules/terraform" 5 | "github.com/stretchr/testify/assert" 6 | "testing" 7 | ) 8 | 9 | // Test the Terraform module in examples/stack using Terratest. 10 | func TestExamplesStack(t *testing.T) { 11 | 12 | terraformOptions := &terraform.Options{ 13 | // The path to where our Terraform code is located 14 | TerraformDir: "../../examples/stack", 15 | Upgrade: true, 16 | // Variables to pass to our Terraform code using -var-file options 17 | VarFiles: []string{"fixtures.tfvars"}, 18 | } 19 | 20 | // At the end of the test, run `terraform destroy` to clean up any resources that were created 21 | defer terraform.Destroy(t, terraformOptions) 22 | 23 | // This will run `terraform init` and `terraform apply` and fail the test if there are any errors 24 | terraform.InitAndApply(t, terraformOptions) 25 | 26 | // Run `terraform output` to get the value of an output variable 27 | stack1Name := terraform.Output(t, terraformOptions, "stack_1_name") 28 | // Verify we're getting back the outputs we expect 29 | assert.Equal(t, "my-stack", stack1Name) 30 | 31 | // Run `terraform output` to get the value of an output variable 32 | stack2Name := terraform.Output(t, terraformOptions, "stack_2_name") 33 | // Verify we're getting back the outputs we expect 34 | assert.Equal(t, "my-stack", stack2Name) 35 | 36 | // Run `terraform output` to get the value of an output variable 37 | stack3Name := terraform.Output(t, terraformOptions, "stack_3_name") 38 | // Verify we're getting back the outputs we expect 39 | assert.Equal(t, "uw2-dev", stack3Name) 40 | 41 | // Run `terraform output` to get the value of an output variable 42 | stack4Name := terraform.Output(t, terraformOptions, "stack_4_name") 43 | // Verify we're getting back the outputs we expect 44 | assert.Equal(t, "acme-uw2-dev", stack4Name) 45 | 46 | // Run `terraform output` to get the value of an output variable 47 | stack5Name := terraform.Output(t, terraformOptions, "stack_5_name") 48 | // Verify we're getting back the outputs we expect 49 | assert.Equal(t, "acme-uw2-dev", stack5Name) 50 | 51 | // Run `terraform output` to get the value of an output variable 52 | stack6Name := terraform.Output(t, terraformOptions, "stack_6_name") 53 | // Verify we're getting back the outputs we expect 54 | assert.Equal(t, "dev-uw2-acme", stack6Name) 55 | 56 | // Run `terraform output` to get the value of an output variable 57 | stack7Name := terraform.Output(t, terraformOptions, "stack_7_name") 58 | // Verify we're getting back the outputs we expect 59 | assert.Equal(t, "uw2-acme-dev", stack7Name) 60 | 61 | // Run `terraform output` to get the value of an output variable 62 | stack8Name := terraform.Output(t, terraformOptions, "stack_8_name") 63 | // Verify we're getting back the outputs we expect 64 | assert.Equal(t, "dev-acme-uw2", stack8Name) 65 | 66 | // Run `terraform output` to get the value of an output variable 67 | stack9Name := terraform.Output(t, terraformOptions, "stack_9_name") 68 | // Verify we're getting back the outputs we expect 69 | assert.Equal(t, "my-stack", stack9Name) 70 | } 71 | -------------------------------------------------------------------------------- /test/src/examples_stacks_test.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "github.com/gruntwork-io/terratest/modules/terraform" 5 | "github.com/stretchr/testify/assert" 6 | "testing" 7 | ) 8 | 9 | // Test the Terraform module in examples/stacks using Terratest. 10 | func TestExamplesStacks(t *testing.T) { 11 | 12 | terraformOptions := &terraform.Options{ 13 | // The path to where our Terraform code is located 14 | TerraformDir: "../../examples/stacks", 15 | Upgrade: true, 16 | // Variables to pass to our Terraform code using -var-file options 17 | VarFiles: []string{"fixtures.tfvars"}, 18 | } 19 | 20 | // At the end of the test, run `terraform destroy` to clean up any resources that were created 21 | defer terraform.Destroy(t, terraformOptions) 22 | 23 | // This will run `terraform init` and `terraform apply` and fail the test if there are any errors 24 | terraform.InitAndApply(t, terraformOptions) 25 | 26 | // Run `terraform output` to get the value of an output variable 27 | var output any 28 | terraform.OutputStruct(t, terraformOptions, "config", &output) 29 | config := output.([]any) 30 | 31 | // Verify we're getting back the outputs we expect 32 | assert.Equal(t, 4, len(config)) 33 | } 34 | -------------------------------------------------------------------------------- /test/src/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/cloudposse/terraform-yaml-stack-config 2 | 3 | go 1.24 4 | 5 | toolchain go1.24.0 6 | 7 | require ( 8 | github.com/gruntwork-io/terratest v0.43.0 9 | github.com/stretchr/testify v1.8.4 10 | ) 11 | 12 | require ( 13 | cloud.google.com/go v0.110.0 // indirect 14 | cloud.google.com/go/compute v1.19.1 // indirect 15 | cloud.google.com/go/compute/metadata v0.2.3 // indirect 16 | cloud.google.com/go/iam v0.13.0 // indirect 17 | cloud.google.com/go/storage v1.28.1 // indirect 18 | github.com/agext/levenshtein v1.2.3 // indirect 19 | github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect 20 | github.com/aws/aws-sdk-go v1.44.122 // indirect 21 | github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect 22 | github.com/davecgh/go-spew v1.1.1 // indirect 23 | github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect 24 | github.com/golang/protobuf v1.5.3 // indirect 25 | github.com/google/go-cmp v0.5.9 // indirect 26 | github.com/google/uuid v1.3.0 // indirect 27 | github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect 28 | github.com/googleapis/gax-go/v2 v2.7.1 // indirect 29 | github.com/hashicorp/errwrap v1.0.0 // indirect 30 | github.com/hashicorp/go-cleanhttp v0.5.2 // indirect 31 | github.com/hashicorp/go-getter v1.7.5 // indirect 32 | github.com/hashicorp/go-multierror v1.1.0 // indirect 33 | github.com/hashicorp/go-safetemp v1.0.0 // indirect 34 | github.com/hashicorp/go-version v1.6.0 // indirect 35 | github.com/hashicorp/hcl/v2 v2.9.1 // indirect 36 | github.com/hashicorp/terraform-json v0.13.0 // indirect 37 | github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a // indirect 38 | github.com/jmespath/go-jmespath v0.4.0 // indirect 39 | github.com/klauspost/compress v1.15.11 // indirect 40 | github.com/mattn/go-zglob v0.0.2-0.20190814121620-e3c945676326 // indirect 41 | github.com/mitchellh/go-homedir v1.1.0 // indirect 42 | github.com/mitchellh/go-testing-interface v1.14.1 // indirect 43 | github.com/mitchellh/go-wordwrap v1.0.1 // indirect 44 | github.com/pmezard/go-difflib v1.0.0 // indirect 45 | github.com/tmccombs/hcl2json v0.3.3 // indirect 46 | github.com/ulikunitz/xz v0.5.10 // indirect 47 | github.com/zclconf/go-cty v1.9.1 // indirect 48 | go.opencensus.io v0.24.0 // indirect 49 | golang.org/x/crypto v0.28.0 // indirect 50 | golang.org/x/net v0.30.0 // indirect 51 | golang.org/x/oauth2 v0.7.0 // indirect 52 | golang.org/x/sys v0.26.0 // indirect 53 | golang.org/x/text v0.19.0 // indirect 54 | golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect 55 | google.golang.org/api v0.114.0 // indirect 56 | google.golang.org/appengine v1.6.7 // indirect 57 | google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect 58 | google.golang.org/grpc v1.56.3 // indirect 59 | google.golang.org/protobuf v1.35.1 // indirect 60 | gopkg.in/yaml.v3 v3.0.1 // indirect 61 | ) 62 | -------------------------------------------------------------------------------- /variables.tf: -------------------------------------------------------------------------------- 1 | variable "stack_config_local_path" { 2 | type = string 3 | description = "Path to local stack configs" 4 | } 5 | 6 | variable "stacks" { 7 | type = list(string) 8 | description = "A list of infrastructure stack names" 9 | } 10 | 11 | variable "stack_deps_processing_enabled" { 12 | type = bool 13 | description = "Boolean flag to enable/disable processing all stack dependencies in the provided stack" 14 | default = false 15 | } 16 | 17 | variable "component_deps_processing_enabled" { 18 | type = bool 19 | description = "Boolean flag to enable/disable processing stack config dependencies for the components in the provided stack" 20 | default = false 21 | } 22 | -------------------------------------------------------------------------------- /versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 0.14.0" 3 | 4 | required_providers { 5 | local = { 6 | source = "hashicorp/local" 7 | version = ">= 1.3" 8 | } 9 | external = { 10 | source = "hashicorp/external" 11 | version = ">= 2.0" 12 | } 13 | utils = { 14 | source = "cloudposse/utils" 15 | version = ">= 1.7.1" 16 | } 17 | } 18 | } 19 | --------------------------------------------------------------------------------