diff --git a/tfrobot/cmd/cancel.go b/tfrobot/cmd/cancel.go index d72c8366..d46145e9 100644 --- a/tfrobot/cmd/cancel.go +++ b/tfrobot/cmd/cancel.go @@ -3,11 +3,9 @@ package cmd import ( "fmt" - "os" - "path/filepath" + "github.com/pkg/errors" "github.com/spf13/cobra" - "github.com/threefoldtech/tfgrid-sdk-go/tfrobot/internal/parser" "github.com/threefoldtech/tfgrid-sdk-go/tfrobot/pkg/deployer" ) @@ -19,36 +17,18 @@ var cancelCmd = &cobra.Command{ if len(cmd.Flags().Args()) != 0 { return fmt.Errorf("'cancel' and %v cannot be used together, please use one command at a time", cmd.Flags().Args()) } - - debug, err := cmd.Flags().GetBool("debug") - if err != nil { - return fmt.Errorf("invalid log debug mode input '%v' with error: %w", debug, err) - } - configPath, err := cmd.Flags().GetString("config") if err != nil { - return fmt.Errorf("error in configuration file: %w", err) - } - - if configPath == "" { - return fmt.Errorf("required configuration file path is empty") + return errors.Wrap(err, "error in configuration file") } - - configFile, err := os.Open(configPath) + debug, err := cmd.Flags().GetBool("debug") if err != nil { - return fmt.Errorf("failed to open configuration file '%s' with error: %w", configPath, err) + return errors.Wrapf(err, "invalid log debug mode input '%v'", debug) } - defer configFile.Close() - jsonFmt := filepath.Ext(configPath) == jsonExt - ymlFmt := filepath.Ext(configPath) == yamlExt || filepath.Ext(configPath) == ymlExt - if !jsonFmt && !ymlFmt { - return fmt.Errorf("unsupported configuration file format '%s', should be [yaml, yml, json]", configPath) - } - - cfg, err := parser.ParseConfig(configFile, jsonFmt) + cfg, err := readConfig(configPath) if err != nil { - return fmt.Errorf("failed to parse configuration file '%s' with error: %w", configPath, err) + return err } tfPluginClient, err := setup(cfg, debug) @@ -58,7 +38,7 @@ var cancelCmd = &cobra.Command{ err = deployer.RunCanceler(cfg, tfPluginClient, debug) if err != nil { - return fmt.Errorf("failed to cancel configured deployments with error: %w", err) + return errors.Wrap(err, "failed to cancel configured deployments") } return nil diff --git a/tfrobot/cmd/deploy.go b/tfrobot/cmd/deploy.go index 823ac7cb..6638b33d 100644 --- a/tfrobot/cmd/deploy.go +++ b/tfrobot/cmd/deploy.go @@ -3,22 +3,12 @@ package cmd import ( "context" - "errors" "fmt" - "os" - "path/filepath" - "github.com/rs/zerolog/log" + "github.com/pkg/errors" "github.com/spf13/cobra" "github.com/threefoldtech/tfgrid-sdk-go/tfrobot/internal/parser" "github.com/threefoldtech/tfgrid-sdk-go/tfrobot/pkg/deployer" - "golang.org/x/sys/unix" -) - -const ( - ymlExt = ".yml" - yamlExt = ".yaml" - jsonExt = ".json" ) var deployCmd = &cobra.Command{ @@ -29,53 +19,26 @@ var deployCmd = &cobra.Command{ if len(cmd.Flags().Args()) != 0 { return fmt.Errorf("'deploy' and %v cannot be used together, please use one command at a time", cmd.Flags().Args()) } - - debug, err := cmd.Flags().GetBool("debug") - if err != nil { - return fmt.Errorf("invalid log debug mode input '%v' with error: %w", debug, err) - } - - outputPath, err := cmd.Flags().GetString("output") - if err != nil { - return fmt.Errorf("error in output file: %w", err) - } - - outJsonFmt := filepath.Ext(outputPath) == jsonExt - outYmlFmt := filepath.Ext(outputPath) == yamlExt || filepath.Ext(outputPath) == ymlExt - if !outJsonFmt && !outYmlFmt { - return fmt.Errorf("unsupported output file format '%s', should be [yaml, yml, json]", outputPath) - } - - _, err = os.Stat(outputPath) - // check if output file is writable - if !errors.Is(err, os.ErrNotExist) && unix.Access(outputPath, unix.W_OK) != nil { - return fmt.Errorf("output path '%s' is not writable", outputPath) - } - configPath, err := cmd.Flags().GetString("config") if err != nil { - return fmt.Errorf("error in configuration file: %w", err) + return errors.Wrap(err, "error in configuration file") } - - if configPath == "" { - return fmt.Errorf("required configuration file path is empty") + debug, err := cmd.Flags().GetBool("debug") + if err != nil { + return errors.Wrapf(err, "invalid log debug mode input '%v'", debug) } - - configFile, err := os.Open(configPath) + outputPath, err := cmd.Flags().GetString("output") if err != nil { - return fmt.Errorf("failed to open configuration file '%s' with error: %w", configPath, err) + return errors.Wrap(err, "error in output file") } - defer configFile.Close() - jsonFmt := filepath.Ext(configPath) == jsonExt - ymlFmt := filepath.Ext(configPath) == yamlExt || filepath.Ext(configPath) == ymlExt - if !jsonFmt && !ymlFmt { - return fmt.Errorf("unsupported configuration file format '%s', should be [yaml, yml, json]", configPath) + if err = checkOutputFile(outputPath); err != nil { + return err } - cfg, err := parser.ParseConfig(configFile, jsonFmt) + cfg, err := readConfig(configPath) if err != nil { - return fmt.Errorf("failed to parse configuration file '%s' with error: %w", configPath, err) + return err } tfPluginClient, err := setup(cfg, debug) @@ -84,14 +47,11 @@ var deployCmd = &cobra.Command{ } if err = parser.ValidateConfig(cfg, tfPluginClient); err != nil { - return fmt.Errorf("failed to validate configuration file '%s' with error: %w", configPath, err) + return errors.Wrapf(err, "failed to validate configuration file '%s' with error", configPath) } - ctx := context.Background() - if errs := deployer.RunDeployer(ctx, cfg, tfPluginClient, outputPath, debug); errs != nil { - log.Error().Msg("deployments failed with errors: ") - fmt.Println(errs) - os.Exit(1) + if errs := deployer.RunDeployer(context.Background(), cfg, tfPluginClient, outputPath, debug); errs != nil { + return errors.Wrap(err, "failed to run deployer") } return nil diff --git a/tfrobot/cmd/load.go b/tfrobot/cmd/load.go index 895dd6bf..e61d3759 100644 --- a/tfrobot/cmd/load.go +++ b/tfrobot/cmd/load.go @@ -3,16 +3,11 @@ package cmd import ( "context" - "errors" "fmt" - "os" - "path/filepath" - "github.com/rs/zerolog/log" + "github.com/pkg/errors" "github.com/spf13/cobra" - "github.com/threefoldtech/tfgrid-sdk-go/tfrobot/internal/parser" "github.com/threefoldtech/tfgrid-sdk-go/tfrobot/pkg/deployer" - "golang.org/x/sys/unix" ) var loadCmd = &cobra.Command{ @@ -24,62 +19,35 @@ var loadCmd = &cobra.Command{ return fmt.Errorf("'load' and %v cannot be used together, please use one command at a time", cmd.Flags().Args()) } - debug, err := cmd.Flags().GetBool("debug") - if err != nil { - return fmt.Errorf("invalid log debug mode input '%v' with error: %w", debug, err) - } - - outputPath, err := cmd.Flags().GetString("output") - if err != nil { - return fmt.Errorf("error in output file: %w", err) - } - outJsonFmt := filepath.Ext(outputPath) == jsonExt - outYmlFmt := filepath.Ext(outputPath) == yamlExt || filepath.Ext(outputPath) == ymlExt - if !outJsonFmt && !outYmlFmt { - return fmt.Errorf("unsupported output file format '%s', should be [yaml, yml, json]", outputPath) - } - - _, err = os.Stat(outputPath) - // check if output file is writable - if !errors.Is(err, os.ErrNotExist) && unix.Access(outputPath, unix.W_OK) != nil { - return fmt.Errorf("output path '%s' is not writable", outputPath) - } - configPath, err := cmd.Flags().GetString("config") if err != nil { - return fmt.Errorf("error in configuration file: %w", err) + return errors.Wrap(err, "error in configuration file") } - if configPath == "" { - return fmt.Errorf("required configuration file path is empty") + debug, err := cmd.Flags().GetBool("debug") + if err != nil { + return errors.Wrapf(err, "invalid log debug mode input '%v'", debug) } - - configFile, err := os.Open(configPath) + outputPath, err := cmd.Flags().GetString("output") if err != nil { - return fmt.Errorf("failed to open configuration file '%s' with error: %w", configPath, err) + return errors.Wrap(err, "error in output file") } - defer configFile.Close() - jsonFmt := filepath.Ext(configPath) == jsonExt - ymlFmt := filepath.Ext(configPath) == yamlExt || filepath.Ext(configPath) == ymlExt - if !jsonFmt && !ymlFmt { - return fmt.Errorf("unsupported configuration file format '%s', should be [yaml, yml, json]", configPath) + if err = checkOutputFile(outputPath); err != nil { + return err } - cfg, err := parser.ParseConfig(configFile, jsonFmt) + cfg, err := readConfig(configPath) if err != nil { - return fmt.Errorf("failed to parse configuration file '%s' with error: %w", configPath, err) + return err } - ctx := context.Background() tfPluginClient, err := setup(cfg, debug) if err != nil { return err } - if err := deployer.RunLoader(ctx, cfg, tfPluginClient, debug, outputPath); err != nil { - log.Error().Msg("failed to load configured deployments") - fmt.Println(err) - os.Exit(1) + if err := deployer.RunLoader(context.Background(), cfg, tfPluginClient, debug, outputPath); err != nil { + return errors.Wrap(err, "failed to load configured deployments") } return nil diff --git a/tfrobot/cmd/setup.go b/tfrobot/cmd/setup.go index da6a821b..e4131a75 100644 --- a/tfrobot/cmd/setup.go +++ b/tfrobot/cmd/setup.go @@ -1,11 +1,23 @@ package cmd import ( + "fmt" + "os" + "path/filepath" + "slices" + + "github.com/pkg/errors" "github.com/rs/zerolog/log" "github.com/threefoldtech/tfgrid-sdk-go/grid-client/deployer" + "github.com/threefoldtech/tfgrid-sdk-go/tfrobot/internal/parser" tfrobot "github.com/threefoldtech/tfgrid-sdk-go/tfrobot/pkg/deployer" + "golang.org/x/sys/unix" ) +const jsonExt = ".json" + +var allowedExt = []string{".yml", ".yaml", jsonExt} + func setup(conf tfrobot.Config, debug bool) (deployer.TFPluginClient, error) { network := conf.Network log.Debug().Str("network", network).Send() @@ -24,3 +36,38 @@ func setup(conf tfrobot.Config, debug bool) (deployer.TFPluginClient, error) { return deployer.NewTFPluginClient(mnemonic, opts...) } + +func readConfig(configPath string) (tfrobot.Config, error) { + if configPath == "" { + return tfrobot.Config{}, errors.New("required configuration file path is empty") + } + + configFile, err := os.Open(configPath) + if err != nil { + return tfrobot.Config{}, errors.Wrapf(err, "failed to open configuration file '%s'", configPath) + } + defer configFile.Close() + + if !slices.Contains(allowedExt, filepath.Ext(configPath)) { + return tfrobot.Config{}, fmt.Errorf("unsupported configuration file format '%s', should be [yaml, yml, json]", configPath) + } + + cfg, err := parser.ParseConfig(configFile, filepath.Ext(configPath) == jsonExt) + if err != nil { + return tfrobot.Config{}, errors.Wrapf(err, "failed to parse configuration file '%s' with error", configPath) + } + return cfg, nil +} + +func checkOutputFile(outputPath string) error { + if !slices.Contains(allowedExt, filepath.Ext(outputPath)) { + return fmt.Errorf("unsupported output file format '%s', should be [yaml, yml, json]", outputPath) + } + + _, err := os.Stat(outputPath) + // check if output file is writable + if !errors.Is(err, os.ErrNotExist) && unix.Access(outputPath, unix.W_OK) != nil { + return fmt.Errorf("output path '%s' is not writable", outputPath) + } + return nil +}