Skip to content

Commit

Permalink
Feature/add backend config (#26)
Browse files Browse the repository at this point in the history
  • Loading branch information
mcalhoun authored Oct 8, 2024
1 parent fc93beb commit ff1ffad
Show file tree
Hide file tree
Showing 8 changed files with 558 additions and 5 deletions.
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,7 @@ github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m3
github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v24.0.7+incompatible h1:Wo6l37AuwP3JaMnZa226lzVXGA3F9Ig1seQen0cKYlM=
github.com/docker/docker v24.0.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v24.0.9+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y=
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=
Expand Down Expand Up @@ -531,6 +532,7 @@ github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4
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/gemnasium/logrus-graylog-hook/v3 v3.0.3/go.mod h1:wi1zWv9tIvyLSMLCAzgRP+YR24oLVQVBHfPPKjtht44=
github.com/gemnasium/logrus-graylog-hook/v3 v3.1.0/go.mod h1:wi1zWv9tIvyLSMLCAzgRP+YR24oLVQVBHfPPKjtht44=
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
Expand Down Expand Up @@ -1009,6 +1011,7 @@ github.com/rebuy-de/aws-nuke/v2 v2.20.0/go.mod h1:bcCkdY0YU58qEMZ2nMByVXR4+a+ec/
github.com/rebuy-de/aws-nuke/v2 v2.25.0 h1:uM/KoDOOIau1Gcx++D3oDFL1vlLPj9uuzQKtNVZxrHs=
github.com/rebuy-de/aws-nuke/v2 v2.25.0/go.mod h1:2TTX8eMpEsFZPYCK1QaAb9uPYtdO9MeLQPKM9GQfY/w=
github.com/rebuy-de/rebuy-go-sdk/v3 v3.12.0/go.mod h1:imLjgHMb9XZeZ2Cj6BEOdEuwkdUyOgDN4oBcSZthzro=
github.com/rebuy-de/rebuy-go-sdk/v4 v4.5.1/go.mod h1:ZSfnIcE8RFKz7IO6AFZjETDbPyMdUjtxCea9R7Q6pQE=
github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
Expand Down Expand Up @@ -1067,6 +1070,7 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
Expand Down
45 changes: 42 additions & 3 deletions pkg/atmos/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package atmos
import (
"fmt"
"os/exec"
"regexp"
"strings"

"github.com/gruntwork-io/terratest/modules/collections"
"github.com/gruntwork-io/terratest/modules/retry"
Expand Down Expand Up @@ -70,9 +72,19 @@ func RunAtmosCommandE(t testing.TestingT, additionalOptions *Options, additional

cmd := generateCommand(options, args...)
description := fmt.Sprintf("%s %v", options.AtmosBinary, args)

return retry.DoWithRetryableErrorsE(t, description, options.RetryableAtmosErrors, options.MaxRetries, options.TimeBetweenRetries, func() (string, error) {
return shell.RunCommandAndGetOutputE(t, cmd)
s, err := shell.RunCommandAndGetOutputE(t, cmd)
if err != nil {
return s, err
}

if err := hasWarning(additionalOptions, s); err != nil {
return s, err
}
return s, err
})

}

// RunAtmosCommandAndGetStdoutE runs atmos with the given arguments and options and returns solely its stdout (but not
Expand All @@ -83,7 +95,16 @@ func RunAtmosCommandAndGetStdoutE(t testing.TestingT, additionalOptions *Options
cmd := generateCommand(options, args...)
description := fmt.Sprintf("%s %v", options.AtmosBinary, args)
return retry.DoWithRetryableErrorsE(t, description, options.RetryableAtmosErrors, options.MaxRetries, options.TimeBetweenRetries, func() (string, error) {
return shell.RunCommandAndGetStdOutE(t, cmd)
s, err := shell.RunCommandAndGetOutputE(t, cmd)
if err != nil {
return s, err
}

if err := hasWarning(additionalOptions, s); err != nil {
return s, err
}

return s, err
})
}

Expand All @@ -100,8 +121,10 @@ func GetExitCodeForAtmosCommand(t testing.TestingT, additionalOptions *Options,
func GetExitCodeForAtmosCommandE(t testing.TestingT, additionalOptions *Options, additionalArgs ...string) (int, error) {
options, args := GetCommonOptions(additionalOptions, additionalArgs...)

additionalOptions.Logger.Logf(t, "Running %s in %s with args %v", options.AtmosBinary, options.AtmosBasePath, args)
additionalOptions.Logger.Logf(t, "Running %s with args %v", options.AtmosBinary, options.AtmosBinary, args)
cmd := generateCommand(options, args...)
cmd.WorkingDir = options.AtmosBasePath

_, err := shell.RunCommandAndGetOutputE(t, cmd)
if err == nil {
return DefaultSuccessExitCode, nil
Expand All @@ -125,3 +148,19 @@ func defaultAtmosExecutable() string {

return AtmosDefaultPath
}

func hasWarning(opts *Options, out string) error {
for k, v := range opts.WarningsAsErrors {
str := fmt.Sprintf("\nWarning: %s[^\n]*\n", k)
re, err := regexp.Compile(str)
if err != nil {
return fmt.Errorf("cannot compile regex for warning detection: %w", err)
}
m := re.FindAllString(out, -1)
if len(m) == 0 {
continue
}
return fmt.Errorf("warning(s) were found: %s:\n%s", v, strings.Join(m, ""))
}
return nil
}
95 changes: 95 additions & 0 deletions pkg/atmos/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package atmos

import (
"fmt"
"reflect"
)

// OutputKeyNotFound occurs when terraform output does not contain a value for the key
// specified in the function call
type OutputKeyNotFound string

func (err OutputKeyNotFound) Error() string {
return fmt.Sprintf("output doesn't contain a value for the key %q", string(err))
}

// OutputValueNotMap occures when casting a found output value to a map fails
type OutputValueNotMap struct {
Value interface{}
}

func (err OutputValueNotMap) Error() string {
return fmt.Sprintf("Output value %q is not a map", err.Value)
}

// OutputValueNotList occurs when casting a found output value to a
// list of interfaces fails
type OutputValueNotList struct {
Value interface{}
}

func (err OutputValueNotList) Error() string {
return fmt.Sprintf("Output value %q is not a list", err.Value)
}

// EmptyOutput is an error that occurs when an output is empty.
type EmptyOutput string

func (outputName EmptyOutput) Error() string {
return fmt.Sprintf("Required output %s was empty", string(outputName))
}

// UnexpectedOutputType is an error that occurs when the output is not of the type we expect
type UnexpectedOutputType struct {
Key string
ExpectedType string
ActualType string
}

func (err UnexpectedOutputType) Error() string {
return fmt.Sprintf("Expected output '%s' to be of type '%s' but got '%s'", err.Key, err.ExpectedType, err.ActualType)
}

// VarFileNotFound is an error that occurs when a var file cannot be found in an option's VarFile list
type VarFileNotFound struct {
Path string
}

func (err VarFileNotFound) Error() string {
return fmt.Sprintf("Var file '%s' not found", err.Path)
}

// InputFileKeyNotFound occurs when tfvar file does not contain a value for the key
// specified in the function call
type InputFileKeyNotFound struct {
FilePath string
Key string
}

func (err InputFileKeyNotFound) Error() string {
return fmt.Sprintf("tfvar file %q doesn't contain a value for the key %q", err.FilePath, err.Key)
}

// PanicWhileParsingVarFile is returned when the HCL parsing routine panics due to errors.
type PanicWhileParsingVarFile struct {
ConfigFile string
RecoveredValue interface{}
}

func (err PanicWhileParsingVarFile) Error() string {
return fmt.Sprintf("Recovering panic while parsing '%s'. Got error of type '%v': %v", err.ConfigFile, reflect.TypeOf(err.RecoveredValue), err.RecoveredValue)
}

// UnsupportedDefaultWorkspaceDeletion is returned when user tries to delete the workspace "default"
type UnsupportedDefaultWorkspaceDeletion struct{}

func (err *UnsupportedDefaultWorkspaceDeletion) Error() string {
return "Deleting the workspace 'default' is not supported"
}

// WorkspaceDoesNotExist is returned when user tries to delete a workspace which does not exist
type WorkspaceDoesNotExist string

func (err WorkspaceDoesNotExist) Error() string {
return fmt.Sprintf("The workspace %q does not exist.", string(err))
}
4 changes: 4 additions & 0 deletions pkg/atmos/format.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ func FormatAtmosTerraformArgs(options *Options, args ...string) []string {

terraformArgs = append(terraformArgs, tt.FormatTerraformArgs("-target", options.Targets)...)

if commandType == "init" {
terraformArgs = append(terraformArgs, tt.FormatTerraformBackendConfigAsArgs(options.BackendConfig)...)
}

if options.NoColor {
terraformArgs = append(terraformArgs, "-no-color")
}
Expand Down
3 changes: 2 additions & 1 deletion pkg/atmos/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ type Options struct {
PlanFilePath string // The path to output a plan file to (for the plan command) or read one from (for the apply command)
PluginDir string // The path of downloaded plugins to pass to the atmos init command (-plugin-dir)
SetVarsAfterVarFiles bool // Pass -var options after -var-file options to Atmos commands
WarningsAsErrors map[string]string // Terraform warning messages that should be treated as errors. The keys are a regexp to match against the warning and the value is what to display to a user if that warning is matched.
}

// Clone makes a deep copy of most fields on the Options object and returns it.
Expand Down Expand Up @@ -121,7 +122,7 @@ func WithDefaultRetryableErrors(t testing.TestingT, originalOptions *Options) *O
}
}

if originalOptions.MaxRetries < 1 {
if originalOptions.MaxRetries < 0 {
newOptions.MaxRetries = 3
newOptions.TimeBetweenRetries = 5 * time.Second
}
Expand Down
10 changes: 9 additions & 1 deletion pkg/atmos/terraform_destroy.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,13 @@ func Destroy(t testing.TestingT, options *Options) string {

// DestroyE runs atmos terraform destroy with the given options and return stdout/stderr.
func DestroyE(t testing.TestingT, options *Options) (string, error) {
return RunAtmosCommandE(t, options, FormatArgs(options, "destroy", "-auto-approve", "-input=false")...)
if options.Component == "" {
return "", ErrorComponentRequired
}

if options.Stack == "" {
return "", ErrorStackRequired
}

return RunAtmosCommandE(t, options, FormatArgs(options, "terraform", "destroy", "-input=false", "-auto-approve")...)
}
Loading

0 comments on commit ff1ffad

Please sign in to comment.