From 4af0ce699ccfad0d55061e0e978f804e976268ba Mon Sep 17 00:00:00 2001 From: Yousong Zhou Date: Mon, 19 Nov 2018 10:37:48 +0000 Subject: [PATCH 01/16] loadbalancers: use httperrors for parameter validation results --- pkg/compute/models/loadbalanceracls.go | 9 +++++---- pkg/compute/models/loadbalanceragents.go | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/pkg/compute/models/loadbalanceracls.go b/pkg/compute/models/loadbalanceracls.go index 67dd190c6c..94fd544b2a 100644 --- a/pkg/compute/models/loadbalanceracls.go +++ b/pkg/compute/models/loadbalanceracls.go @@ -14,6 +14,7 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/validators" + "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" ) @@ -33,16 +34,16 @@ func (aclEntry *SLoadbalancerAclEntry) Validate(data *jsonutils.JSONDict) error } else { ip := net.ParseIP(aclEntry.Cidr).To4() if ip == nil { - return fmt.Errorf("invalid addr %s", aclEntry.Cidr) + return httperrors.NewInputParameterError("invalid addr %s", aclEntry.Cidr) } } if commentLimit := 128; len(aclEntry.Comment) > commentLimit { - return fmt.Errorf("comment too long (%d>=%d)", + return httperrors.NewInputParameterError("comment too long (%d>=%d)", len(aclEntry.Comment), commentLimit) } for _, r := range aclEntry.Comment { if !unicode.IsPrint(r) { - return fmt.Errorf("comment contains non-printable char: %v", r) + return httperrors.NewInputParameterError("comment contains non-printable char: %v", r) } } return nil @@ -68,7 +69,7 @@ func (aclEntries *SLoadbalancerAclEntries) Validate(data *jsonutils.JSONDict) er } if _, ok := found[aclEntry.Cidr]; ok { // error so that the user has a chance to deal with comments - return fmt.Errorf("acl cidr duplicate %s", aclEntry.Cidr) + return httperrors.NewInputParameterError("acl cidr duplicate %s", aclEntry.Cidr) } found[aclEntry.Cidr] = true } diff --git a/pkg/compute/models/loadbalanceragents.go b/pkg/compute/models/loadbalanceragents.go index d73e6ed37c..29269063fd 100644 --- a/pkg/compute/models/loadbalanceragents.go +++ b/pkg/compute/models/loadbalanceragents.go @@ -154,7 +154,7 @@ func (p *SLoadbalancerAgentParamsTelegraf) Validate(data *jsonutils.JSONDict) er if p.InfluxDbOutputUrl != "" { _, err := url.Parse(p.InfluxDbOutputUrl) if err != nil { - return err + return httperrors.NewInputParameterError("telegraf params: invalid influxdb url: %s", err) } } if p.HaproxyInputInterval <= 0 { From f9ac0c020483b77b448a678de7b81e9d34fc158f Mon Sep 17 00:00:00 2001 From: Yousong Zhou Date: Mon, 19 Nov 2018 10:16:28 +0000 Subject: [PATCH 02/16] validators: errors: retain msg fmt and params --- pkg/cloudcommon/validators/errors.go | 46 ++++++++++++---------------- 1 file changed, 20 insertions(+), 26 deletions(-) diff --git a/pkg/cloudcommon/validators/errors.go b/pkg/cloudcommon/validators/errors.go index 9045fc93ed..48f4564ddd 100644 --- a/pkg/cloudcommon/validators/errors.go +++ b/pkg/cloudcommon/validators/errors.go @@ -54,65 +54,59 @@ func (ve *ValidateError) Error() string { // TODO let each validator provide the error func newMissingKeyError(key string) error { - msg := fmt.Sprintf("missing %q", key) - return newError(ERR_MISSING_KEY, msg) + return newError(ERR_MISSING_KEY, "missing %q", key) } func newGeneralError(key string, err error) error { - msg := fmt.Sprintf("general error for %q: %s", key, err) - return newError(ERR_GENERAL, msg) + return newError(ERR_GENERAL, "general error for %q: %s", key, err) } func newInvalidTypeError(key string, typ string, err error) error { - msg := fmt.Sprintf("expecting %s type for %q: %s", typ, key, err) - return newError(ERR_INVALID_TYPE, msg) + return newError(ERR_INVALID_TYPE, "expecting %s type for %q: %s", typ, key, err) } func newInvalidChoiceError(key string, choices Choices, choice string) error { - msg := fmt.Sprintf("invalid %q, want %s, got %s", key, choices, choice) - return newError(ERR_INVALID_CHOICE, msg) + return newError(ERR_INVALID_CHOICE, "invalid %q, want %s, got %s", key, choices, choice) } func newNotInRangeError(key string, value, lower, upper int64) error { - msg := fmt.Sprintf("invalid %q: %d, want [%d,%d]", key, value, lower, upper) - return newError(ERR_NOT_IN_RANGE, msg) + return newError(ERR_NOT_IN_RANGE, "invalid %q: %d, want [%d,%d]", key, value, lower, upper) } func newInvalidValueError(key string, value string) error { - msg := fmt.Sprintf("invalid %q: %s", key, value) - return newError(ERR_INVALID_VALUE, msg) + return newError(ERR_INVALID_VALUE, "invalid %q: %s", key, value) } func newModelManagerError(modelKeyword string) error { - msg := fmt.Sprintf("internal error: getting model manager for %q failed", - modelKeyword) - return newError(ERR_MODEL_MANAGER, msg) + return newError(ERR_MODEL_MANAGER, "failed getting model manager for %q", modelKeyword) } func newModelNotFoundError(modelKeyword, idOrName string, err error) error { - msg := fmt.Sprintf("cannot find %q with id/name %q", - modelKeyword, idOrName) + errFmt := "cannot find %q with id/name %q" + params := []interface{}{modelKeyword, idOrName} if err != sql.ErrNoRows { - msg += ": " + err.Error() + errFmt += ": %s" + params = append(params, err.Error()) } - return newError(ERR_MODEL_NOT_FOUND, msg) + return newError(ERR_MODEL_NOT_FOUND, errFmt, params...) } -func newError(typ ErrType, msg string) error { - err := &ValidateError{ - ErrType: typ, - Msg: msg, - } +func newError(typ ErrType, errFmt string, params ...interface{}) error { + errFmt = fmt.Sprintf("%s: %s", typ, errFmt) if returnHttpError { switch typ { case ERR_SUCCESS: return nil case ERR_GENERAL, ERR_MODEL_MANAGER: - return httperrors.NewInternalServerError(msg) + return httperrors.NewInternalServerError(errFmt, params...) default: - return httperrors.NewInputParameterError(msg) + return httperrors.NewInputParameterError(errFmt, params...) } } + err := &ValidateError{ + ErrType: typ, + Msg: fmt.Sprintf(errFmt, params...), + } return err } From 751525d77937e3e9805b66bf4a3f34bd34355bef Mon Sep 17 00:00:00 2001 From: Yousong Zhou Date: Mon, 19 Nov 2018 10:38:19 +0000 Subject: [PATCH 03/16] validators: add newInvalidStructError() To retain fmt and parameter information {"class":"InputParameterError","code":400,"data":{"fields":["acl_entries","192.168.0.256"],"id":"Invalid value error: invalid %q: invalid addr %s"},"details":"Invalid value error: invalid \"acl_entries\": invalid addr 192.168.0.256"} {"class":"InputParameterError","code":400,"data":{"fields":[],"id":"invalid \"acl_entries\": invalid addr 192.168.0.256"},"details":"invalid \"acl_entries\": invalid addr 192.168.0.256"} --- pkg/cloudcommon/validators/errors.go | 14 ++++++++++++++ pkg/cloudcommon/validators/validators.go | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/pkg/cloudcommon/validators/errors.go b/pkg/cloudcommon/validators/errors.go index 48f4564ddd..9f32801303 100644 --- a/pkg/cloudcommon/validators/errors.go +++ b/pkg/cloudcommon/validators/errors.go @@ -5,6 +5,7 @@ import ( "fmt" "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/onecloud/pkg/util/httputils" ) var returnHttpError = true @@ -77,6 +78,19 @@ func newInvalidValueError(key string, value string) error { return newError(ERR_INVALID_VALUE, "invalid %q: %s", key, value) } +func newInvalidStructError(key string, err error) error { + errFmt := "invalid %q: " + params := []interface{}{key} + jsonClientErr, ok := err.(*httputils.JSONClientError) + if ok { + errFmt += jsonClientErr.Data.Id + for _, f := range jsonClientErr.Data.Fields { + params = append(params, f) + } + } + return newError(ERR_INVALID_VALUE, errFmt, params...) +} + func newModelManagerError(modelKeyword string) error { return newError(ERR_MODEL_MANAGER, "failed getting model manager for %q", modelKeyword) } diff --git a/pkg/cloudcommon/validators/validators.go b/pkg/cloudcommon/validators/validators.go index 9594138a5b..c1af053458 100644 --- a/pkg/cloudcommon/validators/validators.go +++ b/pkg/cloudcommon/validators/validators.go @@ -511,7 +511,7 @@ func (v *ValidatorStruct) Validate(data *jsonutils.JSONDict) error { if valueValidator, ok := v.Value.(IValidatorBase); ok { err = valueValidator.Validate(data) if err != nil { - return newInvalidValueError(v.Key, err.Error()) + return newInvalidStructError(v.Key, err) } } data.Set(v.Key, jsonutils.Marshal(v.Value)) From ff5071eba26efd3e5f66249d28d5e1d66270afe2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B1=88=E8=BD=A9?= Date: Mon, 19 Nov 2018 20:26:24 +0800 Subject: [PATCH 04/16] =?UTF-8?q?priceKey=E6=90=BA=E5=B8=A6region=E4=BF=A1?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/util/azure/classic_instance.go | 3 ++- pkg/util/azure/instance.go | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/pkg/util/azure/classic_instance.go b/pkg/util/azure/classic_instance.go index 388e9f3620..03f622e386 100644 --- a/pkg/util/azure/classic_instance.go +++ b/pkg/util/azure/classic_instance.go @@ -113,7 +113,8 @@ type SClassicInstance struct { func (self *SClassicInstance) GetMetadata() *jsonutils.JSONDict { data := jsonutils.NewDict() - data.Add(jsonutils.NewString(self.Properties.HardwareProfile.Size), "price_key") + priceKey := fmt.Sprintf("%s::%s", self.Properties.HardwareProfile.Size, self.host.zone.region.Name) + data.Add(jsonutils.NewString(priceKey), "price_key") if self.Properties.NetworkProfile.NetworkSecurityGroup != nil { data.Add(jsonutils.NewString(self.Properties.NetworkProfile.NetworkSecurityGroup.ID), "secgroupId") } diff --git a/pkg/util/azure/instance.go b/pkg/util/azure/instance.go index aff99f53ee..5da04a5f94 100644 --- a/pkg/util/azure/instance.go +++ b/pkg/util/azure/instance.go @@ -224,7 +224,8 @@ func (self *SInstance) GetMetadata() *jsonutils.JSONDict { data.Add(jsonutils.NewString(loginKey), "login_key") } - data.Add(jsonutils.NewString(self.Properties.HardwareProfile.VMSize), "price_key") + priceKey := fmt.Sprintf("%s::%s", self.Properties.HardwareProfile.VMSize, self.host.zone.region.Name) + data.Add(jsonutils.NewString(priceKey), "price_key") if nics, err := self.getNics(); err == nil { for _, nic := range nics { if nic.Properties.NetworkSecurityGroup != nil { From 5071e8ae6a3b1570437127d894745d7586374c14 Mon Sep 17 00:00:00 2001 From: ningyu Date: Mon, 19 Nov 2018 20:56:53 +0800 Subject: [PATCH 05/16] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0cloudmon?= =?UTF-8?q?=E6=A8=A1=E5=9D=97=E5=92=8Cclimc=20underutilizedinstances-list?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cmd/climc/shell/underutilizedinstances.go | 34 +++++++++++++++++++ pkg/mcclient/modules/managers.go | 9 +++++ .../modules/mod_underutilizedinstances.go | 13 +++++++ 3 files changed, 56 insertions(+) create mode 100644 cmd/climc/shell/underutilizedinstances.go create mode 100644 pkg/mcclient/modules/mod_underutilizedinstances.go diff --git a/cmd/climc/shell/underutilizedinstances.go b/cmd/climc/shell/underutilizedinstances.go new file mode 100644 index 0000000000..a8bebb1e87 --- /dev/null +++ b/cmd/climc/shell/underutilizedinstances.go @@ -0,0 +1,34 @@ +package shell + +import ( + "yunion.io/x/jsonutils" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/options" +) + +func init() { + + type UnderutilizedInstancesListOptions struct { + options.BaseListOptions + } + R(&UnderutilizedInstancesListOptions{}, "underutilizedinstances-list", "List underutilized instances", func(s *mcclient.ClientSession, args *UnderutilizedInstancesListOptions) error { + var params *jsonutils.JSONDict + { + var err error + params, err = args.BaseListOptions.Params() + if err != nil { + return err + + } + } + result, err := modules.UnderutilizedInstances.List(s, params) + if err != nil { + return err + } + + printList(result, modules.UnderutilizedInstances.GetColumns(s)) + return nil + }) + +} diff --git a/pkg/mcclient/modules/managers.go b/pkg/mcclient/modules/managers.go index cf51952d23..6172530fc7 100644 --- a/pkg/mcclient/modules/managers.go +++ b/pkg/mcclient/modules/managers.go @@ -25,6 +25,15 @@ func NewMonitorManager(keyword, keywordPlural string, columns, adminColumns []st Keyword: keyword, KeywordPlural: keywordPlural} } +func NewCloudmonManager(keyword, keywordPlural string, columns, adminColumns []string) ResourceManager { + return ResourceManager{ + BaseManager: BaseManager{columns: columns, + adminColumns: adminColumns, + version: "v1", + serviceType: "cloudmon"}, + Keyword: keyword, KeywordPlural: keywordPlural} +} + func NewNotifyManager(keyword, keywordPlural string, columns, adminColumns []string) ResourceManager { return ResourceManager{ BaseManager: BaseManager{columns: columns, diff --git a/pkg/mcclient/modules/mod_underutilizedinstances.go b/pkg/mcclient/modules/mod_underutilizedinstances.go new file mode 100644 index 0000000000..8c0e6af42f --- /dev/null +++ b/pkg/mcclient/modules/mod_underutilizedinstances.go @@ -0,0 +1,13 @@ +package modules + +var ( + UnderutilizedInstances ResourceManager +) + +func init() { + UnderutilizedInstances = NewCloudmonManager("underutilizedinstance", "underutilizedinstances", + []string{"id", "vm_id", "vm_name", "time", "advices", "vm_cpu", "vm_disk", "vm_memory", "vm_provider"}, + []string{}) + + register(&UnderutilizedInstances) +} From d1680ade9512ee37e6e8d4a0624ed9f813a3b7ac Mon Sep 17 00:00:00 2001 From: ningyu Date: Mon, 19 Nov 2018 21:11:46 +0800 Subject: [PATCH 06/16] =?UTF-8?q?fix:=20=E4=BF=AE=E6=94=B9=E6=9C=AA?= =?UTF-8?q?=E5=85=85=E5=88=86=E5=88=A9=E7=94=A8=E7=9A=84=E5=AE=9E=E4=BE=8B?= =?UTF-8?q?=E5=88=97=E8=A1=A8API=E7=9A=84climc=E5=91=BD=E5=90=8D=EF=BC=8C?= =?UTF-8?q?=E7=9B=AE=E7=9A=84=E6=98=AF=E9=81=BF=E5=85=8D=E8=BF=87=E9=95=BF?= =?UTF-8?q?=E4=B8=8D=E6=98=93=E8=AF=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cmd/climc/shell/underutilizedinstances.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/climc/shell/underutilizedinstances.go b/cmd/climc/shell/underutilizedinstances.go index a8bebb1e87..84fd17ed08 100644 --- a/cmd/climc/shell/underutilizedinstances.go +++ b/cmd/climc/shell/underutilizedinstances.go @@ -12,7 +12,7 @@ func init() { type UnderutilizedInstancesListOptions struct { options.BaseListOptions } - R(&UnderutilizedInstancesListOptions{}, "underutilizedinstances-list", "List underutilized instances", func(s *mcclient.ClientSession, args *UnderutilizedInstancesListOptions) error { + R(&UnderutilizedInstancesListOptions{}, "underutilized-instances-list", "List underutilized instances", func(s *mcclient.ClientSession, args *UnderutilizedInstancesListOptions) error { var params *jsonutils.JSONDict { var err error From 5652ac4dfb6fe25ced3e4da6136789674403d31f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B1=88=E8=BD=A9?= Date: Tue, 20 Nov 2018 14:42:50 +0800 Subject: [PATCH 07/16] =?UTF-8?q?=E4=BF=AE=E5=A4=8D:=20=E4=BB=BB=E5=8A=A1?= =?UTF-8?q?=E5=A4=B1=E8=B4=A5=E6=97=B6=E4=B8=8D=E5=8F=8A=E6=97=B6=E9=87=8A?= =?UTF-8?q?=E6=94=BEpending-usage-quota?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/compute/tasks/guest_create_task.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pkg/compute/tasks/guest_create_task.go b/pkg/compute/tasks/guest_create_task.go index a57f49afca..916195563d 100644 --- a/pkg/compute/tasks/guest_create_task.go +++ b/pkg/compute/tasks/guest_create_task.go @@ -50,6 +50,7 @@ func (self *GuestCreateTask) OnDiskPreparedFailed(ctx context.Context, obj db.IS guest.SetStatus(self.UserCred, models.VM_DISK_FAILED, "allocation failed") db.OpsLog.LogEvent(guest, db.ACT_ALLOCATE_FAIL, data, self.UserCred) notifyclient.NotifySystemError(guest.Id, guest.Name, models.VM_DISK_FAILED, data.String()) + self.SetStageFailed(ctx, data.String()) } func (self *GuestCreateTask) OnDiskPrepared(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { @@ -77,6 +78,7 @@ func (self *GuestCreateTask) OnCdromPreparedFailed(ctx context.Context, obj db.I guest.SetStatus(self.UserCred, models.VM_DISK_FAILED, "") db.OpsLog.LogEvent(guest, db.ACT_ALLOCATE_FAIL, data, self.UserCred) notifyclient.NotifySystemError(guest.Id, guest.Name, models.VM_DISK_FAILED, fmt.Sprintf("cdrom_failed %s", data)) + self.SetStageFailed(ctx, fmt.Sprintf("cdrom_failed %s", data)) } func (self *GuestCreateTask) StartDeployGuest(ctx context.Context, guest *models.SGuest) { @@ -103,6 +105,7 @@ func (self *GuestCreateTask) OnDeployGuestDescCompleteFailed(ctx context.Context guest.SetStatus(self.UserCred, models.VM_DEPLOY_FAILED, "deploy_failed") db.OpsLog.LogEvent(guest, db.ACT_ALLOCATE_FAIL, data, self.UserCred) notifyclient.NotifySystemError(guest.Id, guest.Name, models.VM_DEPLOY_FAILED, data.String()) + self.SetStageFailed(ctx, data.String()) } func (self *GuestCreateTask) OnAutoStartGuest(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { From 4f63b4ad587375a9e715e0d80f3b53edc9b6b6b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B1=88=E8=BD=A9?= Date: Tue, 20 Nov 2018 16:00:16 +0800 Subject: [PATCH 08/16] =?UTF-8?q?=E9=81=BF=E5=85=8D=E5=9B=A0snapshot?= =?UTF-8?q?=E6=89=BE=E4=B8=8D=E5=88=B0=E8=80=8C=E5=88=A0=E9=99=A4=E5=A4=B1?= =?UTF-8?q?=E8=B4=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/compute/models/snapshots.go | 24 ++++++------------- pkg/compute/tasks/guest_disk_snapshot_task.go | 10 +++++--- pkg/util/aliyun/snapshot.go | 13 ++++++---- 3 files changed, 22 insertions(+), 25 deletions(-) diff --git a/pkg/compute/models/snapshots.go b/pkg/compute/models/snapshots.go index 367f05bb71..94085c7074 100644 --- a/pkg/compute/models/snapshots.go +++ b/pkg/compute/models/snapshots.go @@ -9,7 +9,6 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/util/compare" - "yunion.io/x/pkg/utils" "yunion.io/x/sqlchemy" "yunion.io/x/onecloud/pkg/cloudcommon/db" @@ -319,29 +318,20 @@ func (self *SSnapshot) CustomizeDelete(ctx context.Context, userCred mcclient.To if self.Status == SNAPSHOT_DELETING { return fmt.Errorf("Cannot delete snapshot in status %s", self.Status) } - if self.Status == SNAPSHOT_UNKNOWN { - return self.RealDelete(ctx, userCred) - } if len(self.ExternalId) == 0 { - if utils.IsInStringArray(self.Status, []string{SNAPSHOT_FAILED}) { - return self.RealDelete(ctx, userCred) - } if self.CreatedBy == MANUAL { if !self.FakeDeleted { return self.FakeDelete() - } else { - _, err := SnapshotManager.GetConvertSnapshot(self) - if err != nil { - return fmt.Errorf("Cannot delete snapshot: %s, disk need at least one of snapshot as backing file", err.Error()) - } - return self.StartSnapshotDeleteTask(ctx, userCred, false, "") } - } else { - return fmt.Errorf("Cannot delete snapshot created by %s", self.CreatedBy) + _, err := SnapshotManager.GetConvertSnapshot(self) + if err != nil { + return fmt.Errorf("Cannot delete snapshot: %s, disk need at least one of snapshot as backing file", err.Error()) + } + return self.StartSnapshotDeleteTask(ctx, userCred, false, "") } - } else { - return self.StartSnapshotDeleteTask(ctx, userCred, false, "") + return fmt.Errorf("Cannot delete snapshot created by %s", self.CreatedBy) } + return self.StartSnapshotDeleteTask(ctx, userCred, false, "") } func (self *SSnapshot) AllowPerformDeleted(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { diff --git a/pkg/compute/tasks/guest_disk_snapshot_task.go b/pkg/compute/tasks/guest_disk_snapshot_task.go index 4f5f230ef2..3f5fb8b7e9 100644 --- a/pkg/compute/tasks/guest_disk_snapshot_task.go +++ b/pkg/compute/tasks/guest_disk_snapshot_task.go @@ -162,12 +162,16 @@ func (self *SnapshotDeleteTask) deleteExternalSnapshot(ctx context.Context, snap } cloudSnapshot, err := cloudRegion.GetISnapshotById(snapshot.ExternalId) if err != nil { + if err == cloudprovider.ErrNotFound { + return nil + } log.Errorln(err, cloudSnapshot) return err } - cloudSnapshot.Delete() - err = cloudprovider.WaitDeleted(cloudSnapshot, 10*time.Second, 300*time.Second) - return err + if err := cloudSnapshot.Delete(); err != nil { + return err + } + return cloudprovider.WaitDeleted(cloudSnapshot, 10*time.Second, 300*time.Second) } func (self *SnapshotDeleteTask) StartReloadDisk(ctx context.Context, snapshot *models.SSnapshot, guest *models.SGuest) { diff --git a/pkg/util/aliyun/snapshot.go b/pkg/util/aliyun/snapshot.go index 87d9523970..b85837420a 100644 --- a/pkg/util/aliyun/snapshot.go +++ b/pkg/util/aliyun/snapshot.go @@ -167,11 +167,14 @@ func (self *SRegion) GetSnapshots(instanceId string, diskId string, snapshotName } func (self *SRegion) GetISnapshotById(snapshotId string) (cloudprovider.ICloudSnapshot, error) { - if snapshots, total, err := self.GetSnapshots("", "", "", []string{snapshotId}, 0, 1); err != nil { + snapshots, total, err := self.GetSnapshots("", "", "", []string{snapshotId}, 0, 1) + if err != nil { return nil, err - } else if total != 1 { - return nil, cloudprovider.ErrNotFound - } else { - return &snapshots[0], nil } + if total == 0 { + return nil, cloudprovider.ErrNotFound + } else if total > 1 { + return nil, cloudprovider.ErrDuplicateId + } + return &snapshots[0], nil } From a62f7e1db2fb038ecb915e200ab4710fa4a88235 Mon Sep 17 00:00:00 2001 From: Yousong Zhou Date: Tue, 20 Nov 2018 09:12:40 +0000 Subject: [PATCH 09/16] cloudproviders: reword error message in create data validation --- pkg/compute/models/cloudproviders.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/compute/models/cloudproviders.go b/pkg/compute/models/cloudproviders.go index 5b25fb1cbb..18724288ec 100644 --- a/pkg/compute/models/cloudproviders.go +++ b/pkg/compute/models/cloudproviders.go @@ -130,7 +130,7 @@ func (self *SCloudprovider) ValidateUpdateData(ctx context.Context, userCred mcc } func (self *SCloudproviderManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerProjId string, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) { - return nil, httperrors.NewUnsupportOperationError("Not support create cloudprovider, please considir create cloudaccount") + return nil, httperrors.NewUnsupportOperationError("Directly creating cloudprovider is not supported, create cloudaccount instead") } func (self *SCloudprovider) getPassword() (string, error) { From cf2b42f78b5abbff4c4b1a91e7c3bcc4a54ce6ef Mon Sep 17 00:00:00 2001 From: Yousong Zhou Date: Tue, 20 Nov 2018 09:12:08 +0000 Subject: [PATCH 10/16] climc: cloudprovider: drop cloud-provider-create command It's not allowed since release/2.3.0 --- cmd/climc/shell/cloudproviders.go | 32 ------------------------------- 1 file changed, 32 deletions(-) diff --git a/cmd/climc/shell/cloudproviders.go b/cmd/climc/shell/cloudproviders.go index 9ac65dfcf0..f35da1d11f 100644 --- a/cmd/climc/shell/cloudproviders.go +++ b/cmd/climc/shell/cloudproviders.go @@ -31,38 +31,6 @@ func init() { return nil }) - type CloudproviderCreateOptions struct { - NAME string `help:"Name of cloud provider"` - ACCOUNT string `help:"Account to access the cloud provider, tenantId/subscriptionId for Azure"` - SECRET string `help:"Secret to access the cloud provider, clientId/clientScret for Azure"` - PROVIDER string `help:"Driver for cloud provider" choices:"VMware|Aliyun|Azure"` - AccessURL string `helo:"hello" metavar:"Azure choices: "` - Desc string `help:"Description"` - Enabled bool `help:"Enabled the provider automatically"` - } - R(&CloudproviderCreateOptions{}, "cloud-provider-create", "Create a cloud provider", func(s *mcclient.ClientSession, args *CloudproviderCreateOptions) error { - params := jsonutils.NewDict() - params.Add(jsonutils.NewString(args.NAME), "name") - params.Add(jsonutils.NewString(args.ACCOUNT), "account") - params.Add(jsonutils.NewString(args.SECRET), "secret") - params.Add(jsonutils.NewString(args.PROVIDER), "provider") - if args.Enabled { - params.Add(jsonutils.JSONTrue, "enabled") - } - if len(args.AccessURL) > 0 { - params.Add(jsonutils.NewString(args.AccessURL), "access_url") - } - if len(args.Desc) > 0 { - params.Add(jsonutils.NewString(args.Desc), "description") - } - result, err := modules.Cloudproviders.Create(s, params) - if err != nil { - return err - } - printObject(result) - return nil - }) - type CloudproviderUpdateOptions struct { ID string `help:"ID or Name of cloud provider"` Name string `help:"New name to update"` From f1b9ea55e70803d126c727e7973b5ce2fa17255b Mon Sep 17 00:00:00 2001 From: Qiu Jian Date: Tue, 20 Nov 2018 17:35:58 +0800 Subject: [PATCH 11/16] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=EF=BC=9A=E5=89=8D?= =?UTF-8?q?=E7=AB=AFcheck=20compute=20servers=20perform=20start=E6=9D=83?= =?UTF-8?q?=E9=99=90=E6=8A=A5out=20of=20index=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/cloudcommon/policy/policy.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/cloudcommon/policy/policy.go b/pkg/cloudcommon/policy/policy.go index 7517dfa087..56418e3550 100644 --- a/pkg/cloudcommon/policy/policy.go +++ b/pkg/cloudcommon/policy/policy.go @@ -233,7 +233,8 @@ func (manager *SPolicyManager) explainPolicy(userCred mcclient.TokenCredential, } if len(policySeq) > 4 { for i := 4; i < len(policySeq); i += 1 { - extra[i-4], _ = policySeq[i].GetString() + ev, _ := policySeq[i].GetString() + extra = append(extra, ev) } } From aece52666d51f45d929aa4f96044bcbcee7b504e Mon Sep 17 00:00:00 2001 From: ningyu Date: Tue, 20 Nov 2018 21:46:36 +0800 Subject: [PATCH 12/16] =?UTF-8?q?refacotr:=20=E9=85=8D=E7=BD=AE=E5=BB=BA?= =?UTF-8?q?=E8=AE=AE=EF=BC=8C=E5=A2=9E=E5=8A=A0=E9=98=88=E5=80=BC=E5=8F=82?= =?UTF-8?q?=E6=95=B0=E5=92=8C=E5=BD=93=E5=89=8D=E7=9A=84TOP95=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/mcclient/modules/mod_underutilizedinstances.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/mcclient/modules/mod_underutilizedinstances.go b/pkg/mcclient/modules/mod_underutilizedinstances.go index 8c0e6af42f..0fde51c30e 100644 --- a/pkg/mcclient/modules/mod_underutilizedinstances.go +++ b/pkg/mcclient/modules/mod_underutilizedinstances.go @@ -6,7 +6,7 @@ var ( func init() { UnderutilizedInstances = NewCloudmonManager("underutilizedinstance", "underutilizedinstances", - []string{"id", "vm_id", "vm_name", "time", "advices", "vm_cpu", "vm_disk", "vm_memory", "vm_provider"}, + []string{"id", "vm_id", "vm_name", "datetime_str", "vm_cpu", "vm_disk", "vm_memory", "vm_provider", "cpu_usage_threshold", "netio_rx_bps_threshold", "netio_tx_bps_threshold", "stastics_details"}, []string{}) register(&UnderutilizedInstances) From 4098440c8f9c7319af2eebbdfa00bd03bcb6abf7 Mon Sep 17 00:00:00 2001 From: Zexi Li Date: Wed, 21 Nov 2018 17:49:36 +0800 Subject: [PATCH 13/16] climc: make k8s repo sharable --- cmd/climc/shell/k8s/repos.go | 18 ++++++++++++++++++ pkg/mcclient/options/k8s/repo.go | 6 +++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/cmd/climc/shell/k8s/repos.go b/cmd/climc/shell/k8s/repos.go index 5744130ccb..d61e07045b 100644 --- a/cmd/climc/shell/k8s/repos.go +++ b/cmd/climc/shell/k8s/repos.go @@ -67,4 +67,22 @@ func initRepo() { printObject(repo) return nil }) + + R(&o.RepoGetOptions{}, cmdN("public"), "Make repository public", func(s *mcclient.ClientSession, args *o.RepoGetOptions) error { + repo, err := k8s.Repos.PerformAction(s, args.NAME, "public", nil) + if err != nil { + return err + } + printObject(repo) + return nil + }) + + R(&o.RepoGetOptions{}, cmdN("private"), "Make repository private", func(s *mcclient.ClientSession, args *o.RepoGetOptions) error { + repo, err := k8s.Repos.PerformAction(s, args.NAME, "private", nil) + if err != nil { + return err + } + printObject(repo) + return nil + }) } diff --git a/pkg/mcclient/options/k8s/repo.go b/pkg/mcclient/options/k8s/repo.go index 5c42277134..52d0b890ec 100644 --- a/pkg/mcclient/options/k8s/repo.go +++ b/pkg/mcclient/options/k8s/repo.go @@ -16,13 +16,17 @@ type RepoGetOptions struct { type RepoCreateOptions struct { RepoGetOptions - URL string `help:"Repository url"` + URL string `help:"Repository url"` + Public bool `help:"Make repostitory public"` } func (o RepoCreateOptions) Params() *jsonutils.JSONDict { params := jsonutils.NewDict() params.Add(jsonutils.NewString(o.NAME), "name") params.Add(jsonutils.NewString(o.URL), "url") + if o.Public { + params.Add(jsonutils.JSONTrue, "is_public") + } return params } From bd415e8da9d8dc76e64ae769a79bbe25bf55fcf0 Mon Sep 17 00:00:00 2001 From: Qiu Jian Date: Wed, 21 Nov 2018 21:21:24 +0800 Subject: [PATCH 14/16] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=EF=BC=9Avmware?= =?UTF-8?q?=E4=B8=BB=E6=9C=BA=E8=8E=B7=E5=8F=96=E8=B4=A6=E5=8F=B7=E4=BF=A1?= =?UTF-8?q?=E6=81=AF=E5=A4=B1=E8=B4=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/compute/models/cloudproviders.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/pkg/compute/models/cloudproviders.go b/pkg/compute/models/cloudproviders.go index 18724288ec..19359fe19e 100644 --- a/pkg/compute/models/cloudproviders.go +++ b/pkg/compute/models/cloudproviders.go @@ -400,7 +400,15 @@ func (self *SCloudprovider) getAccount() (SAccount, error) { cloudaccount := self.GetCloudaccount() if cloudaccount == nil { - return account, fmt.Errorf("fail to find cloudaccount???") + // legacy mode + passwd, err := self.getPassword() + if err != nil { + return account, err + } + account.Account = self.Account + account.AccessUrl = self.AccessUrl + account.Secret = passwd + return account, nil // fmt.Errorf("fail to find cloudaccount???") } passwd, err := cloudaccount.getPassword() From 2ed294eaa83dba6a19e92ed341030963614359b2 Mon Sep 17 00:00:00 2001 From: Qiu Jian Date: Thu, 22 Nov 2018 12:02:21 +0800 Subject: [PATCH 15/16] =?UTF-8?q?RBAC=E8=BF=94=E5=9B=9E=E5=80=BC=E5=90=8C?= =?UTF-8?q?=E6=97=B6=E6=90=BA=E5=B8=A6=E8=B5=84=E6=BA=90=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/cloudcommon/policy/policy.go | 36 +++++++++++++++++++------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/pkg/cloudcommon/policy/policy.go b/pkg/cloudcommon/policy/policy.go index 56418e3550..d4a61ff041 100644 --- a/pkg/cloudcommon/policy/policy.go +++ b/pkg/cloudcommon/policy/policy.go @@ -203,20 +203,10 @@ func (manager *SPolicyManager) Allow(isAdmin bool, userCred mcclient.TokenCreden return currentPriv } -func (manager *SPolicyManager) explainPolicy(userCred mcclient.TokenCredential, policyReq jsonutils.JSONObject) (rbacutils.TRbacResult, error) { +func (manager *SPolicyManager) explainPolicy(userCred mcclient.TokenCredential, policyReq jsonutils.JSONObject) ([]string, rbacutils.TRbacResult, error) { policySeq, err := policyReq.GetArray() if err != nil { - return rbacutils.Deny, httperrors.NewInputParameterError("invalid format") - } - isAdmin, _ := policySeq[0].Bool() - if !consts.IsRbacEnabled() { - if !isAdmin { - return rbacutils.OwnerAllow, nil - } else if isAdmin && userCred.IsSystemAdmin() { - return rbacutils.AdminAllow, nil - } else { - return rbacutils.Deny, httperrors.NewForbiddenError("operation not allowed") - } + return nil, rbacutils.Deny, httperrors.NewInputParameterError("invalid format") } service := rbacutils.WILD_MATCH resource := rbacutils.WILD_MATCH @@ -238,7 +228,22 @@ func (manager *SPolicyManager) explainPolicy(userCred mcclient.TokenCredential, } } - return manager.Allow(isAdmin, userCred, service, resource, action, extra...), nil + reqStrs := []string{service, resource, action} + if len(extra) > 0 { + reqStrs = append(reqStrs, extra...) + } + + isAdmin, _ := policySeq[0].Bool() + if !consts.IsRbacEnabled() { + if !isAdmin { + return reqStrs, rbacutils.OwnerAllow, nil + } else if isAdmin && userCred.IsSystemAdmin() { + return reqStrs, rbacutils.AdminAllow, nil + } else { + return reqStrs, rbacutils.Deny, httperrors.NewForbiddenError("operation not allowed") + } + } + return reqStrs, manager.Allow(isAdmin, userCred, service, resource, action, extra...), nil } func (manager *SPolicyManager) ExplainRpc(userCred mcclient.TokenCredential, params jsonutils.JSONObject) (jsonutils.JSONObject, error) { @@ -248,11 +253,12 @@ func (manager *SPolicyManager) ExplainRpc(userCred mcclient.TokenCredential, par } ret := jsonutils.NewDict() for key, policyReq := range paramDict { - result, err := manager.explainPolicy(userCred, policyReq) + reqStrs, result, err := manager.explainPolicy(userCred, policyReq) if err != nil { return nil, err } - ret.Add(jsonutils.NewString(string(result)), key) + reqStrs = append(reqStrs, string(result)) + ret.Add(jsonutils.NewStringArray(reqStrs), key) } return ret, nil } From 78cede69e5d0b9339c853a6cb70272ed6845cbfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B1=88=E8=BD=A9?= Date: Thu, 22 Nov 2018 20:23:00 +0800 Subject: [PATCH 16/16] =?UTF-8?q?=E8=A1=A5=E5=85=85Azure=20disk=20metadata?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/util/azure/classic_disk.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pkg/util/azure/classic_disk.go b/pkg/util/azure/classic_disk.go index 8946493c8e..dd11cf71b7 100644 --- a/pkg/util/azure/classic_disk.go +++ b/pkg/util/azure/classic_disk.go @@ -101,7 +101,9 @@ func (self *SRegion) GetClassicDisks() ([]SClassicDisk, error) { } func (self *SClassicDisk) GetMetadata() *jsonutils.JSONDict { - return nil + data := jsonutils.NewDict() + data.Add(jsonutils.NewString(models.HYPERVISOR_AZURE), "hypervisor") + return data } func (self *SClassicDisk) CreateISnapshot(name, desc string) (cloudprovider.ICloudSnapshot, error) {