diff --git a/bt/stack/init.go b/bt/stack/init.go new file mode 100644 index 0000000..8f29a2e --- /dev/null +++ b/bt/stack/init.go @@ -0,0 +1,86 @@ +package stack + +import ( + "context" + "fmt" + "os" + "path/filepath" + + "github.com/DavidGamba/dgtools/bt/config" + sconfig "github.com/DavidGamba/dgtools/bt/stack/config" + "github.com/DavidGamba/dgtools/bt/terraform" + "github.com/DavidGamba/go-getoptions" +) + +func InitCMD(ctx context.Context, parent *getoptions.GetOpt) *getoptions.GetOpt { + cfg := config.ConfigFromContext(ctx) + + opt := parent.NewCommand("init", "Runs terraform init on each component of the stack") + opt.SetCommandFn(InitRun) + opt.Bool("dry-run", false) + opt.Bool("ignore-cache", false, opt.Description("Ignore the cache and re-run the plan"), opt.Alias("ic")) + opt.Bool("serial", false) + opt.Bool("lock", false, opt.Description("Run 'terraform providers lock' after init")) + opt.String("profile", "default", opt.Description("BT Terraform Profile to use"), opt.GetEnv(cfg.Config.TerraformProfileEnvVar)) + opt.Int("stack-parallelism", 1, opt.Description("Max number of stack components to run in parallel")) + + return opt +} + +func InitRun(ctx context.Context, opt *getoptions.GetOpt, args []string) error { + id := opt.Value("id").(string) + serial := opt.Value("serial").(bool) + stackParallelism := opt.Value("stack-parallelism").(int) + + if id == "" { + fmt.Fprintf(os.Stderr, "ERROR: missing stack id\n") + fmt.Fprint(os.Stderr, opt.Help(getoptions.HelpSynopsis)) + return getoptions.ErrorHelpCalled + } + + cfg := sconfig.ConfigFromContext(ctx) + + wd, err := os.Getwd() + if err != nil { + return fmt.Errorf("failed to get current working directory: %w", err) + } + + wsFn := func(component, dir, ws string, variables []string) getoptions.CommandFn { + return func(ctx context.Context, opt *getoptions.GetOpt, args []string) error { + ctx = terraform.NewComponentContext(ctx, fmt.Sprintf("%s:%s", component, ws)) + ctx = terraform.NewStackContext(ctx, true) + d := filepath.Join(cfg.ConfigRoot, dir) + d, err = filepath.Rel(wd, d) + if err != nil { + return fmt.Errorf("failed to get relative path: %w", err) + } + ctx = terraform.NewDirContext(ctx, d) + + nopt := getoptions.New() + nopt.Bool("dry-run", opt.Value("dry-run").(bool)) + nopt.Bool("ignore-cache", opt.Value("ignore-cache").(bool)) + nopt.String("profile", opt.Value("profile").(string)) + nopt.String("color", opt.Value("color").(string)) + + return terraform.InitRun(ctx, nopt, args) + } + } + + g, err := generateDAG(opt, id, cfg, true, wsFn) + if err != nil { + return err + } + g.SetMaxParallel(stackParallelism) + Logger.Printf("stack parallelism: %d\n", stackParallelism) + + if serial { + g.SetSerial() + } + + err = g.Run(ctx, opt, args) + if err != nil { + return fmt.Errorf("failed to run graph: %w", err) + } + + return nil +} diff --git a/bt/stack/stack.go b/bt/stack/stack.go index e67a544..9e77590 100644 --- a/bt/stack/stack.go +++ b/bt/stack/stack.go @@ -25,6 +25,7 @@ func NewCommand(ctx context.Context, parent *getoptions.GetOpt) *getoptions.GetO ConfigCMD(ctx, opt) GraphCMD(ctx, opt) BuildCMD(ctx, opt) + InitCMD(ctx, opt) MirrorCMD(ctx, opt) return opt } diff --git a/bt/terraform/build.go b/bt/terraform/build.go index d0b18dd..13af82e 100644 --- a/bt/terraform/build.go +++ b/bt/terraform/build.go @@ -76,7 +76,7 @@ func BuildRun(ctx context.Context, opt *getoptions.GetOpt, args []string) error } tm := dag.NewTaskMap() - tm.Add("init", initRun) + tm.Add("init", InitRun) if lock { tm.Add("lock", lockFn) } diff --git a/bt/terraform/init.go b/bt/terraform/init.go index bc154cf..c06f74b 100644 --- a/bt/terraform/init.go +++ b/bt/terraform/init.go @@ -18,11 +18,11 @@ func initCMD(ctx context.Context, parent *getoptions.GetOpt) *getoptions.GetOpt opt := parent.NewCommand("init", "") opt.Bool("dry-run", false) opt.Bool("ignore-cache", false, opt.Description("Ignore the cache and re-run the init"), opt.Alias("ic")) - opt.SetCommandFn(initRun) + opt.SetCommandFn(InitRun) return opt } -func initRun(ctx context.Context, opt *getoptions.GetOpt, args []string) error { +func InitRun(ctx context.Context, opt *getoptions.GetOpt, args []string) error { dryRun := opt.Value("dry-run").(bool) profile := opt.Value("profile").(string) color := opt.Value("color").(string) diff --git a/bt/terraform/init_test.go b/bt/terraform/init_test.go index eb1a4e7..bb5f1ce 100644 --- a/bt/terraform/init_test.go +++ b/bt/terraform/init_test.go @@ -48,7 +48,7 @@ func TestInit(t *testing.T) { opt.Bool("ignore-cache", false) opt.String("profile", "default") opt.String("color", "auto") - err := initRun(ctx, opt, []string{}) + err := InitRun(ctx, opt, []string{}) if err != nil { t.Errorf("TestInit error: %s", err) } @@ -86,7 +86,7 @@ func TestInit(t *testing.T) { opt.Bool("ignore-cache", false) opt.String("profile", "default") opt.String("color", "auto") - err := initRun(ctx, opt, []string{}) + err := InitRun(ctx, opt, []string{}) if err != nil { t.Errorf("TestInit error: %s", err) } @@ -126,7 +126,7 @@ func TestInit(t *testing.T) { opt.Bool("ignore-cache", false) opt.String("profile", "dev") opt.String("color", "auto") - err := initRun(ctx, opt, []string{}) + err := InitRun(ctx, opt, []string{}) if err != nil { t.Errorf("TestInit error: %s", err) } @@ -165,7 +165,7 @@ func TestInit(t *testing.T) { opt.Bool("ignore-cache", false) opt.String("profile", "prod") opt.String("color", "auto") - err := initRun(ctx, opt, []string{}) + err := InitRun(ctx, opt, []string{}) if err != nil { t.Errorf("TestInit error: %s", err) }