From 6c3fb0ed66fad7873b4cd29f1bbc9281effe5930 Mon Sep 17 00:00:00 2001 From: akutz Date: Wed, 3 Feb 2016 13:48:44 -0600 Subject: [PATCH] Config-Based Module Support This patch adds support for configuration modules via the REX-Ray configuration source. For example, the following configuration is loaded by default: rexray: modules: default-admin: type: admin desc: The default admin module. host: tcp://127.0.0.1:7979 default-docker: type: docker desc: The default docker module. host: unix:///run/docker/plugins/rexray.sock spec: /etc/docker/plugins/rexray.spec The above configuration indicates that there are two modules that need to be initialized and started: 1. default-admin 2. default-docker Default modules can be overridden in a custom configuration file by simply using the same names as above. If the `host` or `spec` properties are not defined for a docker module, then the sanitized name of the module is used to build the paths to a socket and spec file. For example: rexray: modules: "isilon 2": type: docker The above configuration would create a Docker module hosted using a socket file at `unix:///run/docker/plugins/isilon-2.sock` and spec file at `/etc/docker/plugins/isilon-2.spec`. If the configuration file is used to override part of the `default-docker` module's configuration, for example its description, it's also possible to omit the `default-docker` module's `host` and `spec` properties as well. The difference is that the `default-docker` module's `host` and `spec` properties will default to values based not on the module name but `unix:///run/docker/plugins/rexray` and `/etc/docker/plugins/rexray.spec`. --- daemon/daemon_modules.go | 2 +- daemon/module/admin/admin.go | 85 +++---- .../docker/remotevolumedriver/notests.go | 1 + .../docker/remotevolumedriver/remvoldriver.go | 2 + .../module/docker/volumedriver/voldriver.go | 87 ++++--- daemon/module/module.go | 212 +++++++++++------- drivers/volume/volume.go | 3 +- rexray/cli/cli.go | 6 +- rexray/cli/cmds_module.go | 38 ++-- 9 files changed, 240 insertions(+), 196 deletions(-) create mode 100644 daemon/module/docker/remotevolumedriver/notests.go diff --git a/daemon/daemon_modules.go b/daemon/daemon_modules.go index a6c81f207..ed2b92853 100644 --- a/daemon/daemon_modules.go +++ b/daemon/daemon_modules.go @@ -5,6 +5,6 @@ package daemon import ( // load the modules _ "github.com/emccode/rexray/daemon/module/admin" - _ "github.com/emccode/rexray/daemon/module/docker/remotevolumedriver" + // _ "github.com/emccode/rexray/daemon/module/docker/remotevolumedriver" _ "github.com/emccode/rexray/daemon/module/docker/volumedriver" ) diff --git a/daemon/module/admin/admin.go b/daemon/module/admin/admin.go index d21750c48..f2cb3ce21 100644 --- a/daemon/module/admin/admin.go +++ b/daemon/module/admin/admin.go @@ -20,13 +20,10 @@ import ( ) const ( - modPort = 7979 - modName = "AdminModule" - modDescription = "The REX-Ray admin module" + modName = "admin" ) type mod struct { - id int32 name string addr string desc string @@ -38,26 +35,17 @@ type jsonError struct { } func init() { - addr := fmt.Sprintf("tcp://:%d", modPort) - mc := &module.Config{ - Address: addr, - } - module.RegisterModule(modName, false, newModule, []*module.Config{mc}) + module.RegisterModule(modName, newModule) } -func newModule(id int32, config *module.Config) (module.Module, error) { +func newModule(c *module.Config) (module.Module, error) { return &mod{ - id: id, - name: modName, - desc: modDescription, - addr: config.Address, + name: c.Name, + desc: c.Description, + addr: c.Address, }, nil } -func (m *mod) ID() int32 { - return m.id -} - func loadAsset(path, defaultValue string) string { devPath := fmt.Sprintf( @@ -158,16 +146,18 @@ func moduleInstGetHandler(w http.ResponseWriter, req *http.Request) { } func moduleInstPostHandler(w http.ResponseWriter, req *http.Request) { - typeID := req.FormValue("typeId") + name := req.FormValue("name") + typeName := req.FormValue("typeName") address := req.FormValue("address") cfgJSON := req.FormValue("config") start := req.FormValue("start") log.WithFields(log.Fields{ - "typeId": typeID, - "address": address, - "start": start, - "config": cfgJSON, + "name": name, + "typeName": typeName, + "address": address, + "start": start, + "config": cfgJSON, }).Debug("received module instance post request") cfg, cfgErr := gofig.FromJSON(cfgJSON) @@ -178,28 +168,21 @@ func moduleInstPostHandler(w http.ResponseWriter, req *http.Request) { } modConfig := &module.Config{ + Name: name, + Type: typeName, Address: address, Config: cfg, } w.Header().Set("Content-Type", "application/json; charset=UTF-8") - if typeID == "" || address == "" { - w.Write(getJSONError("Fields typeId and address are required", nil)) - log.Printf("Fields typeId and address are required\n") - return - } - - typeIDInt, typeIDIntErr := strconv.ParseInt(typeID, 10, 32) - if typeIDIntErr != nil { - w.Write(getJSONError("Error parsing typeId", typeIDIntErr)) - log.Printf("Error parsing typeId ERR: %v\n", typeIDIntErr) + if typeName == "" || address == "" { + w.Write(getJSONError("Fields typeName and address are required", nil)) + log.Printf("Fields typeName and address are required\n") return } - typeIDInt32 := int32(typeIDInt) - - modInst, initErr := module.InitializeModule(typeIDInt32, modConfig) + modInst, initErr := module.InitializeModule(modConfig) if initErr != nil { w.WriteHeader(http.StatusBadRequest) log.Printf("Error initializing module ERR: %v\n", initErr) @@ -219,7 +202,7 @@ func moduleInstPostHandler(w http.ResponseWriter, req *http.Request) { } if startBool { - startErr := module.StartModule(modInst.ID) + startErr := module.StartModule(modInst.Name) if startErr != nil { w.Write(getJSONError("Error starting module", startErr)) log.Printf("Error starting module ERR: %v\n", startErr) @@ -255,27 +238,17 @@ func moduleInstStartHandler(w http.ResponseWriter, req *http.Request) { w.Header().Set("Content-Type", "application/json; charset=UTF-8") vars := mux.Vars(req) - id := vars["id"] - if id == "" { - w.Write(getJSONError("The URL should include the module instance ID", nil)) - log.Printf("The URL should include the module instance ID\n") - return - } - - idInt, idIntErr := strconv.ParseInt(id, 10, 32) - - if idIntErr != nil { - w.Write(getJSONError("Error parsing id", idIntErr)) - log.Printf("Error parsing id ERR: %v\n", idIntErr) + name := vars["name"] + if name == "" { + w.Write(getJSONError("The URL should include the module instance name", nil)) + log.Printf("The URL should include the module instance name\n") return } - idInt32 := int32(idInt) - - modInst, modInstErr := module.GetModuleInstance(idInt32) + modInst, modInstErr := module.GetModuleInstance(name) if modInstErr != nil { - w.Write(getJSONError("Unknown module id", modInstErr)) - log.Printf("Unknown module id ERR: %v\n", modInstErr) + w.Write(getJSONError("Unknown module name", modInstErr)) + log.Printf("Unknown module name ERR: %v\n", modInstErr) return } @@ -291,7 +264,7 @@ func moduleInstStartHandler(w http.ResponseWriter, req *http.Request) { return } - startErr := module.StartModule(idInt32) + startErr := module.StartModule(name) if startErr != nil { w.Write(getJSONError("Error starting moudle", startErr)) @@ -330,7 +303,7 @@ func (m *mod) Start() error { r.Handle("/r/module/instances", handlers.LoggingHandler(stdOut, http.HandlerFunc(moduleInstHandler))) - r.Handle("/r/module/instances/{id}/start", + r.Handle("/r/module/instances/{name}/start", handlers.LoggingHandler(stdOut, http.HandlerFunc(moduleInstStartHandler))) r.Handle("/r/module/types", handlers.LoggingHandler(stdOut, http.HandlerFunc(moduleTypeHandler))) diff --git a/daemon/module/docker/remotevolumedriver/notests.go b/daemon/module/docker/remotevolumedriver/notests.go new file mode 100644 index 000000000..0c471d518 --- /dev/null +++ b/daemon/module/docker/remotevolumedriver/notests.go @@ -0,0 +1 @@ +package remotevolumedriver diff --git a/daemon/module/docker/remotevolumedriver/remvoldriver.go b/daemon/module/docker/remotevolumedriver/remvoldriver.go index 666ff750d..24bd42180 100644 --- a/daemon/module/docker/remotevolumedriver/remvoldriver.go +++ b/daemon/module/docker/remotevolumedriver/remvoldriver.go @@ -1,3 +1,5 @@ +// +build ignore + package remotevolumedriver import ( diff --git a/daemon/module/docker/volumedriver/voldriver.go b/daemon/module/docker/volumedriver/voldriver.go index fdde1e3ed..35ac6dc49 100644 --- a/daemon/module/docker/volumedriver/voldriver.go +++ b/daemon/module/docker/volumedriver/voldriver.go @@ -9,10 +9,10 @@ import ( "os" "path/filepath" "regexp" + "strings" "time" log "github.com/Sirupsen/logrus" - "github.com/akutz/gofig" "github.com/akutz/goof" "github.com/akutz/gotil" @@ -21,54 +21,58 @@ import ( ) const ( - modAddress = "unix:///run/docker/plugins/rexray.sock" - modPort = 7980 - modName = "DockerVolumeDriverModule" - modDescription = "The REX-Ray Docker VolumeDriver module" + modName = "docker" ) type mod struct { - id int32 r *core.RexRay name string addr string desc string } +var ( + separators = regexp.MustCompile(`[ &_=+:]`) + dashes = regexp.MustCompile(`[\-]+`) + illegalPath = regexp.MustCompile(`[^[:alnum:]\~\-\./]`) +) + func init() { - //tcpAddr := fmt.Sprintf("tcp://:%d", ModPort) + module.RegisterModule(modName, newModule) +} - _, fsPath, parseAddrErr := gotil.ParseAddress(modAddress) - if parseAddrErr != nil { - panic(parseAddrErr) - } +func newModule(c *module.Config) (module.Module, error) { - fsPathDir := filepath.Dir(fsPath) - os.MkdirAll(fsPathDir, 0755) + host := strings.Trim(c.Address, " ") - mc := &module.Config{ - Address: modAddress, - Config: gofig.New(), + if host == "" { + if c.Name == "default-docker" { + host = "unix:///run/docker/plugins/rexray.sock" + } else { + fname := cleanName(c.Name) + host = fmt.Sprintf("unix:///run/docker/plugins/%s.sock", fname) + } } - module.RegisterModule(modName, true, newMod, []*module.Config{mc}) -} - -func (m *mod) ID() int32 { - return m.id -} + c.Address = host -func newMod(id int32, cfg *module.Config) (module.Module, error) { return &mod{ - id: id, - r: core.New(cfg.Config), - name: modName, - desc: modDescription, - addr: cfg.Address, + r: core.New(c.Config), + name: c.Name, + desc: c.Description, + addr: host, }, nil } -const driverName = "dockervolumedriver" +func cleanName(s string) string { + s = strings.Trim(strings.ToLower(s), " ") + s = separators.ReplaceAllString(s, "-") + s = illegalPath.ReplaceAllString(s, "") + s = dashes.ReplaceAllString(s, "-") + return s +} + +const driverName = "docker" var ( errMissingHost = goof.New("Missing host parameter") @@ -88,6 +92,11 @@ func (m *mod) Start() error { return parseAddrErr } + if proto == "unix" { + dir := filepath.Dir(addr) + os.MkdirAll(dir, 0755) + } + const validProtoPatt = "(?i)^unix|tcp$" isProtoValid, matchProtoErr := regexp.MatchString(validProtoPatt, proto) if matchProtoErr != nil { @@ -158,10 +167,22 @@ func (m *mod) Start() error { } }() - writeSpecErr := ioutil.WriteFile( - "/etc/docker/plugins/rexray.spec", []byte(specPath), 0644) - if writeSpecErr != nil { - return writeSpecErr + spec := m.r.Config.GetString("spec") + if spec == "" { + if m.name == "default-docker" { + spec = "/etc/docker/plugins/rexray.spec" + } else { + fname := cleanName(m.name) + spec = fmt.Sprintf("/etc/docker/plugins/%s.spec", fname) + } + } + + log.WithField("path", spec).Debug("docker voldriver spec file") + + if !gotil.FileExists(spec) { + if err := ioutil.WriteFile(spec, []byte(specPath), 0644); err != nil { + return err + } } return nil diff --git a/daemon/module/module.go b/daemon/module/module.go index cc3c1d4fb..e727be68f 100644 --- a/daemon/module/module.go +++ b/daemon/module/module.go @@ -2,23 +2,19 @@ package module import ( "fmt" + "strings" "sync" - "sync/atomic" "time" log "github.com/Sirupsen/logrus" - "github.com/akutz/goof" - "github.com/akutz/gofig" + "github.com/akutz/goof" ) // Module is the interface to which types adhere in order to participate as // daemon modules. type Module interface { - // Id gets the module's unique identifier. - ID() int32 - // Start starts the module. Start() error @@ -37,16 +33,13 @@ type Module interface { } // Init initializes the module. -type Init func(id int32, config *Config) (Module, error) +type Init func(config *Config) (Module, error) var ( - nextModTypeID int32 - nextModInstanceID int32 - - modTypes map[int32]*Type + modTypes map[string]*Type modTypesRwl sync.RWMutex - modInstances map[int32]*Instance + modInstances map[string]*Instance modInstancesRwl sync.RWMutex ) @@ -60,24 +53,23 @@ func GetModOptVal(opts map[string]string, key string) string { // Config is a struct used to configure a module. type Config struct { - Address string `json:"address"` - Config gofig.Config `json:"config,omitempty"` + Name string `json:"name"` + Type string `json:"type"` + Description string `json:"description"` + Address string `json:"address"` + Config gofig.Config `json:"config,omitempty"` } // Type is a struct that describes a module type type Type struct { - ID int32 `json:"id"` - Name string `json:"name"` - IgnoreFailOnInit bool `json:"-"` - InitFunc Init `json:"-"` - DefaultConfigs []*Config `json:"defaultConfigs"` + Name string `json:"name"` + InitFunc Init `json:"-"` } // Instance is a struct that describes a module instance type Instance struct { - ID int32 `json:"id"` Type *Type `json:"-"` - TypeID int32 `json:"typeId"` + TypeName string `json:"typeName"` Inst Module `json:"-"` Name string `json:"name"` Config *Config `json:"config,omitempty"` @@ -86,10 +78,27 @@ type Instance struct { } func init() { - nextModTypeID = 0 - nextModInstanceID = 0 - modTypes = make(map[int32]*Type) - modInstances = make(map[int32]*Instance) + modTypes = map[string]*Type{} + modInstances = map[string]*Instance{} + initConfig() +} + +func initConfig() { + cfg := gofig.NewRegistration("Module") + cfg.Yaml(` +rexray: + modules: + default-admin: + type: admin + desc: The default admin module. + host: tcp://127.0.0.1:7979 + default-docker: + type: docker + desc: The default docker module. + host: unix:///run/docker/plugins/rexray.sock + spec: /etc/docker/plugins/rexray.spec +`) + gofig.Register(cfg) } // Types returns a channel that receives the registered module types. @@ -132,92 +141,82 @@ func Instances() <-chan *Instance { // InitializeDefaultModules initializes the default modules. func InitializeDefaultModules() error { - modTypesRwl.Lock() - defer modTypesRwl.Unlock() + modTypesRwl.RLock() + defer modTypesRwl.RUnlock() - for id, mt := range modTypes { - if mt.DefaultConfigs != nil { - for _, mc := range mt.DefaultConfigs { - _, initErr := InitializeModule(id, mc) - if initErr != nil { - if mt.IgnoreFailOnInit { - log.WithField("error", initErr).Warn( - "ignoring initialization failure") - } else { - return initErr - } - } - } + c := gofig.New() + modConfigs, err := getConfiguredModules(c) + if err != nil { + return err + } + + for _, mc := range modConfigs { + mod, err := InitializeModule(mc) + if err != nil { + return err } + func() { + modInstancesRwl.Lock() + defer modInstancesRwl.Unlock() + modInstances[mod.Name] = mod + }() } return nil } // InitializeModule initializes a module. -func InitializeModule( - modTypeID int32, - modConfig *Config) (*Instance, error) { +func InitializeModule(modConfig *Config) (*Instance, error) { modInstancesRwl.Lock() defer modInstancesRwl.Unlock() + typeName := strings.ToLower(modConfig.Type) + lf := log.Fields{ - "typeId": modTypeID, - "address": modConfig.Address, + "typeName": typeName, + "address": modConfig.Address, } - mt, modTypeExists := modTypes[modTypeID] + mt, modTypeExists := modTypes[typeName] if !modTypeExists { return nil, goof.WithFields(lf, "unknown module type") } - lf["typeName"] = mt.Name - lf["ignoreFailOnInit"] = mt.IgnoreFailOnInit - - modInstID := atomic.AddInt32(&nextModInstanceID, 1) - mod, initErr := mt.InitFunc(modInstID, modConfig) + mod, initErr := mt.InitFunc(modConfig) if initErr != nil { - atomic.AddInt32(&nextModInstanceID, -1) return nil, initErr } + modName := mod.Name() + modInst := &Instance{ - ID: modInstID, Type: mt, - TypeID: mt.ID, + TypeName: typeName, Inst: mod, - Name: mod.Name(), + Name: modName, Config: modConfig, Description: mod.Description(), } - modInstances[modInstID] = modInst + modInstances[modName] = modInst - lf["id"] = modInstID + lf["name"] = modName log.WithFields(lf).Info("initialized module instance") return modInst, nil } -// RegisterModule registers a module. -func RegisterModule( - name string, - ignoreFailOnInit bool, - initFunc Init, - defaultConfigs []*Config) int32 { +// RegisterModule registers a module type. +func RegisterModule(name string, initFunc Init) { + modTypesRwl.Lock() defer modTypesRwl.Unlock() - modTypeID := atomic.AddInt32(&nextModTypeID, 1) - modTypes[modTypeID] = &Type{ - ID: modTypeID, - Name: name, - IgnoreFailOnInit: ignoreFailOnInit, - InitFunc: initFunc, - DefaultConfigs: defaultConfigs, + name = strings.ToLower(name) + modTypes[name] = &Type{ + Name: name, + InitFunc: initFunc, } - - return modTypeID } // StartDefaultModules starts the default modules. @@ -225,8 +224,8 @@ func StartDefaultModules() error { modInstancesRwl.RLock() defer modInstancesRwl.RUnlock() - for id := range modInstances { - startErr := StartModule(id) + for name := range modInstances { + startErr := StartModule(name) if startErr != nil { return startErr } @@ -235,37 +234,37 @@ func StartDefaultModules() error { return nil } -// GetModuleInstance gets the module instance with the provided instance ID. -func GetModuleInstance(modInstID int32) (*Instance, error) { +// GetModuleInstance gets the module instance with the provided name. +func GetModuleInstance(name string) (*Instance, error) { modInstancesRwl.RLock() defer modInstancesRwl.RUnlock() - mod, modExists := modInstances[modInstID] + name = strings.ToLower(name) + mod, modExists := modInstances[name] if !modExists { return nil, - goof.WithField("id", modInstID, "unknown module instance") + goof.WithField("name", name, "unknown module instance") } return mod, nil } -// StartModule starts the module with the provided instance ID. -func StartModule(modInstID int32) error { +// StartModule starts the module with the provided instance name. +func StartModule(name string) error { modInstancesRwl.RLock() defer modInstancesRwl.RUnlock() - lf := map[string]interface{}{"id": modInstID} + name = strings.ToLower(name) + lf := map[string]interface{}{"name": name} - mod, modExists := modInstances[modInstID] + mod, modExists := modInstances[name] if !modExists { return goof.WithFields(lf, "unknown module instance") } - lf["id"] = mod.ID - lf["typeId"] = mod.Type.ID lf["typeName"] = mod.Type.Name lf["address"] = mod.Config.Address @@ -280,8 +279,8 @@ func StartModule(modInstID int32) error { m := "error starting module" errMsg := fmt.Sprintf( - "Error starting module type %d, %d-%s at %s", - mod.TypeID, mod.ID, mod.Name, mod.Config.Address) + "Error starting module type=%s, instance=%s at %s", + mod.TypeName, mod.Name, mod.Config.Address) if r == nil { startError <- goof.New(errMsg) @@ -324,3 +323,44 @@ func StartModule(modInstID int32) error { return nil } + +func getConfiguredModules(c gofig.Config) ([]*Config, error) { + + mods := c.Get("rexray.modules") + modMap, ok := mods.(map[string]interface{}) + if !ok { + return nil, goof.New("invalid format rexray.modules") + } + log.WithField("count", len(modMap)).Debug("got modules map") + + modConfigs := []*Config{} + + for name := range modMap { + name = strings.ToLower(name) + + log.WithField("name", name).Debug("processing module config") + + scope := fmt.Sprintf("rexray.modules.%s", name) + log.WithField("scope", scope).Debug("getting scoped config for module") + sc := c.Scope(scope) + + mc := &Config{ + Name: name, + Type: strings.ToLower(sc.GetString("type")), + Description: sc.GetString("desc"), + Address: sc.GetString("host"), + Config: sc, + } + + log.WithFields(log.Fields{ + "name": mc.Name, + "type": mc.Type, + "desc": mc.Description, + "addr": mc.Address, + }).Info("created new mod config") + + modConfigs = append(modConfigs, mc) + } + + return modConfigs, nil +} diff --git a/drivers/volume/volume.go b/drivers/volume/volume.go index 76c513d2d..d3cecccbf 100644 --- a/drivers/volume/volume.go +++ b/drivers/volume/volume.go @@ -2,8 +2,9 @@ package volume import ( // loads the volume drivers - "github.com/akutz/gofig" _ "github.com/emccode/rexray/drivers/volume/docker" + + "github.com/akutz/gofig" ) func init() { diff --git a/rexray/cli/cli.go b/rexray/cli/cli.go index 75263598c..13cc882ce 100644 --- a/rexray/cli/cli.go +++ b/rexray/cli/cli.go @@ -95,8 +95,8 @@ type CLI struct { mountLabel string fsType string overwriteFs bool - moduleTypeID int32 - moduleInstanceID int32 + moduleTypeName string + moduleInstanceName string moduleInstanceAddress string moduleInstanceStart bool moduleConfig []string @@ -267,6 +267,8 @@ func (c *CLI) preRun(cmd *cobra.Command, args []string) { c.updateLogLevel() + c.r.Config = c.r.Config.Scope("rexray.modules.default-docker") + if isHelpFlag(cmd) { cmd.Help() panic(&helpFlagPanic{}) diff --git a/rexray/cli/cmds_module.go b/rexray/cli/cmds_module.go index 9da5c7a24..7455eeb7e 100644 --- a/rexray/cli/cmds_module.go +++ b/rexray/cli/cmds_module.go @@ -105,12 +105,11 @@ func (c *CLI) initModuleCmds() { panic(addrErr) } - if c.moduleTypeID == -1 || c.moduleInstanceAddress == "" { + if c.moduleTypeName == "" || c.moduleInstanceAddress == "" { cmd.Usage() return } - modTypeIDStr := fmt.Sprintf("%d", c.moduleTypeID) modInstStartStr := fmt.Sprintf("%v", c.moduleInstanceStart) u := fmt.Sprintf("http://%s/r/module/instances", addr) @@ -121,19 +120,21 @@ func (c *CLI) initModuleCmds() { } log.WithFields(log.Fields{ - "url": u, - "typeId": modTypeIDStr, - "address": c.moduleInstanceAddress, - "start": modInstStartStr, - "config": cfgJSON}).Debug("post create module instance") + "url": u, + "name": c.moduleInstanceName, + "typeName": c.moduleTypeName, + "address": c.moduleInstanceAddress, + "start": modInstStartStr, + "config": cfgJSON}).Debug("post create module instance") client := &http.Client{} resp, respErr := client.PostForm(u, url.Values{ - "typeId": {modTypeIDStr}, - "address": {c.moduleInstanceAddress}, - "start": {modInstStartStr}, - "config": {cfgJSON}, + "name": {c.moduleInstanceName}, + "typeName": {c.moduleTypeName}, + "address": {c.moduleInstanceAddress}, + "start": {modInstStartStr}, + "config": {cfgJSON}, }) if respErr != nil { panic(respErr) @@ -160,13 +161,13 @@ func (c *CLI) initModuleCmds() { panic(addrErr) } - if c.moduleInstanceID == -1 { + if c.moduleInstanceName == "" { cmd.Usage() return } u := fmt.Sprintf( - "http://%s/r/module/instances/%d/start", addr, c.moduleInstanceID) + "http://%s/r/module/instances/%s/start", addr, c.moduleInstanceName) client := &http.Client{} resp, respErr := client.Get(u) @@ -187,8 +188,11 @@ func (c *CLI) initModuleCmds() { } func (c *CLI) initModuleFlags() { - c.moduleInstancesCreateCmd.Flags().Int32VarP(&c.moduleTypeID, "id", - "i", -1, "The ID of the module type to instance") + c.moduleInstancesCreateCmd.Flags().StringVarP(&c.moduleTypeName, "typeName", + "t", "", "The name of the module type to instance") + + c.moduleInstancesCreateCmd.Flags().StringVarP(&c.moduleInstanceName, "name", + "n", "", "The name of the new module instance") c.moduleInstancesCreateCmd.Flags().StringVarP(&c.moduleInstanceAddress, "address", "a", "", @@ -203,6 +207,6 @@ func (c *CLI) initModuleFlags() { "A comma-seperated string of key=value pairs used by some module "+ "types for custom configuraitons.") - c.moduleInstancesStartCmd.Flags().Int32VarP(&c.moduleInstanceID, "id", - "i", -1, "The ID of the module instance to start") + c.moduleInstancesStartCmd.Flags().StringVarP(&c.moduleInstanceName, "name", + "n", "", "The name of the module instance to start") }