diff --git a/Gopkg.lock b/Gopkg.lock index 7c93a500e3..574d951376 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -908,7 +908,7 @@ branch = "master" name = "yunion.io/x/structarg" packages = ["."] - revision = "adf929ce0f8bd62335ebe57d9b51f023c84e4d7a" + revision = "d5e5d87357b9bc2164215117763f6b15b2a3e75d" [solve-meta] analyzer-name = "dep" diff --git a/cmd/climc/climc.go b/cmd/climc/climc.go index d7a8da1372..6a19ea1144 100644 --- a/cmd/climc/climc.go +++ b/cmd/climc/climc.go @@ -169,6 +169,40 @@ func newClientSession(options *BaseOptions) (*mcclient.ClientSession, error) { return session, nil } +func enterInteractiveMode( + parser *structarg.ArgumentParser, + sessionFactory func() *mcclient.ClientSession, +) { + promputils.InitEnv(parser, sessionFactory()) + defer fmt.Println("Bye!") + p := prompt.New( + promputils.Executor, + promputils.Completer, + prompt.OptionPrefix("climc> "), + prompt.OptionTitle("Climc, a Command Line Interface to Manage Clouds"), + prompt.OptionMaxSuggestion(16), + ) + p.Run() +} + +func executeSubcommand( + subcmd *structarg.SubcommandArgument, + subparser *structarg.ArgumentParser, + options *BaseOptions, + sessionFactory func() *mcclient.ClientSession, +) { + var e error + suboptions := subparser.Options() + if options.SUBCOMMAND == "help" { + e = subcmd.Invoke(suboptions) + } else { + e = subcmd.Invoke(sessionFactory(), suboptions) + } + if e != nil { + showErrorAndExit(e) + } +} + func main() { parser, e := getSubcommandsParser() if e != nil { @@ -179,47 +213,39 @@ func main() { if options.Help { fmt.Print(parser.HelpString()) - } else if options.Version { - fmt.Printf("Yunion API client version:\n %s\n", version.GetJsonString()) - } else if len(os.Args) <= 1 || (options.ApiVersion == "v2" && len(os.Args) <= 3) { - session, e := newClientSession(options) - if e != nil { - showErrorAndExit(e) - } - promputils.InitEnv(parser, session) - defer fmt.Println("Bye!") - p := prompt.New( - promputils.Executor, - promputils.Completer, - prompt.OptionPrefix("climc> "), - prompt.OptionTitle("Climc, a Command Line Interface to Manage Clouds"), - prompt.OptionMaxSuggestion(16), - ) - p.Run() - } else { - subcmd := parser.GetSubcommand() - subparser := subcmd.GetSubParser() - if e != nil { - if subparser != nil { - fmt.Print(subparser.Usage()) - } else { - fmt.Print(parser.Usage()) - } - showErrorAndExit(e) - } else { - session, e := newClientSession(options) - if e != nil { - showErrorAndExit(e) - } - suboptions := subparser.Options() - if options.SUBCOMMAND == "help" { - e = subcmd.Invoke(suboptions) - } else { - e = subcmd.Invoke(session, suboptions) - } - if e != nil { - showErrorAndExit(e) - } - } + return } + + if options.Version { + fmt.Printf("Yunion API client version:\n %s\n", version.GetJsonString()) + return + } + + ensureSessionFactory := func() *mcclient.ClientSession { + session, err := newClientSession(options) + if err != nil { + showErrorAndExit(err) + } + return session + } + + // enter interactive mode when not enough argument and SUBCOMMAND is empty + if _, ok := e.(*structarg.NotEnoughArgumentsError); ok && options.SUBCOMMAND == "" { + enterInteractiveMode(parser, ensureSessionFactory) + return + } + + subcmd := parser.GetSubcommand() + subparser := subcmd.GetSubParser() + if e != nil { + if subparser != nil { + fmt.Print(subparser.Usage()) + } else { + fmt.Print(parser.Usage()) + } + showErrorAndExit(e) + } + + // execute subcommand in non-interactive mode + executeSubcommand(subcmd, subparser, options, ensureSessionFactory) } diff --git a/cmd/climc/shell/cloudproviders.go b/cmd/climc/shell/cloudproviders.go index edfb638d90..36c986ddf2 100644 --- a/cmd/climc/shell/cloudproviders.go +++ b/cmd/climc/shell/cloudproviders.go @@ -140,12 +140,12 @@ func init() { }) type CloudproviderSyncOptions struct { - ID string `help:"ID or Name of cloud provider"` - Force bool `help:"Force sync no matter what"` - FullSync bool `help:"Synchronize everything"` - Region []string `help:"region to sync"` - Zone []string `help:"region to sync"` - Host []string `help:"region to sync"` + ID string `help:"ID or Name of cloud provider"` + Force bool `help:"Force sync no matter what"` + FullSync bool `help:"Synchronize everything"` + Region []string `help:"region to sync"` + Zone []string `help:"region to sync"` + Host []string `help:"region to sync"` } R(&CloudproviderSyncOptions{}, "cloud-provider-sync", "Sync of a cloud provider account", func(s *mcclient.ClientSession, args *CloudproviderSyncOptions) error { params := jsonutils.NewDict() diff --git a/cmd/scheduler/app/server.go b/cmd/scheduler/app/server.go index 3dc1ce9a4f..e3a8f93be8 100644 --- a/cmd/scheduler/app/server.go +++ b/cmd/scheduler/app/server.go @@ -8,10 +8,10 @@ import ( "net/http" "strconv" + "gopkg.in/gin-gonic/gin.v1" "yunion.io/x/log" "yunion.io/x/pkg/util/prometheus" "yunion.io/x/pkg/utils" - "gopkg.in/gin-gonic/gin.v1" o "yunion.io/x/onecloud/cmd/scheduler/options" "yunion.io/x/onecloud/pkg/mcclient/auth" diff --git a/pkg/compute/options/options.go b/pkg/compute/options/options.go index c873819ebd..a018a3e2f1 100644 --- a/pkg/compute/options/options.go +++ b/pkg/compute/options/options.go @@ -21,10 +21,10 @@ type ComputeOptions struct { DefaultDiskSize int `default:"30720" help:"Default disk size in MB if not specified, default to 30GiB"` - EnablePendingDelete bool `default:"true" help:"Turn on/off pending delete VM and disk, default is on"` - PendingDeleteCheckSeconds int `default:"3600" help:"How long to wait to scan pending delete VM or disks, default is 1 hour"` - PendingDeleteExpireSeconds int `default:"259200" help:"How long a pending delete VM/disks cleaned automatically, default 3 days"` - PendingDeleteMaxCleanBatchSize int `default:"50" help:"How many pending delete servers can be clean in a batch"` + EnablePendingDelete bool `default:"true" help:"Turn on/off pending delete VM and disk, default is on"` + PendingDeleteCheckSeconds int `default:"3600" help:"How long to wait to scan pending delete VM or disks, default is 1 hour"` + PendingDeleteExpireSeconds int `default:"259200" help:"How long a pending delete VM/disks cleaned automatically, default 3 days"` + PendingDeleteMaxCleanBatchSize int `default:"50" help:"How many pending delete servers can be clean in a batch"` ImageCacheStoragePolicy string `default:"least_used" choices:"best_fit|least_used" help:"Policy to choose storage for image cache, best_fit or least_used"` MetricsRetentionDays int32 `default:"30" help:"Retention days for monitoring metrics in influxdb"` diff --git a/pkg/util/aliyun/region.go b/pkg/util/aliyun/region.go index db08f85c25..78efb6a653 100644 --- a/pkg/util/aliyun/region.go +++ b/pkg/util/aliyun/region.go @@ -9,9 +9,10 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/log" + "yunion.io/x/pkg/utils" + "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" - "yunion.io/x/pkg/utils" ) type SRegion struct { @@ -564,4 +565,4 @@ func (self *SRegion) updateInstance(instId string, name, desc, passwd, hostname func (self *SRegion) UpdateInstancePassword(instId string, passwd string) error { return self.updateInstance(instId, "", "", passwd, "") -} \ No newline at end of file +} diff --git a/pkg/util/aliyun/shell/instance.go b/pkg/util/aliyun/shell/instance.go index 9c86e47aa8..495e2949cf 100644 --- a/pkg/util/aliyun/shell/instance.go +++ b/pkg/util/aliyun/shell/instance.go @@ -2,6 +2,7 @@ package shell import ( "fmt" + "yunion.io/x/onecloud/pkg/util/aliyun" "yunion.io/x/onecloud/pkg/util/shellutils" ) @@ -82,7 +83,7 @@ func init() { }) type InstanceUpdatePasswordOptions struct { - ID string `help:"Instance ID"` + ID string `help:"Instance ID"` PASSWD string `help:"new password"` } shellutils.R(&InstanceUpdatePasswordOptions{}, "instance-update-password", "Update instance password", func(cli *aliyun.SRegion, args *InstanceUpdatePasswordOptions) error { diff --git a/pkg/util/esxi/manager.go b/pkg/util/esxi/manager.go index 0c0698bfcd..ed1dd5d76d 100644 --- a/pkg/util/esxi/manager.go +++ b/pkg/util/esxi/manager.go @@ -5,10 +5,12 @@ import ( "fmt" "net/url" "reflect" + "strings" "github.com/vmware/govmomi" "github.com/vmware/govmomi/object" "github.com/vmware/govmomi/property" + "github.com/vmware/govmomi/session" "github.com/vmware/govmomi/view" "github.com/vmware/govmomi/vim25/mo" "github.com/vmware/govmomi/vim25/types" @@ -16,10 +18,8 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/log" - "github.com/vmware/govmomi/session" "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" - "strings" ) const ( diff --git a/pkg/util/esxi/mobase.go b/pkg/util/esxi/mobase.go index 23f6aa9c61..c60498ebc5 100644 --- a/pkg/util/esxi/mobase.go +++ b/pkg/util/esxi/mobase.go @@ -1,10 +1,13 @@ package esxi import ( - "github.com/vmware/govmomi/vim25/mo" - "yunion.io/x/log" - "yunion.io/x/onecloud/pkg/cloudprovider" "reflect" + + "github.com/vmware/govmomi/vim25/mo" + + "yunion.io/x/log" + + "yunion.io/x/onecloud/pkg/cloudprovider" ) type SManagedObject struct { diff --git a/pkg/util/seclib2/seclib.go b/pkg/util/seclib2/seclib.go index 86cee26422..d3fd831df3 100644 --- a/pkg/util/seclib2/seclib.go +++ b/pkg/util/seclib2/seclib.go @@ -1,10 +1,10 @@ package seclib2 import ( - "fmt" - "strings" "bytes" + "fmt" "math/rand" + "strings" ) const ( @@ -39,7 +39,7 @@ func RandomPassword2(width int) string { } buf.WriteByte(ch) } - if digitsCnt > 1 && letterCnt > 1 && upperCnt > 1 && puncCnt >=1 && puncCnt <= 2 { + if digitsCnt > 1 && letterCnt > 1 && upperCnt > 1 && puncCnt >= 1 && puncCnt <= 2 { return buf.String() } } diff --git a/vendor/yunion.io/x/structarg/errors.go b/vendor/yunion.io/x/structarg/errors.go new file mode 100644 index 0000000000..3aeeac0b81 --- /dev/null +++ b/vendor/yunion.io/x/structarg/errors.go @@ -0,0 +1,13 @@ +package structarg + +import ( + "fmt" +) + +type NotEnoughArgumentsError struct { + argument Argument +} + +func (e *NotEnoughArgumentsError) Error() string { + return fmt.Sprintf("Not enough arguments, missing %s", e.argument) +} diff --git a/vendor/yunion.io/x/structarg/structarg.go b/vendor/yunion.io/x/structarg/structarg.go index 7e4c9193d5..9eb223f272 100644 --- a/vendor/yunion.io/x/structarg/structarg.go +++ b/vendor/yunion.io/x/structarg/structarg.go @@ -854,7 +854,7 @@ func (this *ArgumentParser) ParseArgs(args []string, ignore_unknown bool) error } } if err == nil && pos_idx < len(this.posArgs) { - err = fmt.Errorf("Not enough arguments, missing %s", this.posArgs[pos_idx]) + err = &NotEnoughArgumentsError{argument: this.posArgs[pos_idx]} } if err == nil { err = this.Validate()