diff --git a/cmd/infra.go b/cmd/infra.go index 8aa47cf2..b7727286 100644 --- a/cmd/infra.go +++ b/cmd/infra.go @@ -7,36 +7,8 @@ import ( "github.com/spf13/cobra" "github.com/spf13/viper" "go.uber.org/zap" - "io/ioutil" - "path/filepath" - "fmt" - "strings" -) - -func writeS3VarsFile(logger *zap.SugaredLogger, tfDir, bucket string) error { - logger.Infof("Writing s3 bucket %s to tfvars\n", bucket) - bucketvarspath := filepath.Join(tfDir, "terraform.tfvars") - input, err := ioutil.ReadFile(bucketvarspath) - if err != nil { - return errors.Wrapf(err, "Error reading bucket vars file %s", bucketvarspath) - } - lines := strings.Split(string(input), "\n") - for i, line := range lines { - if strings.Contains(line, "s3_bucket_name = ") { - lines[i] = fmt.Sprintf("s3_bucket_name = \"%s\"", bucket) - } - } - output := strings.Join(lines, "\n") - - err = ioutil.WriteFile(bucketvarspath, []byte(output), 0644) - if err != nil { - return errors.Wrapf(err, "Error writing providers file %s", bucketvarspath) - } - - logger.Infof("Wrote s3 bucket %s to tfvars\n", bucket) - return nil -} +) func newCreateCommand(logger *zap.SugaredLogger) *cobra.Command { cmd := &cobra.Command{ @@ -53,17 +25,11 @@ func newCreateCommand(logger *zap.SugaredLogger) *cobra.Command { scenariosDir := viper.GetString("scenarios-dir") attackTag := viper.GetString("attack-container-tag") tfDir := viper.GetString("tf-dir") - - //bucket var - logger.Infof("Creating variable %s for terraform s3 bucket\n", bucket) - err := writeS3VarsFile(logger, tfDir, bucket) - if err != nil { - return errors.Wrap(err, "Error saving bucket name") - } + logger.Infof("Created s3 bucket %s for terraform remote state\n", bucket) //bucket var - err = simulator.Create(logger, tfDir, bucket, attackTag) + err := simulator.Create(logger, tfDir, bucket, attackTag) if err != nil { logger.Errorw("Error creating infrastructure", zap.Error(err)) } diff --git a/pkg/simulator/terraform.go b/pkg/simulator/terraform.go index a4cfc5c7..973b618c 100644 --- a/pkg/simulator/terraform.go +++ b/pkg/simulator/terraform.go @@ -5,12 +5,13 @@ import ( "github.com/controlplaneio/simulator-standalone/pkg/util" "github.com/pkg/errors" "go.uber.org/zap" + "fmt" ) // PrepareTfArgs takes a string with the terraform command desired and returns // a slice of strings containing the complete list of arguments including the // command to use when exec'ing terraform -func PrepareTfArgs(cmd string) []string { +func PrepareTfArgs(cmd string, bucket string) []string { arguments := []string{cmd} if cmd == "output" { @@ -20,6 +21,12 @@ func PrepareTfArgs(cmd string) []string { if cmd == "init" || cmd == "plan" || cmd == "apply" || cmd == "destroy" { arguments = append(arguments, "-input=false") arguments = append(arguments, "--var-file=settings/bastion.tfvars") + + } + + if cmd == "init" { + providerBucketArg := fmt.Sprintf("-backend-config=bucket=%s", bucket) + arguments = append(arguments, providerBucketArg) } if cmd == "apply" || cmd == "destroy" { @@ -30,8 +37,8 @@ func PrepareTfArgs(cmd string) []string { } // Terraform wraps running terraform as a child process -func Terraform(wd, cmd string) (*string, error) { - args := PrepareTfArgs(cmd) +func Terraform(wd, cmd string, bucket string) (*string, error) { + args := PrepareTfArgs(cmd, bucket) env := []string{"TF_IS_IN_AUTOMATION=1", "TF_INPUT=0"} if cmd == "output" { // TODO: (rem) deal with non-empty stderr? @@ -77,7 +84,7 @@ func InitIfNeeded(logger *zap.SugaredLogger, tfDir, bucket, attackTag string) er } logger.Info("Running terraform init") - _, err = Terraform(tfDir, "init") + _, err = Terraform(tfDir, "init", bucket) if err != nil { return errors.Wrap(err, "Error initialising terraform") } @@ -97,13 +104,13 @@ func Create(logger *zap.SugaredLogger, tfDir, bucket, attackTag string) error { } logger.Info("Running terraform plan") - _, err = Terraform(tfDir, "plan") + _, err = Terraform(tfDir, "plan", bucket) if err != nil { return err } logger.Info("Running terraform apply") - _, err = Terraform(tfDir, "apply") + _, err = Terraform(tfDir, "apply", bucket) return err } @@ -116,7 +123,7 @@ func Status(logger *zap.SugaredLogger, tfDir, bucket, attackTag string) (*Terraf } logger.Info("Running terraform output") - out, err := Terraform(tfDir, "output") + out, err := Terraform(tfDir, "output", bucket) if err != nil { return nil, errors.Wrap(err, "Error getting terraform outputs") } @@ -140,6 +147,6 @@ func Destroy(logger *zap.SugaredLogger, tfDir, bucket, attackTag string) error { } logger.Info("Running terrraform destroy") - _, err = Terraform(tfDir, "destroy") + _, err = Terraform(tfDir, "destroy", bucket) return err } diff --git a/pkg/simulator/terraform_test.go b/pkg/simulator/terraform_test.go index 2064f521..9a41a370 100644 --- a/pkg/simulator/terraform_test.go +++ b/pkg/simulator/terraform_test.go @@ -11,20 +11,20 @@ import ( var noopLogger = zap.NewNop().Sugar() var tfCommandArgumentsTests = []struct { - command string + prepArgs []string arguments []string }{ - {"output", []string{"output", "-json"}}, - {"init", []string{"init", "-input=false", "--var-file=settings/bastion.tfvars"}}, - {"plan", []string{"plan", "-input=false", "--var-file=settings/bastion.tfvars"}}, - {"apply", []string{"apply", "-input=false", "--var-file=settings/bastion.tfvars", "-auto-approve"}}, - {"destroy", []string{"destroy", "-input=false", "--var-file=settings/bastion.tfvars", "-auto-approve"}}, + {[]string{"output", "test-bucket"}, []string{"output", "-json"}}, + {[]string{"init", "test-bucket"}, []string{"init", "-input=false", "--var-file=settings/bastion.tfvars", "-backend-config=bucket=test-bucket"}}, + {[]string{"plan", "test-bucket"}, []string{"plan", "-input=false", "--var-file=settings/bastion.tfvars"}}, + {[]string{"apply", "test-bucket"}, []string{"apply", "-input=false", "--var-file=settings/bastion.tfvars", "-auto-approve"}}, + {[]string{"destroy", "test-bucket"}, []string{"destroy", "-input=false", "--var-file=settings/bastion.tfvars", "-auto-approve"}}, } func Test_PrepareTfArgs(t *testing.T) { for _, tt := range tfCommandArgumentsTests { - t.Run("Test arguments for "+tt.command, func(t *testing.T) { - assert.Equal(t, simulator.PrepareTfArgs(tt.command), tt.arguments) + t.Run("Test arguments for "+tt.prepArgs[0], func(t *testing.T) { + assert.Equal(t, simulator.PrepareTfArgs(tt.prepArgs[0], tt.prepArgs[1]), tt.arguments) }) } } diff --git a/pkg/simulator/terraform_vars.go b/pkg/simulator/terraform_vars.go index a7b28495..d389f77a 100644 --- a/pkg/simulator/terraform_vars.go +++ b/pkg/simulator/terraform_vars.go @@ -1,12 +1,7 @@ package simulator import ( - "fmt" "github.com/controlplaneio/simulator-standalone/pkg/util" - "github.com/pkg/errors" - "io/ioutil" - "path/filepath" - "strings" ) // TfVars struct representing the input variables for terraform to create the @@ -28,31 +23,8 @@ func NewTfVars(publicKey, accessCIDR, bucketName, attackTag string) TfVars { } } -func writeProvidersFile(tfDir, bucket string) error { - providerspath := filepath.Join(tfDir, "providers.tf") - input, err := ioutil.ReadFile(providerspath) - if err != nil { - return errors.Wrapf(err, "Error reading providers file %s", providerspath) - } - - lines := strings.Split(string(input), "\n") - for i, line := range lines { - if strings.Contains(line, "bucket = ") { - lines[i] = fmt.Sprintf(" bucket = \"%s\"", bucket) - } - } - output := strings.Join(lines, "\n") - - err = ioutil.WriteFile(providerspath, []byte(output), 0644) - if err != nil { - return errors.Wrapf(err, "Error writing providers file %s", providerspath) - } - - return nil -} - func (tfv *TfVars) String() string { - return "access_key = \"" + tfv.PublicKey + "\"\n" + "access_cidr = \"" + tfv.AccessCIDR + "\"\n" + "attack_container_tag = \"" + tfv.AttackTag + "\"\n" + return "access_key = \"" + tfv.PublicKey + "\"\n" + "access_cidr = \"" + tfv.AccessCIDR + "\"\n" + "attack_container_tag = \"" + tfv.AttackTag + "\"\n" + "state_bucket_name = \"" + tfv.BucketName + "\"\n" } @@ -61,11 +33,5 @@ func EnsureLatestTfVarsFile(tfDir, publicKey, accessCIDR, bucket, attackTag stri filename := tfDir + "/settings/bastion.tfvars" tfv := NewTfVars(publicKey, accessCIDR, bucket, attackTag) - err := writeProvidersFile(tfDir, bucket) - if err != nil { - return errors.Wrap(err, "Error saving bucket name") - - } - return util.OverwriteFile(filename, tfv.String()) } diff --git a/pkg/simulator/terraform_vars_test.go b/pkg/simulator/terraform_vars_test.go index d8ef6b91..90fe2d21 100644 --- a/pkg/simulator/terraform_vars_test.go +++ b/pkg/simulator/terraform_vars_test.go @@ -9,10 +9,11 @@ import ( func Test_TfVars_String(t *testing.T) { t.Parallel() - tfv := simulator.NewTfVars("ssh-rsa", "10.0.0.1/16", "test", "latest") + tfv := simulator.NewTfVars("ssh-rsa", "10.0.0.1/16", "test-bucket", "latest") expected := `access_key = "ssh-rsa" access_cidr = "10.0.0.1/16" attack_container_tag = "latest" +state_bucket_name = "test-bucket" ` assert.Equal(t, tfv.String(), expected) } @@ -21,7 +22,7 @@ func Test_Ensure_TfVarsFile_with_settings(t *testing.T) { tfDir := fixture("tf-dir-with-settings") varsFile := tfDir + "/settings/bastion.tfVars" - err := simulator.EnsureLatestTfVarsFile(tfDir, "ssh-rsa", "10.0.0.1/16", "test", "latest") + err := simulator.EnsureLatestTfVarsFile(tfDir, "ssh-rsa", "10.0.0.1/16", "test-bucket", "latest") assert.Nil(t, err, "Got an error") assert.Equal(t, util.MustSlurp(varsFile), "test = true\n") diff --git a/terraform/deployments/AWS/main.tf b/terraform/deployments/AWS/main.tf index fe0344dd..31d9f295 100644 --- a/terraform/deployments/AWS/main.tf +++ b/terraform/deployments/AWS/main.tf @@ -1,6 +1,6 @@ locals { - aws_tags = "${merge(var.default_tags, map("Simulator Bucket", "${var.s3_bucket_name}"))}" + aws_tags = "${merge(var.default_tags, map("Simulator Bucket", "${var.state_bucket_name}"))}" } // Setup networking diff --git a/terraform/deployments/AWS/providers.tf b/terraform/deployments/AWS/providers.tf index 2c9c8cba..2c27257b 100644 --- a/terraform/deployments/AWS/providers.tf +++ b/terraform/deployments/AWS/providers.tf @@ -7,8 +7,6 @@ provider "aws" {} terraform { backend "s3" { key = "simulator.tfstate" - // 'bucket='' must have this exact number of spaces for simulator to replace it properly - bucket = "###REPLACED-BY-SIMULATOR###" // Optional, S3 Bucket Server Side Encryption encrypt = false } diff --git a/terraform/deployments/AWS/terraform.tfvars b/terraform/deployments/AWS/terraform.tfvars deleted file mode 100644 index 8ff176fa..00000000 --- a/terraform/deployments/AWS/terraform.tfvars +++ /dev/null @@ -1 +0,0 @@ -s3_bucket_name = "###replaced by infra.go###" diff --git a/terraform/deployments/AWS/variables.tf b/terraform/deployments/AWS/variables.tf index 7aa601fa..1a6f189d 100644 --- a/terraform/deployments/AWS/variables.tf +++ b/terraform/deployments/AWS/variables.tf @@ -66,8 +66,9 @@ variable "attack_container_tag" { default = "latest" } -variable "s3_bucket_name" { +variable "state_bucket_name" { description = "name of the s3 state bucket" + default = "not-defined" }