diff --git a/examples/quick-start/Dockerfile b/examples/quick-start/Dockerfile index a7971074b..809c89844 100644 --- a/examples/quick-start/Dockerfile +++ b/examples/quick-start/Dockerfile @@ -1,15 +1,15 @@ # Geodesic: https://github.com/cloudposse/geodesic/ -ARG GEODESIC_VERSION=2.9.4 +ARG GEODESIC_VERSION=2.9.5 ARG GEODESIC_OS=debian # Atmos # https://atmos.tools/ # https://github.com/cloudposse/atmos # https://github.com/cloudposse/atmos/releases -ARG ATMOS_VERSION=1.66.0 +ARG ATMOS_VERSION=1.67.0 # Terraform: https://github.com/hashicorp/terraform/releases -ARG TF_VERSION=1.7.3 +ARG TF_VERSION=1.7.5 FROM cloudposse/geodesic:${GEODESIC_VERSION}-${GEODESIC_OS} diff --git a/examples/quick-start/stacks/orgs/acme/_defaults.yaml b/examples/quick-start/stacks/orgs/acme/_defaults.yaml index cc786942e..79a159e60 100644 --- a/examples/quick-start/stacks/orgs/acme/_defaults.yaml +++ b/examples/quick-start/stacks/orgs/acme/_defaults.yaml @@ -1,19 +1,6 @@ vars: namespace: acme -# Terraform S3 backend configuration -#terraform: -# backend_type: s3 -# backend: -# s3: -# acl: "bucket-owner-full-control" -# encrypt: true -# bucket: "your-s3-bucket-name" -# dynamodb_table: "your-dynamodb-table-name" -# key: "terraform.tfstate" -# region: "your-aws-region" -# role_arn: "arn:aws:iam:::role/" - terraform: vars: tags: @@ -25,3 +12,27 @@ terraform: # https://masterminds.github.io/sprig/date.html # https://pkg.go.dev/time#pkg-constants provisioned_at: '{{ dateInZone "2006-01-02T15:04:05Z07:00" (now) "UTC" }}' + + # Terraform backend configuration + # https://atmos.tools/core-concepts/components/terraform-backends + # https://developer.hashicorp.com/terraform/language/settings/backends/configuration + # backend_type: cloud # s3, cloud + # backend: + # # AWS S3 backend + # s3: + # acl: "bucket-owner-full-control" + # encrypt: true + # bucket: "your-s3-bucket-name" + # dynamodb_table: "your-dynamodb-table-name" + # key: "terraform.tfstate" + # region: "us-east-2" + # role_arn: "arn:aws:iam:::role/" + # # Terraform Cloud backend + # # https://developer.hashicorp.com/terraform/cli/cloud/settings + # cloud: + # organization: "your-org" + # hostname: "app.terraform.io" + # workspaces: + # # The token `{terraform_workspace}` will be automatically replaced with the + # # Terraform workspace for each Atmos component + # name: "{terraform_workspace}" diff --git a/examples/quick-start/stacks/schemas/atmos/atmos-manifest/1.0/atmos-manifest.json b/examples/quick-start/stacks/schemas/atmos/atmos-manifest/1.0/atmos-manifest.json index 50617fdb7..d7bd762a8 100644 --- a/examples/quick-start/stacks/schemas/atmos/atmos-manifest/1.0/atmos-manifest.json +++ b/examples/quick-start/stacks/schemas/atmos/atmos-manifest/1.0/atmos-manifest.json @@ -439,7 +439,8 @@ "vault", "static", "azurerm", - "gcs" + "gcs", + "cloud" ], "description": "Backend type", "title": "backend_type" @@ -455,7 +456,9 @@ "remote", "vault", "static", - "azurerm" + "azurerm", + "gcs", + "cloud" ], "description": "Remote state backend type", "title": "remote_state_backend_type" @@ -523,6 +526,14 @@ "azurerm": { "type": "object", "additionalProperties": true + }, + "gcs": { + "type": "object", + "additionalProperties": true + }, + "cloud": { + "type": "object", + "additionalProperties": true } }, "required": [], diff --git a/examples/tests/stacks/catalog/terraform/spacelift-and-backend-override-1.yaml b/examples/tests/stacks/catalog/terraform/spacelift-and-backend-override-1.yaml index d615890aa..f2a9fe15e 100644 --- a/examples/tests/stacks/catalog/terraform/spacelift-and-backend-override-1.yaml +++ b/examples/tests/stacks/catalog/terraform/spacelift-and-backend-override-1.yaml @@ -7,7 +7,7 @@ settings: terraform: vars: {} - backend_type: s3 # s3, remote, vault, etc. + backend_type: s3 # s3, remote, vault, static, azurerm, gcs, cloud backend: s3: encrypt: true diff --git a/examples/tests/stacks/orgs/cp/_defaults.yaml b/examples/tests/stacks/orgs/cp/_defaults.yaml index f3d1a70fa..5985d03a0 100644 --- a/examples/tests/stacks/orgs/cp/_defaults.yaml +++ b/examples/tests/stacks/orgs/cp/_defaults.yaml @@ -12,7 +12,9 @@ terraform: region: "{{ .vars.region }}" terraform_workspace: "{{ .workspace }}" - backend_type: s3 # s3, remote, vault, static, azurerm, etc. + backend_type: s3 # s3, remote, vault, static, azurerm, gcs, cloud + + # https://developer.hashicorp.com/terraform/language/settings/backends/configuration backend: s3: encrypt: true @@ -30,6 +32,12 @@ terraform: key: dev.atmos remote: {} vault: {} + # https://developer.hashicorp.com/terraform/cli/cloud/settings + cloud: + organization: "my-org" + hostname: "app.terraform.io" + workspaces: + name: "{terraform_workspace}" remote_state_backend: s3: diff --git a/go.mod b/go.mod index 2fa8658eb..2e3bc48fb 100644 --- a/go.mod +++ b/go.mod @@ -12,13 +12,13 @@ require ( github.com/charmbracelet/lipgloss v0.10.0 github.com/elewis787/boa v0.1.2 github.com/fatih/color v1.16.0 - github.com/go-git/go-git/v5 v5.11.0 - github.com/google/go-containerregistry v0.19.0 + github.com/go-git/go-git/v5 v5.12.0 + github.com/google/go-containerregistry v0.19.1 github.com/google/go-github/v59 v59.0.0 github.com/google/uuid v1.6.0 github.com/hashicorp/go-getter v1.7.3 github.com/hashicorp/hcl v1.0.0 - github.com/hashicorp/hcl/v2 v2.20.0 + github.com/hashicorp/hcl/v2 v2.20.1 github.com/hashicorp/terraform-config-inspect v0.0.0-20231204233900-a34142ec2a72 github.com/imdario/mergo v0.3.13 github.com/ivanpirog/coloredcobra v1.0.1 @@ -27,7 +27,7 @@ require ( github.com/lrstanley/bubblezone v0.0.0-20240125042004-b7bafc493195 github.com/mitchellh/go-homedir v1.1.0 github.com/mitchellh/mapstructure v1.5.0 - github.com/open-policy-agent/opa v0.62.1 + github.com/open-policy-agent/opa v0.63.0 github.com/otiai10/copy v1.14.0 github.com/pkg/errors v0.9.1 github.com/samber/lo v1.39.0 @@ -36,7 +36,7 @@ require ( github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.18.2 github.com/stretchr/testify v1.9.0 - github.com/zclconf/go-cty v1.14.3 + github.com/zclconf/go-cty v1.14.4 gopkg.in/yaml.v2 v2.4.0 mvdan.cc/sh/v3 v3.8.0 ) @@ -54,7 +54,7 @@ require ( github.com/Microsoft/go-winio v0.6.1 // indirect github.com/Microsoft/hcsshim v0.11.4 // indirect github.com/OneOfOne/xxhash v1.2.8 // indirect - github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 // indirect + github.com/ProtonMail/go-crypto v1.0.0 // indirect github.com/agext/levenshtein v1.2.2 // indirect github.com/agnivade/levenshtein v1.1.1 // indirect github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect @@ -69,15 +69,15 @@ require ( github.com/cloudflare/circl v1.3.7 // indirect github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be // indirect github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 // indirect - github.com/containerd/containerd v1.7.13 // indirect + github.com/containerd/containerd v1.7.14 // indirect github.com/containerd/log v0.1.0 // indirect github.com/containerd/stargz-snapshotter/estargz v0.14.3 // indirect github.com/cyphar/filepath-securejoin v0.2.4 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/dlclark/regexp2 v1.4.0 // indirect - github.com/docker/cli v24.0.0+incompatible // indirect - github.com/docker/distribution v2.8.2+incompatible // indirect - github.com/docker/docker v25.0.3+incompatible // indirect + github.com/docker/cli v26.0.0+incompatible // indirect + github.com/docker/distribution v2.8.3+incompatible // indirect + github.com/docker/docker v26.0.0+incompatible // indirect github.com/docker/docker-credential-helpers v0.7.0 // indirect github.com/emirpasic/gods v1.18.1 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect @@ -89,7 +89,7 @@ require ( github.com/go-logr/stdr v1.2.2 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/golang/protobuf v1.5.3 // indirect + github.com/golang/protobuf v1.5.4 // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/google/s2a-go v0.1.7 // indirect @@ -136,10 +136,10 @@ require ( github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/sahilm/fuzzy v0.1.1-0.20230530133925-c48e322e2a8f // indirect - github.com/sergi/go-diff v1.3.1 // indirect + github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect github.com/shopspring/decimal v1.2.0 // indirect github.com/sirupsen/logrus v1.9.3 // indirect - github.com/skeema/knownhosts v1.2.1 // indirect + github.com/skeema/knownhosts v1.2.2 // indirect github.com/sourcegraph/conc v0.3.0 // indirect github.com/spf13/afero v1.11.0 // indirect github.com/spf13/cast v1.6.0 // indirect @@ -176,8 +176,8 @@ require ( google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240123012728-ef4313101c80 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80 // indirect - google.golang.org/grpc v1.62.0 // indirect - google.golang.org/protobuf v1.32.0 // indirect + google.golang.org/grpc v1.62.1 // indirect + google.golang.org/protobuf v1.33.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index 1cdad2cc9..07a20d990 100644 --- a/go.sum +++ b/go.sum @@ -206,8 +206,8 @@ github.com/Microsoft/hcsshim v0.11.4/go.mod h1:smjE4dvqPX9Zldna+t5FG3rnoHhaB7QYx github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/OneOfOne/xxhash v1.2.8 h1:31czK/TI9sNkxIKfaUfGlU47BAxQ0ztGgd9vPyqimf8= github.com/OneOfOne/xxhash v1.2.8/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= -github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 h1:kkhsdkhsCvIsutKu5zLMgWtgh9YxGCNAw8Ad8hjwfYg= -github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= +github.com/ProtonMail/go-crypto v1.0.0 h1:LRuvITjQWX+WIfr930YHG2HNfjR1uOfyf5vE0kC2U78= +github.com/ProtonMail/go-crypto v1.0.0/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= github.com/agext/levenshtein v1.2.2 h1:0S/Yg6LYmFJ5stwQeRp6EeOcCbj7xiqQSdNelsXvaqE= github.com/agext/levenshtein v1.2.2/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= github.com/agnivade/levenshtein v1.1.1 h1:QY8M92nrzkmr798gCo3kmMyqXFzdQVpxLlGPRBij0P8= @@ -281,8 +281,8 @@ github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaD github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw= github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 h1:q2hJAaP1k2wIvVRd/hEHD7lacgqrCPS+k8g1MndzfWY= github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk= -github.com/containerd/containerd v1.7.13 h1:wPYKIeGMN8vaggSKuV1X0wZulpMz4CrgEsZdaCyB6Is= -github.com/containerd/containerd v1.7.13/go.mod h1:zT3up6yTRfEUa6+GsITYIJNgSVL9NQ4x4h1RPzk0Wu4= +github.com/containerd/containerd v1.7.14 h1:H/XLzbnGuenZEGK+v0RkwTdv2u1QFAruMe5N0GNPJwA= +github.com/containerd/containerd v1.7.14/go.mod h1:YMC9Qt5yzNqXx/fO4j/5yYVIHXSRrlB3H7sxkUTvspg= github.com/containerd/continuity v0.4.2 h1:v3y/4Yz5jwnvqPKJJ+7Wf93fyWoCB3F5EclWG023MDM= github.com/containerd/continuity v0.4.2/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ= github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= @@ -308,12 +308,12 @@ github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48 h1:fRzb/w+pyskVMQ+ github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA= github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E= github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= -github.com/docker/cli v24.0.0+incompatible h1:0+1VshNwBQzQAx9lOl+OYCTCEAD8fKs/qeXMx3O0wqM= -github.com/docker/cli v24.0.0+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= -github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= -github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v25.0.3+incompatible h1:D5fy/lYmY7bvZa0XTZ5/UJPljor41F+vdyJG5luQLfQ= -github.com/docker/docker v25.0.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/cli v26.0.0+incompatible h1:90BKrx1a1HKYpSnnBFR6AgDq/FqkHxwlUyzJVPxD30I= +github.com/docker/cli v26.0.0+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk= +github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v26.0.0+incompatible h1:Ng2qi+gdKADUa/VM+6b6YaY2nlZhk/lVJiKR/2bMudU= +github.com/docker/docker v26.0.0+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker-credential-helpers v0.7.0 h1:xtCHsjxogADNZcdv1pKUHXryefjlVRqWqIhk/uXJp0A= github.com/docker/docker-credential-helpers v0.7.0/go.mod h1:rETQfLdHNT3foU5kuNkFR1R1V12OJRRO5lzt2D1b5X0= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= @@ -351,16 +351,16 @@ github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7z github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY= -github.com/gliderlabs/ssh v0.3.5/go.mod h1:8XB4KraRrX39qHhT6yxPsHedjA08I/uBVwj4xC+/+z4= +github.com/gliderlabs/ssh v0.3.7 h1:iV3Bqi942d9huXnzEF2Mt+CY9gLu8DNM4Obd+8bODRE= +github.com/gliderlabs/ssh v0.3.7/go.mod h1:zpHEXBstFnQYtGnB8k8kQLol82umzn/2/snG7alWVD8= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU= github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII= -github.com/go-git/go-git/v5 v5.11.0 h1:XIZc1p+8YzypNr34itUfSvYJcv+eYdTnTvOZ2vD3cA4= -github.com/go-git/go-git/v5 v5.11.0/go.mod h1:6GFcX2P3NM7FPBfpePbpLd21XxsgdAt+lKqXmCUiUCY= +github.com/go-git/go-git/v5 v5.12.0 h1:7Md+ndsjrzZxbddRDZjF14qK+NN56sy6wkqaVrjZtys= +github.com/go-git/go-git/v5 v5.12.0/go.mod h1:FTM9VKtnI2m65hNI/TenDDDnUf2Q9FHnXYjuz9i5OEY= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -411,8 +411,8 @@ github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= @@ -437,8 +437,8 @@ github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-containerregistry v0.19.0 h1:uIsMRBV7m/HDkDxE/nXMnv1q+lOOSPlQ/ywc5JbB8Ic= -github.com/google/go-containerregistry v0.19.0/go.mod h1:u0qB2l7mvtWVR5kNcbFIhFY1hLbf8eeGapA+vbFDCtQ= +github.com/google/go-containerregistry v0.19.1 h1:yMQ62Al6/V0Z7CqIrrS1iYoA5/oQCm88DeNujc7C1KY= +github.com/google/go-containerregistry v0.19.1/go.mod h1:YCMFNQeeXeLF+dnhhWkqDItx/JSkH01j1Kis4PsjzFI= github.com/google/go-github/v59 v59.0.0 h1:7h6bgpF5as0YQLLkEiVqpgtJqjimMYhBkD4jT5aN3VA= github.com/google/go-github/v59 v59.0.0/go.mod h1:rJU4R0rQHFVFDOkqGWxfLNo6vEk4dv40oDjhV/gH6wM= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= @@ -508,8 +508,8 @@ github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/hcl/v2 v2.20.0 h1:l++cRs/5jQOiKVvqXZm/P1ZEfVXJmvLS9WSVxkaeTb4= -github.com/hashicorp/hcl/v2 v2.20.0/go.mod h1:WmcD/Ym72MDOOx5F62Ly+leloeu6H7m0pG7VBiU6pQk= +github.com/hashicorp/hcl/v2 v2.20.1 h1:M6hgdyz7HYt1UN9e61j+qKJBqR3orTWbI1HKBJEdxtc= +github.com/hashicorp/hcl/v2 v2.20.1/go.mod h1:TZDqQ4kNKCbh1iJp99FdPiUaVDDUPivbqxZulxDYqL4= github.com/hashicorp/terraform-config-inspect v0.0.0-20231204233900-a34142ec2a72 h1:nZ5gGjbe5o7XUu1d7j+Y5Ztcxlp+yaumTKH9i0D3wlg= github.com/hashicorp/terraform-config-inspect v0.0.0-20231204233900-a34142ec2a72/go.mod h1:l8HcFPm9cQh6Q0KSWoYPiePqMvRFenybP1CH2MjKdlg= github.com/huandu/xstrings v1.3.3 h1:/Gcsuc1x8JVbJ9/rlye4xZnVAbEkGauT8lbebqcQws4= @@ -606,8 +606,8 @@ github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8= github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= -github.com/open-policy-agent/opa v0.62.1 h1:UcxBQ0fe6NEjkYc775j4PWoUFFhx4f6yXKIKSTAuTVk= -github.com/open-policy-agent/opa v0.62.1/go.mod h1:YqiSIIuvKwyomtnnXkJvy0E3KtVKbavjPJ/hNMuOmeM= +github.com/open-policy-agent/opa v0.63.0 h1:ztNNste1v8kH0/vJMJNquE45lRvqwrM5mY9Ctr9xIXw= +github.com/open-policy-agent/opa v0.63.0/go.mod h1:9VQPqEfoB2N//AToTxzZ1pVTVPUoF2Mhd64szzjWPpU= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0-rc6 h1:XDqvyKsJEbRtATzkgItUqBA7QHk58yxX1Ov9HERHNqU= @@ -655,16 +655,16 @@ github.com/samber/lo v1.39.0 h1:4gTz1wUhNYLhFSKl6O+8peW0v2F4BCY034GRpU9WnuA= github.com/samber/lo v1.39.0/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA= github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 h1:lZUw3E0/J3roVtGQ+SCrUrg3ON6NgVqpn3+iol9aGu4= github.com/santhosh-tekuri/jsonschema/v5 v5.3.1/go.mod h1:uToXkOrWAZ6/Oc07xWQrPOhJotwFIyu2bBVN41fcDUY= -github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= -github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= +github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= +github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/skeema/knownhosts v1.2.1 h1:SHWdIUa82uGZz+F+47k8SY4QhhI291cXCpopT1lK2AQ= -github.com/skeema/knownhosts v1.2.1/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo= +github.com/skeema/knownhosts v1.2.2 h1:Iug2P4fLmDw9f41PB6thxUkNUkJzB5i+1/exaj40L3A= +github.com/skeema/knownhosts v1.2.2/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo= github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= @@ -719,8 +719,10 @@ github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -github.com/zclconf/go-cty v1.14.3 h1:1JXy1XroaGrzZuG6X9dt7HL6s9AwbY+l4UNL8o5B6ho= -github.com/zclconf/go-cty v1.14.3/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE= +github.com/zclconf/go-cty v1.14.4 h1:uXXczd9QDGsgu0i/QFR/hzI5NYCHLf6NQw/atrbnhq8= +github.com/zclconf/go-cty v1.14.4/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE= +github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b h1:FosyBZYxY34Wul7O/MSKey3txpPYyCqVO5ZyceuQJEI= +github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b/go.mod h1:ZRKQfBXbGkpdV6QMzT3rU1kSTAnfu1dO8dPKjYprgj8= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -1272,8 +1274,8 @@ google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACu google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.62.0 h1:HQKZ/fa1bXkX1oFOvSjmZEUL8wLSaZTjCcLAlmZRtdk= -google.golang.org/grpc v1.62.0/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= +google.golang.org/grpc v1.62.1 h1:B4n+nfKzOICUXMgyrNd19h/I9oH0L1pizfk1d4zSgTk= +google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= @@ -1290,8 +1292,8 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= -google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/internal/exec/terraform.go b/internal/exec/terraform.go index 829c0556a..255a99934 100644 --- a/internal/exec/terraform.go +++ b/internal/exec/terraform.go @@ -205,11 +205,15 @@ func ExecuteTerraform(info schema.ConfigAndStacksInfo) error { if cliConfig.Components.Terraform.AutoGenerateBackendFile { backendFileName := path.Join(workingDir, "backend.tf.json") - u.LogDebug(cliConfig, "Writing the backend config to file:") + u.LogDebug(cliConfig, "\nWriting the backend config to file:") u.LogDebug(cliConfig, backendFileName) if !info.DryRun { - var componentBackendConfig = generateComponentBackendConfig(info.ComponentBackendType, info.ComponentBackendSection) + componentBackendConfig, err := generateComponentBackendConfig(info.ComponentBackendType, info.ComponentBackendSection, info.TerraformWorkspace) + if err != nil { + return err + } + err = u.WriteToFileAsJSON(backendFileName, componentBackendConfig, 0644) if err != nil { return err diff --git a/internal/exec/terraform_generate_backend.go b/internal/exec/terraform_generate_backend.go index f4fc73d79..251f7ec38 100644 --- a/internal/exec/terraform_generate_backend.go +++ b/internal/exec/terraform_generate_backend.go @@ -52,7 +52,10 @@ func ExecuteTerraformGenerateBackendCmd(cmd *cobra.Command, args []string) error return fmt.Errorf("\nCould not find 'backend' config for the '%s' component.\n", component) } - componentBackendConfig := generateComponentBackendConfig(info.ComponentBackendType, info.ComponentBackendSection) + componentBackendConfig, err := generateComponentBackendConfig(info.ComponentBackendType, info.ComponentBackendSection, info.TerraformWorkspace) + if err != nil { + return err + } u.LogDebug(cliConfig, "Component backend config:\n\n") diff --git a/internal/exec/terraform_generate_backends.go b/internal/exec/terraform_generate_backends.go index 6844d7eda..464ae1c0b 100644 --- a/internal/exec/terraform_generate_backends.go +++ b/internal/exec/terraform_generate_backends.go @@ -201,7 +201,11 @@ func ExecuteTerraformGenerateBackends(cliConfig schema.CliConfiguration, fileTem u.LogDebug(cliConfig, fmt.Sprintf("Writing backend config for the component '%s' to file '%s'", terraformComponent, backendFilePath)) if format == "json" { - componentBackendConfig := generateComponentBackendConfig(backendType, backendSection) + componentBackendConfig, err := generateComponentBackendConfig(backendType, backendSection, "") + if err != nil { + return err + } + err = u.WriteToFileAsJSON(backendFileAbsolutePath, componentBackendConfig, 0644) if err != nil { return err diff --git a/internal/exec/utils.go b/internal/exec/utils.go index 2532abc98..6a9f917d8 100644 --- a/internal/exec/utils.go +++ b/internal/exec/utils.go @@ -935,14 +935,47 @@ func processArgsAndFlags(componentType string, inputArgsAndFlags []string) (sche } // generateComponentBackendConfig generates backend config for components -func generateComponentBackendConfig(backendType string, backendConfig map[any]any) map[string]any { +func generateComponentBackendConfig(backendType string, backendConfig map[any]any, terraformWorkspace string) (map[string]any, error) { + + // Generate backend config file for Terraform Cloud + // https://developer.hashicorp.com/terraform/cli/cloud/settings + if backendType == "cloud" { + var backendConfigFinal = backendConfig + + if terraformWorkspace != "" { + // Process template tokens in the backend config + backendConfigStr, err := u.ConvertToYAML(backendConfig) + if err != nil { + return nil, err + } + + ctx := schema.Context{ + TerraformWorkspace: terraformWorkspace, + } + + backendConfigStrReplaced := cfg.ReplaceContextTokens(ctx, backendConfigStr) + + backendConfigFinal, err = c.YAMLToMapOfInterfaces(backendConfigStrReplaced) + if err != nil { + return nil, err + } + } + + return map[string]any{ + "terraform": map[string]any{ + "cloud": backendConfigFinal, + }, + }, nil + } + + // Generate backend config file for all other Terraform backends return map[string]any{ "terraform": map[string]any{ "backend": map[string]any{ backendType: backendConfig, }, }, - } + }, nil } // generateComponentProviderOverrides generates provider overrides for components diff --git a/pkg/config/utils.go b/pkg/config/utils.go index 404ad4075..db9daa142 100644 --- a/pkg/config/utils.go +++ b/pkg/config/utils.go @@ -516,6 +516,7 @@ func ReplaceContextTokens(context schema.Context, pattern string) string { "{tenant}", context.Tenant, "{stage}", context.Stage, "{workspace}", context.Workspace, + "{terraform_workspace}", context.TerraformWorkspace, "{attributes}", strings.Join(u.SliceOfInterfacesToSliceOdStrings(context.Attributes), "-"), ) return r.Replace(pattern) diff --git a/pkg/schema/schema.go b/pkg/schema/schema.go index 9648b99af..7d914f430 100644 --- a/pkg/schema/schema.go +++ b/pkg/schema/schema.go @@ -61,18 +61,19 @@ type Logs struct { } type Context struct { - Namespace string `yaml:"namespace" json:"namespace" mapstructure:"namespace"` - Tenant string `yaml:"tenant" json:"tenant" mapstructure:"tenant"` - Environment string `yaml:"environment" json:"environment" mapstructure:"environment"` - Stage string `yaml:"stage" json:"stage" mapstructure:"stage"` - Region string `yaml:"region" json:"region" mapstructure:"region"` - Component string `yaml:"component" json:"component" mapstructure:"component"` - BaseComponent string `yaml:"base_component" json:"base_component" mapstructure:"base_component"` - ComponentPath string `yaml:"component_path" json:"component_path" mapstructure:"component_path"` - Workspace string `yaml:"workspace" json:"workspace" mapstructure:"workspace"` - Attributes []any `yaml:"attributes" json:"attributes" mapstructure:"attributes"` - File string `yaml:"file" json:"file" mapstructure:"file"` - Folder string `yaml:"folder" json:"folder" mapstructure:"folder"` + Namespace string `yaml:"namespace" json:"namespace" mapstructure:"namespace"` + Tenant string `yaml:"tenant" json:"tenant" mapstructure:"tenant"` + Environment string `yaml:"environment" json:"environment" mapstructure:"environment"` + Stage string `yaml:"stage" json:"stage" mapstructure:"stage"` + Region string `yaml:"region" json:"region" mapstructure:"region"` + Component string `yaml:"component" json:"component" mapstructure:"component"` + BaseComponent string `yaml:"base_component" json:"base_component" mapstructure:"base_component"` + ComponentPath string `yaml:"component_path" json:"component_path" mapstructure:"component_path"` + Workspace string `yaml:"workspace" json:"workspace" mapstructure:"workspace"` + Attributes []any `yaml:"attributes" json:"attributes" mapstructure:"attributes"` + File string `yaml:"file" json:"file" mapstructure:"file"` + Folder string `yaml:"folder" json:"folder" mapstructure:"folder"` + TerraformWorkspace string `yaml:"terraform_workspace" json:"terraform_workspace" mapstructure:"terraform_workspace"` } type ArgsAndFlagsInfo struct { diff --git a/website/docs/core-concepts/components/terraform-backends.mdx b/website/docs/core-concepts/components/terraform-backends.mdx new file mode 100644 index 000000000..bf6e09d57 --- /dev/null +++ b/website/docs/core-concepts/components/terraform-backends.mdx @@ -0,0 +1,689 @@ +--- +title: Terraform Backends +sidebar_position: 11 +sidebar_label: Terraform Backends +description: Configure Terraform Backends. +id: terraform-backends +--- + +import Terminal from '@site/src/components/Terminal' + +Backends define where Terraform stores its [state](https://developer.hashicorp.com/terraform/language/state) data files. + +Atmos supports all the backends supported by Terraform: + +- [local](https://developer.hashicorp.com/terraform/language/settings/backends/local) +- [s3](https://developer.hashicorp.com/terraform/language/settings/backends/s3) +- [azurerm](https://developer.hashicorp.com/terraform/language/settings/backends/azurerm) +- [gcs](https://developer.hashicorp.com/terraform/language/settings/backends/gcs) +- [remote](https://developer.hashicorp.com/terraform/language/settings/backends/remote) +- [consul](https://developer.hashicorp.com/terraform/language/settings/backends/consul) +- [cos](https://developer.hashicorp.com/terraform/language/settings/backends/cos) +- [http](https://developer.hashicorp.com/terraform/language/settings/backends/http) +- [kubernetes](https://developer.hashicorp.com/terraform/language/settings/backends/kubernetes) +- [oss](https://developer.hashicorp.com/terraform/language/settings/backends/oss) +- [pg](https://developer.hashicorp.com/terraform/language/settings/backends/pg) +- [cloud](https://developer.hashicorp.com/terraform/cli/cloud/settings) + +## Local Backend + +By default, Terraform will use a backend called [local](https://developer.hashicorp.com/terraform/language/settings/backends/local), which stores +Terraform state on the local filesystem, locks that state using system APIs, and performs operations locally. + +Terraform's local backend is designed for development and testing purposes and is generally not recommended for production use. There are several +reasons why using the local backend in a production environment may not be suitable: + +- **State Management**: The local backend stores the Terraform state file on the local file system. In a production environment, it's crucial to have +a robust and scalable solution for managing the Terraform state. Storing state locally can lead to issues with collaboration, concurrency, and +consistency. + +- **Concurrency and Locking**: When multiple users or automation processes are working with Terraform concurrently, it's essential to ensure that only +one process can modify the infrastructure at a time. The local backend lacks built-in support for locking mechanisms that prevent multiple Terraform +instances from modifying the state simultaneously. This can lead to race conditions and conflicting changes. + +- **Collaboration**: In a production environment with multiple team members, it's important to have a centralized and shared state. The local backend +does not provide a way to easily share the state across different team members or systems. A remote backend, such as Amazon S3, Azure Storage, or +HashiCorp Consul, is more suitable for collaboration. + +- **Durability and Backup**: The local backend does not provide durability or backup features. If the machine where Terraform is run experiences +issues, there's a risk of losing the state file, leading to potential data loss. Remote backends offer better durability and often provide features +for versioning and backup. + +- **Remote Execution and Automation**: In production, it's common to use Terraform in automated workflows, such as continuous integration/continuous +deployment (CI/CD) pipelines. Remote backends are better suited for these scenarios, allowing for seamless integration with automation tools and +supporting the deployment of infrastructure as code in a reliable and controlled manner. + +To address these concerns, it's recommended to use one of the supported remote backends, such as Amazon S3, Azure Storage, Google Cloud Storage, +HashiCorp Consul, or Terraform Cloud, for production environments. Remote backends provide better scalability, collaboration support, and durability, +making them more suitable for managing infrastructure at scale in production environments. + +## AWS S3 Backend + +Terraform's [S3](https://developer.hashicorp.com/terraform/language/settings/backends/s3) backend is a popular remote +backend for storing Terraform state files in an Amazon Simple Storage Service (S3) bucket. Using S3 as a backend offers +many advantages, particularly in production environments. + +To configure Terraform to use an S3 backend, you typically provide the S3 bucket name and an optional key prefix in your Terraform configuration. +Here's a simplified example: + + +```hcl +terraform { + backend "s3" { + acl = "bucket-owner-full-control" + bucket = "your-s3-bucket-name" + key = "path/to/terraform.tfstate" + region = "your-aws-region" + encrypt = true + dynamodb_table = "terraform_locks" + } +} +``` + + +
+ +In the example, `terraform_locks` is a DynamoDB table used for state locking. DynamoDB is recommended for locking when using the S3 backend to ensure +safe concurrent access. + +Once the S3 bucket and DynamoDB table are provisioned, you can start using them to store Terraform state for the Terraform components. +There are two ways of doing this: + +- Manually create `backend.tf` file in each component's folder with the following content: + + +```hcl +terraform { + backend "s3" { + acl = "bucket-owner-full-control" + bucket = "your-s3-bucket-name" + dynamodb_table = "your-dynamodb-table-name" + encrypt = true + key = "terraform.tfstate" + region = "your-aws-region" + role_arn = "arn:aws:iam::xxxxxxxx:role/IAM Role with permissions to access the Terraform backend" + workspace_key_prefix = "component name, e.g. `vpc` or `vpc-flow-logs-bucket`" + } +} +``` + + +
+ +- Configure Terraform S3 backend with Atmos to automatically generate a backend file for each Atmos component. This is the recommended way +of configuring Terraform state backend since it offers many advantages and will save you from manually creating a backend configuration file for +each component + +Configuring Terraform S3 backend with Atmos consists of the three steps: + +- Set `auto_generate_backend_file` to `true` in the `atmos.yaml` CLI config file in the `components.terraform` section: + + +```yaml +components: + terraform: + # Can also be set using 'ATMOS_COMPONENTS_TERRAFORM_AUTO_GENERATE_BACKEND_FILE' ENV var, or '--auto-generate-backend-file' command-line argument + auto_generate_backend_file: true +``` + + +
+ +- Configure the S3 backend in one of the `_defaults.yaml` manifests. You can configure it for the entire Organization, or per OU/tenant, or per +region, or per account. + +:::note +The `_defaults.yaml` manifests contain the default settings for Organizations, Organizational Units and accounts. +::: + +
+ +To configure the S3 backend for the entire Organization, add the following config in `stacks/orgs/acme/_defaults.yaml`: + + +```yaml +terraform: + backend_type: s3 + backend: + s3: + acl: "bucket-owner-full-control" + encrypt: true + bucket: "your-s3-bucket-name" + dynamodb_table: "your-dynamodb-table-name" + key: "terraform.tfstate" + region: "your-aws-region" + role_arn: "arn:aws:iam::xxxxxxxx:role/IAM Role with permissions to access the Terraform backend" +``` + + +
+ +- (This step is optional) For each component, you can add `workspace_key_prefix` similar to the following: + + +```yaml +components: + terraform: + # `vpc` is the Atmos component name + vpc: + # Optional backend configuration for the component + backend: + s3: + workspace_key_prefix: vpc + metadata: + # Point to the Terraform component + component: vpc + settings: {} + vars: {} + env: {} +``` + + +
+ +Note that this is optional. If you don’t add `backend.s3.workspace_key_prefix` to the component manifest, the Atmos component name will be used +automatically (which is this example is `vpc`). `/` (slash) in the Atmos component name will be replaced with `-` (dash). + +We usually don’t specify `workspace_key_prefix` for each component and let Atmos use the component name as `workspace_key_prefix`. + +
+ +Once all the above is configured, when you run the commands `atmos terraform plan vpc -s ` +or `atmos terraform apply vpc -s `, before executing the Terraform commands, Atmos will [deep-merge](#terraform-backend-inheritance) +the backend configurations from the `_defaults.yaml` manifest and from the component itself, and will generate a backend +config JSON file `backend.tf.json` in the component's folder, similar to the following example: + + +```json +{ + "terraform": { + "backend": { + "s3": { + "acl": "bucket-owner-full-control", + "bucket": "your-s3-bucket-name", + "dynamodb_table": "your-dynamodb-table-name", + "encrypt": true, + "key": "terraform.tfstate", + "region": "your-aws-region", + "role_arn": "arn:aws:iam::xxxxxxxx:role/IAM Role with permissions to access the Terraform backend", + "workspace_key_prefix": "vpc" + } + } + } +} +``` + + +
+ +You can also generate the backend configuration file for a component in a stack by executing the +command [atmos terraform generate backend](/cli/commands/terraform/generate-backend). Or generate the backend configuration files for all components +by executing the command [atmos terraform generate backends](/cli/commands/terraform/generate-backends). + +## Azure Blob Storage Backend + +[`azurerm`](https://developer.hashicorp.com/terraform/language/settings/backends/azurerm) backend stores the state as a +Blob with the given Key within the Blob Container within the Blob Storage Account. This backend supports state locking +and consistency checking with Azure Blob Storage native capabilities. + +To configure the [Azure Blob Storage backend](https://developer.hashicorp.com/terraform/language/settings/backends/azurerm) +in Atmos, add the following config to an Atmos manifest in `_defaults.yaml`: + + +```yaml +terraform: + backend_type: azurerm + backend: + azurerm: + resource_group_name: "StorageAccount-ResourceGroup" + storage_account_name: "abcd1234" + container_name: "tfstate" + # Other parameters +``` + + +
+ +For each component, you can optionally add the `key` parameter similar to the following: + + +```yaml +components: + terraform: + my-component: + # Optional backend configuration for the component + backend: + azurerm: + key: "my-component" +``` + + +
+ +If the `key` is not specified for a component, Atmos will use the component name (`my-component` in the example above) +to auto-generate the `key` parameter in the format `.terraform.tfstate` replacing `` +with the Atmos component name. In ``, all occurrences of `/` (slash) will be replaced with `-` (dash). + +If `auto_generate_backend_file` is set to `true` in the `atmos.yaml` CLI config file in the `components.terraform` section, +Atmos will [deep-merge](#terraform-backend-inheritance) the backend configurations from the `_defaults.yaml` manifests and +from the component itself, and will generate a backend config JSON file `backend.tf.json` in the component's folder, +similar to the following example: + + +```json +{ + "terraform": { + "backend": { + "azurerm": { + "resource_group_name": "StorageAccount-ResourceGroup", + "storage_account_name": "abcd1234", + "container_name": "tfstate", + "key": "my-component.terraform.tfstate" + } + } + } +} +``` + + +
+ +## Google Cloud Storage Backend + +[`gcs`](https://developer.hashicorp.com/terraform/language/settings/backends/gcs) backend stores the state as an object +in a configurable `prefix` in a pre-existing bucket on Google Cloud Storage (GCS). +The bucket must exist prior to configuring the backend. The backend supports state locking. + +To configure the [Google Cloud Storage backend](https://developer.hashicorp.com/terraform/language/settings/backends/gcs) +in Atmos, add the following config to an Atmos manifest in `_defaults.yaml`: + + +```yaml +terraform: + backend_type: gcs + backend: + gcs: + bucket: "tf-state" + # Other parameters +``` + + +
+ +For each component, you can optionally add the `prefix` parameter similar to the following: + + +```yaml +components: + terraform: + my-component: + # Optional backend configuration for the component + backend: + gcp: + prefix: "my-component" +``` + + +
+ +If the `prefix` is not specified for a component, Atmos will use the component name (`my-component` in the example above) +to auto-generate the `prefix`. In the component name, all occurrences of `/` (slash) will be replaced with `-` (dash). + +If `auto_generate_backend_file` is set to `true` in the `atmos.yaml` CLI config file in the `components.terraform` section, +Atmos will [deep-merge](#terraform-backend-inheritance) the backend configurations from the `_defaults.yaml` manifests and +from the component itself, and will generate a backend config JSON file `backend.tf.json` in the component's folder, +similar to the following example: + + +```json +{ + "terraform": { + "backend": { + "gcp": { + "bucket": "tf-state", + "prefix": "my-component" + } + } + } +} +``` + + +
+ +## Terraform Cloud Backend + +[Terraform Cloud](https://developer.hashicorp.com/terraform/cli/cloud/settings) backend uses a `cloud` block to specify +which organization and workspace(s) to use. + +To configure the [Terraform Cloud backend](https://developer.hashicorp.com/terraform/cli/cloud/settings) +in Atmos, add the following config to an Atmos manifest in `_defaults.yaml`: + + +```yaml +terraform: + backend_type: cloud + backend: + cloud: + organization: "my-org" + hostname: "app.terraform.io" + workspaces: + # Parameters for workspaces +``` + + +
+ +For each component, you can optionally specify the `workspaces.name` parameter similar to the following: + + +```yaml +components: + terraform: + my-component: + # Optional backend configuration for the component + backend: + cloud: + workspaces: + name: "my-component-workspace" +``` + + +
+ +If `auto_generate_backend_file` is set to `true` in the `atmos.yaml` CLI config file in the `components.terraform` section, +Atmos will [deep-merge](#terraform-backend-inheritance) the backend configurations from the `_defaults.yaml` manifests and +from the component itself, and will generate a backend config JSON file `backend.tf.json` in the component's folder, +similar to the following example: + + +```json +{ + "terraform": { + "cloud": { + "hostname": "app.terraform.io", + "organization": "my-org", + "workspaces": { + "name": "my-component-workspace" + } + } + } +} +``` + + +
+ +Instead of specifying the `workspaces.name` parameter for each component in the component manifests, you can use +the `{terraform_workspace}` token in the `cloud` backend config in the `_defaults.yaml` manifest. +The token `{terraform_workspace}` will be automatically replaced by Atmos with the Terraform workspace for each component. +This will make the entire configuration DRY. + + +```yaml +terraform: + backend_type: cloud + backend: + cloud: + organization: "my-org" + hostname: "app.terraform.io" + workspaces: + # The token `{terraform_workspace}` will be automatically replaced with the + # Terraform workspace for each Atmos component + name: "{terraform_workspace}" +``` + + +
+ +:::tip +Refer to [Terraform Workspaces in Atmos](/core-concepts/components/terraform-workspaces) for more information on how +Atmos calculates Terraform workspaces for components, and how workspaces can be overridden for each component. +::: + +## Terraform Backend Inheritance + +Suppose that for security and audit reasons, you want to use different Terraform backends for `dev`, `staging` and `prod`. +Each account needs to have a separate S3 bucket, DynamoDB table, and IAM role with different permissions +(for example, the `development` Team should be able to access the Terraform backend only in the `dev` account, but not in `staging` and `prod`). + +Atmos supports this use-case by using deep-merging of stack manifests, [Imports](/core-concepts/stacks/imports) +and [Inheritance](/core-concepts/components/inheritance), which makes the backend configuration reusable and DRY. + +We'll split the backend config between the Organization and the accounts. + +Add the following config to the Organization stack manifest in `stacks/orgs/acme/_defaults.yaml`: + + +```yaml +terraform: + backend_type: s3 + backend: + s3: + acl: "bucket-owner-full-control" + encrypt: true + key: "terraform.tfstate" + region: "your-aws-region" +``` + + +
+ +Add the following config to the `dev` stack manifest in `stacks/orgs/acme/plat/dev/_defaults.yaml`: + + +```yaml +terraform: + backend_type: s3 + backend: + s3: + bucket: "your-dev-s3-bucket-name" + dynamodb_table: "your-dev-dynamodb-table-name" + role_arn: "IAM Role with permissions to access the 'dev' Terraform backend" +``` + + +
+ +Add the following config to the `staging` stack manifest in `stacks/orgs/acme/plat/staging/_defaults.yaml`: + + +```yaml +terraform: + backend_type: s3 + backend: + s3: + bucket: "your-staging-s3-bucket-name" + dynamodb_table: "your-staging-dynamodb-table-name" + role_arn: "IAM Role with permissions to access the 'staging' Terraform backend" +``` + + +
+ +Add the following config to the `prod` stack manifest in `stacks/orgs/acme/plat/prod/_defaults.yaml`: + + +```yaml +terraform: + backend_type: s3 + backend: + s3: + bucket: "your-prod-s3-bucket-name" + dynamodb_table: "your-prod-dynamodb-table-name" + role_arn: "IAM Role with permissions to access the 'prod' Terraform backend" +``` + + +
+ +When you provision the `vpc` component into the `dev` account (by executing the command `atmos terraform apply vpc -s plat-ue2-dev`), Atmos will +deep-merge the backend configuration from the Organization-level manifest with the configuration from the `dev` manifest, and will automatically +add `workspace_key_prefix` for the component, generating the following final deep-merged backend config for the `vpc` component in the `dev` account: + + +```json +{ + "terraform": { + "backend": { + "s3": { + "acl": "bucket-owner-full-control", + "bucket": "your-dev-s3-bucket-name", + "dynamodb_table": "your-dev-dynamodb-table-name", + "encrypt": true, + "key": "terraform.tfstate", + "region": "your-aws-region", + "role_arn": "", + "workspace_key_prefix": "vpc" + } + } + } +} +``` + + +
+ +In the same way, you can create different Terraform backends per Organizational Unit, per region, per account (or a group of accounts, e.g. `prod` +and `non-prod`), or even per component or a set of components (e.g. root-level components like `account` and IAM roles can have a separate backend), +and then configure parts of the backend config in the corresponding Atmos stack manifests. Atmos will deep-merge all the parts from the +different scopes and generate the final backend config for the components in the stacks. + +## Terraform Backend with Multiple Component Instances + +We mentioned before that you can configure the Terraform backend for the components manually (by creating a file `backend.tf` in each Terraform +component's folder), or you can set up Atmos to generate the backend configuration for each component in the stacks automatically. While +auto-generating the backend config file is helpful and saves you from creating the backend files for each component, it becomes a requirement +when you provision multiple instances of a Terraform component into the same environment (same account and region). + +You can provision more than one instance of the same Terraform component (with the same or different settings) into the same environment by defining +many Atmos components that provide configuration for the Terraform component. + +:::tip +For more information on configuring and provision multiple instances of a Terraform component, +refer to [Multiple Component Instances Atmos Design Patterns](/design-patterns/multiple-component-instances) +::: + +
+ +For example, the following config shows how to define two Atmos +components, `vpc/1` and `vpc/2`, which both point to the same Terraform component `vpc`: + + +```yaml +import: + # Import the defaults for all VPC components + - catalog/vpc/defaults + +components: + terraform: + # Atmos component `vpc/1` + vpc/1: + metadata: + # Point to the Terraform component in `components/terraform/vpc` + component: vpc + # Inherit the defaults for all VPC components + inherits: + - vpc/defaults + # Define variables specific to this `vpc/1` component + vars: + name: vpc-1 + ipv4_primary_cidr_block: 10.9.0.0/18 + # Optional backend configuration for the component + # If not specified, the Atmos component name `vpc/1` will be used (`/` will be replaced with `-`) + backend: + s3: + workspace_key_prefix: vpc-1 + + # Atmos component `vpc/2` + vpc/2: + metadata: + # Point to the Terraform component in `components/terraform/vpc` + component: vpc + # Inherit the defaults for all VPC components + inherits: + - vpc/defaults + # Define variables specific to this `vpc/2` component + vars: + name: vpc-2 + ipv4_primary_cidr_block: 10.10.0.0/18 + # Optional backend configuration for the component + # If not specified, the Atmos component name `vpc/2` will be used (`/` will be replaced with `-`) + backend: + s3: + workspace_key_prefix: vpc-2 +``` + + +
+ +If we manually create a `backend.tf` file for the `vpc` Terraform component in the `components/terraform/vpc` folder +using `workspace_key_prefix: "vpc"`, then both `vpc/1` and `vpc/2` Atmos components will use the same `workspace_key_prefix`, and they will +not function correctly. + +On the other hand, if we configure Atmos to auto-generate the backend config file, then each component will have a different `workspace_key_prefix` +auto-generated by Atmos by using the Atmos component name (or you can override this behavior by specifying `workspace_key_prefix` for each component +in the component manifest in the `backend.s3.workspace_key_prefix` section). + +For example, when the command `atmos terraform apply vpc/1 -s plat-ue2-dev` is executed, the following `backend.tf.json` file is generated in the +`components/terraform/vpc` folder: + + +```json +{ + "terraform": { + "backend": { + "s3": { + "acl": "bucket-owner-full-control", + "bucket": "your-dev-s3-bucket-name", + "dynamodb_table": "your-dev-dynamodb-table-name", + "encrypt": true, + "key": "terraform.tfstate", + "region": "your-aws-region", + "role_arn": "", + "workspace_key_prefix": "vpc-1" + } + } + } +} +``` + + +
+ +Similarly, when the command `atmos terraform apply vpc/2 -s plat-ue2-dev` is executed, the following `backend.tf.json` file is generated in the +`components/terraform/vpc` folder: + + +```json +{ + "terraform": { + "backend": { + "s3": { + "acl": "bucket-owner-full-control", + "bucket": "your-dev-s3-bucket-name", + "dynamodb_table": "your-dev-dynamodb-table-name", + "encrypt": true, + "key": "terraform.tfstate", + "region": "your-aws-region", + "role_arn": "", + "workspace_key_prefix": "vpc-2" + } + } + } +} +``` + + +
+ +The generated files will have different `workspace_key_prefix` attribute auto-generated by Atmos. + +For this reason, configuring Atmos to auto-generate the backend configuration for the components in the stacks is recommended +for all supported backend types. + +## References + +- [Terraform Backend Configuration](https://developer.hashicorp.com/terraform/language/settings/backends/configuration) +- [Terraform Cloud Settings](https://developer.hashicorp.com/terraform/cli/cloud/settings) +- [Multiple Component Instances Atmos Design Patterns](/design-patterns/multiple-component-instances) diff --git a/website/docs/core-concepts/components/terraform-providers.mdx b/website/docs/core-concepts/components/terraform-providers.mdx index 9af260ef6..44740bc27 100644 --- a/website/docs/core-concepts/components/terraform-providers.mdx +++ b/website/docs/core-concepts/components/terraform-providers.mdx @@ -1,6 +1,6 @@ --- title: Terraform Providers -sidebar_position: 10 +sidebar_position: 12 sidebar_label: Terraform Providers description: Configure and override Terraform Providers. id: terraform-providers diff --git a/website/docs/core-concepts/components/terraform-workspaces.mdx b/website/docs/core-concepts/components/terraform-workspaces.mdx new file mode 100644 index 000000000..12e6942b2 --- /dev/null +++ b/website/docs/core-concepts/components/terraform-workspaces.mdx @@ -0,0 +1,210 @@ +--- +title: Terraform Workspaces +sidebar_position: 10 +sidebar_label: Terraform Workspaces +description: Terraform Workspaces. +id: terraform-workspaces +--- + +import Terminal from '@site/src/components/Terminal' + +In Terraform, a [workspace](https://developer.hashicorp.com/terraform/language/state/workspaces) is a feature that allows +you to manage multiple "state" environments within a Terraform configuration. Each workspace maintains its own state, +allowing you to deploy and manage infrastructure configurations independently. + +Workspaces are useful in several scenarios: + +- **Environment Isolation**: Workspaces enable you to have separate environments within a Terraform configuration. +Each workspace can have its own set of resources and configurations. + +- **Parallel Development**: Workspaces facilitate parallel development by allowing different team members to work on +different workspaces concurrently without interfering with each other's changes. + +- **Testing and Experimentation**: Workspaces are helpful for testing and experimentation. +You can create temporary workspaces to test changes or new configurations without affecting the main production environment. + +- **State Management**: Workspaces manage separate states for each environment. +This helps in maintaining clarity and avoiding conflicts when multiple environments are being managed. + +- **Deployment Strategies**: Workspaces can be used to implement different deployment strategies. +For example, you might use separate workspaces for blue-green deployments or canary releases. + +To work with workspaces in Terraform, you can use commands like `terraform workspace new`, `terraform workspace select`, +and `terraform workspace delete` to create, switch between, and delete workspaces respectively. +Additionally, the ENV variable [`TF_WORKSPACE`](https://developer.hashicorp.com/terraform/cli/config/environment-variables#tf_workspace) +can be used to create and select Terraform workspaces. + +## Terraform Workspaces in Atmos + +Atmos uses and automatically calculates Terraform workspaces to manage top-level stacks. By default, Atmos uses the stack +name as the Terraform workspace when provisioning components in the stack. For example, consider the following manifest +for the component `vpc` in the stack `ue2-dev`: + + +```yaml +vars: + # Context variables that define the Atmos stack `ue2-dev` + environment: ue2 + stage: dev + +components: + terraform: + vpc: + metadata: + # Point to the Terraform component in `components/terraform/vpc` + component: vpc + # Define the variables specific to this component + vars: + name: my-vpc + ipv4_primary_cidr_block: 10.9.0.0/18 +``` + + +
+ +When you provision the `vpc` component in the stack `ue2-dev` by executing the following command: + + + ```shell + atmos terraform apply vpc -s ue2-dev + ``` + + +
+ +Atmos sets the [`TF_WORKSPACE`](https://developer.hashicorp.com/terraform/cli/config/environment-variables#tf_workspace) +ENV variable to the name of the stack `ue2-dev`, and Terraform then selects this workspace or creates it if it does not exist. + +The exception to the default rule (using the stack name as Terraform workspace) is when we provision more than one +instance of the same Terraform component (with the same or different settings) into the same stack by defining multiple +Atmos components. In this case, Atmos calculates the Terraform workspace for each component by joining the stack name +with the component name. + +For example, the following manifest shows how to define two Atmos components, `vpc/1` and `vpc/2`, +which both point to the same Terraform component `vpc`, in the stack `ue2-dev`: + + +```yaml +vars: + # Context variables that define the Atmos stack `ue2-dev` + environment: ue2 + stage: dev + +components: + terraform: + # Atmos component `vpc/1` + vpc/1: + metadata: + # Point to the Terraform component in `components/terraform/vpc` + component: vpc + # Inherit the defaults for all VPC components + inherits: + - vpc/defaults + # Define/override variables specific to this `vpc/1` component + vars: + name: vpc-1 + ipv4_primary_cidr_block: 10.9.0.0/18 + + # Atmos component `vpc/2` + vpc/2: + metadata: + # Point to the Terraform component in `components/terraform/vpc` + component: vpc + # Inherit the defaults for all VPC components + inherits: + - vpc/defaults + # Define/override variables specific to this `vpc/2` component + vars: + name: vpc-2 + ipv4_primary_cidr_block: 10.10.0.0/18 +``` + + +
+ +When you provision the components by executing the commands: + + + ```shell + atmos terraform apply vpc/1 -s ue2-dev + atmos terraform apply vpc/2 -s ue2-dev + ``` + + +
+ +Atmos sets the [`TF_WORKSPACE`](https://developer.hashicorp.com/terraform/cli/config/environment-variables#tf_workspace) +environment variable to `ue2-dev-vpc-1` and `ue2-dev-vpc-2` respectively, and Terraform selects (or creates) different workspaces +for the components. This is done because the same Terraform component `vpc` is used as the workspace prefix +(in case of [AWS S3 backend](https://developer.hashicorp.com/terraform/language/settings/backends/s3), +folder in the S3 state bucket), and it's necessary to have different subfolders (`ue2-dev-vpc-1` +and `ue2-dev-vpc-2` instead of just `ue2-dev`) to store the Terraform state files. + +## Terraform Workspace Override in Atmos + +You can override Terraform workspaces for Atmos components by using `metadata.terraform_workspace` and +`metadata.terraform_workspace_pattern` attributes. For example: + + +```yaml +vars: + environment: ue2 + stage: dev + +components: + terraform: + vpc/1: + metadata: + component: vpc + # Override Terraform workspace + terraform_workspace: "vpc-1-workspace-override" + + vpc/2: + metadata: + component: vpc + # Override Terraform workspace + terraform_workspace_pattern: "{environment}-{stage}-{component}-workspace-override" +``` + + +
+ +When you provision the components by executing the commands: + + + ```shell + atmos terraform apply vpc/1 -s ue2-dev + atmos terraform apply vpc/2 -s ue2-dev + ``` + + +
+ +Atmos sets the Terraform workspace `vpc-1-workspace-override` for the `vpc/1` component, and +`ue2-dev-vpc-2-workspace-override` for the `vpc/2` component. + +The following context tokens are supported by the `metadata.terraform_workspace_pattern` attribute: + +- `{namespace}` +- `{tenant}` +- `{environment}` +- `{region}` +- `{stage}` +- `{attributes}` +- `{component}` +- `{base-component}` + +
+ +:::tip +For more information on Atmos base and derived components, and to understand the `{base-component}` token, +refer to [Atmos Component Inheritance](/core-concepts/components/inheritance) +::: + +
+ +## References + +- [Terraform Workspaces](https://developer.hashicorp.com/terraform/language/state/workspaces) +- [Managing Terraform Workspaces](https://developer.hashicorp.com/terraform/cli/workspaces) +- [Terraform Environment Variables](https://developer.hashicorp.com/terraform/cli/config/environment-variables) diff --git a/website/docs/integrations/atlantis.mdx b/website/docs/integrations/atlantis.mdx index deb65caed..8f113f012 100644 --- a/website/docs/integrations/atlantis.mdx +++ b/website/docs/integrations/atlantis.mdx @@ -686,7 +686,7 @@ on: branches: [ main ] env: - ATMOS_VERSION: 1.66.0 + ATMOS_VERSION: 1.67.0 ATMOS_CLI_CONFIG_PATH: ./ jobs: diff --git a/website/docs/integrations/github-actions/setup-atmos.md b/website/docs/integrations/github-actions/setup-atmos.md index c85d11439..c5582bd31 100644 --- a/website/docs/integrations/github-actions/setup-atmos.md +++ b/website/docs/integrations/github-actions/setup-atmos.md @@ -27,5 +27,5 @@ jobs: uses: cloudposse/github-action-setup-atmos with: # Make sure to pin to the latest version of atmos - atmos_version: 1.66.0 + atmos_version: 1.67.0 ``` diff --git a/website/docs/introduction/faq.mdx b/website/docs/introduction/faq.mdx index 9c13e98ff..e37158415 100644 --- a/website/docs/introduction/faq.mdx +++ b/website/docs/introduction/faq.mdx @@ -5,8 +5,8 @@ sidebar_label: FAQ sidebar_position: 3 --- + import ReactPlayer from 'react-player' -import Link from '@docusaurus/Link' ### Why is the tool called Atmos? @@ -71,9 +71,9 @@ Furthermore, Atmos delivers prescriptive guidance on [design patterns](/design-p ### Can Atmos be used together with Terragrunt? -Yes, technically, Atmos and Terragrunt can be used in conjunction. However, it's important to acknowledge that this combination introduces a significant overlap in functionality and some philosophical differences. Developers generally prefer to minimize the number of layers in their tooling to avoid complexity, and integrating these two tools could steepen the learning curve for teams. +Yes, technically, Atmos and Terragrunt can be used in conjunction. However, it's important to acknowledge that this combination introduces a significant overlap in functionality and some philosophical differences. Developers generally prefer to minimize the number of layers in their tooling to avoid complexity, and integrating these two tools could steepen the learning curve for teams. -The key motivation for integrating Terragrunt within Atmos would be to offer a seamless CLI (Command Line Interface) experience, facilitating a gradual transition to Atmos's methodologies. This strategy allows teams to utilize Terragrunt for existing infrastructure management ("for historical reasons") while adopting Atmos for new projects. Essentially, it's a strategic approach to support migration to Atmos, enabling the tool to invoke Terragrunt where necessary, as teams progressively shift towards fully embracing Atmos for infrastructure orchestration. +The key motivation for integrating Terragrunt within Atmos would be to offer a seamless CLI (Command Line Interface) experience, facilitating a gradual transition to Atmos's methodologies. This strategy allows teams to utilize Terragrunt for existing infrastructure management ("for historical reasons") while adopting Atmos for new projects. Essentially, it's a strategic approach to support migration to Atmos, enabling the tool to invoke Terragrunt where necessary, as teams progressively shift towards fully embracing Atmos for infrastructure orchestration. There are a few ways to accomplish it, depending on your needs or preferences. @@ -100,7 +100,7 @@ Here's why it should work with any CI/CD system. - Commit those `.tfvar`, then run Terraform as normal, passing the appropriate `.tfvar` file to the `terraform` command with the `-vars` argument. Our recommended way of practicing GitOps with Terraform is with our turn-key [GitHub Actions](/integrations/github-actions/). - + ### Does Atmos work with Atlantis? Yes, it does. See our [integration page](/integrations/atlantis). @@ -124,7 +124,7 @@ ensuring straightforward and accessible functionality without the need for ongoi Atmos is free and open source under the permissive APACHE2 license. :::tip Words of Wisdom -We believe the most successful open-source tools are not themselves the end products sold in the market; instead, they serve as enablers, +We believe the most successful open-source tools are not themselves the end products sold in the market; instead, they serve as enablers, empowering others to build and innovate successful products. ::: diff --git a/website/docs/quick-start/configure-terraform-backend.md b/website/docs/quick-start/configure-terraform-backend.md index 1e3bead3f..3b1074703 100644 --- a/website/docs/quick-start/configure-terraform-backend.md +++ b/website/docs/quick-start/configure-terraform-backend.md @@ -131,7 +131,7 @@ There are two ways of doing this: key = "terraform.tfstate" region = "your-aws-region" role_arn = "arn:aws:iam:::role/" - workspace_key_prefix = " - -# Terraform Backend Inheritance +## Terraform Backend Inheritance In the previous section, we configured the S3 backend for the entire Organization by adding the `terraform.backend.s3` section to the `stacks/orgs/acme/_defaults.yaml` stack manifest. The same backend configuration (S3 bucket, DynamoDB table, and IAM role) will be used for all @@ -338,12 +336,21 @@ different scopes and generate the final backend config for the components in the We mentioned before that you can configure the Terraform backend for the components manually (by creating a file `backend.tf` in each Terraform component's folder), or you can set up Atmos to generate the backend configuration for each component in the stacks automatically. While -auto-generating the backend config file is helpful and saves you from creating the backend files for each component, it becomes a requirements -when you provision multiple instance of a Terraform component into the same environment (same account and region). +auto-generating the backend config file is helpful and saves you from creating the backend files for each component, it becomes a requirement +when you provision multiple instances of a Terraform component into the same environment (same account and region). You can provision more than one instance of the same Terraform component (with the same or different settings) into the same environment by defining -many Atmos components that provide configuration for the Terraform component. For example, the following config shows how to define two Atmos -components, `vpc/1` and `vpc/2`, which both point to the same Terraform component `vpc`: +many Atmos components that provide configuration for the Terraform component. + +:::tip +For more information on configuring and provision multiple instances of a Terraform component, +refer to [Multiple Component Instances Atmos Design Patterns](/design-patterns/multiple-component-instances) +::: + +
+ +For example, the following config shows how to define two Atmos components, `vpc/1` and `vpc/2`, which both point to +the same Terraform component `vpc`: ```yaml import: @@ -398,7 +405,7 @@ auto-generated by Atmos by using the Atmos component name (or you can override t in the component manifest in the `backend.s3.workspace_key_prefix` section). For example, when the command `atmos terraform apply vpc/1 -s plat-ue2-dev` is executed, the following `backend.tf.json` file is generated in the -`components/terrafrom/vpc` folder: +`components/terraform/vpc` folder: ```json { @@ -420,7 +427,7 @@ For example, when the command `atmos terraform apply vpc/1 -s plat-ue2-dev` is e ``` Similarly, when the command `atmos terraform apply vpc/2 -s plat-ue2-dev` is executed, the following `backend.tf.json` file is generated in the -`components/terrafrom/vpc` folder: +`components/terraform/vpc` folder: ```json { diff --git a/website/package-lock.json b/website/package-lock.json index e2bf957f2..77fe2a814 100644 --- a/website/package-lock.json +++ b/website/package-lock.json @@ -13,7 +13,7 @@ "@docusaurus/plugin-client-redirects": "^3.1.1", "@docusaurus/preset-classic": "^3.1.1", "@docusaurus/theme-mermaid": "^3.1.1", - "@grnet/docusaurus-terminology": "^2.0.0-rc", + "@grnet/docusaurus-terminology": "^2.0.0-rc.1", "@mdx-js/react": "^3.0.1", "clsx": "^2.1.0", "custom-loaders": "file:plugins/custom-loaders", @@ -2917,9 +2917,9 @@ } }, "node_modules/@grnet/docusaurus-glossary-view": { - "version": "2.0.0-rc", - "resolved": "https://registry.npmjs.org/@grnet/docusaurus-glossary-view/-/docusaurus-glossary-view-2.0.0-rc.tgz", - "integrity": "sha512-8DtR125GvoLMsHkYOhzVywyGzxecmf0McTbcV/+UYDF+h22Ti8oyPcw9CD8tmIWZhEK2iHf8PTAqR7NvQuYOjA==", + "version": "2.0.0-rc.1", + "resolved": "https://registry.npmjs.org/@grnet/docusaurus-glossary-view/-/docusaurus-glossary-view-2.0.0-rc.1.tgz", + "integrity": "sha512-Bhlo+EB410/zQzwMdOqQmZbG5Jvl71zMmx/vPMKjZY2ovqpe2rqkp04AAUxvZzaHcG81IBV/gh2yftxKTs6N1g==", "peerDependencies": { "@docusaurus/core": "^3.0.1", "react": "^18.0.0", @@ -2927,9 +2927,9 @@ } }, "node_modules/@grnet/docusaurus-term-preview": { - "version": "2.0.0-rc", - "resolved": "https://registry.npmjs.org/@grnet/docusaurus-term-preview/-/docusaurus-term-preview-2.0.0-rc.tgz", - "integrity": "sha512-NekSLJG9MQM/DG++mjGJE6JA2umf2huOjGbp22p7mj/dFoHfDN6ZVbrb5KmzXK+0bG3xDE0f53J4ibljcrvvGA==", + "version": "2.0.0-rc.1", + "resolved": "https://registry.npmjs.org/@grnet/docusaurus-term-preview/-/docusaurus-term-preview-2.0.0-rc.1.tgz", + "integrity": "sha512-JkLCHN5g613ZWf4whMw9yE8jx1HMvBY0jTS4NK7X47W/Tuu509Wl5BqP3k+FH5t5pVT49n0PyBWXCJ8JDY9yxA==", "dependencies": { "postel": "0.1.5", "rc-tooltip": "5.0.2", @@ -2965,38 +2965,38 @@ } }, "node_modules/@grnet/docusaurus-terminology": { - "version": "2.0.0-rc", - "resolved": "https://registry.npmjs.org/@grnet/docusaurus-terminology/-/docusaurus-terminology-2.0.0-rc.tgz", - "integrity": "sha512-LaXewwysKVIual5EQ/ZIm/XYfeYjyTBGELsjBQMkKqxerrBuwsXoGO1T/nl2NX8jPFZCkWgcrpJSiwTKtHaC4Q==", + "version": "2.0.0-rc.1", + "resolved": "https://registry.npmjs.org/@grnet/docusaurus-terminology/-/docusaurus-terminology-2.0.0-rc.1.tgz", + "integrity": "sha512-Ww8JarC8Orz+1ql6SmZ4nGtOrGrHdfz6S+t2CIiX9rPPI7M84Ru5rVjdZglRQSCZy8miq8Htj9r9AMiMXnLJJg==", "dependencies": { - "@grnet/docusaurus-glossary-view": "2.0.0-rc", - "@grnet/docusaurus-term-preview": "2.0.0-rc", - "@grnet/terminology-store": "2.0.0-rc", - "@grnet/webpack-glossary-loader": "2.0.0-rc", - "@grnet/webpack-terms-loader": "2.0.0-rc", - "@grnet/webpack-terms-replace-loader": "2.0.0-rc" + "@grnet/docusaurus-glossary-view": "2.0.0-rc.1", + "@grnet/docusaurus-term-preview": "2.0.0-rc.1", + "@grnet/terminology-store": "2.0.0-rc.1", + "@grnet/webpack-glossary-loader": "2.0.0-rc.1", + "@grnet/webpack-terms-loader": "2.0.0-rc.1", + "@grnet/webpack-terms-replace-loader": "2.0.0-rc.1" } }, "node_modules/@grnet/terminology-store": { - "version": "2.0.0-rc", - "resolved": "https://registry.npmjs.org/@grnet/terminology-store/-/terminology-store-2.0.0-rc.tgz", - "integrity": "sha512-mI5b1/9rQy4Uj+3FcH+ovvUbAazmfOU3Exr+0ib9hwYAwLdKJjNy4nksxyL/IZqpQ9B3gvf+LNW+QSbb1PoQUQ==" + "version": "2.0.0-rc.1", + "resolved": "https://registry.npmjs.org/@grnet/terminology-store/-/terminology-store-2.0.0-rc.1.tgz", + "integrity": "sha512-vS7Xh5gSenaOLnDFblchSRZJAT1POFZL9bjuANUlZUyfT9f6GNP75+jDAwe6POeQNdu61uh853RdS3jRLzZGTQ==" }, "node_modules/@grnet/webpack-glossary-loader": { - "version": "2.0.0-rc", - "resolved": "https://registry.npmjs.org/@grnet/webpack-glossary-loader/-/webpack-glossary-loader-2.0.0-rc.tgz", - "integrity": "sha512-WZHjUEiSFIolT1bP5LjxipeJfWr71NH3R7XJr9wrSX8P0J7wudlbua/QGK0tD5iZls6COoviML16lVidk+ArMw==", + "version": "2.0.0-rc.1", + "resolved": "https://registry.npmjs.org/@grnet/webpack-glossary-loader/-/webpack-glossary-loader-2.0.0-rc.1.tgz", + "integrity": "sha512-Mw3ZtTDhrjQEtnh0vErRyDT2JHGSAvj5X3AqHqn6T6tG6DQNFaz3t97v3DdgFlmY2SKpNEMJ8P02p6UL4jVisA==", "dependencies": { - "@grnet/terminology-store": "2.0.0-rc", + "@grnet/terminology-store": "2.0.0-rc.1", "parse-md": "2.0.4" } }, "node_modules/@grnet/webpack-terms-loader": { - "version": "2.0.0-rc", - "resolved": "https://registry.npmjs.org/@grnet/webpack-terms-loader/-/webpack-terms-loader-2.0.0-rc.tgz", - "integrity": "sha512-4C/e7DS5AvPQlYscNvW1hQdUs23dNgzC41J4JqMYdBKiCwAour+7UHxj63mZthUM+D8NuCGn5OoaPJ9p1HL/EQ==", + "version": "2.0.0-rc.1", + "resolved": "https://registry.npmjs.org/@grnet/webpack-terms-loader/-/webpack-terms-loader-2.0.0-rc.1.tgz", + "integrity": "sha512-xlfouJrjev+5TR/dout/xb3LQR0txRIX1YXDKTKuEM/77LC4gSJX64iSGwlLrgqL3ivoXiTCr8hTSTerBmb6mQ==", "dependencies": { - "@grnet/terminology-store": "2.0.0-rc", + "@grnet/terminology-store": "2.0.0-rc.1", "parse-md": "2.0.4", "remark": "13.0.0", "remark-html": "13.0.2" @@ -3180,11 +3180,11 @@ } }, "node_modules/@grnet/webpack-terms-replace-loader": { - "version": "2.0.0-rc", - "resolved": "https://registry.npmjs.org/@grnet/webpack-terms-replace-loader/-/webpack-terms-replace-loader-2.0.0-rc.tgz", - "integrity": "sha512-AEfdUtBPROhXIbR73yWM3A0XVmk2fAl/BHrkI6XLWWWK4bxMdC/pfa9iuvCPTO51Z8MhN36eFnXcn5NRTJKtig==", + "version": "2.0.0-rc.1", + "resolved": "https://registry.npmjs.org/@grnet/webpack-terms-replace-loader/-/webpack-terms-replace-loader-2.0.0-rc.1.tgz", + "integrity": "sha512-zYVLTH2wp5+WBvCPXqOO2a/5W0QgBcJpw7jwhL318cQhYnTvwU4wJNh4NUj13BOm+CZsb+kvgAGizgRtAMr0DA==", "dependencies": { - "@grnet/terminology-store": "2.0.0-rc", + "@grnet/terminology-store": "2.0.0-rc.1", "parse-md": "2.0.4", "pkg-up": "3.1.0" } @@ -14309,9 +14309,9 @@ } }, "node_modules/rc-util": { - "version": "5.38.1", - "resolved": "https://registry.npmjs.org/rc-util/-/rc-util-5.38.1.tgz", - "integrity": "sha512-e4ZMs7q9XqwTuhIK7zBIVFltUtMSjphuPPQXHoHlzRzNdOwUxDejo0Zls5HYaJfRKNURcsS/ceKVULlhjBrxng==", + "version": "5.39.1", + "resolved": "https://registry.npmjs.org/rc-util/-/rc-util-5.39.1.tgz", + "integrity": "sha512-OW/ERynNDgNr4y0oiFmtes3rbEamXw7GHGbkbNd9iRr7kgT03T6fT0b9WpJ3mbxKhyOcAHnGcIoh5u/cjrC2OQ==", "dependencies": { "@babel/runtime": "^7.18.3", "react-is": "^18.2.0" diff --git a/website/package.json b/website/package.json index 550d46695..626a7b0e4 100644 --- a/website/package.json +++ b/website/package.json @@ -19,7 +19,7 @@ "@docusaurus/plugin-client-redirects": "^3.1.1", "@docusaurus/preset-classic": "^3.1.1", "@docusaurus/theme-mermaid": "^3.1.1", - "@grnet/docusaurus-terminology": "^2.0.0-rc", + "@grnet/docusaurus-terminology": "^2.0.0-rc.1", "@mdx-js/react": "^3.0.1", "clsx": "^2.1.0", "custom-loaders": "file:plugins/custom-loaders", diff --git a/website/static/schemas/atmos/atmos-manifest/1.0/atmos-manifest.json b/website/static/schemas/atmos/atmos-manifest/1.0/atmos-manifest.json index 50617fdb7..d7bd762a8 100644 --- a/website/static/schemas/atmos/atmos-manifest/1.0/atmos-manifest.json +++ b/website/static/schemas/atmos/atmos-manifest/1.0/atmos-manifest.json @@ -439,7 +439,8 @@ "vault", "static", "azurerm", - "gcs" + "gcs", + "cloud" ], "description": "Backend type", "title": "backend_type" @@ -455,7 +456,9 @@ "remote", "vault", "static", - "azurerm" + "azurerm", + "gcs", + "cloud" ], "description": "Remote state backend type", "title": "remote_state_backend_type" @@ -523,6 +526,14 @@ "azurerm": { "type": "object", "additionalProperties": true + }, + "gcs": { + "type": "object", + "additionalProperties": true + }, + "cloud": { + "type": "object", + "additionalProperties": true } }, "required": [],