-
Notifications
You must be signed in to change notification settings - Fork 2
/
root.go
146 lines (131 loc) · 5.21 KB
/
root.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
package cmd
import (
"fmt"
"os"
"github.com/logicmonitor/k8s-release-manager/pkg/config"
"github.com/logicmonitor/k8s-release-manager/pkg/constants"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
var rlsmgrconfig *config.Config
var cfgFile string
var debug bool
var dryRun bool
var verbose bool
var kubeConfig string
var kubeContext string
var storagePath string
var releaseName string
// RootCmd represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
Use: "releasemanager",
Short: "Release Manager is a tool for importing and exporting Helm release state",
Long: `
Release Manager provides functionality for exporting and importing the
state of Helm releases currently deployed to a Kubernetes cluster. The state
of the installed releases is saved to a configurable backend for easy
restoration of previously-deployed releases or for simplified re-deployment of
those releases to a new Kubernetes cluster.
Release Manager operations can be run locally or within the Kubernetes cluster.
The application also supports a daemon mode that will periodically update the
saved state.
To export releases, Release Manager queries the target Kubernetes cluster to collect metadata for all
releases currently deployed in the source cluster and writes this metadata to
the configured backend data store. If the Release Manager is deployed in
daemon mode via its own Helm chart, it will also store metadata about itself.
This metadata is used to prevent import operations from creating a new Release
Manager with the same configuration as the previous managed, causing both
instances to write conflicting state to the backend.
To import releases, Release Manager retrieves the state stored in the backend,
connects to the target Kubernetes cluster, and deploys the saved
releases to the cluster.
Release Manager will use --kubeconfig/--kubecontext, $KUBECONFIG, or
~/.kube/config to establish a connection to the Kubernetes cluster. If none of
these configuration are set, an in-cluster connection will be attempted. All
actions will be performed against the current cluster and a given command will
only perform actions against a single cluster, i.e. 'export' will
export releases from the configured cluster while 'import' will deploy releases
to the configured cluster and 'clear' requires no custer connection whatsoever.
`,
PersistentPreRun: func(cmd *cobra.Command, args []string) {
rlsmgrconfig.DebugMode = viper.GetBool("debug")
rlsmgrconfig.DryRun = viper.GetBool("dryRun")
rlsmgrconfig.VerboseMode = viper.GetBool("verbose")
rlsmgrconfig.Backend = &config.BackendConfig{
StoragePath: viper.GetString("path"),
}
// check env for KUBECONFIG
kubeConfig = viper.GetString("kubeconfig")
if kubeConfig == "" && os.Getenv(constants.EnvKubeConfig) != "" {
kubeConfig = os.Getenv(constants.EnvKubeConfig)
}
rlsmgrconfig.ClusterConfig = &config.ClusterConfig{
KubeConfig: kubeConfig,
KubeContext: viper.GetString("kubecontext"),
}
if rlsmgrconfig.DebugMode {
log.SetLevel(log.DebugLevel)
} else {
log.SetLevel(log.WarnLevel)
}
if rlsmgrconfig.DryRun {
fmt.Println("Dry run. No changes will be made.")
}
},
}
// Execute adds all child commands to the root command and sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
if err := RootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
}
}
func init() {
rlsmgrconfig = &config.Config{}
cobra.OnInitialize(initConfig)
RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "Set a custom configuration path")
RootCmd.PersistentFlags().BoolVarP(&debug, "debug", "", false, "Enable debugging output")
RootCmd.PersistentFlags().BoolVarP(&dryRun, "dry-run", "", false, "Print planned actions without making any modifications")
RootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "Enable verbose output")
RootCmd.PersistentFlags().StringVarP(&kubeConfig, "kubeconfig", "", "", "Use this kubeconfig path, otherwise use the environment variable KUBECONFIG or ~/.kube/config")
RootCmd.PersistentFlags().StringVarP(&kubeContext, "kubecontext", "", "", "Use this kube context, otherwise use the default")
RootCmd.PersistentFlags().StringVarP(&storagePath, "path", "", "", "Required. Use this path within the backend for state storage")
err := bindConfigFlags(RootCmd, map[string]string{
"debug": "debug",
"dryRun": "dry-run",
"verbose": "verbose",
"kubeconfig": "kubeconfig",
"kubecontext": "kubecontext",
"path": "path",
})
if err != nil {
fmt.Println(err)
os.Exit(1)
}
}
func bindConfigFlags(cmd *cobra.Command, mapping map[string]string) (err error) {
for k, v := range mapping {
err = viper.BindPFlag(k, cmd.PersistentFlags().Lookup(v))
if err != nil {
return err
}
}
return err
}
func initConfig() {
if cfgFile != "" {
// Use config file from the flag.
viper.SetConfigFile(cfgFile)
} else {
// Search config in home directory with name ".cobra" (without extension).
viper.AddConfigPath(constants.DefaultConfigPath)
viper.SetConfigName("config")
}
err := viper.ReadInConfig()
if err != nil && cfgFile != "" {
fmt.Println("Can't read config:", err)
os.Exit(1)
}
}