Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Terraform multi-state #472

Merged
merged 22 commits into from
Sep 30, 2022
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
9901f46
added a simple example of a multi-state monorepo
psihachina Sep 26, 2022
296746b
added `depends_on` option for terraform struct
psihachina Sep 26, 2022
66c47bf
added `findDuplicates` function
psihachina Sep 27, 2022
cee1348
added `name` parameter for `GenerateTerraformFiles` function
psihachina Sep 27, 2022
9f9c7ea
added `GetStates` function
psihachina Sep 27, 2022
c56e7d4
added `ize up apps` command
psihachina Sep 27, 2022
ee7414c
added an exception for the `infra` state
psihachina Sep 27, 2022
66aa491
added support multiple terraform states & configurations
psihachina Sep 28, 2022
44c11ea
fixed terraform e2e test
psihachina Sep 28, 2022
dda6448
updated .gitignore
psihachina Sep 28, 2022
6487177
updated ize.toml in examples/multistate-monorepo
psihachina Sep 28, 2022
32be2ee
renamed `statePath` to `stackPath`
psihachina Sep 28, 2022
a996082
added `explain` flag
psihachina Sep 29, 2022
5e71166
added call `terraform init` before `terraform destroy` in `ize down`/…
psihachina Sep 29, 2022
01c8478
changed logic of generating terraform state key
psihachina Sep 30, 2022
33263d8
updated examples
psihachina Sep 30, 2022
3afa764
removed `infra` as default stack
psihachina Sep 30, 2022
4b28a58
updated sls monorepo example
psihachina Sep 30, 2022
ef786cb
Merge pull request #475 from hazelops/IZE-599-ize-infra-down-doesnt-r…
psihachina Sep 30, 2022
04a26c8
Merge branch 'IZE-582-IZE-361-IZE-446' into IZE-516-ize-up-infra-expl…
psihachina Sep 30, 2022
96cc544
Merge pull request #474 from hazelops/IZE-516-ize-up-infra-explain-ba…
psihachina Sep 30, 2022
fa1d3a9
updated ize.toml
psihachina Sep 30, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,5 @@ ize
.terraform
examples/**/.ize/env/*
!examples/**/.ize/env/testnut
backend.tf
terraform.tfvars
Empty file.
11 changes: 11 additions & 0 deletions examples/multistate-monorepo/.ize/env/testnut/api/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
variable "env" {}
variable "namespace" {}
variable "aws_profile" {}
variable "aws_region" {}
variable "ssh_public_key" {}
variable "ec2_key_pair_name" {}

locals {
env = var.env
namespace = var.namespace
}
11 changes: 11 additions & 0 deletions examples/multistate-monorepo/.ize/env/testnut/ize.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
aws_region = "us-east-1" # (required) AWS Region of this environment should be specified here. Can be overriden by AWS_PROFILE env var or --aws-region flag.
namespace = "testnut" # (required) Namespace of the project can be specified here. It is used as a base for all naming. It can be overridden by NAMESPACE env var or --namespace flag.
terraform_version = "1.2.6" # (optional) Terraform version can be set here. 1.1.3 by default

[terraform.api]
depends_on = ["vpc"]

[terraform.vpc]
depends_on = ["infra"]

[terraform.infra]
AutomationD marked this conversation as resolved.
Show resolved Hide resolved
Empty file.
11 changes: 11 additions & 0 deletions examples/multistate-monorepo/.ize/env/testnut/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
variable "env" {}
variable "namespace" {}
variable "aws_profile" {}
variable "aws_region" {}
variable "ssh_public_key" {}
variable "ec2_key_pair_name" {}

locals {
env = var.env
namespace = var.namespace
}
Empty file.
11 changes: 11 additions & 0 deletions examples/multistate-monorepo/.ize/env/testnut/vpc/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
variable "env" {}
variable "namespace" {}
variable "aws_profile" {}
variable "aws_region" {}
variable "ssh_public_key" {}
variable "ec2_key_pair_name" {}

