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

feat: use viper standard for command inputs #645

Merged
merged 2 commits into from
Nov 3, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 0 additions & 4 deletions cmd/local/local.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,7 @@ func NewCommand() *cobra.Command {
localCmd.Flags().StringVar(&metaphorBranch, "metaphor-branch", "main", "metaphro application branch")
localCmd.Flags().StringVar(&gitOpsBranch, "gitops-branch", "main", "version/branch used on git clone - former: version-gitops flag")
localCmd.Flags().StringVar(&gitOpsRepo, "gitops-repo", "gitops", "")

localCmd.Flags().BoolVar(&enableConsole, "enable-console", true, "If hand-off screen will be presented on a browser UI")
// todo:
//initCmd.Flags().StringP("config", "c", "", "File to be imported to bootstrap configs")
//viper.BindPFlag("config.file", currentCommand.Flags().Lookup("config-load"))

return localCmd
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/local/prerun.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ func validateLocal(cmd *cobra.Command, args []string) error {

// convert available disk size to GB format
availableDiskSize := float64(free) / humanize.GByte
if availableDiskSize > pkg.MinimumAvailableDiskSize {
if availableDiskSize < pkg.MinimumAvailableDiskSize {
return fmt.Errorf(
"there is not enough space to proceed with the installation, a minimum of %d GB is required to proceed",
pkg.MinimumAvailableDiskSize,
Expand Down
12 changes: 5 additions & 7 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package cmd
import (
"fmt"
"github.com/kubefirst/kubefirst/cmd/local"
"github.com/kubefirst/kubefirst/configs"
"os"

"github.com/kubefirst/kubefirst/internal/progressPrinter"
Expand All @@ -16,8 +17,11 @@ var rootCmd = &cobra.Command{
Long: `kubefirst management cluster installer provisions an
open source application delivery platform in under an hour.
checkout the docs at docs.kubefirst.io.`,
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
// wire viper config for flags for all commands
return configs.InitializeViperConfig(cmd)
},
Run: func(cmd *cobra.Command, args []string) {
//log.Println(viper.Get("name"))
fmt.Println("To learn more about kubefirst, run:")
fmt.Println(" kubefirst help")
},
Expand All @@ -38,11 +42,5 @@ func Execute() {

func init() {
cobra.OnInitialize()

// Cobra also supports local flags, which will only run, when this action is called directly.
rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")

// todo: temporary, move it into CLI tree
rootCmd.AddCommand(local.NewCommand())

}
99 changes: 99 additions & 0 deletions configs/viperConfig.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package configs

// code from: https://github.com/carolynvs/stingoftheviper

import (
"fmt"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"github.com/spf13/viper"
"strings"
)

// it follows Viper precedence:
// 1. explicit call to Set
// 2. flag
// 3. env
// 4. config
// 5. key/value store
// 6. default

// the input file that is able to provide is called kubefirst.yaml, and should be at the root folder, where the user has
// it's Kubefirst binary. Following the flag name convention is enough to have a Kubefirst config file.

// FLAGS VARIABLE
// example loading values from flags:
// go run . command-name --admin-email user@example.com

// ENVIRONMENT VARIABLE
// example loading environment variables:
// export KUBEFIRST_CLOUD=k3d
// command line commands loads the values from the environment variable and override the command flag.

// YAML
// example of a YAML Kubefirst file:
// admin-email: user@example.com
// cloud: k3d
// command line commands loads the value from the kubefirst.yaml and override the command flags.

const (
// The name of our config file, without the file extension because viper supports many different config file languages.
defaultConfigFilename = "kubefirst"

// The environment variable prefix of all environment variables bound to our command line flags.
// For example, --number is bound to STING_NUMBER.
envPrefix = "KUBEFIRST"
)

func InitializeViperConfig(cmd *cobra.Command) error {
v := viper.New()

// Set the base name of the config file, without the file extension.
v.SetConfigName(defaultConfigFilename)
v.SetConfigType("yaml")

// Set as many paths as you like where viper should look for the
// config file. We are only looking in the current working directory.
v.AddConfigPath(".")

// Attempt to read the config file, gracefully ignoring errors
// caused by a config file not being found. Return an error
// if we cannot parse the config file.
if err := v.ReadInConfig(); err != nil {
// It's okay if there isn't a config file
if _, ok := err.(viper.ConfigFileNotFoundError); !ok {
return err
}
}

// When we bind flags to environment variables expect that the
// environment variables are prefixed, e.g. a flag like --number
// binds to an environment variable STING_NUMBER. This helps
// avoid conflicts.
v.SetEnvPrefix(envPrefix)

// Bind to environment variables
// Works great for simple config names, but needs help for names
// like --favorite-color which we fix in the bindFlags function
v.AutomaticEnv()

// Bind the current command's flags to viper
bindFlags(cmd, v)

return nil
}

// Bind each cobra flag to its associated viper configuration (config file and environment variable)
func bindFlags(cmd *cobra.Command, v *viper.Viper) {
cmd.Flags().VisitAll(func(f *pflag.Flag) {
// Environment variables can't have dashes in them, so bind them to their equivalent
// keys with underscores, e.g. --favorite-color to STING_FAVORITE_COLOR
v.SetEnvKeyReplacer(strings.NewReplacer("-", "_"))

// Apply the viper config value to the flag when the flag is not set and viper has a value
if !f.Changed && v.IsSet(f.Name) {
val := v.Get(f.Name)
cmd.Flags().Set(f.Name, fmt.Sprintf("%v", val))
}
6za marked this conversation as resolved.
Show resolved Hide resolved
})
}