Skip to content

Implement atmos toolchain to install 3rd party tools #927

@osterman

Description

@osterman

Describe the Feature

Atmos should automatically add the packages base-path as a priority search PATH when executing any commands.

Expected Behavior

Packages are automatically installed and available to atmos components, custom commands, and workflows.

When running atmos terraform plan and it depends on opentofu@1.10.3, if not installed it should automatically install it (if it's configured).

When running a custom command, that needs tflint, it should be able to automatically install it.

When running a workflow that needs tfsec, it should automatically install it.

Available Commands:
  add         Add or update a tool and version in .tool-versions
  aliases     List configured tool aliases
  clean       Remove all installed tools by deleting the .tools directory
  completion  Generate the autocompletion script for the specified shell
  exec        Exec a specific version of a tool (replaces current process)
  get         Show all versions configured for a tool, sorted in semver order
  help        Help about any command
  info        Display tool configuration from registry
  install     Install a CLI binary from the registry
  list        List configured tools and their installation status
  path        Emit the complete PATH environment variable for configured tool versions
  remove      Remove a tool or a specific version from .tool-versions
  run         Run a specific version of a tool
  set         Set a specific version for a tool in .tool-versions
  uninstall   Uninstall a CLI binary from the registry
  which       Display the path to an executable

Flags:
  -h, --help                   help for toolchain
      --log-level string       Set log level (debug, info, warn, error)
      --tool-versions string   Path to tool-versions file (default ".tool-versions")
      --tools-config string    Path to tools configuration file (default "tools.yaml")
      --tools-dir string       Directory to store installed tools (default ".tools")

Use Case

  • Install versions of opentofu or terraform
  • Install helmfile
  • Install terraform-docs, tflint, etc.
  • Support multiple concurrent versions
  • Install any other binaries needed by workflows, custom commands, etc
  • Atmos should act as a wrapper for atmos, to install and exec any version of atmos using the use keyword

Describe Ideal Solution

Atmos Commands

# Install all packages
atmos toolchain install
# Update packages 
atmos toolchain update

Atmos Configuration

# atmos.yaml

# Automatically install (if not installed) and use this version of atmos, and exec (replacing PID).
# See `exec` example in `toolchain-experiment`
# THis replaces the current process, it's NOT A SUBSHELL.
# This ensures everyone uses the right version based on the configuration.
use 1.183.1


# Define packages required for a specific type of component
# In this example, we're refering to the "opentofu" alias and 
# specifying the version of 1.10.3
components:
  terraform:
    command: opentofu@1.10.3
  helmfile:
    command: helmfile@1.1.3

The use keyword will install atmos at version 1.183.1, then call syscall.Exec to replace the current process with the atmos at the correct version, if the current version is not already 1.183.1.

Aliases

Aliases map a short name like opentofu to a registry configuration of opentofu/opentofu or terraform to something like hashicorp/terraform

# toolchain subcommand configuration
toolchain:

  
  # Tool name aliases for .tool-versions compatibility
  # Maps common tool names to their registry owner/repo paths
  aliases:
    terraform: hashicorp/terraform
    opentofu: opentofu/opentofu
    helm: helm/helm
    kubectl: kubernetes-sigs/kubectl
    kustomize: kubernetes-sigs/kustomize
    kind: kubernetes-sigs/kind
    krew: kubernetes-sigs/krew
    github-comment: suzuki-shunsuke/github-comment
    tflint: terraform-linters/tflint
    tfsec: aquasecurity/tfsec
    checkov: bridgecrewio/checkov
    terragrunt: gruntwork-io/terragrunt
    packer: hashicorp/packer
    vault: hashicorp/vault
    consul: hashicorp/consul
    nomad: hashicorp/nomad
    waypoint: hashicorp/waypoint
    boundary: hashicorp/boundary
    helmfile: helmfile/helmfile
    atmos: cloudposse/atmos

Tool Versions

We should use the simple .tool-versions convention popularized by asdf

tool1 1.2.3 4.5.7
tool2 2.3.4
tool3 5.6.7

The first semver is the default version, when nothing is specified

This file is consulted when calling install/uninstall/add/remove.

We should use aliases in this file to refer to toolchain tools. This is so we can change the mapping in the future.

Aqua Registry Configuration

We're going to add partial Aqua support for registries and expand the implementation over time. To start, we want to support the essential packages we depend on.

Local Configuration

We also want a local toolchain configuration, when not depending on the Aqua registry.

# toolchain subcommand configuration
toolchain:

  # this is relative to the repo root
  install-dir: .tools/bin

  # Local tools configuration
  # This file is consulted first before the Aqua registry
  # Allows local overrides and custom tool definitions
  

  tools:
    # Atmos configuration supporting both raw and gzipped binaries
    cloudposse/atmos:
      type: github_release
      repo_owner: cloudposse
      repo_name: atmos
      binary_name: atmos
      version_constraints:
        - constraint: ">= 1.0.0"
          asset: atmos_{{trimV .Version}}_{{.OS}}_{{.Arch}}
          format: raw
        - constraint: ">= 1.0.0"
          asset: atmos_{{trimV .Version}}_{{.OS}}_{{.Arch}}.gz
          format: gzip
  
    # Override a registry tool with local settings
    hashicorp/terraform:
      type: http
      url: https://releases.hashicorp.com/terraform/{{trimV .Version}}/terraform_{{trimV .Version}}_{{.OS}}_{{.Arch}}.zip
      format: zip
      binary_name: terraform
  
    # TFLint configuration
    terraform-linters/tflint:
      type: github_release
      repo_owner: terraform-linters
      repo_name: tflint
      binary_name: tflint
  
    # Custom tool not in registry
    my-custom-tool:
      type: github_release
      repo_owner: myorg
      repo_name: my-custom-tool
      asset: my-custom-tool_{{trimV .Version}}_{{.OS}}_{{.Arch}}.tar.gz
      format: tar.gz
      binary_name: my-custom-tool
  
    # Override OpenTofu to use a specific version constraint
    opentofu/opentofu:
      type: github_release
      repo_owner: opentofu
      repo_name: opentofu
      binary_name: tofu
      version_constraints:
        - constraint: ">= 1.10.0"
          asset: tofu_{{trimV .Version}}_{{.OS}}_{{.Arch}}.tar.gz
          format: tar.gz
        - constraint: "< 1.10.0"
          asset: tofu_{{trimV .Version}}_{{.OS}}_{{.Arch}}.zip
          format: zip
  
    helm/helm:
      type: http
      repo_owner: helm
      repo_name: helm
      url: https://get.helm.sh/helm-v{{.Version}}-{{.OS}}-{{.Arch}}.tar.gz
      format: tar.gz
      binary_name: helm

Stack Configuration

# stacks/_defaults.yaml
components:
  terraform:
    vpc:
      command: hashicorp/terraform@v1.11.4

When the command is evaluated, it's first checked against the toolchain, and if it's not installed, it will be automatically installed.

The PATH for exec will be updated to use the directory containing terraform for version 1.11.4

Workflows

workflows:
  tflint:
    description: "Run tflint on a component"
    needs:
    - tflint@1.2.3
    - opentofu@1.10.3
    steps:
      - name: tflint
        type: shell
        command: |
          cd terraform/components
          tflint --recursive

Custom Commands

# Custom CLI commands
commands:
  - name: tfsec
    description: Run tfsec against a specified Terraform component
    arguments:
      - name: component
        description: Name of the component to scan
    needs:
    - tfsec@1.2.3
    steps:
      # Navigate to the Terraform component directory
      - cd components/terraform/{{ .Arguments.component }}
      # Run tfsec scan
      - tfsec .

Alternatives Considered

Using aqua directly. However, the aims of the Aqua Project are different than our aims and Aqua does not expose an SDK or stable interfaces for other CLIs to use Aqua.

https://github.com/suzuki-shunsuke

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions