From a9ea3839d025d9c46479fb282af9eb2a690e8cf7 Mon Sep 17 00:00:00 2001 From: Qu Xuan Date: Mon, 30 Nov 2020 21:15:37 +0800 Subject: [PATCH 1/2] feat(region): add server delete options --- pkg/apis/compute/guests.go | 22 ++++++++++++++++++++++ pkg/compute/models/guests.go | 15 +++------------ 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/pkg/apis/compute/guests.go b/pkg/apis/compute/guests.go index a1d97a9bbf..ba8a1c5434 100644 --- a/pkg/apis/compute/guests.go +++ b/pkg/apis/compute/guests.go @@ -482,3 +482,25 @@ type ServerSaveImageInput struct { // swagger: ignore ImageId string } + +type ServerDeleteInput struct { + // 是否越过回收站直接删除 + // default: false + OverridePendingDelete bool + + // 是否仅删除本地资源 + // default: false + Purge bool + + // 是否删除快照 + // default: false + DeleteSnapshots bool + + // 是否删除关联的EIP + // default: false + DeleteEip bool + + // 是否删除关联的数据盘 + // default: false + DeleteDisks bool +} diff --git a/pkg/compute/models/guests.go b/pkg/compute/models/guests.go index 0ee72caa28..dc56da0608 100644 --- a/pkg/compute/models/guests.go +++ b/pkg/compute/models/guests.go @@ -3823,18 +3823,9 @@ func (self *SGuest) AllowDeleteItem(ctx context.Context, userCred mcclient.Token return self.IsOwner(userCred) || db.IsAdminAllowDelete(userCred, self) } -func (self *SGuest) CustomizeDelete(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) error { - var ( - overridePendingDelete = false - purge = false - deleteSnapshots = false - ) - if query != nil { - overridePendingDelete = jsonutils.QueryBoolean(query, "override_pending_delete", false) - purge = jsonutils.QueryBoolean(query, "purge", false) - deleteSnapshots = jsonutils.QueryBoolean(query, "delete_snapshots", false) - } - return self.StartDeleteGuestTask(ctx, userCred, "", purge, overridePendingDelete, deleteSnapshots) +// 删除虚拟机 +func (self *SGuest) CustomizeDelete(ctx context.Context, userCred mcclient.TokenCredential, query api.ServerDeleteInput, data jsonutils.JSONObject) error { + return self.StartDeleteGuestTask(ctx, userCred, "", query.Purge, query.OverridePendingDelete, query.DeleteSnapshots) } func (self *SGuest) DeleteAllDisksInDB(ctx context.Context, userCred mcclient.TokenCredential) error { From 108d6827e83aa47cc7382e27ca182c5d66840af1 Mon Sep 17 00:00:00 2001 From: Qu Xuan Date: Tue, 1 Dec 2020 09:58:54 +0800 Subject: [PATCH 2/2] feat(region): disks and eip delete with server --- pkg/apis/compute/disk.go | 3 +- pkg/apis/list.go | 4 ++ pkg/cloudcommon/db/auto_delete.go | 54 +++++++++++++++++++ pkg/compute/models/disks.go | 19 +++---- pkg/compute/models/guest_actions.go | 20 +++---- pkg/compute/models/guests.go | 17 ++++-- pkg/compute/models/host_recycle.go | 5 +- .../baremetal_convert_hypervisor_task.go | 3 +- .../baremetal_unconvert_hypervisor_task.go | 3 +- pkg/compute/tasks/guest_delete_task.go | 7 ++- .../tasks/guest_detach_scalinggroup.go | 4 +- pkg/mcclient/options/servers.go | 2 + 12 files changed, 105 insertions(+), 36 deletions(-) create mode 100644 pkg/cloudcommon/db/auto_delete.go diff --git a/pkg/apis/compute/disk.go b/pkg/apis/compute/disk.go index 14f917989f..910d0eeaa8 100644 --- a/pkg/apis/compute/disk.go +++ b/pkg/apis/compute/disk.go @@ -106,6 +106,7 @@ type DiskListInput struct { apis.VirtualResourceListInput apis.ExternalizedResourceBaseListInput apis.MultiArchResourceBaseListInput + apis.AutoDeleteResourceBaseListInput billing.BillingResourceListInput StorageFilterListInput @@ -134,8 +135,6 @@ type DiskListInput struct { DiskSize int `json:"disk_size"` - AutoDelete *bool `json:"auto_delete"` - FsFormat string `json:"fs_format"` // 镜像 diff --git a/pkg/apis/list.go b/pkg/apis/list.go index d8e2e804a0..e969b23500 100644 --- a/pkg/apis/list.go +++ b/pkg/apis/list.go @@ -319,3 +319,7 @@ type EnabledStatusInfrasResourceBaseListInput struct { type MultiArchResourceBaseListInput struct { OsArch string `json:"os_arch"` } + +type AutoDeleteResourceBaseListInput struct { + AutoDelete *bool +} diff --git a/pkg/cloudcommon/db/auto_delete.go b/pkg/cloudcommon/db/auto_delete.go new file mode 100644 index 0000000000..eba4d43fd2 --- /dev/null +++ b/pkg/cloudcommon/db/auto_delete.go @@ -0,0 +1,54 @@ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by model-api-gen. DO NOT EDIT. + +package db + +import ( + "context" + + "yunion.io/x/sqlchemy" + + "yunion.io/x/onecloud/pkg/apis" + "yunion.io/x/onecloud/pkg/mcclient" +) + +// +onecloud:model-api-gen +type SAutoDeleteResourceBase struct { + // 是否跟随资源自动删除 + // example: false + AutoDelete bool `nullable:"false" default:"false" get:"user" update:"user" json:"auto_delete"` +} + +type SAutoDeleteResourceBaseManager struct{} + +func (manager *SAutoDeleteResourceBaseManager) ListItemFilter( + ctx context.Context, + q *sqlchemy.SQuery, + userCred mcclient.TokenCredential, + query apis.AutoDeleteResourceBaseListInput, +) (*sqlchemy.SQuery, error) { + if query.AutoDelete != nil { + q = q.Equals("auto_delete", *query.AutoDelete) + } + + return q, nil +} + +func (self *SAutoDeleteResourceBase) SetAutoDelete(model IModel, userCred mcclient.TokenCredential, autoDelete bool) error { + _, err := Update(model, func() error { + self.AutoDelete = autoDelete + return nil + }) + return err +} diff --git a/pkg/compute/models/disks.go b/pkg/compute/models/disks.go index 5014fc94a6..6730f54cbc 100644 --- a/pkg/compute/models/disks.go +++ b/pkg/compute/models/disks.go @@ -60,6 +60,7 @@ type SDiskManager struct { SStorageResourceBaseManager SBillingResourceBaseManager db.SMultiArchResourceBaseManager + db.SAutoDeleteResourceBaseManager } var DiskManager *SDiskManager @@ -83,6 +84,7 @@ type SDisk struct { SBillingResourceBase SStorageResourceBase `width:"128" charset:"ascii" nullable:"true" list:"admin" create:"optional"` db.SMultiArchResourceBase + db.SAutoDeleteResourceBase // 磁盘存储类型 // example: qcow2 @@ -93,10 +95,6 @@ type SDisk struct { // 磁盘路径 AccessPath string `width:"256" charset:"ascii" nullable:"true" get:"user" json:"access_path"` - // 是否跟随云主机自动删除, 仅绑定到云主机时才生效 - // example: false - AutoDelete bool `nullable:"false" default:"false" get:"user" update:"user" json:"auto_delete"` - // 存储Id // StorageId string `width:"128" charset:"ascii" nullable:"true" list:"admin" create:"optional"` @@ -174,6 +172,11 @@ func (manager *SDiskManager) ListItemFilter( return nil, errors.Wrap(err, "SMultiArchResourceBaseManager.ListItemFilter") } + q, err = manager.SAutoDeleteResourceBaseManager.ListItemFilter(ctx, q, userCred, query.AutoDeleteResourceBaseListInput) + if err != nil { + return nil, errors.Wrapf(err, "SAutoDeleteResourceBaseManager.ListItemFilter") + } + if query.Unused != nil { guestdisks := GuestdiskManager.Query().SubQuery() sq := guestdisks.Query(guestdisks.Field("disk_id")) @@ -224,14 +227,6 @@ func (manager *SDiskManager) ListItemFilter( q = q.Equals("disk_size", query.DiskSize) } - if query.AutoDelete != nil { - if *query.AutoDelete { - q = q.IsTrue("auto_delete") - } else { - q = q.IsFalse("auto_delete") - } - } - if len(query.FsFormat) > 0 { q = q.Equals("fs_format", query.FsFormat) } diff --git a/pkg/compute/models/guest_actions.go b/pkg/compute/models/guest_actions.go index bae54ab8e8..292b029f1d 100644 --- a/pkg/compute/models/guest_actions.go +++ b/pkg/compute/models/guest_actions.go @@ -1074,24 +1074,17 @@ func (self *SGuest) StartSyncstatus(ctx context.Context, userCred mcclient.Token func (self *SGuest) StartAutoDeleteGuestTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error { db.OpsLog.LogEvent(self, db.ACT_DELETE, "auto-delete after stop", userCred) - return self.StartDeleteGuestTask(ctx, userCred, parentTaskId, false, false, false) + opts := api.ServerDeleteInput{} + return self.StartDeleteGuestTask(ctx, userCred, parentTaskId, opts) } func (self *SGuest) StartDeleteGuestTask( ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string, - isPurge, overridePendingDelete, deleteSnapshots bool, + opts api.ServerDeleteInput, ) error { params := jsonutils.NewDict() params.Add(jsonutils.NewString(self.Status), "guest_status") - if isPurge { - params.Add(jsonutils.JSONTrue, "purge") - } - if overridePendingDelete { - params.Add(jsonutils.JSONTrue, "override_pending_delete") - } - if deleteSnapshots { - params.Add(jsonutils.JSONTrue, "delete_snapshots") - } + params.Update(jsonutils.Marshal(opts)) self.SetStatus(userCred, api.VM_START_DELETE, "") return self.GetDriver().StartDeleteGuestTask(ctx, userCred, self, params, parentTaskId) } @@ -1388,7 +1381,10 @@ func (self *SGuest) PerformPurge(ctx context.Context, userCred mcclient.TokenCre if host != nil && host.GetEnabled() { return nil, httperrors.NewInvalidStatusError("Cannot purge server on enabled host") } - err = self.StartDeleteGuestTask(ctx, userCred, "", true, false, false) + opts := api.ServerDeleteInput{ + Purge: true, + } + err = self.StartDeleteGuestTask(ctx, userCred, "", opts) return nil, err } diff --git a/pkg/compute/models/guests.go b/pkg/compute/models/guests.go index dc56da0608..69161d1e28 100644 --- a/pkg/compute/models/guests.go +++ b/pkg/compute/models/guests.go @@ -3825,7 +3825,7 @@ func (self *SGuest) AllowDeleteItem(ctx context.Context, userCred mcclient.Token // 删除虚拟机 func (self *SGuest) CustomizeDelete(ctx context.Context, userCred mcclient.TokenCredential, query api.ServerDeleteInput, data jsonutils.JSONObject) error { - return self.StartDeleteGuestTask(ctx, userCred, "", query.Purge, query.OverridePendingDelete, query.DeleteSnapshots) + return self.StartDeleteGuestTask(ctx, userCred, "", query) } func (self *SGuest) DeleteAllDisksInDB(ctx context.Context, userCred mcclient.TokenCredential) error { @@ -4635,7 +4635,10 @@ func (manager *SGuestManager) CleanPendingDeleteServers(ctx context.Context, use return } for i := 0; i < len(guests); i += 1 { - guests[i].StartDeleteGuestTask(ctx, userCred, "", false, true, false) + opts := api.ServerDeleteInput{ + OverridePendingDelete: true, + } + guests[i].StartDeleteGuestTask(ctx, userCred, "", opts) } } @@ -4706,7 +4709,7 @@ func (manager *SGuestManager) DeleteExpiredPrepaidServers(ctx context.Context, u if guests == nil { return } - deteleSnapshot := options.Options.DeleteSnapshotExpiredRelease + deleteSnapshot := options.Options.DeleteSnapshotExpiredRelease for i := 0; i < len(guests); i += 1 { // fake delete expired prepaid servers if len(guests[i].ExternalId) > 0 { @@ -4716,7 +4719,10 @@ func (manager *SGuestManager) DeleteExpiredPrepaidServers(ctx context.Context, u } } guests[i].SetDisableDelete(userCred, false) - guests[i].StartDeleteGuestTask(ctx, userCred, "", false, false, deteleSnapshot) + opts := api.ServerDeleteInput{ + DeleteSnapshots: deleteSnapshot, + } + guests[i].StartDeleteGuestTask(ctx, userCred, "", opts) } } @@ -4752,7 +4758,8 @@ func (manager *SGuestManager) DeleteExpiredPostpaidServers(ctx context.Context, } } guests[i].SetDisableDelete(userCred, false) - guests[i].StartDeleteGuestTask(ctx, userCred, "", false, false, deleteSnapshot) + opts := api.ServerDeleteInput{DeleteSnapshots: deleteSnapshot} + guests[i].StartDeleteGuestTask(ctx, userCred, "", opts) } } diff --git a/pkg/compute/models/host_recycle.go b/pkg/compute/models/host_recycle.go index 37e65ae7c9..d5d7191776 100644 --- a/pkg/compute/models/host_recycle.go +++ b/pkg/compute/models/host_recycle.go @@ -90,7 +90,10 @@ func (self *SGuest) DoPerformPrepaidRecycle(ctx context.Context, userCred mcclie logclient.AddActionLogWithContext(ctx, self, logclient.ACT_RECYCLE_PREPAID, self.GetShortDesc(ctx), userCred, true) if autoDelete { - self.StartDeleteGuestTask(ctx, userCred, "", false, true, false) + opts := api.ServerDeleteInput{ + OverridePendingDelete: true, + } + self.StartDeleteGuestTask(ctx, userCred, "", opts) } return nil, nil diff --git a/pkg/compute/tasks/baremetal_convert_hypervisor_task.go b/pkg/compute/tasks/baremetal_convert_hypervisor_task.go index ebfc6144f8..0792501384 100644 --- a/pkg/compute/tasks/baremetal_convert_hypervisor_task.go +++ b/pkg/compute/tasks/baremetal_convert_hypervisor_task.go @@ -90,7 +90,8 @@ func (self *BaremetalConvertHypervisorTask) OnGuestDeployCompleteFailed(ctx cont guest := self.getGuest() guest.SetDisableDelete(self.UserCred, false) self.SetStage("OnGuestDeleteComplete", nil) - guest.StartDeleteGuestTask(ctx, self.UserCred, self.GetTaskId(), false, true, false) + opts := api.ServerDeleteInput{OverridePendingDelete: true} + guest.StartDeleteGuestTask(ctx, self.UserCred, self.GetTaskId(), opts) logclient.AddActionLogWithStartable(self, baremetal, logclient.ACT_BM_CONVERT_HYPER, fmt.Sprintf("convert deploy failed: %s", body.String()), self.UserCred, false) } diff --git a/pkg/compute/tasks/baremetal_unconvert_hypervisor_task.go b/pkg/compute/tasks/baremetal_unconvert_hypervisor_task.go index 16a02a0f58..c547662e56 100644 --- a/pkg/compute/tasks/baremetal_unconvert_hypervisor_task.go +++ b/pkg/compute/tasks/baremetal_unconvert_hypervisor_task.go @@ -51,7 +51,8 @@ func (self *BaremetalUnconvertHypervisorTask) OnInit(ctx context.Context, obj db if len(guests) == 1 { guest := guests[0] self.SetStage("OnGuestDeleteComplete", nil) - guest.StartDeleteGuestTask(ctx, self.UserCred, self.GetTaskId(), false, true, false) + opts := api.ServerDeleteInput{OverridePendingDelete: true} + guest.StartDeleteGuestTask(ctx, self.UserCred, self.GetTaskId(), opts) } else { self.OnGuestDeleteComplete(ctx, baremetal, nil) } diff --git a/pkg/compute/tasks/guest_delete_task.go b/pkg/compute/tasks/guest_delete_task.go index f2d69f206e..b8a915f9cb 100644 --- a/pkg/compute/tasks/guest_delete_task.go +++ b/pkg/compute/tasks/guest_delete_task.go @@ -127,7 +127,8 @@ func (self *GuestDeleteTask) OnStartEipDissociate(ctx context.Context, guest *mo self.OnEipDissociateComplete(ctx, guest, nil) } else { self.SetStage("OnEipDissociateComplete", nil) - eip.StartEipDissociateTask(ctx, self.UserCred, false, self.GetTaskId()) + autoDelete := jsonutils.QueryBoolean(self.GetParams(), "delete_eip", false) + eip.StartEipDissociateTask(ctx, self.UserCred, autoDelete, self.GetTaskId()) } } else { self.OnEipDissociateComplete(ctx, guest, nil) @@ -157,6 +158,10 @@ func (self *GuestDeleteTask) OnDiskDetachComplete(ctx context.Context, obj db.IS } // detach last detachable disk lastDisk := guestdisks[len(guestdisks)-1].GetDisk() + deleteDisks := jsonutils.QueryBoolean(self.Params, "delete_disks", false) + if deleteDisks { + lastDisk.SetAutoDelete(lastDisk, self.GetUserCred(), true) + } log.Debugf("lastDisk IsDetachable?? %v", lastDisk.IsDetachable()) if !lastDisk.IsDetachable() { // no more disk need detach diff --git a/pkg/compute/tasks/guest_detach_scalinggroup.go b/pkg/compute/tasks/guest_detach_scalinggroup.go index 80f14f5946..bc670fa8b1 100644 --- a/pkg/compute/tasks/guest_detach_scalinggroup.go +++ b/pkg/compute/tasks/guest_detach_scalinggroup.go @@ -98,7 +98,9 @@ func (self *GuestDetachScalingGroupTask) OnDetachLoadbalancerComplete(ctx contex } self.Params.Set("guest_name", jsonutils.NewString(guest.GetName())) self.SetStage("OnDeleteGuestComplete", nil) - if err := guest.StartDeleteGuestTask(ctx, self.UserCred, self.Id, false, true, true); err != nil { + opts := api.ServerDeleteInput{Purge: false, OverridePendingDelete: true, DeleteSnapshots: true} + err := guest.StartDeleteGuestTask(ctx, self.UserCred, self.Id, opts) + if err != nil { self.taskFailed(ctx, sg, nil, jsonutils.NewString(err.Error())) } } diff --git a/pkg/mcclient/options/servers.go b/pkg/mcclient/options/servers.go index 893496abe8..5a54f860c9 100644 --- a/pkg/mcclient/options/servers.go +++ b/pkg/mcclient/options/servers.go @@ -614,6 +614,8 @@ type ServerDeleteOptions struct { ServerIdsOptions OverridePendingDelete *bool `help:"Delete server directly instead of pending delete" short-token:"f"` DeleteSnapshots *bool `help:"Delete server snapshots"` + DeleteDisks *bool `help:"Delete server disks"` + DeleteEip *bool `help:"Delete eip"` } func (o *ServerDeleteOptions) QueryParams() (jsonutils.JSONObject, error) {