You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by ro...@apache.org on 2018/04/13 22:06:55 UTC

[cloudstack-cloudmonkey] 02/04: config: implement ini based config same as legacy cloudmonkey

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
rohit@apache.org.