Skip to content

Commit

Permalink
feat: check terraform version for state command
Browse files Browse the repository at this point in the history
  • Loading branch information
c4po committed Mar 20, 2024
1 parent d67591a commit ecdcd92
Show file tree
Hide file tree
Showing 8 changed files with 139 additions and 69 deletions.
30 changes: 1 addition & 29 deletions cmd/terraform-demux/main.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package main

import (
"errors"
"io"
"log"
"os"
Expand All @@ -27,13 +26,7 @@ func main() {

log.Printf("terraform-demux version %s, using arch '%s'", version, arch)

newArgs, err := checkStateCommand(os.Args)
if err != nil {
log.SetOutput(os.Stderr)
log.Fatal("error: ", err)
}

exitCode, err := wrapper.RunTerraform(newArgs[1:], arch)
exitCode, err := wrapper.RunTerraform(os.Args[1:], arch)

if err != nil {
log.SetOutput(os.Stderr)
Expand All @@ -43,24 +36,3 @@ func main() {

os.Exit(exitCode)
}

func checkStateCommand(args []string) ([]string, error) {
if checkArgsExists(args, "state") > 0 {
force_pos := checkArgsExists(args, "--force")
if force_pos > 0 {
return append(args[:force_pos], args[force_pos+1:]...), nil
} else {
return args, errors.New("--force flag is required for the 'state' command. Consider using Terraform configuration blocks (moved, import) instead")
}
}
return args, nil
}

func checkArgsExists(args []string, cmd string) int {
for i, arg := range args {
if arg == cmd {
return i
}
}
return -1
}
33 changes: 0 additions & 33 deletions cmd/terraform-demux/main_test.go

This file was deleted.

2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module github.com/etsy/terraform-demux
go 1.21

require (
github.com/Masterminds/semver/v3 v3.1.1
github.com/Masterminds/semver/v3 v3.2.1
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79
github.com/hashicorp/terraform-config-inspect v0.0.0-20231204233900-a34142ec2a72
github.com/natefinch/atomic v1.0.1
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc=
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0=
github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
github.com/agext/levenshtein v1.2.1/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
github.com/agext/levenshtein v1.2.2 h1:0S/Yg6LYmFJ5stwQeRp6EeOcCbj7xiqQSdNelsXvaqE=
github.com/agext/levenshtein v1.2.2/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
Expand Down
6 changes: 3 additions & 3 deletions internal/releaseapi/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ func (c *Client) ListReleases() (ReleaseIndex, error) {
if err != nil {
return releaseIndex, errors.Wrap(err, "could not send request for Terraform release index")
} else if response.StatusCode != http.StatusOK {
return releaseIndex, errors.Errorf("error: unexpected status code '%s' in response", response.StatusCode)
return releaseIndex, errors.Errorf("error: unexpected status code '%d' in response", response.StatusCode)
}

if response.Header.Get(httpcache.XFromCache) != "" {
Expand Down Expand Up @@ -133,7 +133,7 @@ func (c *Client) getReleaseCheckSums(release Release) (string, error) {
}
defer response.Body.Close()
if response.StatusCode != http.StatusOK {
return "", errors.Errorf("error: unexpected status code '%s' in response", response.StatusCode)
return "", errors.Errorf("error: unexpected status code '%d' in response", response.StatusCode)
}

bodyBytes, err := io.ReadAll(response.Body)
Expand Down Expand Up @@ -245,7 +245,7 @@ func (c *Client) downloadReleaseArchive(build Build) (*os.File, int64, error) {
defer response.Body.Close()

if response.StatusCode != http.StatusOK {
return nil, 0, errors.Errorf("unexpected status code '%s' in response", response.StatusCode)
return nil, 0, errors.Errorf("unexpected status code '%d' in response", response.StatusCode)
}

tmp, err := os.CreateTemp("", filepath.Base(build.URL))
Expand Down
45 changes: 45 additions & 0 deletions internal/wrapper/checkargs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package wrapper

import (
"errors"

"github.com/Masterminds/semver/v3"
)

func checkStateCommand(args []string, version *semver.Version) ([]string, error) {
versionImport, _ := semver.NewConstraint(">= 1.5.0")
versionMoved, _ := semver.NewConstraint(">= 1.1.0")
versionImport.Check(version)
if checkArgsExists(args, "state") >= 0 &&
checkArgsExists(args, "import") >= 0 &&
versionImport.Check(version) {
force_pos := checkArgsExists(args, "--force")
if force_pos > 0 {
return append(args[:force_pos], args[force_pos+1:]...), nil
} else {
return args, errors.New("--force flag is required for the 'state import' command. Consider using Terraform configuration import block instead")
}
}

if checkArgsExists(args, "state") >= 0 &&
checkArgsExists(args, "mv") >= 0 &&
versionMoved.Check(version) {
force_pos := checkArgsExists(args, "--force")
if force_pos > 0 {
return append(args[:force_pos], args[force_pos+1:]...), nil
} else {
return args, errors.New("--force flag is required for the 'state mv' command. Consider using Terraform configuration moved block instead")
}
}

return args, nil
}

func checkArgsExists(args []string, cmd string) int {
for i, arg := range args {
if arg == cmd {
return i
}
}
return -1
}
80 changes: 80 additions & 0 deletions internal/wrapper/checkargs_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package wrapper

import (
"slices"
"testing"

"github.com/Masterminds/semver/v3"
)

func TestCheckStateCommand(t *testing.T) {
t.Run("Valid state import command with --force flag on 1.5.0", func(t *testing.T) {
args := []string{"state", "import", "--force"}
version, _ := semver.NewVersion("1.5.0")
result, err := checkStateCommand(args, version)
if err != nil || !slices.Equal(result, []string{"state", "import"}) {
t.Errorf("Expected no error, got: %v, %v", err, result)
}
})

t.Run("Valid state import command without --force flag on 1.4.7", func(t *testing.T) {
args := []string{"state", "import"}
version, _ := semver.NewVersion("1.4.7")
result, err := checkStateCommand(args, version)
if err != nil || !slices.Equal(result, []string{"state", "import"}) {
t.Errorf("Expected no error, got: %v", err)
}
})

t.Run("Invalid state import command without --force flag on 1.5.0", func(t *testing.T) {
args := []string{"state", "import"}
version, _ := semver.NewVersion("1.6.0")
result, err := checkStateCommand(args, version)
if err == nil {
t.Errorf("Expected error, got: %v, %v", err, result)
}
})

t.Run("Valid state mv command with --force flag on 1.6.0", func(t *testing.T) {
args := []string{"state", "mv", "--force"}
version, _ := semver.NewVersion("1.6.0")
result, err := checkStateCommand(args, version)
if err != nil || !slices.Equal(result, []string{"state", "mv"}) {
t.Errorf("Expected no error, got: %v, %v", err, result)
}
})
}

func TestCheckArgsExists(t *testing.T) {
t.Run("Check 'state import --force' command", func(t *testing.T) {
args := []string{"state", "import", "--force"}
result := checkArgsExists(args, "state")
if result != 0 {
t.Errorf("Expected 0, got: %v", result)
}
result = checkArgsExists(args, "import")
if result != 1 {
t.Errorf("Expected 1, got: %v", result)
}
result = checkArgsExists(args, "--force")
if result != 2 {
t.Errorf("Expected 2, got: %v", result)
}
})

t.Run("Check 'state moved' command", func(t *testing.T) {
args := []string{"state", "mv"}
result := checkArgsExists(args, "state")
if result != 0 {
t.Errorf("Expected 0, got: %v", result)
}
result = checkArgsExists(args, "mv")
if result != 1 {
t.Errorf("Expected 1, got: %v", result)
}
result = checkArgsExists(args, "--force")
if result != -1 {
t.Errorf("Expected -1, got: %v", result)
}
})
}
8 changes: 7 additions & 1 deletion internal/wrapper/wrapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,19 @@ func RunTerraform(args []string, arch string) (int, error) {

log.Printf("version '%s' matches all constraints", matchingRelease.Version)

newArgs, err := checkStateCommand(args, matchingRelease.Version)
if err != nil {
log.SetOutput(os.Stderr)
log.Fatal("error: ", err)
}

executablePath, err := client.DownloadRelease(matchingRelease, runtime.GOOS, arch)

if err != nil {
return 1, err
}

return runTerraform(executablePath, args)
return runTerraform(executablePath, newArgs)
}

func ensureCacheDirectory() (string, error) {
Expand Down

0 comments on commit ecdcd92

Please sign in to comment.