Skip to content

Commit

Permalink
Add Atlantis support. Add atmos terraform generate varfiles and `at…
Browse files Browse the repository at this point in the history
…mos atlantis generate repo-config` CLI commands (#189)

* Add custom integrations

* Add custom integrations

* Add custom integrations

* Add custom integrations

* Add `terraform generate varfiles` command

* Add `terraform generate varfiles` command

* Add `terraform generate varfiles` command

* Add `terraform generate varfiles` command

* Add `terraform generate varfiles` command

* Add `terraform generate varfiles` command

* Add `terraform generate varfiles` command

* Add `terraform generate varfiles` command

* Add `terraform generate varfiles` command

* Add `terraform generate varfiles` command

* Add `terraform generate varfiles` command

* Add `terraform generate varfiles` command

* Add `terraform generate varfiles` command

* Add `terraform generate varfiles` command

* Add `terraform generate varfiles` command

* Add `terraform generate varfiles` command

* Add `terraform generate varfiles` command

* Add `terraform generate varfiles` command

* Add `terraform generate varfiles` command

* Add `terraform generate varfiles` command

* Add `terraform generate varfiles` command

* Add `terraform generate varfiles` command

* Add `terraform generate varfiles` command

* Add `terraform generate varfiles` command

* Add `terraform generate varfiles` command

* Add `atlantis` commands

* Add `atlantis generate repo-config` command

* Add `atlantis generate repo-config` command

* Add `atlantis generate repo-config` command

* Add `atlantis generate repo-config` command

* Add `atlantis generate repo-config` command

* Add `atlantis generate repo-config` command

* Add `atlantis generate repo-config` command

* Add `atlantis generate repo-config` command

* Add `atlantis generate repo-config` command

* Add `atlantis generate repo-config` command

* Add `atlantis generate repo-config` command

* Add `atlantis generate repo-config` command

* Update README

* Cleanup code

* Cleanup code

* Updates

* Updates

* Updates

* Updates

* Updates

* Updates

* Updates

* Updates

* Updates

* Updates

* Updates

* Updates

* Updates

* Updates

* Updates

* Updates

* Updates

* Updates
  • Loading branch information
aknysh committed Sep 7, 2022
1 parent 9940032 commit 9189ae8
Show file tree
Hide file tree
Showing 25 changed files with 1,364 additions and 92 deletions.
63 changes: 63 additions & 0 deletions atmos.yaml
Expand Up @@ -128,3 +128,66 @@ commands:
steps:
- echo Playing ping-pong...
- echo pong

# Integrations
integrations:

# Atlantis integration
# https://www.runatlantis.io/docs/repo-level-atlantis-yaml.html
atlantis:
# Path and name of the Atlantis config file `atlantis.yaml`
# Supports absolute and relative paths
# All the intermediate folders will be created automatically (e.g. `path: /config/atlantis/atlantis.yaml`)
# Can be overridden on the command line by using `--output-path` command-line argument in `atmos atlantis generate repo-config` command
# If not specified (set to an empty string/omitted here, and set to an empty string on the command line), the content of the file will be dumped to `stdout`
# On Linux/macOS, you can also use `--output-path=/dev/stdout` to dump the content to `stdout` without setting it to an empty string in `atlantis.path`
path: "atlantis.yaml"

# Config templates
# Select a template by using the `--config-template <config_template>` command-line argument in `atmos atlantis generate repo-config` command
config_templates:
config-1:
version: 3
automerge: true
delete_source_branch_on_merge: true
parallel_plan: true
parallel_apply: true
allowed_regexp_prefixes:
- dev/
- staging/
- prod/

# Project templates
# Select a template by using the `--project-template <project_template>` command-line argument in `atmos atlantis generate repo-config` command
project_templates:
project-1:
# generate a project entry for each component in every stack
name: "{tenant}-{environment}-{stage}-{component}"
workspace: "{workspace}"
dir: "{component-path}"
terraform_version: v1.2
delete_source_branch_on_merge: true
autoplan:
enabled: true
when_modified:
- "**/*.tf"
- "varfiles/$PROJECT_NAME.tfvars.json"
apply_requirements:
- "approved"

# Workflow templates
# https://www.runatlantis.io/docs/custom-workflows.html#custom-init-plan-apply-commands
# https://www.runatlantis.io/docs/custom-workflows.html#custom-run-command
# Select a template by using the `--workflow-template <workflow_template>` command-line argument in `atmos atlantis generate repo-config` command
workflow_templates:
workflow-1:
plan:
steps:
- run: terraform init -input=false
# When using workspaces, you need to select the workspace using the $WORKSPACE environment variable
- run: terraform workspace select $WORKSPACE
# You must output the plan using `-out $PLANFILE` because Atlantis expects plans to be in a specific location
- run: terraform plan -input=false -refresh -out $PLANFILE -var-file varfiles/$PROJECT_NAME.tfvars.json
apply:
steps:
- run: terraform apply $PLANFILE
17 changes: 17 additions & 0 deletions cmd/atlantis.go
@@ -0,0 +1,17 @@
package cmd

import (
"github.com/spf13/cobra"
)

// atlantisCmd executes Atlantis commands
var atlantisCmd = &cobra.Command{
Use: "atlantis",
Short: "Execute 'atlantis' commands",
Long: `This command executes Atlantis integration commands`,
FParseErrWhitelist: struct{ UnknownFlags bool }{UnknownFlags: false},
}

func init() {
RootCmd.AddCommand(atlantisCmd)
}
17 changes: 17 additions & 0 deletions cmd/atlantis_generate.go
@@ -0,0 +1,17 @@
package cmd

import (
"github.com/spf13/cobra"
)

// atlantisGenerateCmd generates various Atlantis configurations
var atlantisGenerateCmd = &cobra.Command{
Use: "generate",
Short: "Execute 'atlantis generate' commands",
Long: "This command generates various Atlantis configurations",
FParseErrWhitelist: struct{ UnknownFlags bool }{UnknownFlags: true},
}

func init() {
atlantisCmd.AddCommand(atlantisGenerateCmd)
}
61 changes: 61 additions & 0 deletions cmd/atlantis_generate_repo_config.go
@@ -0,0 +1,61 @@
package cmd

import (
e "github.com/cloudposse/atmos/internal/exec"
u "github.com/cloudposse/atmos/pkg/utils"
"github.com/spf13/cobra"
)

// atlantisGenerateRepoConfigCmd generates repository configuration for Atlantis
var atlantisGenerateRepoConfigCmd = &cobra.Command{
Use: "repo-config",
Short: "Execute 'atlantis generate repo-config`",
Long: "This command generates repository configuration for Atlantis",
FParseErrWhitelist: struct{ UnknownFlags bool }{UnknownFlags: true},
Run: func(cmd *cobra.Command, args []string) {
err := e.ExecuteAtlantisGenerateRepoConfigCmd(cmd, args)
if err != nil {
u.PrintErrorToStdErrorAndExit(err)
}
},
}

func init() {
atlantisGenerateRepoConfigCmd.DisableFlagParsing = false

atlantisGenerateRepoConfigCmd.PersistentFlags().String("output-path", "", "atmos atlantis generate repo-config --output-path ./atmos.yaml --config-template config-1 --project-template project-1 --workflow-template workflow-1")
atlantisGenerateRepoConfigCmd.PersistentFlags().String("config-template", "", "atmos atlantis generate repo-config --config-template config-1 --project-template project-1 --workflow-template workflow-1")
atlantisGenerateRepoConfigCmd.PersistentFlags().String("project-template", "", "atmos atlantis generate repo-config --config-template config-1 --project-template project-1 --workflow-template workflow-1")
atlantisGenerateRepoConfigCmd.PersistentFlags().String("workflow-template", "", "atmos atlantis generate repo-config --config-template config-1 --project-template project-1 --workflow-template workflow-1")

atlantisGenerateRepoConfigCmd.PersistentFlags().String("stacks", "",
"Only generate config for the specified stacks (comma-separated values).\n"+
"atmos atlantis generate repo-config --config-template <config_template> --project-template <project_template> --stacks <stack1>,<stack2>\n"+
"The filter can contain the names of the top-level stack config files and the logical stack names (derived from the context vars)\n"+
"atmos atlantis generate repo-config --config-template <config_template> --project-template <project_template> --workflow-template <workflow_template> --stacks orgs/cp/tenant1/staging/us-east-2,orgs/cp/tenant2/dev/us-east-2\n"+
"atmos atlantis generate repo-config --config-template <config_template> --project-template <project_template> --workflow-template <workflow_template> --stacks tenant1-ue2-staging,tenant1-ue2-prod\n"+
"atmos atlantis generate repo-config --config-template <config_template> --project-template <project_template> --workflow-template <workflow_template> --stacks orgs/cp/tenant1/staging/us-east-2,tenant1-ue2-prod",
)

atlantisGenerateRepoConfigCmd.PersistentFlags().String("components", "",
"Only generate config for the specified components (comma-separated values).\n"+
"atmos atlantis generate repo-config --config-template <config_template> --project-template <project_template> --workflow-template <workflow_template> --components <component1>,<component2>",
)

err := atlantisGenerateRepoConfigCmd.MarkPersistentFlagRequired("config-template")
if err != nil {
u.PrintErrorToStdErrorAndExit(err)
}

err = atlantisGenerateRepoConfigCmd.MarkPersistentFlagRequired("project-template")
if err != nil {
u.PrintErrorToStdErrorAndExit(err)
}

err = atlantisGenerateRepoConfigCmd.MarkPersistentFlagRequired("workflow-template")
if err != nil {
u.PrintErrorToStdErrorAndExit(err)
}

atlantisGenerateCmd.AddCommand(atlantisGenerateRepoConfigCmd)
}
59 changes: 59 additions & 0 deletions cmd/terraform_generate_varfiles.go
@@ -0,0 +1,59 @@
package cmd

import (
e "github.com/cloudposse/atmos/internal/exec"
u "github.com/cloudposse/atmos/pkg/utils"
"github.com/spf13/cobra"
)

// terraformGenerateVarfilesCmd generates varfiles for all terraform components in all stacks
var terraformGenerateVarfilesCmd = &cobra.Command{
Use: "varfiles",
Short: "Execute 'terraform generate varfiles' command",
Long: `This command generates varfiles for all terraform components in all stacks`,
FParseErrWhitelist: struct{ UnknownFlags bool }{UnknownFlags: false},
Run: func(cmd *cobra.Command, args []string) {
err := e.ExecuteTerraformGenerateVarfilesCmd(cmd, args)
if err != nil {
u.PrintErrorToStdErrorAndExit(err)
}
},
}

func init() {
terraformGenerateVarfilesCmd.DisableFlagParsing = false

terraformGenerateVarfilesCmd.PersistentFlags().String("file-template", "",
"Varfile template (the file path, file name, and file extension).\n"+
"Supports absolute and relative paths.\n"+
"Supports context tokens: {namespace}, {tenant}, {environment}, {region}, {stage}, {component}, {component-path}.\n"+
"atmos terraform generate varfiles --file-template {component-path}/{environment}-{stage}.tfvars.json\n"+
"atmos terraform generate varfiles --file-template /configs/{tenant}/{environment}/{stage}/{component}.json\n"+
"atmos terraform generate varfiles --file-template /{tenant}/{stage}/{region}/{component}.yaml\n"+
"All subfolders in the path will be created automatically.",
)

terraformGenerateVarfilesCmd.PersistentFlags().String("stacks", "",
"Only process the specified stacks (comma-separated values).\n"+
"atmos terraform generate varfiles --file-template <file_template> --stacks <stack1>,<stack2>\n"+
"The filter can contain the names of the top-level stack config files and the logical stack names (derived from the context vars)\n"+
"atmos terraform generate varfiles --stacks orgs/cp/tenant1/staging/us-east-2,orgs/cp/tenant2/dev/us-east-2\n"+
"atmos terraform generate varfiles --stacks tenant1-ue2-staging,tenant1-ue2-prod\n"+
"atmos terraform generate varfiles --stacks orgs/cp/tenant1/staging/us-east-2,tenant1-ue2-prod",
)

terraformGenerateVarfilesCmd.PersistentFlags().String("components", "",
"Only process the specified components (comma-separated values).\n"+
"atmos terraform generate varfiles --file-template <file_template> --components <component1>,<component2>",
)

terraformGenerateVarfilesCmd.PersistentFlags().String("format", "json", "Output format.\n"+
"atmos terraform generate varfiles --file-template <file_template> --format=json/yaml ('json' is default)")

err := terraformGenerateVarfilesCmd.MarkPersistentFlagRequired("file-template")
if err != nil {
u.PrintErrorToStdErrorAndExit(err)
}

terraformGenerateCmd.AddCommand(terraformGenerateVarfilesCmd)
}
2 changes: 1 addition & 1 deletion examples/complete/Dockerfile
Expand Up @@ -2,7 +2,7 @@
ARG GEODESIC_VERSION=1.2.3
ARG GEODESIC_OS=debian
# atmos: https://github.com/cloudposse/atmos
ARG ATMOS_VERSION=1.4.28
ARG ATMOS_VERSION=1.5.0
# Terraform: https://github.com/hashicorp/terraform/releases
ARG TF_VERSION=1.2.8

Expand Down
63 changes: 63 additions & 0 deletions examples/complete/atmos.yaml
Expand Up @@ -128,3 +128,66 @@ commands:
steps:
- echo Playing ping-pong...
- echo pong

# Integrations
integrations:

# Atlantis integration
# https://www.runatlantis.io/docs/repo-level-atlantis-yaml.html
atlantis:
# Path and name of the Atlantis config file `atlantis.yaml`
# Supports absolute and relative paths
# All the intermediate folders will be created automatically (e.g. `path: /config/atlantis/atlantis.yaml`)
# Can be overridden on the command line by using `--output-path` command-line argument in `atmos atlantis generate repo-config` command
# If not specified (set to an empty string/omitted here, and set to an empty string on the command line), the content of the file will be dumped to `stdout`
# On Linux/macOS, you can also use `--output-path=/dev/stdout` to dump the content to `stdout` without setting it to an empty string in `atlantis.path`
path: "atlantis.yaml"

# Config templates
# Select a template by using the `--config-template <config_template>` command-line argument in `atmos atlantis generate repo-config` command
config_templates:
config-1:
version: 3
automerge: true
delete_source_branch_on_merge: true
parallel_plan: true
parallel_apply: true
allowed_regexp_prefixes:
- dev/
- staging/
- prod/

# Project templates
# Select a template by using the `--project-template <project_template>` command-line argument in `atmos atlantis generate repo-config` command
project_templates:
project-1:
# generate a project entry for each component in every stack
name: "{tenant}-{environment}-{stage}-{component}"
workspace: "{workspace}"
dir: "{component-path}"
terraform_version: v1.2
delete_source_branch_on_merge: true
autoplan:
enabled: true
when_modified:
- "**/*.tf"
- "varfiles/$PROJECT_NAME.tfvars.json"
apply_requirements:
- "approved"

# Workflow templates
# https://www.runatlantis.io/docs/custom-workflows.html#custom-init-plan-apply-commands
# https://www.runatlantis.io/docs/custom-workflows.html#custom-run-command
# Select a template by using the `--workflow-template <workflow_template>` command-line argument in `atmos atlantis generate repo-config` command
workflow_templates:
workflow-1:
plan:
steps:
- run: terraform init -input=false
# When using workspaces, you need to select the workspace using the $WORKSPACE environment variable
- run: terraform workspace select $WORKSPACE
# You must output the plan using `-out $PLANFILE` because Atlantis expects plans to be in a specific location
- run: terraform plan -input=false -refresh -out $PLANFILE -var-file varfiles/$PROJECT_NAME.tfvars.json
apply:
steps:
- run: terraform apply $PLANFILE
2 changes: 1 addition & 1 deletion examples/complete/stacks/mixins/region/us-east-1.yaml
Expand Up @@ -4,7 +4,7 @@ vars:

components:
terraform:
vpc:
infra/vpc:
vars:
availability_zones:
- us-east-1a
Expand Down
2 changes: 1 addition & 1 deletion examples/complete/stacks/mixins/region/us-east-2.yaml
Expand Up @@ -4,7 +4,7 @@ vars:

components:
terraform:
vpc:
infra/vpc:
vars:
availability_zones:
- us-east-2a
Expand Down
36 changes: 20 additions & 16 deletions go.mod
Expand Up @@ -12,23 +12,27 @@ require (
github.com/otiai10/copy v1.7.0
github.com/pkg/errors v0.9.1
github.com/spf13/cobra v1.5.0
github.com/spf13/viper v1.12.0
github.com/spf13/viper v1.13.0
github.com/stretchr/testify v1.8.0
gopkg.in/yaml.v2 v2.4.0
)

require (
cloud.google.com/go v0.100.2 // indirect
cloud.google.com/go/compute v1.6.1 // indirect
cloud.google.com/go/iam v0.3.0 // indirect
cloud.google.com/go/storage v1.14.0 // indirect
cloud.google.com/go v0.102.1 // indirect
cloud.google.com/go/compute v1.7.0 // indirect
cloud.google.com/go/iam v0.4.0 // indirect
cloud.google.com/go/storage v1.22.1 // indirect
github.com/aws/aws-sdk-go v1.15.78 // indirect
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fsnotify/fsnotify v1.5.4 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/go-cmp v0.5.8 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.1.0 // indirect
github.com/googleapis/gax-go/v2 v2.4.0 // indirect
github.com/googleapis/go-type-adapters v1.0.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-safetemp v1.0.0 // indirect
github.com/hashicorp/go-version v1.1.0 // indirect
Expand All @@ -44,25 +48,25 @@ require (
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pelletier/go-toml v1.9.5 // indirect
github.com/pelletier/go-toml/v2 v2.0.1 // indirect
github.com/pelletier/go-toml/v2 v2.0.5 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/spf13/afero v1.8.2 // indirect
github.com/spf13/cast v1.5.0 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/subosito/gotenv v1.3.0 // indirect
github.com/subosito/gotenv v1.4.1 // indirect
github.com/ulikunitz/xz v0.5.8 // indirect
go.opencensus.io v0.23.0 // indirect
golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2 // indirect
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 // indirect
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e // indirect
golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2 // indirect
golang.org/x/sys v0.0.0-20220624220833-87e55d714810 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df // indirect
google.golang.org/api v0.81.0 // indirect
golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f // indirect
google.golang.org/api v0.93.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd // indirect
google.golang.org/grpc v1.46.2 // indirect
google.golang.org/protobuf v1.28.0 // indirect
gopkg.in/ini.v1 v1.66.4 // indirect
google.golang.org/genproto v0.0.0-20220815135757-37a418bb8959 // indirect
google.golang.org/grpc v1.48.0 // indirect
google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

0 comments on commit 9189ae8

Please sign in to comment.