From 5b63de31bc7c3a9d2369153420f0a60b98831281 Mon Sep 17 00:00:00 2001 From: Qiu Jian Date: Thu, 3 Jan 2019 19:39:22 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=EF=BC=9A1.=20=E5=88=A0?= =?UTF-8?q?=E9=99=A4=E4=BC=AA=E5=88=A0=E9=99=A4=E4=B8=BB=E6=9C=BA=E3=80=81?= =?UTF-8?q?=E7=A3=81=E7=9B=98=E9=9C=80=E8=A6=81override-pending-delete?= =?UTF-8?q?=E5=8F=82=E6=95=B0=202.=20joint-update=E6=94=AF=E6=8C=81auto=5F?= =?UTF-8?q?create=E5=8F=82=E6=95=B0=203.=20=E5=88=A0=E9=99=A4=E4=B8=BB?= =?UTF-8?q?=E6=9C=BA=E6=97=B6=E5=80=99detach=E7=A3=81=E7=9B=98=EF=BC=8C?= =?UTF-8?q?=E6=B8=85=E7=90=86=E5=AE=89=E5=85=A8=E7=BB=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/cloudcommon/db/db_joint_dispatcher.go | 5 ++ pkg/compute/models/disks.go | 20 +++++++ pkg/compute/models/guest_actions.go | 44 ++++++++-------- pkg/compute/models/guests.go | 6 +-- pkg/compute/tasks/disk_delete_task.go | 9 +++- pkg/compute/tasks/guest_delete_task.go | 63 ++++++++++++++++++++--- 6 files changed, 115 insertions(+), 32 deletions(-) diff --git a/pkg/cloudcommon/db/db_joint_dispatcher.go b/pkg/cloudcommon/db/db_joint_dispatcher.go index f98143e9ac..1295541862 100644 --- a/pkg/cloudcommon/db/db_joint_dispatcher.go +++ b/pkg/cloudcommon/db/db_joint_dispatcher.go @@ -206,6 +206,11 @@ func (dispatcher *DBJointModelDispatcher) Update(ctx context.Context, id1 string userCred := fetchUserCredential(ctx) master, slave, item, err := fetchJointItem(dispatcher, ctx, userCred, id1, id2, query) if err == sql.ErrNoRows { + if jsonutils.QueryBoolean(query, "auto_create", false) { + queryDict := query.(*jsonutils.JSONDict) + queryDict.Remove("auto_create") + return dispatcher.Attach(ctx, id1, id2, query, data) + } return nil, httperrors.NewResourceNotFoundError2(dispatcher.modelManager.Keyword(), id1+"-"+id2) } else if err != nil { return nil, httperrors.NewGeneralError(err) diff --git a/pkg/compute/models/disks.go b/pkg/compute/models/disks.go index c9a4117009..53032dc3e9 100644 --- a/pkg/compute/models/disks.go +++ b/pkg/compute/models/disks.go @@ -1609,3 +1609,23 @@ func (self *SDisk) SaveRenewInfo(ctx context.Context, userCred mcclient.TokenCre db.OpsLog.LogEvent(self, db.ACT_RENEW, self.GetShortDesc(ctx), userCred) return nil } + +func (self *SDisk) IsDetachable() bool { + storage := self.GetStorage() + if storage == nil { + return true + } + if storage.IsLocal() { + return false + } + if self.BillingType == BILLING_TYPE_PREPAID { + return false + } + if utils.IsInStringArray(self.DiskType, []string{DISK_TYPE_SYS, DISK_TYPE_SWAP}) { + return false + } + if self.AutoDelete { + return false + } + return true +} diff --git a/pkg/compute/models/guest_actions.go b/pkg/compute/models/guest_actions.go index 2e3bcc76a3..79198ccf58 100644 --- a/pkg/compute/models/guest_actions.go +++ b/pkg/compute/models/guest_actions.go @@ -129,6 +129,9 @@ func (self *SGuest) AllowPerformSync(ctx context.Context, userCred mcclient.Toke } func (self *SGuest) PerformSync(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { + if !utils.IsInStringArray(self.Status, []string{VM_READY, VM_RUNNING}) { + return nil, httperrors.NewResourceBusyError("Cannot sync in status %s", self.Status) + } if err := self.StartSyncTask(ctx, userCred, false, ""); err != nil { return nil, err } @@ -422,9 +425,7 @@ func (self *SGuest) PerformAttachdisk(ctx context.Context, userCred mcclient.Tok } func (self *SGuest) StartSyncTask(ctx context.Context, userCred mcclient.TokenCredential, fw_only bool, parentTaskId string) error { - if !utils.IsInStringArray(self.Status, []string{VM_READY, VM_RUNNING}) { - return httperrors.NewResourceBusyError("Cannot sync in status %s", self.Status) - } + data := jsonutils.NewDict() if fw_only { data.Add(jsonutils.JSONTrue, "fw_only") @@ -846,7 +847,7 @@ func (self *SGuest) PerformSetSecgroup(ctx context.Context, userCred mcclient.To setSecgroupNames = append(setSecgroupNames, secgrp.GetName()) } - if err := self.revokeAllSecgroups(ctx, userCred); err != nil { + if err := self.RevokeAllSecgroups(ctx, userCred); err != nil { return nil, err } @@ -1122,14 +1123,8 @@ func (self *SGuest) PerformDetachdisk(ctx context.Context, userCred mcclient.Tok return nil, httperrors.NewInputParameterError("Cannot keep detached disk") } if utils.IsInStringArray(self.Status, detachDiskStatus) { - if disk.Status == DISK_INIT { - disk.SetStatus(userCred, DISK_DETACHING, "") - } - taskData := jsonutils.NewDict() - taskData.Add(jsonutils.NewString(disk.Id), "disk_id") - taskData.Add(jsonutils.NewBool(keepDisk), "keep_disk") - self.GetDriver().StartGuestDetachdiskTask(ctx, userCred, self, taskData, "") - return nil, nil + err = self.StartGuestDetachdiskTask(ctx, userCred, disk, keepDisk, "") + return nil, err } else { return nil, httperrors.NewInvalidStatusError("Server in %s not able to detach disk", self.Status) } @@ -1140,6 +1135,16 @@ func (self *SGuest) PerformDetachdisk(ctx context.Context, userCred mcclient.Tok return nil, httperrors.NewResourceNotFoundError("Disk %s not found", diskId) } +func (self *SGuest) StartGuestDetachdiskTask(ctx context.Context, userCred mcclient.TokenCredential, disk *SDisk, keepDisk bool, parentTaskId string) error { + if disk.Status == DISK_INIT { + disk.SetStatus(userCred, DISK_DETACHING, "") + } + taskData := jsonutils.NewDict() + taskData.Add(jsonutils.NewString(disk.Id), "disk_id") + taskData.Add(jsonutils.NewBool(keepDisk), "keep_disk") + return self.GetDriver().StartGuestDetachdiskTask(ctx, userCred, self, taskData, "") +} + func (self *SGuest) AllowPerformDetachIsolatedDevice(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { return self.IsOwner(userCred) || db.IsAdminAllowPerform(userCred, self, "detach-isolated-device") } @@ -1525,12 +1530,12 @@ func (self *SGuest) StartChangeConfigTask(ctx context.Context, userCred mcclient return nil } -func (self *SGuest) revokeAllSecgroups(ctx context.Context, userCred mcclient.TokenCredential) error { - err := self.revokeSecgroup(ctx, userCred, self.getSecgroup()) +func (self *SGuest) RevokeAllSecgroups(ctx context.Context, userCred mcclient.TokenCredential) error { + err := GuestsecgroupManager.DeleteGuestSecgroup(ctx, userCred, self, nil) if err != nil { return err } - err = GuestsecgroupManager.DeleteGuestSecgroup(ctx, userCred, self, nil) + err = self.revokeSecgroup(ctx, userCred, self.getSecgroup()) if err != nil { return err } @@ -1542,16 +1547,13 @@ func (self *SGuest) DoPendingDelete(ctx context.Context, userCred mcclient.Token if eip != nil { eip.DoPendingDelete(ctx, userCred) } - // revoke all secgroups - // TODO: sync revoked secgroups to remote cloud - self.revokeAllSecgroups(ctx, userCred) - // remove detachable disks + for _, guestdisk := range self.GetDisks() { disk := guestdisk.GetDisk() - storage := disk.GetStorage() - if storage.IsLocal() || disk.BillingType == BILLING_TYPE_PREPAID || utils.IsInStringArray(disk.DiskType, []string{DISK_TYPE_SYS, DISK_TYPE_SWAP}) || (utils.IsInStringArray(self.Hypervisor, PUBLIC_CLOUD_HYPERVISORS) && disk.AutoDelete) { + if ! disk.IsDetachable() { disk.DoPendingDelete(ctx, userCred) } else { + log.Warningf("detachable disk on pending delete guests!!! should be removed earlier") self.DetachDisk(ctx, disk, userCred) } } diff --git a/pkg/compute/models/guests.go b/pkg/compute/models/guests.go index cfd0a33ad2..eac688fa09 100644 --- a/pkg/compute/models/guests.go +++ b/pkg/compute/models/guests.go @@ -2625,9 +2625,9 @@ func (self *SGuest) RealDelete(ctx context.Context, userCred mcclient.TokenCrede func (self *SGuest) AllowDeleteItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { overridePendingDelete := false purge := false - if data != nil { - overridePendingDelete = jsonutils.QueryBoolean(data, "override_pending_delete", false) - purge = jsonutils.QueryBoolean(data, "purge", false) + if query != nil { + overridePendingDelete = jsonutils.QueryBoolean(query, "override_pending_delete", false) + purge = jsonutils.QueryBoolean(query, "purge", false) } if (overridePendingDelete || purge) && !db.IsAdminAllowDelete(userCred, self) { return false diff --git a/pkg/compute/tasks/disk_delete_task.go b/pkg/compute/tasks/disk_delete_task.go index c185b6eca8..cad04bafc1 100644 --- a/pkg/compute/tasks/disk_delete_task.go +++ b/pkg/compute/tasks/disk_delete_task.go @@ -29,7 +29,14 @@ func (self *DiskDeleteTask) OnInit(ctx context.Context, obj db.IStandaloneModel, db.OpsLog.LogEvent(disk, db.ACT_DELOCATE_FAIL, reason, self.UserCred) return } - if options.Options.EnablePendingDelete && !disk.PendingDeleted && !jsonutils.QueryBoolean(self.Params, "purge", false) && !jsonutils.QueryBoolean(self.Params, "override_pending_delete", false) { + + isPurge := jsonutils.QueryBoolean(self.Params, "purge", false) + overridePendingDelete := jsonutils.QueryBoolean(self.Params, "override_pending_delete", false) + if options.Options.EnablePendingDelete && !isPurge && !overridePendingDelete { + if disk.PendingDeleted { + self.SetStageComplete(ctx, nil) + return + } self.startPendingDeleteDisk(ctx, disk) } else { self.startDeleteDisk(ctx, disk) diff --git a/pkg/compute/tasks/guest_delete_task.go b/pkg/compute/tasks/guest_delete_task.go index b34e28d2ec..6a0db89c6c 100644 --- a/pkg/compute/tasks/guest_delete_task.go +++ b/pkg/compute/tasks/guest_delete_task.go @@ -80,20 +80,69 @@ func (self *GuestDeleteTask) OnGuestStopComplete(ctx context.Context, obj db.ISt } } +func (self *GuestDeleteTask) OnGuestStopCompleteFailed(ctx context.Context, obj db.IStandaloneModel, err jsonutils.JSONObject) { + self.OnGuestStopComplete(ctx, obj, err) // ignore stop error +} + func (self *GuestDeleteTask) OnEipDissociateCompleteFailed(ctx context.Context, obj db.IStandaloneModel, err jsonutils.JSONObject) { guest := obj.(*models.SGuest) self.OnFailed(ctx, guest, err) } func (self *GuestDeleteTask) OnEipDissociateComplete(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { + self.SetStage("OnDiskDetachComplete", nil) + self.OnDiskDetachComplete(ctx, obj, data) +} + +// remove detachable disks +func (self *GuestDeleteTask) OnDiskDetachComplete(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { + log.Debugf("OnDiskDetachComplete") guest := obj.(*models.SGuest) - if options.Options.EnablePendingDelete && !guest.PendingDeleted && - !jsonutils.QueryBoolean(self.Params, "purge", false) && - !jsonutils.QueryBoolean(self.Params, "override_pending_delete", false) { + guestdisks := guest.GetDisks() + if len(guestdisks) == 0 { + self.doClearSecurityGroupComplete(ctx, guest) + return + } + lastDisk := guestdisks[len(guestdisks)-1].GetDisk() // remove last detachable disk + log.Debugf("lastDisk IsDetachable?? %v", lastDisk.IsDetachable()) + if ! lastDisk.IsDetachable() { + self.doClearSecurityGroupComplete(ctx, guest) + return + } + guest.StartGuestDetachdiskTask(ctx, self.UserCred, lastDisk, true, self.GetTaskId()) +} + +func (self *GuestDeleteTask) OnDiskDetachCompleteFailed(ctx context.Context, obj db.IStandaloneModel, err jsonutils.JSONObject) { + guest := obj.(*models.SGuest) + self.OnFailed(ctx, guest, err) +} + +// revoke all secgroups +func (self *GuestDeleteTask) doClearSecurityGroupComplete(ctx context.Context, guest *models.SGuest) { + log.Debugf("doClearSecurityGroupComplete") + models.IsolatedDeviceManager.ReleaseDevicesOfGuest(ctx, guest, self.UserCred) + guest.RevokeAllSecgroups(ctx, self.UserCred) + // sync revoked secgroups to remote cloud + self.SetStage("OnSyncConfigComplete", nil) + guest.StartSyncTask(ctx, self.UserCred, false, self.GetTaskId()) +} + +func (self *GuestDeleteTask) OnSyncConfigComplete(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { + guest := obj.(*models.SGuest) + + isPurge := jsonutils.QueryBoolean(self.Params, "purge", false) + overridePendingDelete := jsonutils.QueryBoolean(self.Params, "override_pending_delete", false) + + if options.Options.EnablePendingDelete && !isPurge && !overridePendingDelete { + if guest.PendingDeleted { + self.SetStageComplete(ctx, nil) + return + } log.Debugf("XXXXXXX Do guest pending delete... XXXXXXX") guestStatus, _ := self.Params.GetString("guest_status") - if !utils.IsInStringArray(guestStatus, []string{models.VM_SCHEDULE_FAILED, models.VM_NETWORK_FAILED, models.VM_DISK_FAILED, + if !utils.IsInStringArray(guestStatus, []string{ + models.VM_SCHEDULE_FAILED, models.VM_NETWORK_FAILED, models.VM_DISK_FAILED, models.VM_CREATE_FAILED, models.VM_DEVICE_FAILED}) { self.StartPendingDeleteGuest(ctx, guest) return @@ -103,8 +152,9 @@ func (self *GuestDeleteTask) OnEipDissociateComplete(ctx context.Context, obj db self.doStartDeleteGuest(ctx, guest) } -func (self *GuestDeleteTask) OnGuestStopCompleteFailed(ctx context.Context, obj db.IStandaloneModel, err jsonutils.JSONObject) { - self.OnGuestStopComplete(ctx, obj, err) // ignore stop error +func (self *GuestDeleteTask) OnSyncConfigCompleteFailed(ctx context.Context, obj db.IStandaloneModel, err jsonutils.JSONObject) { + guest := obj.(*models.SGuest) + self.OnFailed(ctx, guest, err) } func (self *GuestDeleteTask) OnGuestDeleteFailed(ctx context.Context, obj db.IStandaloneModel, err jsonutils.JSONObject) { @@ -121,7 +171,6 @@ func (self *GuestDeleteTask) doStartDeleteGuest(ctx context.Context, obj db.ISta func (self *GuestDeleteTask) StartPendingDeleteGuest(ctx context.Context, guest *models.SGuest) { guest.DoPendingDelete(ctx, self.UserCred) - models.IsolatedDeviceManager.ReleaseDevicesOfGuest(ctx, guest, self.UserCred) self.SetStage("on_pending_delete_complete", nil) guest.StartSyncstatus(ctx, self.UserCred, self.GetTaskId()) } From 929ea31d3efebc3a7aed9bcf7196237367cc7289 Mon Sep 17 00:00:00 2001 From: Qiu Jian Date: Thu, 3 Jan 2019 20:00:50 +0800 Subject: [PATCH 2/3] disk add allowdeleteitem --- pkg/compute/models/disks.go | 13 +++++++++++++ pkg/compute/models/guest_actions.go | 2 +- pkg/compute/tasks/guest_delete_task.go | 2 +- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/pkg/compute/models/disks.go b/pkg/compute/models/disks.go index 53032dc3e9..e0ad82657e 100644 --- a/pkg/compute/models/disks.go +++ b/pkg/compute/models/disks.go @@ -787,6 +787,19 @@ func (self *SDisk) validateDeleteCondition(ctx context.Context, isPurge bool) er return self.SSharableVirtualResourceBase.ValidateDeleteCondition(ctx) } +func (self *SDisk) AllowDeleteItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { + overridePendingDelete := false + purge := false + if query != nil { + overridePendingDelete = jsonutils.QueryBoolean(query, "override_pending_delete", false) + purge = jsonutils.QueryBoolean(query, "purge", false) + } + if (overridePendingDelete || purge) && !db.IsAdminAllowDelete(userCred, self) { + return false + } + return self.IsOwner(userCred) || db.IsAdminAllowDelete(userCred, self) +} + func (self *SDisk) GetTemplateId() string { return self.TemplateId } diff --git a/pkg/compute/models/guest_actions.go b/pkg/compute/models/guest_actions.go index 79198ccf58..c19dfb14aa 100644 --- a/pkg/compute/models/guest_actions.go +++ b/pkg/compute/models/guest_actions.go @@ -1550,7 +1550,7 @@ func (self *SGuest) DoPendingDelete(ctx context.Context, userCred mcclient.Token for _, guestdisk := range self.GetDisks() { disk := guestdisk.GetDisk() - if ! disk.IsDetachable() { + if !disk.IsDetachable() { disk.DoPendingDelete(ctx, userCred) } else { log.Warningf("detachable disk on pending delete guests!!! should be removed earlier") diff --git a/pkg/compute/tasks/guest_delete_task.go b/pkg/compute/tasks/guest_delete_task.go index 6a0db89c6c..8a7746daca 100644 --- a/pkg/compute/tasks/guest_delete_task.go +++ b/pkg/compute/tasks/guest_delete_task.go @@ -106,7 +106,7 @@ func (self *GuestDeleteTask) OnDiskDetachComplete(ctx context.Context, obj db.IS } lastDisk := guestdisks[len(guestdisks)-1].GetDisk() // remove last detachable disk log.Debugf("lastDisk IsDetachable?? %v", lastDisk.IsDetachable()) - if ! lastDisk.IsDetachable() { + if !lastDisk.IsDetachable() { self.doClearSecurityGroupComplete(ctx, guest) return } From d1d032411efb09a65ce6076ada84ddef172f8146 Mon Sep 17 00:00:00 2001 From: Qiu Jian Date: Thu, 3 Jan 2019 20:13:47 +0800 Subject: [PATCH 3/3] =?UTF-8?q?host-list=E5=A2=9E=E5=8A=A0mem=5Fcmtbound?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/compute/models/hosts.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/compute/models/hosts.go b/pkg/compute/models/hosts.go index 5b6b1bf0bc..685c6d4d25 100644 --- a/pkg/compute/models/hosts.go +++ b/pkg/compute/models/hosts.go @@ -140,9 +140,9 @@ type SHost struct { CpuReserved int8 `nullable:"true" default:"0" list:"admin" update:"admin" create:"admin_optional"` // Column(TINYINT, nullable=True, default=0) CpuCmtbound float32 `nullable:"true" default:"8.0" list:"admin" update:"admin" create:"admin_optional"` // = Column(Float, nullable=True) - MemSize int `nullable:"true" list:"admin" update:"admin" create:"admin_optional"` // Column(Integer, nullable=True) # memory size in MB - MemReserved int `nullable:"true" default:"0" list:"admin" update:"admin" create:"admin_optional"` // Column(Integer, nullable=True, default=0) # memory reserved in MB - MemCmtbound float32 `nullable:"true" default:"1.0" update:"admin" create:"admin_optional"` // = Column(Float, nullable=True) + MemSize int `nullable:"true" list:"admin" update:"admin" create:"admin_optional"` // Column(Integer, nullable=True) # memory size in MB + MemReserved int `nullable:"true" default:"0" list:"admin" update:"admin" create:"admin_optional"` // Column(Integer, nullable=True, default=0) # memory reserved in MB + MemCmtbound float32 `nullable:"true" default:"1.0" list:"admin" update:"admin" create:"admin_optional"` // = Column(Float, nullable=True) StorageSize int `nullable:"true" list:"admin" update:"admin" create:"admin_optional"` // Column(Integer, nullable=True) # storage size in MB StorageType string `width:"20" charset:"ascii" nullable:"true" list:"admin" update:"admin" create:"admin_optional"` // Column(VARCHAR(20, charset='ascii'), nullable=True)