Skip to content

Commit

Permalink
Merge pull request #40 from bpineau/split_cmd
Browse files Browse the repository at this point in the history
Split cmd for readability sake
  • Loading branch information
bpineau authored Apr 20, 2018
2 parents 6fa5415 + d787f20 commit a295e74
Show file tree
Hide file tree
Showing 6 changed files with 166 additions and 141 deletions.
32 changes: 16 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,22 +58,22 @@ Available Commands:
version Print the version number
Flags:
-s, --api-server string Kubernetes api-server url
-c, --config string Configuration file (default "/etc/katafygio/katafygio.yaml")
-d, --dry-run Dry-run mode: don't store anything.
-m, --dump-only Dump mode: dump everything and exit
-x, --exclude-kind stringSlice Ressource kind to exclude. Eg. 'deployment'
-y, --exclude-object stringSlice Object to exclude. Eg. 'configmap:kube-system/kube-dns'
-l, --filter string Label filter. Select only objects matching the label.
-g, --git-url string Git repository URL
-p, --healthcheck-port int Port for answering healthchecks on /health url
-h, --help help for katafygio
-k, --kube-config string Kubernetes config path
-e, --local-dir string Where to dump yaml files (default "./kubernetes-backup")
-v, --log-level string Log level (default "info")
-o, --log-output string Log output (default "stderr")
-r, --log-server string Log server (if using syslog)
-i, --resync-interval int Resync interval in seconds (0 to disable) (default 300)
-s, --api-server string Kubernetes api-server url
-c, --config string Configuration file (default "/etc/katafygio/katafygio.yaml")
-d, --dry-run Dry-run mode: don't store anything
-m, --dump-only Dump mode: dump everything once and exit
-x, --exclude-kind strings Ressource kind to exclude. Eg. 'deployment'
-y, --exclude-object strings Object to exclude. Eg. 'configmap:kube-system/kube-dns'
-l, --filter string Label filter. Select only objects matching the label
-g, --git-url string Git repository URL
-p, --healthcheck-port int Port for answering healthchecks on /health url
-h, --help help for katafygio
-k, --kube-config string Kubernetes config path
-e, --local-dir string Where to dump yaml files (default "./kubernetes-backup")
-v, --log-level string Log level (default "info")
-o, --log-output string Log output (default "stderr")
-r, --log-server string Log server (if using syslog)
-i, --resync-interval int Full resync interval in seconds (0 to disable) (default 900)
```

## Config file and env variables
Expand Down
36 changes: 36 additions & 0 deletions cmd/configfile.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package cmd

import (
"os"
"strings"

"github.com/spf13/viper"
"k8s.io/client-go/util/homedir"
)

func loadConfigFile() {
viper.SetConfigType("yaml")
viper.SetConfigName(appName)

// all possible config file paths, by priority
viper.AddConfigPath("/etc/katafygio/")
if home := homedir.HomeDir(); home != "" {
viper.AddConfigPath(home)
}
viper.AddConfigPath(".")

// prefer the config file path provided by cli flag, if any
if _, err := os.Stat(cfgFile); !os.IsNotExist(err) {
viper.SetConfigFile(cfgFile)
}

// allow config params through prefixed env variables
viper.SetEnvPrefix("KF")
replacer := strings.NewReplacer("-", "_", ".", "_DOT_")
viper.SetEnvKeyReplacer(replacer)
viper.AutomaticEnv()

if err := viper.ReadInConfig(); err == nil {
RootCmd.Printf("Using config file: %s", viper.ConfigFileUsed())
}
}
133 changes: 11 additions & 122 deletions cmd/execute.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,76 +2,51 @@ package cmd

import (
"fmt"
"log"
"os"
"strings"
"time"

"github.com/spf13/cobra"
"github.com/spf13/viper"
"k8s.io/client-go/util/homedir"

"github.com/bpineau/katafygio/config"
klog "github.com/bpineau/katafygio/pkg/log"
"github.com/bpineau/katafygio/pkg/log"
"github.com/bpineau/katafygio/pkg/run"
)

const appName = "katafygio"

var (
version = "0.3.0"

cfgFile string
apiServer string
kubeConf string
dryRun bool
dumpMode bool
logLevel string
logOutput string
logServer string
filter string
localDir string
gitURL string
healthP int
resync int
exclkind []string
exclobj []string

versionCmd = &cobra.Command{
Use: "version",
Short: "Print the version number",
Run: func(cmd *cobra.Command, args []string) {
RootCmd.Printf("%s version %s\n", appName, version)
},
}

// RootCmd represents the base command when called without any subcommands
// RootCmd is our main entry point, launching pkg/run.Run()
RootCmd = &cobra.Command{
Use: appName,
Short: "Backup Kubernetes cluster as yaml files",
Long: "Backup Kubernetes cluster as yaml files in a git repository.\n" +
"--exclude-kind (x) and --exclude-object (-y) may be specified several times.",
"--exclude-kind (-x) and --exclude-object (-y) may be specified several times.",

RunE: func(cmd *cobra.Command, args []string) error {
resync := time.Duration(viper.GetInt("resync-interval")) * time.Second
logger := log.New(viper.GetString("log.level"),
viper.GetString("log.server"),
viper.GetString("log.output"))

conf := &config.KfConfig{
DryRun: viper.GetBool("dry-run"),
DumpMode: viper.GetBool("dump-only"),
Logger: klog.New(viper.GetString("log.level"), viper.GetString("log.server"), viper.GetString("log.output")),
Logger: logger,
LocalDir: viper.GetString("local-dir"),
GitURL: viper.GetString("git-url"),
Filter: viper.GetString("filter"),
ExcludeKind: viper.GetStringSlice("exclude-kind"),
ExcludeObject: viper.GetStringSlice("exclude-object"),
HealthPort: viper.GetInt("healthcheck-port"),
ResyncIntv: time.Duration(viper.GetInt("resync-interval")) * time.Second,
ResyncIntv: resync,
}

err := conf.Init(viper.GetString("api-server"), viper.GetString("kube-config"))
if err != nil {
return fmt.Errorf("Failed to initialize the configuration: %v", err)
}

run.Run(conf)
run.Run(conf) // <- this is where things happens
return nil
},
}
Expand All @@ -81,89 +56,3 @@ var (
func Execute() error {
return RootCmd.Execute()
}

func bindPFlag(key string, cmd string) {
if err := viper.BindPFlag(key, RootCmd.PersistentFlags().Lookup(cmd)); err != nil {
log.Fatal("Failed to bind cli argument:", err)
}
}

func init() {
cobra.OnInitialize(initConfig)
RootCmd.AddCommand(versionCmd)

defaultCfg := "/etc/katafygio/" + appName + ".yaml"
RootCmd.PersistentFlags().StringVarP(&cfgFile, "config", "c", defaultCfg, "Configuration file")

RootCmd.PersistentFlags().StringVarP(&apiServer, "api-server", "s", "", "Kubernetes api-server url")
bindPFlag("api-server", "api-server")

RootCmd.PersistentFlags().StringVarP(&kubeConf, "kube-config", "k", "", "Kubernetes config path")
bindPFlag("kube-config", "kube-config")
if err := viper.BindEnv("kube-config", "KUBECONFIG"); err != nil {
log.Fatal("Failed to bind cli argument:", err)
}

RootCmd.PersistentFlags().BoolVarP(&dryRun, "dry-run", "d", false, "Dry-run mode: don't store anything")
bindPFlag("dry-run", "dry-run")

RootCmd.PersistentFlags().BoolVarP(&dumpMode, "dump-only", "m", false, "Dump mode: dump everything once and exit")
bindPFlag("dump-only", "dump-only")

RootCmd.PersistentFlags().StringVarP(&logLevel, "log-level", "v", "info", "Log level")
bindPFlag("log.level", "log-level")

RootCmd.PersistentFlags().StringVarP(&logOutput, "log-output", "o", "stderr", "Log output")
bindPFlag("log.output", "log-output")

RootCmd.PersistentFlags().StringVarP(&logServer, "log-server", "r", "", "Log server (if using syslog)")
bindPFlag("log.server", "log-server")

RootCmd.PersistentFlags().StringVarP(&localDir, "local-dir", "e", "./kubernetes-backup", "Where to dump yaml files")
bindPFlag("local-dir", "local-dir")

RootCmd.PersistentFlags().StringVarP(&gitURL, "git-url", "g", "", "Git repository URL")
bindPFlag("git-url", "git-url")

RootCmd.PersistentFlags().StringSliceVarP(&exclkind, "exclude-kind", "x", nil, "Ressource kind to exclude. Eg. 'deployment'")
bindPFlag("exclude-kind", "exclude-kind")

RootCmd.PersistentFlags().StringSliceVarP(&exclobj, "exclude-object", "y", nil, "Object to exclude. Eg. 'configmap:kube-system/kube-dns'")
bindPFlag("exclude-object", "exclude-object")

RootCmd.PersistentFlags().StringVarP(&filter, "filter", "l", "", "Label filter. Select only objects matching the label.")
bindPFlag("filter", "filter")

RootCmd.PersistentFlags().IntVarP(&healthP, "healthcheck-port", "p", 0, "Port for answering healthchecks on /health url")
bindPFlag("healthcheck-port", "healthcheck-port")

RootCmd.PersistentFlags().IntVarP(&resync, "resync-interval", "i", 900, "Full resync interval in seconds (0 to disable)")
bindPFlag("resync-interval", "resync-interval")
}

func initConfig() {
viper.SetConfigType("yaml")
viper.SetConfigName(appName)

// all possible config file paths, by priority
viper.AddConfigPath("/etc/katafygio/")
if home := homedir.HomeDir(); home != "" {
viper.AddConfigPath(home)
}
viper.AddConfigPath(".")

// prefer the config file path provided by cli flag, if any
if _, err := os.Stat(cfgFile); !os.IsNotExist(err) {
viper.SetConfigFile(cfgFile)
}

// allow config params through prefixed env variables
viper.SetEnvPrefix("KF")
replacer := strings.NewReplacer("-", "_", ".", "_DOT_")
viper.SetEnvKeyReplacer(replacer)
viper.AutomaticEnv()

if err := viper.ReadInConfig(); err == nil {
RootCmd.Printf("Using config file: %s", viper.ConfigFileUsed())
}
}
85 changes: 85 additions & 0 deletions cmd/flags.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package cmd

import (
"log"

"github.com/spf13/cobra"
"github.com/spf13/viper"
)

var (
cfgFile string
apiServer string
kubeConf string
dryRun bool
dumpMode bool
logLevel string
logOutput string
logServer string
filter string
localDir string
gitURL string
healthP int
resync int
exclkind []string
exclobj []string
)

func bindPFlag(key string, cmd string) {
if err := viper.BindPFlag(key, RootCmd.PersistentFlags().Lookup(cmd)); err != nil {
log.Fatal("Failed to bind cli argument:", err)
}
}

func init() {
cobra.OnInitialize(loadConfigFile)
RootCmd.AddCommand(versionCmd)

defaultCfg := "/etc/katafygio/" + appName + ".yaml"
RootCmd.PersistentFlags().StringVarP(&cfgFile, "config", "c", defaultCfg, "Configuration file")

RootCmd.PersistentFlags().StringVarP(&apiServer, "api-server", "s", "", "Kubernetes api-server url")
bindPFlag("api-server", "api-server")

RootCmd.PersistentFlags().StringVarP(&kubeConf, "kube-config", "k", "", "Kubernetes config path")
bindPFlag("kube-config", "kube-config")
if err := viper.BindEnv("kube-config", "KUBECONFIG"); err != nil {
log.Fatal("Failed to bind cli argument:", err)
}

RootCmd.PersistentFlags().BoolVarP(&dryRun, "dry-run", "d", false, "Dry-run mode: don't store anything")
bindPFlag("dry-run", "dry-run")

RootCmd.PersistentFlags().BoolVarP(&dumpMode, "dump-only", "m", false, "Dump mode: dump everything once and exit")
bindPFlag("dump-only", "dump-only")

RootCmd.PersistentFlags().StringVarP(&logLevel, "log-level", "v", "info", "Log level")
bindPFlag("log.level", "log-level")

RootCmd.PersistentFlags().StringVarP(&logOutput, "log-output", "o", "stderr", "Log output")
bindPFlag("log.output", "log-output")

RootCmd.PersistentFlags().StringVarP(&logServer, "log-server", "r", "", "Log server (if using syslog)")
bindPFlag("log.server", "log-server")

RootCmd.PersistentFlags().StringVarP(&localDir, "local-dir", "e", "./kubernetes-backup", "Where to dump yaml files")
bindPFlag("local-dir", "local-dir")

RootCmd.PersistentFlags().StringVarP(&gitURL, "git-url", "g", "", "Git repository URL")
bindPFlag("git-url", "git-url")

RootCmd.PersistentFlags().StringSliceVarP(&exclkind, "exclude-kind", "x", nil, "Ressource kind to exclude. Eg. 'deployment'")
bindPFlag("exclude-kind", "exclude-kind")

RootCmd.PersistentFlags().StringSliceVarP(&exclobj, "exclude-object", "y", nil, "Object to exclude. Eg. 'configmap:kube-system/kube-dns'")
bindPFlag("exclude-object", "exclude-object")

RootCmd.PersistentFlags().StringVarP(&filter, "filter", "l", "", "Label filter. Select only objects matching the label.")
bindPFlag("filter", "filter")

RootCmd.PersistentFlags().IntVarP(&healthP, "healthcheck-port", "p", 0, "Port for answering healthchecks on /health url")
bindPFlag("healthcheck-port", "healthcheck-port")

RootCmd.PersistentFlags().IntVarP(&resync, "resync-interval", "i", 900, "Full resync interval in seconds (0 to disable)")
bindPFlag("resync-interval", "resync-interval")
}
15 changes: 15 additions & 0 deletions cmd/version.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package cmd

import "github.com/spf13/cobra"

var (
version = "0.3.0"

versionCmd = &cobra.Command{
Use: "version",
Short: "Print the version number",
Run: func(cmd *cobra.Command, args []string) {
RootCmd.Printf("%s version %s\n", appName, version)
},
}
)
6 changes: 3 additions & 3 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,16 @@ import (
"github.com/bpineau/katafygio/cmd"
)

//var privateExitHandler func(code int) = os.Exit
var privateExitHandler = os.Exit

// ExitWrapper allow unit tests on main() exit values
// ExitWrapper allow tests on main() exit values
func ExitWrapper(exit int) {
privateExitHandler(exit)
}

func main() {
if err := cmd.Execute(); err != nil {
err := cmd.Execute()
if err != nil {
fmt.Printf("%+v", err)
ExitWrapper(1)
}
Expand Down

0 comments on commit a295e74

Please sign in to comment.