From cbc0c234f28fa943a257ba9311d2f37b8b77b06c Mon Sep 17 00:00:00 2001 From: Zexi Date: Fri, 17 Aug 2018 02:27:39 +0800 Subject: [PATCH] =?UTF-8?q?-=20climc:=20=E8=AE=BE=E7=BD=AE=20option=20?= =?UTF-8?q?=E6=B2=A1=E6=9C=89=20subcommand=20=E7=9A=84=E6=83=85=E5=86=B5?= =?UTF-8?q?=E4=B8=8B=E8=BF=9B=E5=85=A5=E4=BA=A4=E4=BA=92=E6=A8=A1=E5=BC=8F?= =?UTF-8?q?,=20=E4=BB=A3=E7=A0=81=E9=80=BB=E8=BE=91=E5=8F=98=E6=B8=85?= =?UTF-8?q?=E6=99=B0=20-=20make=20fmt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Gopkg.lock | 2 +- cmd/climc/climc.go | 110 +++++++++++++--------- cmd/climc/shell/cloudproviders.go | 12 +-- cmd/scheduler/app/server.go | 2 +- pkg/cloudcommon/cronman/cronman.go | 21 ++--- pkg/cloudcommon/db/taskman/subtasks.go | 3 +- pkg/compute/models/disks.go | 6 +- pkg/compute/models/guests.go | 6 +- pkg/compute/options/options.go | 8 +- pkg/compute/service/service.go | 4 +- pkg/util/aliyun/region.go | 5 +- pkg/util/aliyun/shell/instance.go | 3 +- pkg/util/esxi/manager.go | 4 +- pkg/util/esxi/mobase.go | 9 +- pkg/util/seclib2/seclib.go | 6 +- vendor/yunion.io/x/structarg/errors.go | 13 +++ vendor/yunion.io/x/structarg/structarg.go | 2 +- 17 files changed, 130 insertions(+), 86 deletions(-) create mode 100644 vendor/yunion.io/x/structarg/errors.go diff --git a/Gopkg.lock b/Gopkg.lock index 8323a741ba..5b287504a8 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -902,7 +902,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 217724a188..af582a1693 100644 --- a/cmd/climc/climc.go +++ b/cmd/climc/climc.go @@ -133,6 +133,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 { @@ -143,47 +177,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 { - 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/cloudcommon/cronman/cronman.go b/pkg/cloudcommon/cronman/cronman.go index b2e443d983..d01cc096d5 100644 --- a/pkg/cloudcommon/cronman/cronman.go +++ b/pkg/cloudcommon/cronman/cronman.go @@ -1,33 +1,33 @@ package cronman import ( - "time" - "runtime/debug" "context" + "reflect" + "runtime" + "runtime/debug" + "time" "yunion.io/x/log" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/auth" - "reflect" - "runtime" ) const ( - DEFAULT_CRON_INTERVAL = 60*time.Second // default resolution is 1 monutes + DEFAULT_CRON_INTERVAL = 60 * time.Second // default resolution is 1 monutes ) type SCronJobManager struct { checkInterval time.Duration - timer *time.Timer - jobs []SCronJob + timer *time.Timer + jobs []SCronJob } type SCronJob struct { - name string + name string runInterval time.Duration - job func(ctx context.Context, userCred mcclient.TokenCredential) - lastRun time.Time + job func(ctx context.Context, userCred mcclient.TokenCredential) + lastRun time.Time } func NewCronJobManager(interval time.Duration) *SCronJobManager { @@ -92,4 +92,3 @@ func runJob(name string, job func(ctx context.Context, userCred mcclient.TokenCr userCred := auth.AdminCredential() job(ctx, userCred) } - diff --git a/pkg/cloudcommon/db/taskman/subtasks.go b/pkg/cloudcommon/db/taskman/subtasks.go index cf82841cc8..8ad2c2902e 100644 --- a/pkg/cloudcommon/db/taskman/subtasks.go +++ b/pkg/cloudcommon/db/taskman/subtasks.go @@ -1,11 +1,12 @@ package taskman import ( + "database/sql" + "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/onecloud/pkg/cloudcommon/db" - "database/sql" ) const ( diff --git a/pkg/compute/models/disks.go b/pkg/compute/models/disks.go index 4d0b190436..047863499a 100644 --- a/pkg/compute/models/disks.go +++ b/pkg/compute/models/disks.go @@ -634,8 +634,8 @@ func (self *SDisk) PerformCancelDelete(ctx context.Context, userCred mcclient.To return nil, nil } -func (manager *SDiskManager) getExpiredPendingDeleteDisks() ([]SDisk) { - deadline := time.Now().Add(time.Duration(options.Options.PendingDeleteExpireSeconds)*time.Second) +func (manager *SDiskManager) getExpiredPendingDeleteDisks() []SDisk { + deadline := time.Now().Add(time.Duration(options.Options.PendingDeleteExpireSeconds) * time.Second) q := manager.Query() q = q.IsTrue("pending_deleted").LT("pending_deleted_at", deadline).Limit(options.Options.PendingDeleteMaxCleanBatchSize) @@ -658,4 +658,4 @@ func (manager *SDiskManager) CleanPendingDeleteDisks(ctx context.Context, userCr for i := 0; i < len(disks); i += 1 { disks[i].StartDiskDeleteTask(ctx, userCred, "", false) } -} \ No newline at end of file +} diff --git a/pkg/compute/models/guests.go b/pkg/compute/models/guests.go index 8c93ed56fe..401bdbd1b0 100644 --- a/pkg/compute/models/guests.go +++ b/pkg/compute/models/guests.go @@ -2661,8 +2661,8 @@ func (manager *SGuestManager) getIpsByExit(ips []string, isExitOnly bool) []stri return extRet } -func (manager *SGuestManager) getExpiredPendingDeleteGuests() ([]SGuest) { - deadline := time.Now().Add(time.Duration(options.Options.PendingDeleteExpireSeconds)*time.Second) +func (manager *SGuestManager) getExpiredPendingDeleteGuests() []SGuest { + deadline := time.Now().Add(time.Duration(options.Options.PendingDeleteExpireSeconds) * time.Second) q := manager.Query() q = q.IsTrue("pending_deleted").LT("pending_deleted_at", deadline).In("hypervisor", []string{"aliyun"}).Limit(options.Options.PendingDeleteMaxCleanBatchSize) @@ -2685,4 +2685,4 @@ func (manager *SGuestManager) CleanPendingDeleteServers(ctx context.Context, use for i := 0; i < len(guests); i += 1 { guests[i].StartDeleteGuestTask(ctx, userCred, "", false, true) } -} \ No newline at end of file +} 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/compute/service/service.go b/pkg/compute/service/service.go index c26b0bdab2..227874f9d6 100644 --- a/pkg/compute/service/service.go +++ b/pkg/compute/service/service.go @@ -9,14 +9,14 @@ import ( "yunion.io/x/log" "yunion.io/x/onecloud/pkg/cloudcommon" + "yunion.io/x/onecloud/pkg/cloudcommon/cronman" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/compute" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/compute/options" - "yunion.io/x/onecloud/pkg/cloudcommon/cronman" - _ "yunion.io/x/onecloud/pkg/compute/tasks" _ "yunion.io/x/onecloud/pkg/compute/guestdrivers" + _ "yunion.io/x/onecloud/pkg/compute/tasks" _ "yunion.io/x/onecloud/pkg/util/aliyun/provider" _ "yunion.io/x/onecloud/pkg/util/esxi/provider" ) diff --git a/pkg/util/aliyun/region.go b/pkg/util/aliyun/region.go index c9a8954b67..cdea189749 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 { @@ -563,4 +564,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()