Skip to content

Commit

Permalink
Set custom User Agent for Terraform providers (#729)
Browse files Browse the repository at this point in the history
* feat: extend terraform schema for append user agent

* Set custom user agent for terraform #2335

* fix: trim user aggent in append user

* feat: adding user aggent for terraform second step

* added new pkg version for more modular packages

* flag for user append agent

* improve error msg for append user flag

* added append user agent flag in docs

* update print append user aggent message

* add append user agent to atmos yaml and rename it

* updated usage terraform docs

* utils flag standard for append user agent

* added generic data for append user agent command docs

* user append flag docs added

* feat: update help print message

* feat: update help print message

---------

Co-authored-by: Andriy Knysh <[email protected]>
  • Loading branch information
Cerebrovinny and aknysh authored Oct 29, 2024
1 parent 5a9eaf1 commit a48ed22
Show file tree
Hide file tree
Showing 16 changed files with 70 additions and 14 deletions.
2 changes: 1 addition & 1 deletion .goreleaser.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ builds:
binary: atmos
ldflags:
# Set `atmos` version to the GitHub release tag using Go `ldflags`
- '-s -w -X "github.com/cloudposse/atmos/cmd.Version={{.Version}}"'
- '-s -w -X "github.com/cloudposse/atmos/pkg/version.Version={{.Version}}"'

archives:
- format: binary
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ get:
go get

build: get
env $(if $(GOOS),GOOS=$(GOOS)) $(if $(GOARCH),GOARCH=$(GOARCH)) go build -o build/atmos -v -ldflags "-X 'github.com/cloudposse/atmos/cmd.Version=${VERSION}'"
env $(if $(GOOS),GOOS=$(GOOS)) $(if $(GOARCH),GOARCH=$(GOARCH)) go build -o build/atmos -v -ldflags "-X 'github.com/cloudposse/atmos/pkg/version.Version=${VERSION}'"

version: build
chmod +x ./build/atmos
Expand Down
2 changes: 1 addition & 1 deletion build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

version="0.0.1"

go build -o build/atmos -v -ldflags "-X 'github.com/cloudposse/atmos/cmd.Version=$version'"
go build -o build/atmos -v -ldflags "-X 'github.com/cloudposse/atmos/version.Version=$version'"

# https://www.digitalocean.com/community/tutorials/using-ldflags-to-set-version-information-for-go-applications
# https://blog.kowalczyk.info/article/vEja/embedding-build-number-in-go-executable.html
Expand Down
7 changes: 3 additions & 4 deletions cmd/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,9 @@ import (
tuiUtils "github.com/cloudposse/atmos/internal/tui/utils"
"github.com/cloudposse/atmos/pkg/schema"
u "github.com/cloudposse/atmos/pkg/utils"
"github.com/cloudposse/atmos/pkg/version"
)

var Version = "0.0.1"

var versionCmd = &cobra.Command{
Use: "version",
Short: "Print the CLI version",
Expand All @@ -27,14 +26,14 @@ var versionCmd = &cobra.Command{
u.LogErrorAndExit(schema.CliConfiguration{}, err)
}

u.PrintMessage(fmt.Sprintf("\U0001F47D Atmos %s on %s/%s", Version, runtime.GOOS, runtime.GOARCH))
u.PrintMessage(fmt.Sprintf("\U0001F47D Atmos %s on %s/%s", version.Version, runtime.GOOS, runtime.GOARCH))
fmt.Println()

// Check for the latest Atmos release on GitHub
latestReleaseTag, err := u.GetLatestGitHubRepoRelease("cloudposse", "atmos")
if err == nil && latestReleaseTag != "" {
latestRelease := strings.TrimPrefix(latestReleaseTag, "v")
currentRelease := strings.TrimPrefix(Version, "v")
currentRelease := strings.TrimPrefix(version.Version, "v")
if latestRelease != currentRelease {
printMessageToUpgradeToAtmosLatestRelease(latestRelease)
}
Expand Down
6 changes: 6 additions & 0 deletions internal/exec/help.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

"github.com/cloudposse/atmos/pkg/schema"
u "github.com/cloudposse/atmos/pkg/utils"
"github.com/cloudposse/atmos/pkg/version"
)

// processHelp processes help commands
Expand Down Expand Up @@ -45,6 +46,11 @@ func processHelp(componentType string, command string) error {
u.PrintMessage(" - double-dash '--' can be used to signify the end of the options for Atmos and the start of the additional " +
"native arguments and flags for the 'terraform' commands. " +
"For example: atmos terraform plan <component> -s <stack> -- -refresh=false -lock=false")

u.PrintMessage(fmt.Sprintf(" - '--append-user-agent' flag sets the TF_APPEND_USER_AGENT environment variable to customize the User-Agent string in Terraform provider requests. "+
"Example: 'Atmos/%s (Cloud Posse; +https://atmos.tools)'. "+
"If not specified, defaults to 'atmos %s'\n", version.Version, version.Version))

}

if componentType == "helmfile" {
Expand Down
10 changes: 10 additions & 0 deletions internal/exec/terraform.go
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,16 @@ func ExecuteTerraform(info schema.ConfigAndStacksInfo) error {
// https://developer.hashicorp.com/terraform/cli/config/environment-variables#tf_in_automation
info.ComponentEnvList = append(info.ComponentEnvList, "TF_IN_AUTOMATION=true")

// Set 'TF_APPEND_USER_AGENT' ENV var based on precedence
// Precedence: Environment Variable > atmos.yaml > Default
appendUserAgent := cliConfig.Components.Terraform.AppendUserAgent
if envUA, exists := os.LookupEnv("TF_APPEND_USER_AGENT"); exists && envUA != "" {
appendUserAgent = envUA
}
if appendUserAgent != "" {
info.ComponentEnvList = append(info.ComponentEnvList, fmt.Sprintf("TF_APPEND_USER_AGENT=%s", appendUserAgent))
}

// Print ENV vars if they are found in the component's stack config
if len(info.ComponentEnvList) > 0 {
u.LogDebug(cliConfig, "\nUsing ENV vars:")
Expand Down
14 changes: 14 additions & 0 deletions internal/exec/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ var (
cfg.DeployRunInitFlag,
cfg.InitRunReconfigure,
cfg.AutoGenerateBackendFileFlag,
cfg.AppendUserAgentFlag,
cfg.FromPlanFlag,
cfg.PlanFileFlag,
cfg.HelpFlag1,
Expand Down Expand Up @@ -668,6 +669,19 @@ func processArgsAndFlags(componentType string, inputArgsAndFlags []string) (sche
info.TerraformDir = terraformDirFlagParts[1]
}

if arg == cfg.AppendUserAgentFlag {
if len(inputArgsAndFlags) <= (i + 1) {
return info, fmt.Errorf("invalid flag: %s", arg)
}
info.AppendUserAgent = inputArgsAndFlags[i+1]
} else if strings.HasPrefix(arg+"=", cfg.AppendUserAgentFlag) {
var appendUserAgentFlagParts = strings.Split(arg, "=")
if len(appendUserAgentFlagParts) != 2 {
return info, fmt.Errorf("invalid flag: %s", arg)
}
info.AppendUserAgent = appendUserAgentFlagParts[1]
}

if arg == cfg.HelmfileCommandFlag {
if len(inputArgsAndFlags) <= (i + 1) {
return info, fmt.Errorf("invalid flag: %s", arg)
Expand Down
8 changes: 8 additions & 0 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (

"github.com/cloudposse/atmos/pkg/schema"
u "github.com/cloudposse/atmos/pkg/utils"
"github.com/cloudposse/atmos/pkg/version"
)

var (
Expand Down Expand Up @@ -43,6 +44,7 @@ var (
DeployRunInit: true,
InitRunReconfigure: true,
AutoGenerateBackendFile: true,
AppendUserAgent: fmt.Sprintf("Atmos/%s (Cloud Posse; +https://atmos.tools)", version.Version),
},
Helmfile: schema.Helmfile{
BasePath: "components/helmfile",
Expand Down Expand Up @@ -105,6 +107,7 @@ func InitCliConfig(configAndStacksInfo schema.ConfigAndStacksInfo, processStacks

// Default configuration values
v.SetDefault("components.helmfile.use_eks", true)
v.SetDefault("components.terraform.append_user_agent", fmt.Sprintf("Atmos/%s (Cloud Posse; +https://atmos.tools)", version.Version))

// Process config in system folder
configFilePath1 := ""
Expand Down Expand Up @@ -243,6 +246,11 @@ func InitCliConfig(configAndStacksInfo schema.ConfigAndStacksInfo, processStacks
cliConfig.BasePath = configAndStacksInfo.AtmosBasePath
}

// After unmarshalling, ensure AppendUserAgent is set if still empty
if cliConfig.Components.Terraform.AppendUserAgent == "" {
cliConfig.Components.Terraform.AppendUserAgent = fmt.Sprintf("Atmos/%s (Cloud Posse; +https://atmos.tools)", version.Version)
}

// Check config
err = checkConfig(cliConfig)
if err != nil {
Expand Down
1 change: 1 addition & 0 deletions pkg/config/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ const (

DeployRunInitFlag = "--deploy-run-init"
AutoGenerateBackendFileFlag = "--auto-generate-backend-file"
AppendUserAgentFlag = "--append-user-agent"
InitRunReconfigure = "--init-run-reconfigure"

FromPlanFlag = "--from-plan"
Expand Down
6 changes: 6 additions & 0 deletions pkg/config/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,12 @@ func processEnvVars(cliConfig *schema.CliConfiguration) error {
cliConfig.Logs.Level = logsLevel
}

tfAppendUserAgent := os.Getenv("ATMOS_COMPONENTS_TERRAFORM_APPEND_USER_AGENT")
if len(tfAppendUserAgent) > 0 {
u.LogTrace(*cliConfig, fmt.Sprintf("Found ENV var ATMOS_COMPONENTS_TERRAFORM_APPEND_USER_AGENT=%s", tfAppendUserAgent))
cliConfig.Components.Terraform.AppendUserAgent = tfAppendUserAgent
}

listMergeStrategy := os.Getenv("ATMOS_SETTINGS_LIST_MERGE_STRATEGY")
if len(listMergeStrategy) > 0 {
u.LogTrace(*cliConfig, fmt.Sprintf("Found ENV var ATMOS_SETTINGS_LIST_MERGE_STRATEGY=%s", listMergeStrategy))
Expand Down
2 changes: 2 additions & 0 deletions pkg/schema/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ type TemplatesSettingsGomplate struct {
type Terraform struct {
BasePath string `yaml:"base_path" json:"base_path" mapstructure:"base_path"`
ApplyAutoApprove bool `yaml:"apply_auto_approve" json:"apply_auto_approve" mapstructure:"apply_auto_approve"`
AppendUserAgent string `yaml:"append_user_agent" json:"append_user_agent" mapstructure:"append_user_agent"`
DeployRunInit bool `yaml:"deploy_run_init" json:"deploy_run_init" mapstructure:"deploy_run_init"`
InitRunReconfigure bool `yaml:"init_run_reconfigure" json:"init_run_reconfigure" mapstructure:"init_run_reconfigure"`
AutoGenerateBackendFile bool `yaml:"auto_generate_backend_file" json:"auto_generate_backend_file" mapstructure:"auto_generate_backend_file"`
Expand Down Expand Up @@ -132,6 +133,7 @@ type ArgsAndFlagsInfo struct {
DeployRunInit string
InitRunReconfigure string
AutoGenerateBackendFile string
AppendUserAgent string
UseTerraformPlan bool
PlanFile string
DryRun bool
Expand Down
5 changes: 5 additions & 0 deletions pkg/version/version.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package version

// Version holds the current version of the Atmos CLI.
// It can be set dynamically during build time using ldflags.
var Version = "0.0.1" // Default version; will be overridden during build
14 changes: 8 additions & 6 deletions website/docs/cli/commands/terraform/usage.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@ atmos terraform workspace test/test-component-override-3 -s tenant1-ue2-dev --re
atmos terraform workspace test/test-component-override-3 -s tenant1-ue2-dev --redirect-stderr ./errors.txt

atmos terraform plan test/test-component -s tenant1-ue2-dev -- -refresh=false -lock=false

atmos terraform plan test/test-component -s tenant1-ue2-dev --append-user-agent "Acme/1.0 (Build 1234; arm64)"
```

## Arguments
Expand All @@ -124,12 +126,12 @@ atmos terraform plan test/test-component -s tenant1-ue2-dev -- -refresh=false -l

## Flags

| Flag | Description | Alias | Required |
| :------------------ | :-------------------------------------------------------------------------------------------------------------------------------------------- | :---- | :------- |
| `--stack` | Atmos stack | `-s` | yes |
| `--dry-run` | Dry run | | no |
| `--redirect-stderr` | File descriptor to redirect `stderr` to.<br/>Errors can be redirected to any file or any standard file descriptor<br/>(including `/dev/null`) | | no |

| Flag | Description | Alias | Required |
| :------------------ | :-------------------------------------------------------------------------------------------------------------------------------------------- | :---- | :------- |
| `--stack` | Atmos stack | `-s` | yes |
| `--dry-run` | Dry run | | no |
| `--redirect-stderr` | File descriptor to redirect `stderr` to.<br/>Errors can be redirected to any file or any standard file descriptor<br/>(including `/dev/null`) | | no |
| `--append-user-agent` | Append a custom User-Agent to Terraform requests. Can also be set using the ATMOS_COMPONENTS_TERRAFORM_APPEND_USER_AGENT environment variable.| | no |
<br />

:::note
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ components:
init_run_reconfigure: true
# 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: false
# Can also be set using 'ATMOS_COMPONENTS_TERRAFORM_APPEND_USER_AGENT' ENV var, or '--append-user-agent' command-line argument
append_user_agent: "Acme/1.0 (Build 1234; arm64)"
```
<dl>
Expand Down
2 changes: 1 addition & 1 deletion website/docs/quick-start/install-atmos.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ Atmos has a few other ways to install, including using Go, asdf, mise, aqua, bui
or run this and replace `$version` with the version that should be returned with `atmos version`.

```shell
go build -o build/atmos -v -ldflags "-X 'github.com/cloudposse/atmos/cmd.Version=$version'"
go build -o build/atmos -v -ldflags "-X 'github.com/cloudposse/atmos/pkg/version.Version=$version'"
```
</TabItem>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
- 'atmos terraform generate varfile' command generates a varfile for an 'atmos' component in a stack
- 'atmos terraform generate varfiles' command generates varfiles for all 'atmos' components in all stacks
- 'atmos terraform shell' command configures an environment for an 'atmos' component in a stack and starts a new shell allowing executing all native terraform commands inside the shell without using atmos-specific arguments and flags
- `--append-user-agent` flag allows you to customize the User-Agent string appended to Terraform requests for enhanced observability and traceability.
- double-dash '--' can be used to signify the end of the options for Atmos and the start of the additional native arguments and flags for the 'terraform' commands. For example: atmos terraform plan &lt;component&gt; -s &lt;stack&gt; -- -refresh=false -lock=false

Usage: terraform [global options] &lt;subcommand&gt; [args]
Expand Down

0 comments on commit a48ed22

Please sign in to comment.