From f7217245a7bac55713502b18eb5549239e5abe5d Mon Sep 17 00:00:00 2001 From: Ruslan Aliev Date: Wed, 7 Oct 2020 17:36:01 -0500 Subject: [PATCH] Add --overwrite option to config init cmd Currently airshipctl will overwrite an existing config file by default during config init execution. This patch adds an appropriate flag to explicitly control whether the user wants to overwrite an existing file or not. Change-Id: I9f4756b98e9d1245145809aed203974e99feb662 Signed-off-by: Ruslan Aliev --- cmd/config/init.go | 35 +++++++++++-------- cmd/config/set_management_configuration.go | 2 +- .../config-cmd-with-help.golden | 2 +- .../config-init-help.golden | 24 +++++++++---- docs/source/cli/airshipctl_config.md | 2 +- docs/source/cli/airshipctl_config_init.md | 29 +++++++++++---- pkg/config/config.go | 14 +++++--- pkg/config/config_helper.go | 8 ++--- pkg/config/config_test.go | 7 ++-- pkg/config/errors.go | 9 +++++ 10 files changed, 91 insertions(+), 41 deletions(-) diff --git a/cmd/config/init.go b/cmd/config/init.go index d746fecdc..ef950b70a 100644 --- a/cmd/config/init.go +++ b/cmd/config/init.go @@ -22,34 +22,41 @@ import ( const ( initLong = ` -Generate an airshipctl config file and its associated kubeConfig file. -These files will be written to the $HOME/.airship directory, and will contain -default configurations. +Generate an airshipctl config file. This file by default will be written to the $HOME/.airship directory, +and will contain default configuration. In case if flag --airshipconf provided - the file will be +written to the specified location instead. If a configuration file already exists at the specified path, +an error will be thrown; to overwrite it, specify the --overwrite flag. +` + initExample = ` +# Create new airshipctl config file at the default location +airshipctl config init -NOTE: This will overwrite any existing config files in $HOME/.airship +# Create new airshipctl config file at the custom location +airshipctl config init --airshipconf path/to/config + +# Create new airshipctl config file at custom location and overwrite it +airshipctl config init --overwrite --airshipconf path/to/config ` ) -// NewInitCommand creates a command for generating default airshipctl config files. +// NewInitCommand creates a command for generating default airshipctl config file. func NewInitCommand() *cobra.Command { - // TODO(howell): It'd be nice to have a flag to tell - // airshipctl where to store the new files. - // TODO(howell): Currently, this command overwrites whatever the user - // has in their airship directory. We should remove that functionality - // as default and provide and optional --overwrite flag. + var overwrite bool cmd := &cobra.Command{ - Use: "init", - Short: "Generate initial configuration files for airshipctl", - Long: initLong[1:], + Use: "init", + Short: "Generate initial configuration file for airshipctl", + Long: initLong[1:], + Example: initExample, RunE: func(cmd *cobra.Command, args []string) error { airshipConfigPath, err := cmd.Flags().GetString("airshipconf") if err != nil { airshipConfigPath = "" } - return config.CreateConfig(airshipConfigPath) + return config.CreateConfig(airshipConfigPath, overwrite) }, } + cmd.Flags().BoolVar(&overwrite, "overwrite", false, "overwrite config file") return cmd } diff --git a/cmd/config/set_management_configuration.go b/cmd/config/set_management_configuration.go index 82a899ba7..bcca48a2e 100644 --- a/cmd/config/set_management_configuration.go +++ b/cmd/config/set_management_configuration.go @@ -92,7 +92,7 @@ func NewSetManagementConfigCommand(cfgFactory config.Factory) *cobra.Command { return nil } - return cfg.PersistConfig() + return cfg.PersistConfig(true) }, } diff --git a/cmd/config/testdata/TestConfigGoldenOutput/config-cmd-with-help.golden b/cmd/config/testdata/TestConfigGoldenOutput/config-cmd-with-help.golden index 6912569ee..53de3049f 100644 --- a/cmd/config/testdata/TestConfigGoldenOutput/config-cmd-with-help.golden +++ b/cmd/config/testdata/TestConfigGoldenOutput/config-cmd-with-help.golden @@ -9,7 +9,7 @@ Available Commands: get-management-config View a management config or all management configs defined in the airshipctl config get-manifest Get a manifest information from the airshipctl config help Help about any command - init Generate initial configuration files for airshipctl + init Generate initial configuration file for airshipctl set-context Manage contexts set-encryption-config Manage encryption configs in airship config set-management-config Modify an out-of-band management configuration diff --git a/cmd/config/testdata/TestConfigInitGoldenOutput/config-init-help.golden b/cmd/config/testdata/TestConfigInitGoldenOutput/config-init-help.golden index fcc51693f..e3ed66334 100644 --- a/cmd/config/testdata/TestConfigInitGoldenOutput/config-init-help.golden +++ b/cmd/config/testdata/TestConfigInitGoldenOutput/config-init-help.golden @@ -1,11 +1,23 @@ -Generate an airshipctl config file and its associated kubeConfig file. -These files will be written to the $HOME/.airship directory, and will contain -default configurations. - -NOTE: This will overwrite any existing config files in $HOME/.airship +Generate an airshipctl config file. This file by default will be written to the $HOME/.airship directory, +and will contain default configuration. In case if flag --airshipconf provided - the file will be +written to the specified location instead. If a configuration file already exists at the specified path, +an error will be thrown; to overwrite it, specify the --overwrite flag. Usage: init [flags] +Examples: + +# Create new airshipctl config file at the default location +airshipctl config init + +# Create new airshipctl config file at the custom location +airshipctl config init --airshipconf path/to/config + +# Create new airshipctl config file at custom location and overwrite it +airshipctl config init --overwrite --airshipconf path/to/config + + Flags: - -h, --help help for init + -h, --help help for init + --overwrite overwrite config file diff --git a/docs/source/cli/airshipctl_config.md b/docs/source/cli/airshipctl_config.md index 23e06f4d1..f40149c59 100644 --- a/docs/source/cli/airshipctl_config.md +++ b/docs/source/cli/airshipctl_config.md @@ -26,7 +26,7 @@ Manage the airshipctl config file * [airshipctl config get-encryption-config](airshipctl_config_get-encryption-config.md) - Get an encryption config information from the airshipctl config * [airshipctl config get-management-config](airshipctl_config_get-management-config.md) - View a management config or all management configs defined in the airshipctl config * [airshipctl config get-manifest](airshipctl_config_get-manifest.md) - Get a manifest information from the airshipctl config -* [airshipctl config init](airshipctl_config_init.md) - Generate initial configuration files for airshipctl +* [airshipctl config init](airshipctl_config_init.md) - Generate initial configuration file for airshipctl * [airshipctl config set-context](airshipctl_config_set-context.md) - Manage contexts * [airshipctl config set-encryption-config](airshipctl_config_set-encryption-config.md) - Manage encryption configs in airship config * [airshipctl config set-management-config](airshipctl_config_set-management-config.md) - Modify an out-of-band management configuration diff --git a/docs/source/cli/airshipctl_config_init.md b/docs/source/cli/airshipctl_config_init.md index 44fff0ca5..fbdbd0223 100644 --- a/docs/source/cli/airshipctl_config_init.md +++ b/docs/source/cli/airshipctl_config_init.md @@ -1,24 +1,39 @@ ## airshipctl config init -Generate initial configuration files for airshipctl +Generate initial configuration file for airshipctl ### Synopsis -Generate an airshipctl config file and its associated kubeConfig file. -These files will be written to the $HOME/.airship directory, and will contain -default configurations. - -NOTE: This will overwrite any existing config files in $HOME/.airship +Generate an airshipctl config file. This file by default will be written to the $HOME/.airship directory, +and will contain default configuration. In case if flag --airshipconf provided - the file will be +written to the specified location instead. If a configuration file already exists at the specified path, +an error will be thrown; to overwrite it, specify the --overwrite flag. ``` airshipctl config init [flags] ``` +### Examples + +``` + +# Create new airshipctl config file at the default location +airshipctl config init + +# Create new airshipctl config file at the custom location +airshipctl config init --airshipconf path/to/config + +# Create new airshipctl config file at custom location and overwrite it +airshipctl config init --overwrite --airshipconf path/to/config + +``` + ### Options ``` - -h, --help help for init + -h, --help help for init + --overwrite overwrite config file ``` ### Options inherited from parent commands diff --git a/pkg/config/config.go b/pkg/config/config.go index f3f599eb0..1f8f9297b 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -94,11 +94,11 @@ func CreateFactory(airshipConfigPath *string) Factory { } } -// CreateConfig saves default config to specified paths -func CreateConfig(airshipConfigPath string) error { +// CreateConfig saves default config to the specified path +func CreateConfig(airshipConfigPath string, overwrite bool) error { cfg := NewConfig() cfg.initConfigPath(airshipConfigPath) - return cfg.PersistConfig() + return cfg.PersistConfig(overwrite) } // initConfigPath - Initializes loadedConfigPath variable for Config object @@ -177,8 +177,12 @@ func (c *Config) EnsureComplete() error { // PersistConfig updates the airshipctl config file to match // the current Config object. // If file did not previously exist, the file will be created. -// Otherwise, the file will be overwritten -func (c *Config) PersistConfig() error { +// The file will be overwritten if overwrite argument set to true +func (c *Config) PersistConfig(overwrite bool) error { + if _, err := os.Stat(c.loadedConfigPath); err == nil && !overwrite { + return ErrConfigFileExists{Path: c.loadedConfigPath} + } + airshipConfigYaml, err := c.ToYaml() if err != nil { return err diff --git a/pkg/config/config_helper.go b/pkg/config/config_helper.go index 8b9de108f..9803a5f7d 100644 --- a/pkg/config/config_helper.go +++ b/pkg/config/config_helper.go @@ -60,7 +60,7 @@ func RunSetContext(o *ContextOptions, airconfig *Config, writeToStorage bool) (b } // Update configuration file just in time persistence approach if writeToStorage { - if err := airconfig.PersistConfig(); err != nil { + if err := airconfig.PersistConfig(true); err != nil { // Error that it didnt persist the changes return modified, ErrConfigFailed{} } @@ -77,7 +77,7 @@ func RunUseContext(desiredContext string, airconfig *Config) error { if airconfig.CurrentContext != desiredContext { airconfig.CurrentContext = desiredContext - if err := airconfig.PersistConfig(); err != nil { + if err := airconfig.PersistConfig(true); err != nil { return err } } @@ -107,7 +107,7 @@ func RunSetManifest(o *ManifestOptions, airconfig *Config, writeToStorage bool) } // Update configuration file just in time persistence approach if writeToStorage { - if err := airconfig.PersistConfig(); err != nil { + if err := airconfig.PersistConfig(true); err != nil { // Error that it didnt persist the changes return modified, ErrConfigFailed{} } @@ -138,7 +138,7 @@ func RunSetEncryptionConfig(o *EncryptionConfigOptions, airconfig *Config, write } // Update configuration file just in time persistence approach if writeToStorage { - if err := airconfig.PersistConfig(); err != nil { + if err := airconfig.PersistConfig(true); err != nil { // Error that it didnt persist the changes return modified, ErrConfigFailed{} } diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go index 93bf74656..97711f000 100644 --- a/pkg/config/config_test.go +++ b/pkg/config/config_test.go @@ -101,11 +101,14 @@ func TestPersistConfig(t *testing.T) { conf.SetLoadedConfigPath(conf.LoadedConfigPath() + ".new") - err := conf.PersistConfig() + err := conf.PersistConfig(true) require.NoError(t, err) // Check that the files were created assert.FileExists(t, conf.LoadedConfigPath()) + + err = conf.PersistConfig(false) + require.Error(t, err, config.ErrConfigFileExists{Path: conf.LoadedConfigPath()}) } func TestEnsureComplete(t *testing.T) { @@ -206,7 +209,7 @@ func TestPurge(t *testing.T) { defer cleanup(t) // Store it - err := conf.PersistConfig() + err := conf.PersistConfig(true) assert.NoErrorf(t, err, "Unable to persist configuration expected at %v", conf.LoadedConfigPath()) // Verify that the file is there diff --git a/pkg/config/errors.go b/pkg/config/errors.go index 641510935..1b63a6cc4 100644 --- a/pkg/config/errors.go +++ b/pkg/config/errors.go @@ -305,3 +305,12 @@ type ErrCheckFile struct { func (e ErrCheckFile) Error() string { return fmt.Sprintf("could not read %s data from '%s': %v", e.FlagName, e.Path, e.InternalErr) } + +// ErrConfigFileExists is returned when there is an existing file at specified location +type ErrConfigFileExists struct { + Path string +} + +func (e ErrConfigFileExists) Error() string { + return fmt.Sprintf("could not create default config at %s, file already exists", e.Path) +}