mirror of
https://github.com/thegeeklab/wp-opentofu.git
synced 2024-11-21 14:20:40 +00:00
refactor: switch to plugin Cmd and add tests (#44)
This commit is contained in:
parent
2eda2b50fc
commit
dcc53a341d
4
go.mod
4
go.mod
@ -5,6 +5,7 @@ go 1.22
|
||||
require (
|
||||
github.com/Masterminds/semver/v3 v3.2.1
|
||||
github.com/rs/zerolog v1.32.0
|
||||
github.com/stretchr/testify v1.9.0
|
||||
github.com/thegeeklab/wp-plugin-go/v2 v2.3.1
|
||||
github.com/urfave/cli/v2 v2.27.2
|
||||
golang.org/x/sys v0.20.0
|
||||
@ -14,6 +15,7 @@ require (
|
||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||
github.com/Masterminds/sprig/v3 v3.2.3 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/google/uuid v1.1.1 // indirect
|
||||
github.com/huandu/xstrings v1.3.3 // indirect
|
||||
github.com/imdario/mergo v0.3.11 // indirect
|
||||
@ -22,10 +24,12 @@ require (
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mitchellh/copystructure v1.0.0 // indirect
|
||||
github.com/mitchellh/reflectwalk v1.0.0 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/shopspring/decimal v1.2.0 // indirect
|
||||
github.com/spf13/cast v1.3.1 // indirect
|
||||
github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 // indirect
|
||||
golang.org/x/crypto v0.23.0 // indirect
|
||||
golang.org/x/net v0.25.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
1
go.sum
1
go.sum
@ -90,6 +90,7 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
||||
|
@ -8,7 +8,9 @@ import (
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/thegeeklab/wp-opentofu/tofu"
|
||||
"github.com/thegeeklab/wp-plugin-go/v2/trace"
|
||||
"github.com/thegeeklab/wp-plugin-go/v2/types"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -43,21 +45,21 @@ func (p *Plugin) run(ctx context.Context) error {
|
||||
|
||||
func (p *Plugin) FlagsFromContext() error {
|
||||
if p.Context.String("init-option") != "" {
|
||||
initOptions := InitOptions{}
|
||||
initOptions := tofu.InitOptions{}
|
||||
if err := json.Unmarshal([]byte(p.Context.String("init-option")), &initOptions); err != nil {
|
||||
return fmt.Errorf("cannot unmarshal init_option: %w", err)
|
||||
}
|
||||
|
||||
p.Settings.InitOptions = initOptions
|
||||
p.Settings.Tofu.InitOptions = initOptions
|
||||
}
|
||||
|
||||
if p.Context.String("fmt-option") != "" {
|
||||
fmtOptions := FmtOptions{}
|
||||
fmtOptions := tofu.FmtOptions{}
|
||||
if err := json.Unmarshal([]byte(p.Context.String("fmt-option")), &fmtOptions); err != nil {
|
||||
return fmt.Errorf("cannot unmarshal fmt_option: %w", err)
|
||||
}
|
||||
|
||||
p.Settings.FmtOptions = fmtOptions
|
||||
p.Settings.Tofu.FmtOptions = fmtOptions
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -70,9 +72,9 @@ func (p *Plugin) Validate() error {
|
||||
p.Settings.DataDir = value
|
||||
}
|
||||
|
||||
p.Settings.OutFile = "plan.tfout"
|
||||
p.Settings.Tofu.OutFile = "plan.tfout"
|
||||
if p.Settings.DataDir == ".terraform" {
|
||||
p.Settings.OutFile = fmt.Sprintf("%s.plan.tfout", p.Settings.DataDir)
|
||||
p.Settings.Tofu.OutFile = fmt.Sprintf("%s.plan.tfout", p.Settings.DataDir)
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -80,8 +82,8 @@ func (p *Plugin) Validate() error {
|
||||
|
||||
// Execute provides the implementation of the plugin.
|
||||
func (p *Plugin) Execute() error {
|
||||
batchCmd := make([]*Cmd, 0)
|
||||
batchCmd = append(batchCmd, p.versionCommand())
|
||||
batchCmd := make([]*types.Cmd, 0)
|
||||
batchCmd = append(batchCmd, p.Settings.Tofu.Version())
|
||||
|
||||
if p.Settings.TofuVersion != "" {
|
||||
err := installPackage(p.Plugin.Network.Context, p.Plugin.Network.Client, p.Settings.TofuVersion, maxDecompressionSize)
|
||||
@ -90,29 +92,29 @@ func (p *Plugin) Execute() error {
|
||||
}
|
||||
}
|
||||
|
||||
batchCmd = append(batchCmd, p.initCommand())
|
||||
batchCmd = append(batchCmd, p.getModulesCommand())
|
||||
batchCmd = append(batchCmd, p.Settings.Tofu.Init())
|
||||
batchCmd = append(batchCmd, p.Settings.Tofu.GetModules())
|
||||
|
||||
for _, action := range p.Settings.Action.Value() {
|
||||
switch action {
|
||||
case "fmt":
|
||||
batchCmd = append(batchCmd, p.fmtCommand())
|
||||
batchCmd = append(batchCmd, p.Settings.Tofu.Fmt())
|
||||
case "validate":
|
||||
batchCmd = append(batchCmd, p.validateCommand())
|
||||
batchCmd = append(batchCmd, p.Settings.Tofu.Validate())
|
||||
case "plan":
|
||||
batchCmd = append(batchCmd, p.planCommand(false))
|
||||
batchCmd = append(batchCmd, p.Settings.Tofu.Plan(false))
|
||||
case "plan-destroy":
|
||||
batchCmd = append(batchCmd, p.planCommand(true))
|
||||
batchCmd = append(batchCmd, p.Settings.Tofu.Plan(true))
|
||||
case "apply":
|
||||
batchCmd = append(batchCmd, p.applyCommand())
|
||||
batchCmd = append(batchCmd, p.Settings.Tofu.Apply())
|
||||
case "destroy":
|
||||
batchCmd = append(batchCmd, p.destroyCommand())
|
||||
batchCmd = append(batchCmd, p.Settings.Tofu.Destroy())
|
||||
default:
|
||||
return fmt.Errorf("%w: %s", ErrActionUnknown, action)
|
||||
}
|
||||
}
|
||||
|
||||
if err := deleteDir(p.Settings.DataDir); err != nil {
|
||||
if err := os.RemoveAll(p.Settings.DataDir); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -136,5 +138,5 @@ func (p *Plugin) Execute() error {
|
||||
}
|
||||
}
|
||||
|
||||
return deleteDir(p.Settings.DataDir)
|
||||
return os.RemoveAll(p.Settings.DataDir)
|
||||
}
|
||||
|
@ -3,9 +3,9 @@ package plugin
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/thegeeklab/wp-opentofu/tofu"
|
||||
wp "github.com/thegeeklab/wp-plugin-go/v2/plugin"
|
||||
"github.com/urfave/cli/v2"
|
||||
"golang.org/x/sys/execabs"
|
||||
)
|
||||
|
||||
//go:generate go run ../internal/docs/main.go -output=../docs/data/data-raw.yaml
|
||||
@ -18,39 +18,11 @@ type Plugin struct {
|
||||
|
||||
// Settings for the Plugin.
|
||||
type Settings struct {
|
||||
Action cli.StringSlice
|
||||
|
||||
TofuVersion string
|
||||
InitOptions InitOptions
|
||||
FmtOptions FmtOptions
|
||||
|
||||
Action cli.StringSlice
|
||||
RootDir string
|
||||
DataDir string
|
||||
OutFile string
|
||||
Parallelism int
|
||||
Targets cli.StringSlice
|
||||
Refresh bool
|
||||
NoLog bool
|
||||
}
|
||||
|
||||
// InitOptions include options for the OpenTofu init command.
|
||||
type InitOptions struct {
|
||||
BackendConfig []string `json:"backend-config"`
|
||||
Lock *bool `json:"lock"`
|
||||
LockTimeout string `json:"lock-timeout"`
|
||||
}
|
||||
|
||||
// FmtOptions fmt options for the OpenTofu fmt command.
|
||||
type FmtOptions struct {
|
||||
List *bool `json:"list"`
|
||||
Write *bool `json:"write"`
|
||||
Diff *bool `json:"diff"`
|
||||
Check *bool `json:"check"`
|
||||
}
|
||||
|
||||
type Cmd struct {
|
||||
*execabs.Cmd
|
||||
Private bool
|
||||
TofuVersion string
|
||||
Tofu tofu.Tofu
|
||||
}
|
||||
|
||||
func New(e wp.ExecuteFunc, build ...string) *Plugin {
|
||||
@ -123,14 +95,14 @@ func Flags(settings *Settings, category string) []cli.Flag {
|
||||
Name: "no-log",
|
||||
Usage: "suppress tofu command output for `plan`, `apply` and `destroy` action",
|
||||
EnvVars: []string{"PLUGIN_NO_LOG"},
|
||||
Destination: &settings.NoLog,
|
||||
Destination: &settings.Tofu.NoLog,
|
||||
Category: category,
|
||||
},
|
||||
&cli.StringSliceFlag{
|
||||
Name: "targets",
|
||||
Usage: "targets to run `plan` or `apply` action on",
|
||||
EnvVars: []string{"PLUGIN_TARGETS"},
|
||||
Destination: &settings.Targets,
|
||||
Destination: &settings.Tofu.Targets,
|
||||
Category: category,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
@ -144,7 +116,7 @@ func Flags(settings *Settings, category string) []cli.Flag {
|
||||
Name: "refresh",
|
||||
Usage: "enables refreshing of the state before `plan` and `apply` commands",
|
||||
EnvVars: []string{"PLUGIN_REFRESH"},
|
||||
Destination: &settings.Refresh,
|
||||
Destination: &settings.Tofu.Refresh,
|
||||
Value: true,
|
||||
Category: category,
|
||||
},
|
||||
|
172
plugin/tofu.go
172
plugin/tofu.go
@ -1,172 +0,0 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/sys/execabs"
|
||||
)
|
||||
|
||||
const (
|
||||
tofuBin = "/usr/local/bin/tofu"
|
||||
)
|
||||
|
||||
func (p *Plugin) versionCommand() *Cmd {
|
||||
return &Cmd{
|
||||
Cmd: execabs.Command(tofuBin, "version"),
|
||||
Private: p.Settings.NoLog,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Plugin) initCommand() *Cmd {
|
||||
args := []string{
|
||||
"init",
|
||||
}
|
||||
|
||||
for _, v := range p.Settings.InitOptions.BackendConfig {
|
||||
args = append(args, fmt.Sprintf("-backend-config=%s", v))
|
||||
}
|
||||
|
||||
// Fail tofu execution on prompt
|
||||
args = append(args, "-input=false")
|
||||
|
||||
return &Cmd{
|
||||
Cmd: execabs.Command(tofuBin, args...),
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Plugin) getModulesCommand() *Cmd {
|
||||
return &Cmd{
|
||||
Cmd: execabs.Command(tofuBin, "get"),
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Plugin) validateCommand() *Cmd {
|
||||
return &Cmd{
|
||||
Cmd: execabs.Command(tofuBin, "validate"),
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Plugin) fmtCommand() *Cmd {
|
||||
args := []string{
|
||||
"fmt",
|
||||
}
|
||||
|
||||
if p.Settings.FmtOptions.List != nil {
|
||||
args = append(args, fmt.Sprintf("-list=%t", *p.Settings.FmtOptions.List))
|
||||
}
|
||||
|
||||
if p.Settings.FmtOptions.Write != nil {
|
||||
args = append(args, fmt.Sprintf("-write=%t", *p.Settings.FmtOptions.Write))
|
||||
}
|
||||
|
||||
if p.Settings.FmtOptions.Diff != nil {
|
||||
args = append(args, fmt.Sprintf("-diff=%t", *p.Settings.FmtOptions.Diff))
|
||||
}
|
||||
|
||||
if p.Settings.FmtOptions.Check != nil {
|
||||
args = append(args, fmt.Sprintf("-check=%t", *p.Settings.FmtOptions.Check))
|
||||
}
|
||||
|
||||
return &Cmd{
|
||||
Cmd: execabs.Command(tofuBin, args...),
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Plugin) planCommand(destroy bool) *Cmd {
|
||||
args := []string{
|
||||
"plan",
|
||||
}
|
||||
|
||||
if destroy {
|
||||
args = append(args, "-destroy")
|
||||
} else {
|
||||
args = append(args, fmt.Sprintf("-out=%s", p.Settings.OutFile))
|
||||
}
|
||||
|
||||
for _, value := range p.Settings.Targets.Value() {
|
||||
args = append(args, "--target", value)
|
||||
}
|
||||
|
||||
if p.Settings.Parallelism > 0 {
|
||||
args = append(args, fmt.Sprintf("-parallelism=%d", p.Settings.Parallelism))
|
||||
}
|
||||
|
||||
if p.Settings.InitOptions.Lock != nil {
|
||||
args = append(args, fmt.Sprintf("-lock=%t", *p.Settings.InitOptions.Lock))
|
||||
}
|
||||
|
||||
if p.Settings.InitOptions.LockTimeout != "" {
|
||||
args = append(args, fmt.Sprintf("-lock-timeout=%s", p.Settings.InitOptions.LockTimeout))
|
||||
}
|
||||
|
||||
if !p.Settings.Refresh {
|
||||
args = append(args, "-refresh=false")
|
||||
}
|
||||
|
||||
return &Cmd{
|
||||
Cmd: execabs.Command(tofuBin, args...),
|
||||
Private: p.Settings.NoLog,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Plugin) applyCommand() *Cmd {
|
||||
args := []string{
|
||||
"apply",
|
||||
}
|
||||
|
||||
for _, v := range p.Settings.Targets.Value() {
|
||||
args = append(args, "--target", v)
|
||||
}
|
||||
|
||||
if p.Settings.Parallelism > 0 {
|
||||
args = append(args, fmt.Sprintf("-parallelism=%d", p.Settings.Parallelism))
|
||||
}
|
||||
|
||||
if p.Settings.InitOptions.Lock != nil {
|
||||
args = append(args, fmt.Sprintf("-lock=%t", *p.Settings.InitOptions.Lock))
|
||||
}
|
||||
|
||||
if p.Settings.InitOptions.LockTimeout != "" {
|
||||
args = append(args, fmt.Sprintf("-lock-timeout=%s", p.Settings.InitOptions.LockTimeout))
|
||||
}
|
||||
|
||||
if !p.Settings.Refresh {
|
||||
args = append(args, "-refresh=false")
|
||||
}
|
||||
|
||||
args = append(args, p.Settings.OutFile)
|
||||
|
||||
return &Cmd{
|
||||
Cmd: execabs.Command(tofuBin, args...),
|
||||
Private: p.Settings.NoLog,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Plugin) destroyCommand() *Cmd {
|
||||
args := []string{
|
||||
"destroy",
|
||||
}
|
||||
|
||||
for _, v := range p.Settings.Targets.Value() {
|
||||
args = append(args, fmt.Sprintf("-target=%s", v))
|
||||
}
|
||||
|
||||
if p.Settings.Parallelism > 0 {
|
||||
args = append(args, fmt.Sprintf("-parallelism=%d", p.Settings.Parallelism))
|
||||
}
|
||||
|
||||
if p.Settings.InitOptions.Lock != nil {
|
||||
args = append(args, fmt.Sprintf("-lock=%t", *p.Settings.InitOptions.Lock))
|
||||
}
|
||||
|
||||
if p.Settings.InitOptions.LockTimeout != "" {
|
||||
args = append(args, fmt.Sprintf("-lock-timeout=%s", p.Settings.InitOptions.LockTimeout))
|
||||
}
|
||||
|
||||
args = append(args, "-auto-approve")
|
||||
|
||||
return &Cmd{
|
||||
Cmd: execabs.Command(tofuBin, args...),
|
||||
Private: p.Settings.NoLog,
|
||||
}
|
||||
}
|
@ -13,6 +13,7 @@ import (
|
||||
|
||||
"github.com/Masterminds/semver/v3"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/thegeeklab/wp-opentofu/tofu"
|
||||
)
|
||||
|
||||
func installPackage(ctx context.Context, client *http.Client, version string, maxSize int64) error {
|
||||
@ -34,7 +35,7 @@ func installPackage(ctx context.Context, client *http.Client, version string, ma
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = deleteDir(tmpdir)
|
||||
_ = os.RemoveAll(tmpdir)
|
||||
}()
|
||||
|
||||
log.Debug().
|
||||
@ -51,7 +52,7 @@ func installPackage(ctx context.Context, client *http.Client, version string, ma
|
||||
return fmt.Errorf("failed to unzip: %w", err)
|
||||
}
|
||||
|
||||
if err := os.Rename(filepath.Join(tmpdir, "tofu"), tofuBin); err != nil {
|
||||
if err := os.Rename(filepath.Join(tmpdir, "tofu"), tofu.TofuBin); err != nil {
|
||||
return fmt.Errorf("failed to rename: %w", err)
|
||||
}
|
||||
|
||||
@ -169,7 +170,3 @@ func sanitizeArchivePath(d, t string) (string, error) {
|
||||
|
||||
return "", fmt.Errorf("%w: %v", ErrTaintedPath, t)
|
||||
}
|
||||
|
||||
func deleteDir(path string) error {
|
||||
return os.RemoveAll(path)
|
||||
}
|
||||
|
200
tofu/tofu.go
Normal file
200
tofu/tofu.go
Normal file
@ -0,0 +1,200 @@
|
||||
package tofu
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/thegeeklab/wp-plugin-go/v2/types"
|
||||
"github.com/urfave/cli/v2"
|
||||
"golang.org/x/sys/execabs"
|
||||
)
|
||||
|
||||
const TofuBin = "/usr/local/bin/tofu"
|
||||
|
||||
type Tofu struct {
|
||||
InitOptions InitOptions
|
||||
FmtOptions FmtOptions
|
||||
|
||||
OutFile string
|
||||
Parallelism int
|
||||
Targets cli.StringSlice
|
||||
Refresh bool
|
||||
NoLog bool
|
||||
}
|
||||
|
||||
// InitOptions include options for the OpenTofu init command.
|
||||
type InitOptions struct {
|
||||
BackendConfig []string `json:"backend-config"`
|
||||
Lock *bool `json:"lock"`
|
||||
LockTimeout string `json:"lock-timeout"`
|
||||
}
|
||||
|
||||
// FmtOptions fmt options for the OpenTofu fmt command.
|
||||
type FmtOptions struct {
|
||||
List *bool `json:"list"`
|
||||
Write *bool `json:"write"`
|
||||
Diff *bool `json:"diff"`
|
||||
Check *bool `json:"check"`
|
||||
}
|
||||
|
||||
func (t *Tofu) Version() *types.Cmd {
|
||||
return &types.Cmd{
|
||||
Cmd: execabs.Command(TofuBin, "version"),
|
||||
Private: t.NoLog,
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Tofu) Init() *types.Cmd {
|
||||
args := []string{
|
||||
"init",
|
||||
}
|
||||
|
||||
for _, v := range t.InitOptions.BackendConfig {
|
||||
args = append(args, fmt.Sprintf("-backend-config=%s", v))
|
||||
}
|
||||
|
||||
// Fail tofu execution on prompt
|
||||
args = append(args, "-input=false")
|
||||
|
||||
return &types.Cmd{
|
||||
Cmd: execabs.Command(TofuBin, args...),
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Tofu) GetModules() *types.Cmd {
|
||||
return &types.Cmd{
|
||||
Cmd: execabs.Command(TofuBin, "get"),
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Tofu) Validate() *types.Cmd {
|
||||
return &types.Cmd{
|
||||
Cmd: execabs.Command(TofuBin, "validate"),
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Tofu) Fmt() *types.Cmd {
|
||||
args := []string{
|
||||
"fmt",
|
||||
}
|
||||
|
||||
if t.FmtOptions.List != nil {
|
||||
args = append(args, fmt.Sprintf("-list=%t", *t.FmtOptions.List))
|
||||
}
|
||||
|
||||
if t.FmtOptions.Write != nil {
|
||||
args = append(args, fmt.Sprintf("-write=%t", *t.FmtOptions.Write))
|
||||
}
|
||||
|
||||
if t.FmtOptions.Diff != nil {
|
||||
args = append(args, fmt.Sprintf("-diff=%t", *t.FmtOptions.Diff))
|
||||
}
|
||||
|
||||
if t.FmtOptions.Check != nil {
|
||||
args = append(args, fmt.Sprintf("-check=%t", *t.FmtOptions.Check))
|
||||
}
|
||||
|
||||
return &types.Cmd{
|
||||
Cmd: execabs.Command(TofuBin, args...),
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Tofu) Plan(destroy bool) *types.Cmd {
|
||||
args := []string{
|
||||
"plan",
|
||||
}
|
||||
|
||||
if destroy {
|
||||
args = append(args, "-destroy")
|
||||
} else if t.OutFile != "" {
|
||||
args = append(args, fmt.Sprintf("-out=%s", t.OutFile))
|
||||
}
|
||||
|
||||
for _, value := range t.Targets.Value() {
|
||||
args = append(args, "--target", value)
|
||||
}
|
||||
|
||||
if t.Parallelism > 0 {
|
||||
args = append(args, fmt.Sprintf("-parallelism=%d", t.Parallelism))
|
||||
}
|
||||
|
||||
if t.InitOptions.Lock != nil {
|
||||
args = append(args, fmt.Sprintf("-lock=%t", *t.InitOptions.Lock))
|
||||
}
|
||||
|
||||
if t.InitOptions.LockTimeout != "" {
|
||||
args = append(args, fmt.Sprintf("-lock-timeout=%s", t.InitOptions.LockTimeout))
|
||||
}
|
||||
|
||||
if !t.Refresh {
|
||||
args = append(args, "-refresh=false")
|
||||
}
|
||||
|
||||
return &types.Cmd{
|
||||
Cmd: execabs.Command(TofuBin, args...),
|
||||
Private: t.NoLog,
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Tofu) Apply() *types.Cmd {
|
||||
args := []string{
|
||||
"apply",
|
||||
}
|
||||
|
||||
for _, v := range t.Targets.Value() {
|
||||
args = append(args, "--target", v)
|
||||
}
|
||||
|
||||
if t.Parallelism > 0 {
|
||||
args = append(args, fmt.Sprintf("-parallelism=%d", t.Parallelism))
|
||||
}
|
||||
|
||||
if t.InitOptions.Lock != nil {
|
||||
args = append(args, fmt.Sprintf("-lock=%t", *t.InitOptions.Lock))
|
||||
}
|
||||
|
||||
if t.InitOptions.LockTimeout != "" {
|
||||
args = append(args, fmt.Sprintf("-lock-timeout=%s", t.InitOptions.LockTimeout))
|
||||
}
|
||||
|
||||
if !t.Refresh {
|
||||
args = append(args, "-refresh=false")
|
||||
}
|
||||
|
||||
if t.OutFile != "" {
|
||||
args = append(args, t.OutFile)
|
||||
}
|
||||
|
||||
return &types.Cmd{
|
||||
Cmd: execabs.Command(TofuBin, args...),
|
||||
Private: t.NoLog,
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Tofu) Destroy() *types.Cmd {
|
||||
args := []string{
|
||||
"destroy",
|
||||
}
|
||||
|
||||
for _, v := range t.Targets.Value() {
|
||||
args = append(args, fmt.Sprintf("-target=%s", v))
|
||||
}
|
||||
|
||||
if t.Parallelism > 0 {
|
||||
args = append(args, fmt.Sprintf("-parallelism=%d", t.Parallelism))
|
||||
}
|
||||
|
||||
if t.InitOptions.Lock != nil {
|
||||
args = append(args, fmt.Sprintf("-lock=%t", *t.InitOptions.Lock))
|
||||
}
|
||||
|
||||
if t.InitOptions.LockTimeout != "" {
|
||||
args = append(args, fmt.Sprintf("-lock-timeout=%s", t.InitOptions.LockTimeout))
|
||||
}
|
||||
|
||||
args = append(args, "-auto-approve")
|
||||
|
||||
return &types.Cmd{
|
||||
Cmd: execabs.Command(TofuBin, args...),
|
||||
Private: t.NoLog,
|
||||
}
|
||||
}
|
545
tofu/tofu_test.go
Normal file
545
tofu/tofu_test.go
Normal file
@ -0,0 +1,545 @@
|
||||
package tofu
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
func boolPtr(b bool) *bool {
|
||||
return &b
|
||||
}
|
||||
|
||||
func TestTofu_Version(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
tofu *Tofu
|
||||
want []string
|
||||
}{
|
||||
{
|
||||
name: "test version command",
|
||||
tofu: &Tofu{},
|
||||
want: []string{TofuBin, "version"},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
cmd := tt.tofu.Version()
|
||||
assert.Equal(t, tt.want, cmd.Cmd.Args)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestTofu_Init(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
tofu *Tofu
|
||||
want []string
|
||||
}{
|
||||
{
|
||||
name: "init with no backend config",
|
||||
tofu: &Tofu{},
|
||||
want: []string{
|
||||
TofuBin,
|
||||
"init",
|
||||
"-input=false",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "init with single backend config",
|
||||
tofu: &Tofu{
|
||||
InitOptions: InitOptions{
|
||||
BackendConfig: []string{"key=value"},
|
||||
},
|
||||
},
|
||||
want: []string{
|
||||
TofuBin,
|
||||
"init",
|
||||
"-backend-config=key=value",
|
||||
"-input=false",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "init with multiple backend configs",
|
||||
tofu: &Tofu{
|
||||
InitOptions: InitOptions{
|
||||
BackendConfig: []string{"key1=value1", "key2=value2"},
|
||||
},
|
||||
},
|
||||
want: []string{
|
||||
TofuBin,
|
||||
"init",
|
||||
"-backend-config=key1=value1",
|
||||
"-backend-config=key2=value2",
|
||||
"-input=false",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
cmd := tt.tofu.Init()
|
||||
assert.Equal(t, tt.want, cmd.Cmd.Args)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestTofu_GetModules(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
tofu *Tofu
|
||||
want []string
|
||||
}{
|
||||
{
|
||||
name: "get modules command",
|
||||
tofu: &Tofu{},
|
||||
want: []string{TofuBin, "get"},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
cmd := tt.tofu.GetModules()
|
||||
assert.Equal(t, tt.want, cmd.Cmd.Args)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestTofu_Validate(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
tofu *Tofu
|
||||
want []string
|
||||
}{
|
||||
{
|
||||
name: "validate command",
|
||||
tofu: &Tofu{},
|
||||
want: []string{TofuBin, "validate"},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
cmd := tt.tofu.Validate()
|
||||
assert.Equal(t, tt.want, cmd.Cmd.Args)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestTofu_Fmt(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
tofu *Tofu
|
||||
want []string
|
||||
}{
|
||||
{
|
||||
name: "fmt with no options",
|
||||
tofu: &Tofu{},
|
||||
want: []string{
|
||||
TofuBin,
|
||||
"fmt",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "fmt with list option",
|
||||
tofu: &Tofu{
|
||||
FmtOptions: FmtOptions{
|
||||
List: boolPtr(true),
|
||||
},
|
||||
},
|
||||
want: []string{
|
||||
TofuBin,
|
||||
"fmt",
|
||||
"-list=true",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "fmt with write option",
|
||||
tofu: &Tofu{
|
||||
FmtOptions: FmtOptions{
|
||||
Write: boolPtr(true),
|
||||
},
|
||||
},
|
||||
want: []string{
|
||||
TofuBin,
|
||||
"fmt",
|
||||
"-write=true",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "fmt with diff option",
|
||||
tofu: &Tofu{
|
||||
FmtOptions: FmtOptions{
|
||||
Diff: boolPtr(true),
|
||||
},
|
||||
},
|
||||
want: []string{
|
||||
TofuBin,
|
||||
"fmt",
|
||||
"-diff=true",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "fmt with check option",
|
||||
tofu: &Tofu{
|
||||
FmtOptions: FmtOptions{
|
||||
Check: boolPtr(true),
|
||||
},
|
||||
},
|
||||
want: []string{
|
||||
TofuBin,
|
||||
"fmt",
|
||||
"-check=true",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "fmt with multiple options",
|
||||
tofu: &Tofu{
|
||||
FmtOptions: FmtOptions{
|
||||
List: boolPtr(true),
|
||||
Write: boolPtr(true),
|
||||
Diff: boolPtr(true),
|
||||
Check: boolPtr(true),
|
||||
},
|
||||
},
|
||||
want: []string{
|
||||
TofuBin,
|
||||
"fmt",
|
||||
"-list=true",
|
||||
"-write=true",
|
||||
"-diff=true",
|
||||
"-check=true",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
cmd := tt.tofu.Fmt()
|
||||
assert.Equal(t, tt.want, cmd.Cmd.Args)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestTofu_Plan(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
tofu *Tofu
|
||||
destroy bool
|
||||
want []string
|
||||
}{
|
||||
{
|
||||
name: "plan with no options",
|
||||
tofu: &Tofu{},
|
||||
destroy: false,
|
||||
want: []string{
|
||||
TofuBin,
|
||||
"plan",
|
||||
"-refresh=false",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "plan with output options",
|
||||
tofu: &Tofu{
|
||||
OutFile: "plan.tfout",
|
||||
},
|
||||
destroy: false,
|
||||
want: []string{
|
||||
TofuBin,
|
||||
"plan",
|
||||
"-out=plan.tfout",
|
||||
"-refresh=false",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "plan with destroy option",
|
||||
tofu: &Tofu{},
|
||||
destroy: true,
|
||||
want: []string{
|
||||
TofuBin,
|
||||
"plan",
|
||||
"-destroy",
|
||||
"-refresh=false",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "plan with targets",
|
||||
tofu: &Tofu{
|
||||
Targets: *cli.NewStringSlice("target1", "target2"),
|
||||
},
|
||||
destroy: false,
|
||||
want: []string{
|
||||
TofuBin,
|
||||
"plan",
|
||||
"--target", "target1",
|
||||
"--target", "target2",
|
||||
"-refresh=false",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "plan with parallelism",
|
||||
tofu: &Tofu{
|
||||
Parallelism: 10,
|
||||
},
|
||||
destroy: false,
|
||||
want: []string{
|
||||
TofuBin,
|
||||
"plan",
|
||||
"-parallelism=10",
|
||||
"-refresh=false",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "plan with lock option",
|
||||
tofu: &Tofu{
|
||||
InitOptions: InitOptions{
|
||||
Lock: boolPtr(true),
|
||||
},
|
||||
},
|
||||
destroy: false,
|
||||
want: []string{
|
||||
TofuBin,
|
||||
"plan",
|
||||
"-lock=true",
|
||||
"-refresh=false",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "plan with lock timeout",
|
||||
tofu: &Tofu{
|
||||
InitOptions: InitOptions{
|
||||
LockTimeout: "10s",
|
||||
},
|
||||
},
|
||||
destroy: false,
|
||||
want: []string{
|
||||
TofuBin,
|
||||
"plan",
|
||||
"-lock-timeout=10s",
|
||||
"-refresh=false",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "plan with refresh option",
|
||||
tofu: &Tofu{
|
||||
Refresh: true,
|
||||
},
|
||||
destroy: false,
|
||||
want: []string{
|
||||
TofuBin,
|
||||
"plan",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
cmd := tt.tofu.Plan(tt.destroy)
|
||||
assert.Equal(t, tt.want, cmd.Cmd.Args)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestTofu_Apply(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
tofu *Tofu
|
||||
want []string
|
||||
}{
|
||||
{
|
||||
name: "apply with no options",
|
||||
tofu: &Tofu{},
|
||||
want: []string{
|
||||
TofuBin,
|
||||
"apply",
|
||||
"-refresh=false",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "apply with targets",
|
||||
tofu: &Tofu{
|
||||
Targets: *cli.NewStringSlice("target1", "target2"),
|
||||
},
|
||||
want: []string{
|
||||
TofuBin,
|
||||
"apply",
|
||||
"--target", "target1",
|
||||
"--target", "target2",
|
||||
"-refresh=false",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "apply with parallelism",
|
||||
tofu: &Tofu{
|
||||
Parallelism: 10,
|
||||
},
|
||||
want: []string{
|
||||
TofuBin,
|
||||
"apply",
|
||||
"-parallelism=10",
|
||||
"-refresh=false",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "apply with lock option",
|
||||
tofu: &Tofu{
|
||||
InitOptions: InitOptions{
|
||||
Lock: boolPtr(true),
|
||||
},
|
||||
},
|
||||
want: []string{
|
||||
TofuBin,
|
||||
"apply",
|
||||
"-lock=true",
|
||||
"-refresh=false",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "apply with lock timeout",
|
||||
tofu: &Tofu{
|
||||
InitOptions: InitOptions{
|
||||
LockTimeout: "10s",
|
||||
},
|
||||
},
|
||||
want: []string{
|
||||
TofuBin,
|
||||
"apply",
|
||||
"-lock-timeout=10s",
|
||||
"-refresh=false",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "apply with refresh option",
|
||||
tofu: &Tofu{
|
||||
Refresh: true,
|
||||
},
|
||||
want: []string{
|
||||
TofuBin,
|
||||
"apply",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "apply with output file",
|
||||
tofu: &Tofu{
|
||||
OutFile: "out.tfout",
|
||||
},
|
||||
want: []string{
|
||||
TofuBin,
|
||||
"apply",
|
||||
"-refresh=false",
|
||||
"out.tfout",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "apply with no log",
|
||||
tofu: &Tofu{
|
||||
NoLog: true,
|
||||
},
|
||||
want: []string{
|
||||
TofuBin,
|
||||
"apply",
|
||||
"-refresh=false",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
cmd := tt.tofu.Apply()
|
||||
assert.Equal(t, tt.want, cmd.Cmd.Args)
|
||||
assert.Equal(t, tt.tofu.NoLog, cmd.Private)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestTofu_Destroy(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
tofu *Tofu
|
||||
want []string
|
||||
}{
|
||||
{
|
||||
name: "destroy with no options",
|
||||
tofu: &Tofu{},
|
||||
want: []string{
|
||||
TofuBin,
|
||||
"destroy",
|
||||
"-auto-approve",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "destroy with targets",
|
||||
tofu: &Tofu{
|
||||
Targets: *cli.NewStringSlice("target1", "target2"),
|
||||
},
|
||||
want: []string{
|
||||
TofuBin,
|
||||
"destroy",
|
||||
"-target=target1",
|
||||
"-target=target2",
|
||||
"-auto-approve",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "destroy with parallelism",
|
||||
tofu: &Tofu{
|
||||
Parallelism: 10,
|
||||
},
|
||||
want: []string{
|
||||
TofuBin,
|
||||
"destroy",
|
||||
"-parallelism=10",
|
||||
"-auto-approve",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "destroy with lock option",
|
||||
tofu: &Tofu{
|
||||
InitOptions: InitOptions{
|
||||
Lock: boolPtr(true),
|
||||
},
|
||||
},
|
||||
want: []string{
|
||||
TofuBin,
|
||||
"destroy",
|
||||
"-lock=true",
|
||||
"-auto-approve",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "destroy with lock timeout",
|
||||
tofu: &Tofu{
|
||||
InitOptions: InitOptions{
|
||||
LockTimeout: "10s",
|
||||
},
|
||||
},
|
||||
want: []string{
|
||||
TofuBin,
|
||||
"destroy",
|
||||
"-lock-timeout=10s",
|
||||
"-auto-approve",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "destroy with no log",
|
||||
tofu: &Tofu{
|
||||
NoLog: true,
|
||||
},
|
||||
want: []string{
|
||||
TofuBin,
|
||||
"destroy",
|
||||
"-auto-approve",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
cmd := tt.tofu.Destroy()
|
||||
assert.Equal(t, tt.want, cmd.Cmd.Args)
|
||||
assert.Equal(t, tt.tofu.NoLog, cmd.Private)
|
||||
})
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user