This is an automated email from the ASF dual-hosted git repository. rohit pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/cloudstack-cloudmonkey.git
commit ed77ec07d952c49d987a26a3c3d355bcaf00233b Author: Rohit Yadav <ro...@apache.org> AuthorDate: Sat Apr 14 03:24:27 2018 +0530 config: implement ini based config same as legacy cloudmonkey Signed-off-by: Rohit Yadav <ro...@apache.org> --- cli/completer.go | 2 +- cli/selector.go | 2 +- cli/shell.go | 3 + cmd/network.go | 6 +- config/about.go | 1 + config/config.go | 211 +++++++++++++++++++++++++++++++++++-------------------- 6 files changed, 144 insertions(+), 81 deletions(-) diff --git a/cli/completer.go b/cli/completer.go index 9cd9a04..58ff60b 100644 --- a/cli/completer.go +++ b/cli/completer.go @@ -188,7 +188,7 @@ func (t *CliCompleter) Do(line []rune, pos int) (options [][]rune, offset int) { return nil, 0 } - r := cmd.NewRequest(nil, config.NewConfig(), nil, nil) + r := cmd.NewRequest(nil, shellConfig, nil, nil) autocompleteApiArgs := []string{"listall=true"} if autocompleteApi.Noun == "templates" { autocompleteApiArgs = append(autocompleteApiArgs, "templatefilter=all") diff --git a/cli/selector.go b/cli/selector.go index 0f0b998..27e03b2 100644 --- a/cli/selector.go +++ b/cli/selector.go @@ -21,8 +21,8 @@ import ( "fmt" "strings" - "github.com/manifoldco/promptui" "github.com/chzyer/readline" + "github.com/manifoldco/promptui" ) type SelectOption struct { diff --git a/cli/shell.go b/cli/shell.go index f8fc031..1dfc075 100644 --- a/cli/shell.go +++ b/cli/shell.go @@ -28,7 +28,10 @@ import ( "github.com/chzyer/readline" ) +var shellConfig *config.Config + func ExecShell(cfg *config.Config) { + shellConfig = cfg shell, err := readline.NewEx(&readline.Config{ Prompt: cfg.GetPrompt(), HistoryFile: cfg.HistoryFile, diff --git a/cmd/network.go b/cmd/network.go index 6ff7d7c..94f67ad 100644 --- a/cmd/network.go +++ b/cmd/network.go @@ -66,8 +66,8 @@ func NewAPIRequest(r *Request, api string, args []string) (map[string]interface{ } } - apiKey := r.Config.ActiveProfile.ApiKey - secretKey := r.Config.ActiveProfile.SecretKey + apiKey := r.Config.Core.ActiveProfile.ApiKey + secretKey := r.Config.Core.ActiveProfile.SecretKey if len(apiKey) > 0 { params.Add("apiKey", apiKey) @@ -81,7 +81,7 @@ func NewAPIRequest(r *Request, api string, args []string) (map[string]interface{ signature := base64.StdEncoding.EncodeToString(mac.Sum(nil)) encodedParams = encodedParams + fmt.Sprintf("&signature=%s", url.QueryEscape(signature)) - apiUrl := fmt.Sprintf("%s?%s", r.Config.ActiveProfile.Url, encodedParams) + apiUrl := fmt.Sprintf("%s?%s", r.Config.Core.ActiveProfile.Url, encodedParams) //fmt.Println("[debug] Requesting: ", apiUrl) response, err := http.Get(apiUrl) diff --git a/config/about.go b/config/about.go new file mode 100644 index 0000000..d912156 --- /dev/null +++ b/config/about.go @@ -0,0 +1 @@ +package config diff --git a/config/config.go b/config/config.go index 9122ec8..b89cc54 100644 --- a/config/config.go +++ b/config/config.go @@ -19,56 +19,54 @@ package config import ( "fmt" - homedir "github.com/mitchellh/go-homedir" + "github.com/mitchellh/go-homedir" + "gopkg.in/ini.v1" "os" "path" + "strconv" ) -var name = "cloudmonkey" -var version = "6.0.0-alpha1" - -func getDefaultConfigDir() string { - home, err := homedir.Dir() - if err != nil { - fmt.Println(err) - os.Exit(1) - } - return path.Join(home, ".cmk") -} - -type OutputFormat string - const ( - Json OutputFormat = "json" - Xml OutputFormat = "xml" - Table OutputFormat = "table" - Text OutputFormat = "text" + Json = "json" + Xml = "xml" + Table = "table" + Text = "text" ) -type Profile struct { - Name string - Url string - VerifyCert bool - Username string - Password string - Domain string - ApiKey string - SecretKey string +type ServerProfile struct { + Url string `ini:"url"` + Username string `ini:"username"` + Password string `ini:"password"` + Domain string `ini:"domain"` + ApiKey string `ini:"apikey"` + SecretKey string `ini:"secretkey"` + VerifyCert bool `ini:"verifycert"` +} + +type Core struct { + AsyncBlock bool `ini:"asyncblock"` + Timeout int `ini:"timeout"` + Output string `ini:"output"` + ProfileName string `ini:"profile"` + ActiveProfile *ServerProfile `ini:"-"` } type Config struct { - Dir string - ConfigFile string - HistoryFile string - CacheFile string - LogFile string - Output OutputFormat - AsyncBlock bool - ActiveProfile Profile + Dir string + ConfigFile string + HistoryFile string + CacheFile string + LogFile string + Core *Core } -func NewConfig() *Config { - return loadConfig() +func getDefaultConfigDir() string { + home, err := homedir.Dir() + if err != nil { + fmt.Println(err) + os.Exit(1) + } + return path.Join(home, ".cmk") } func defaultConfig() *Config { @@ -76,58 +74,86 @@ func defaultConfig() *Config { return &Config{ Dir: configDir, ConfigFile: path.Join(configDir, "config"), - HistoryFile: path.Join(configDir, "history"), CacheFile: path.Join(configDir, "cache"), + HistoryFile: path.Join(configDir, "history"), LogFile: path.Join(configDir, "log"), - Output: Json, - AsyncBlock: true, - ActiveProfile: Profile{ - Name: "local", - Url: "http://192.168.1.10:8080/client/api", - VerifyCert: false, - Username: "admin", - Password: "password", - Domain: "/", - // TODO: remove test data - ApiKey: "IgrUOA_46IVoBNzAR_Th2JbdbgIs2lMW1kGe9A80F9X0uOnfGO0Su23IqOSqbdzZW3To95PNrcdWsk60ieXYBQ", - SecretKey: "E7NRSv5d_1VhqXUHJEqvAsm7htR_V_vtPJZsCPkgPKSgkiS3sh4SOrIqMm_eWhSFoL6RHRIlxtA_viQAt7EDVA", + Core: &Core{ + AsyncBlock: false, + Timeout: 1800, + Output: Json, + ProfileName: "local", + ActiveProfile: &ServerProfile{ + Url: "http://localhost:8080/client/api", + Username: "admin", + Password: "password", + Domain: "/", + ApiKey: "", + SecretKey: "", + VerifyCert: false, + }, }, } } -func loadConfig() *Config { - cfg := defaultConfig() +func reloadConfig(cfg *Config) *Config { if _, err := os.Stat(cfg.Dir); err != nil { os.Mkdir(cfg.Dir, 0700) } + // Save on missing config if _, err := os.Stat(cfg.ConfigFile); err != nil { - // FIXME: write default cfg - } else { - //load config? + defaultConf := defaultConfig() + conf := ini.Empty() + conf.Section(ini.DEFAULT_SECTION).ReflectFrom(defaultConf.Core) + conf.Section(cfg.Core.ProfileName).ReflectFrom(defaultConf.Core.ActiveProfile) + conf.SaveTo(cfg.ConfigFile) } - LoadCache(cfg) - - return cfg -} + // Read config + conf, err := ini.LoadSources(ini.LoadOptions{ + IgnoreInlineComment: true, + }, cfg.ConfigFile) -func (c *Config) Name() string { - return name -} + if err != nil { + fmt.Printf("Fail to read config file: %v", err) + os.Exit(1) + } -func (c *Config) Version() string { - return version -} + core, err := conf.GetSection(ini.DEFAULT_SECTION) + if core == nil { + section, _ := conf.NewSection(ini.DEFAULT_SECTION) + section.ReflectFrom(&defaultConfig().Core) + } else { + // Write + if cfg.Core != nil { + conf.Section(ini.DEFAULT_SECTION).ReflectFrom(&cfg.Core) + } + // Update + core := new(Core) + conf.Section(ini.DEFAULT_SECTION).MapTo(core) + cfg.Core = core + } -func (c *Config) PrintHeader() { - fmt.Printf("Apache CloudStack 🐵 cloudmonkey %s.\n", version) - fmt.Printf("Type \"help\" for details, \"sync\" to update API cache or press tab to list commands.\n\n") -} + profile, err := conf.GetSection(cfg.Core.ProfileName) + if profile == nil { + section, _ := conf.NewSection(cfg.Core.ProfileName) + section.ReflectFrom(&defaultConfig().Core.ActiveProfile) + } else { + // Write + if cfg.Core.ActiveProfile != nil { + conf.Section(cfg.Core.ProfileName).ReflectFrom(&cfg.Core.ActiveProfile) + } + // Update + profile := new(ServerProfile) + conf.Section(cfg.Core.ProfileName).MapTo(profile) + cfg.Core.ActiveProfile = profile + } + // Save + conf.SaveTo(cfg.ConfigFile) -func (c *Config) GetPrompt() string { - return fmt.Sprintf("(%s) 🐒 > ", c.ActiveProfile.Name) + fmt.Println("Updating config to:", cfg.Core, cfg.Core.ActiveProfile) + return cfg } func (c *Config) UpdateGlobalConfig(key string, value string) { @@ -135,9 +161,42 @@ func (c *Config) UpdateGlobalConfig(key string, value string) { } func (c *Config) UpdateConfig(namespace string, key string, value string) { - fmt.Println("👌 Updating for key", key, ", value=", value, ", in ns=", namespace) - if key == "profile" { - //FIXME - c.ActiveProfile.Name = value + switch key { + case "asyncblock": + c.Core.AsyncBlock = value == "true" + case "output": + c.Core.Output = value + case "timeout": + intValue, _ := strconv.Atoi(value) + c.Core.Timeout = intValue + case "profile": + c.Core.ProfileName = value + c.Core.ActiveProfile = nil + case "url": + c.Core.ActiveProfile.Url = value + case "username": + c.Core.ActiveProfile.Username = value + case "password": + c.Core.ActiveProfile.Password = value + case "domain": + c.Core.ActiveProfile.Domain = value + case "apikey": + c.Core.ActiveProfile.ApiKey = value + case "secretkey": + c.Core.ActiveProfile.SecretKey = value + case "verifycert": + c.Core.ActiveProfile.VerifyCert = value == "true" + default: + return } + + reloadConfig(c) +} + +func NewConfig() *Config { + defaultConf := defaultConfig() + defaultConf.Core = nil + cfg := reloadConfig(defaultConf) + LoadCache(cfg) + return cfg } -- To stop receiving notification emails like this one, please contact ro...@apache.org.