locals {
env = var.env
namespace = var.namespace
}
4 changes: 2 additions & 2 deletions examples/sls-apps-monorepo/.ize/env/testnut/ize.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ terraform_version = "1.2.6" # (optional) Terraform version can be se
# config_file = "" # (optional) Path to ize.toml config file can be specified, but normally it's read from the environment's directory automatically.
# home = "" # (optional) User home directory can be specified here. Normally $HOME is used.

# [terraform.infra]
# aws_region = "" # (optional) Terraform-specific AWS Region of this environment should be specified here. Normally global AWS_REGION is used.
[terraform.infra]
aws_region = "us-east-1" # (optional) Terraform-specific AWS Region of this environment should be specified here. Normally global AWS_REGION is used.
# aws_profile = "" # (optional) Terraform-specific AWS profile (optional) can be specified here (but normally it should be inherited from a global AWS_PROFILE).
# version = "" # (optional) Terraform version can be set here. 1.1.3 by default.
# state_bucket_region = "" # (optional) Terraform state bucket region can be specified here. Normally AWS_REGION is used here. Can be overriden via env vars or flags.
Expand Down
112 changes: 44 additions & 68 deletions internal/commands/down.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/pterm/pterm"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"time"
)

type DownOptions struct {
Expand Down Expand Up @@ -114,20 +115,21 @@ func (o *DownOptions) Complete(cmd *cobra.Command, args []string) error {
}

if o.Config.Terraform == nil {
o.Config.Terraform = map[string]*config.Terraform{}
o.Config.Terraform["infra"] = &config.Terraform{}
return fmt.Errorf("you must specify at least one terraform stack in ize.toml")
}

if len(o.Config.Terraform["infra"].AwsProfile) == 0 {
o.Config.Terraform["infra"].AwsProfile = o.Config.AwsProfile
}
if _, ok := o.Config.Terraform["infra"]; ok {
if len(o.Config.Terraform["infra"].AwsProfile) == 0 {
o.Config.Terraform["infra"].AwsProfile = o.Config.AwsProfile
}

if len(o.Config.Terraform["infra"].AwsRegion) == 0 {
o.Config.Terraform["infra"].AwsRegion = o.Config.AwsRegion
}
if len(o.Config.Terraform["infra"].AwsRegion) == 0 {
o.Config.Terraform["infra"].AwsRegion = o.Config.AwsRegion
}

if len(o.Config.Terraform["infra"].Version) == 0 {
o.Config.Terraform["infra"].Version = o.Config.TerraformVersion
if len(o.Config.Terraform["infra"].Version) == 0 {
o.Config.Terraform["infra"].Version = o.Config.TerraformVersion
}
}
} else {
if err := requirements.CheckRequirements(requirements.WithIzeStructure(), requirements.WithConfigFile()); err != nil {
Expand Down Expand Up @@ -172,7 +174,7 @@ func (o *DownOptions) Run() error {
return err
}
} else {
err := destroyApp(ui, o)
err := destroyApp(o.AppName, o.Config, ui)
if err != nil {
return err
}
Expand Down Expand Up @@ -218,58 +220,34 @@ func destroyAll(ui terminal.UI, o *DownOptions) error {
err := manager.InReversDependencyOrder(aws.BackgroundContext(), o.Config.GetApps(), func(c context.Context, name string) error {
o.Config.AwsProfile = o.Config.Terraform["infra"].AwsProfile

var m manager.Manager

if app, ok := o.Config.Serverless[name]; ok {
app.Name = name
m = &serverless.Manager{
Project: o.Config,
App: app,
}
}
if app, ok := o.Config.Alias[name]; ok {
app.Name = name
m = &alias.Manager{
Project: o.Config,
App: app,
}
}
if app, ok := o.Config.Ecs[name]; ok {
app.Name = name
m = &ecs.Manager{
Project: o.Config,
App: app,
}
}

// destroy
err := m.Destroy(ui)
if err != nil {
return fmt.Errorf("can't destroy app: %w", err)
}

return nil
return destroyApp(name, o.Config, ui)
})
if err != nil {
return err
}

err = destroyInfra(ui, o.Config, o.SkipGen)
if err != nil {
return err
if _, ok := o.Config.Terraform["infra"]; ok {
err = destroyInfra("infra", o.Config, o.SkipGen, ui)
if err != nil {
return err
}
}

err = manager.InReversDependencyOrder(aws.BackgroundContext(), o.Config.GetStates(), func(c context.Context, name string) error {
o.Config.AwsProfile = o.Config.Terraform["infra"].AwsProfile

return destroyInfra(name, o.Config, o.SkipGen, ui)
})

ui.Output("Destroy all completed!\n", terminal.WithSuccessStyle())
time.Sleep(time.Millisecond * 200)

return nil
}

func destroyInfra(ui terminal.UI, config *config.Project, skipGen bool) error {
func destroyInfra(state string, config *config.Project, skipGen bool, ui terminal.UI) error {
if !skipGen {
err := GenerateTerraformFiles(
config,
"",
)
err := GenerateTerraformFiles(state, "", config)
if err != nil {
return err
}
Expand All @@ -296,9 +274,9 @@ func destroyInfra(ui terminal.UI, config *config.Project, skipGen bool) error {

switch config.PreferRuntime {
case "docker":
tf = terraform.NewDockerTerraform(config.Terraform["infra"].Version, []string{"destroy", "-auto-approve"}, env, nil, config)
tf = terraform.NewDockerTerraform(state, []string{"destroy", "-auto-approve"}, env, nil, config)
case "native":
tf = terraform.NewLocalTerraform(config.Terraform["infra"].Version, []string{"destroy", "-auto-approve"}, env, nil, config)
tf = terraform.NewLocalTerraform(state, []string{"destroy", "-auto-approve"}, env, nil, config)
err = tf.Prepare()
if err != nil {
return fmt.Errorf("can't destroy infra: %w", err)
Expand All @@ -319,35 +297,35 @@ func destroyInfra(ui terminal.UI, config *config.Project, skipGen bool) error {
return nil
}

func destroyApp(ui terminal.UI, o *DownOptions) error {
func destroyApp(name string, cfg *config.Project, ui terminal.UI) error {
var m manager.Manager
var icon string

m = &ecs.Manager{
Project: o.Config,
App: &config.Ecs{Name: o.AppName},
Project: cfg,
App: &config.Ecs{Name: name},
}

if app, ok := o.Config.Serverless[o.AppName]; ok {
app.Name = o.AppName
if app, ok := cfg.Serverless[name]; ok {
app.Name = name
m = &serverless.Manager{
Project: o.Config,
Project: cfg,
App: app,
}
icon = app.Icon
}
if app, ok := o.Config.Alias[o.AppName]; ok {
app.Name = o.AppName
if app, ok := cfg.Alias[name]; ok {
app.Name = name
m = &alias.Manager{
Project: o.Config,
Project: cfg,
App: app,
}
icon = app.Icon
}
if app, ok := o.Config.Ecs[o.AppName]; ok {
app.Name = o.AppName
if app, ok := cfg.Ecs[name]; ok {
app.Name = name
m = &ecs.Manager{
Project: o.Config,
Project: cfg,
App: app,
}
icon = app.Icon
Expand All @@ -357,16 +335,14 @@ func destroyApp(ui terminal.UI, o *DownOptions) error {
icon += " "
}

ui.Output("Destroying %s%s app...\n", icon, o.AppName, terminal.WithHeaderStyle())
sg := ui.StepGroup()
defer sg.Wait()
ui.Output("Destroying %s%s app...\n", icon, name, terminal.WithHeaderStyle())

err := m.Destroy(ui)
if err != nil {
return fmt.Errorf("can't down: %w", err)
}

ui.Output("Destroy app %s%s completed\n", icon, o.AppName, terminal.WithSuccessStyle())
ui.Output("Destroy app %s%s completed\n", icon, name, terminal.WithSuccessStyle())

return nil
}
60 changes: 40 additions & 20 deletions internal/commands/down_infra.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ package commands
import (
"context"
"fmt"
"github.com/aws/aws-sdk-go/aws"
"github.com/hazelops/ize/internal/config"
"github.com/hazelops/ize/internal/manager"
"github.com/hazelops/ize/internal/requirements"
"github.com/hazelops/ize/pkg/terminal"
"github.com/spf13/cobra"
Expand All @@ -16,6 +18,7 @@ type DownInfraOptions struct {
AwsProfile string
AwsRegion string
SkipGen bool
OnlyInfra bool
}

func NewDownInfraFlags(project *config.Project) *DownInfraOptions {
Expand Down Expand Up @@ -55,6 +58,7 @@ func NewCmdDownInfra(project *config.Project) *cobra.Command {
cmd.Flags().StringVar(&o.AwsProfile, "infra.terraform.aws-profile", "", "set aws profile")
cmd.Flags().StringVar(&o.AwsRegion, "infra.terraform.aws-region", "", "set aws region")
cmd.Flags().BoolVar(&o.SkipGen, "skip-gen", false, "skip generating terraform files")
cmd.Flags().BoolVar(&o.OnlyInfra, "only-infra", false, "down only infra state")

return cmd
}
Expand All @@ -65,32 +69,33 @@ func (o *DownInfraOptions) Complete() error {
}

if o.Config.Terraform == nil {
o.Config.Terraform = map[string]*config.Terraform{}
o.Config.Terraform["infra"] = &config.Terraform{}
return fmt.Errorf("you must specify at least one terraform stack in ize.toml")
}

if len(o.AwsProfile) != 0 {
o.Config.Terraform["infra"].AwsProfile = o.AwsProfile
}
if _, ok := o.Config.Terraform["infra"]; ok {
if len(o.AwsProfile) != 0 {
o.Config.Terraform["infra"].AwsProfile = o.AwsProfile
}

if len(o.Config.Terraform["infra"].AwsProfile) == 0 {
o.Config.Terraform["infra"].AwsProfile = o.Config.AwsProfile
}
if len(o.Config.Terraform["infra"].AwsProfile) == 0 {
o.Config.Terraform["infra"].AwsProfile = o.Config.AwsProfile
}

if len(o.AwsProfile) != 0 {
o.Config.Terraform["infra"].AwsRegion = o.AwsRegion
}
if len(o.AwsProfile) != 0 {
o.Config.Terraform["infra"].AwsRegion = o.AwsRegion
}

if len(o.Config.Terraform["infra"].AwsRegion) == 0 {
o.Config.Terraform["infra"].AwsRegion = o.Config.AwsRegion
}
if len(o.Config.Terraform["infra"].AwsRegion) == 0 {
o.Config.Terraform["infra"].AwsRegion = o.Config.AwsRegion
}

if len(o.Version) != 0 {
o.Config.Terraform["infra"].Version = o.Version
}
if len(o.Version) != 0 {
o.Config.Terraform["infra"].Version = o.Version
}

if len(o.Config.Terraform["infra"].Version) == 0 {
o.Config.Terraform["infra"].Version = o.Config.TerraformVersion
if len(o.Config.Terraform["infra"].Version) == 0 {
o.Config.Terraform["infra"].Version = o.Config.TerraformVersion
}
}

o.ui = terminal.ConsoleUI(context.Background(), o.Config.PlainText)
Expand All @@ -108,5 +113,20 @@ func (o *DownInfraOptions) Validate() error {

func (o *DownInfraOptions) Run() error {
ui := o.ui
return destroyInfra(ui, o.Config, o.SkipGen)

if _, ok := o.Config.Terraform["infra"]; ok {
err := destroyInfra("infra", o.Config, o.SkipGen, ui)
if err != nil {
return err
}
}

err := manager.InReversDependencyOrder(aws.BackgroundContext(), o.Config.GetApps(), func(c context.Context, name string) error {
return destroyInfra(name, o.Config, o.SkipGen, ui)
})
if err != nil {

}

return nil
}
4 changes: 2 additions & 2 deletions internal/commands/terraform.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,9 +126,9 @@ func (o *TerraformOptions) Run(args []string) error {

switch o.Config.PreferRuntime {
case "docker":
tf = terraform.NewDockerTerraform(o.Version, args, env, nil, o.Config)
tf = terraform.NewDockerTerraform("infra", args, env, nil, o.Config)
case "native":
tf = terraform.NewLocalTerraform(o.Version, args, env, nil, o.Config)
tf = terraform.NewLocalTerraform("infra", args, env, nil, o.Config)
err = tf.Prepare()
if err != nil {
return err
Expand Down
Loading