mirror of
https://hubproxy.babadafafafafa.cn/https://github.com/yunionio/cloudpods.git
synced 2026-09-20 08:03:53 +08:00
fix(region): snapshot policy operation (#24251)
This commit is contained in:
@@ -42,32 +42,18 @@ import (
|
||||
func init() {
|
||||
cmd := shell.NewResourceCmd(&modules.Disks)
|
||||
cmd.List(&compute_options.DiskListOptions{})
|
||||
cmd.Show(&compute_options.DiskIdOptions{})
|
||||
cmd.Perform("public", &compute_options.DiskIdOptions{})
|
||||
cmd.Perform("private", &compute_options.DiskIdOptions{})
|
||||
cmd.Perform("syncstatus", &compute_options.DiskIdOptions{})
|
||||
cmd.Perform("change-owner-candidate-domains", &compute_options.DiskIdOptions{})
|
||||
cmd.Perform("disk-cancel-delete", &compute_options.DiskIdOptions{})
|
||||
cmd.Perform("set-class-metadata", &options.ResourceMetadataOptions{})
|
||||
cmd.Perform("rebuild", &options.ResourceIdOptions{})
|
||||
cmd.Perform("migrate", &compute_options.DiskMigrateOptions{})
|
||||
cmd.Perform("change-billing-type", new(compute_options.DiskChangeBillingTypeOptions))
|
||||
cmd.Perform("change-storage-type", &compute_options.DiskChangeStorageTypeOptions{})
|
||||
|
||||
type DiskDetailOptions struct {
|
||||
ID string `help:"ID or Name of disk"`
|
||||
}
|
||||
R(&DiskDetailOptions{}, "disk-show", "Show details of disk", func(s *mcclient.ClientSession, args *DiskDetailOptions) error {
|
||||
disk, e := modules.Disks.Get(s, args.ID, nil)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
printObject(disk)
|
||||
return nil
|
||||
})
|
||||
R(&DiskDetailOptions{}, "disk-cancel-delete", "Cancel pending delete disks", func(s *mcclient.ClientSession, args *DiskDetailOptions) error {
|
||||
disk, e := modules.Disks.PerformAction(s, args.ID, "cancel-delete", nil)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
printObject(disk)
|
||||
return nil
|
||||
})
|
||||
|
||||
type DiskDeleteOptions struct {
|
||||
ID []string `help:"ID of disks to delete" metavar:"DISK"`
|
||||
OverridePendingDelete bool `help:"Delete disk directly instead of pending delete" short-token:"f"`
|
||||
@@ -96,25 +82,7 @@ func init() {
|
||||
return nil
|
||||
})
|
||||
|
||||
R(&DiskDetailOptions{}, "disk-public", "Make a disk public", func(s *mcclient.ClientSession, args *DiskDetailOptions) error {
|
||||
disk, e := modules.Disks.PerformAction(s, args.ID, "public", nil)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
printObject(disk)
|
||||
return nil
|
||||
})
|
||||
|
||||
R(&DiskDetailOptions{}, "disk-private", "Make a disk private", func(s *mcclient.ClientSession, args *DiskDetailOptions) error {
|
||||
disk, e := modules.Disks.PerformAction(s, args.ID, "private", nil)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
printObject(disk)
|
||||
return nil
|
||||
})
|
||||
|
||||
R(&DiskDetailOptions{}, "disk-metadata", "Get metadata of a disk", func(s *mcclient.ClientSession, args *DiskDetailOptions) error {
|
||||
R(&compute_options.DiskIdOptions{}, "disk-metadata", "Get metadata of a disk", func(s *mcclient.ClientSession, args *compute_options.DiskIdOptions) error {
|
||||
meta, e := modules.Disks.GetMetadata(s, args.ID, nil)
|
||||
if e != nil {
|
||||
return e
|
||||
@@ -123,15 +91,6 @@ func init() {
|
||||
return nil
|
||||
})
|
||||
|
||||
R(&DiskDetailOptions{}, "disk-syncstatus", "Sync status for disk", func(s *mcclient.ClientSession, args *DiskDetailOptions) error {
|
||||
ret, e := modules.Disks.PerformAction(s, args.ID, "syncstatus", nil)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
printObject(ret)
|
||||
return nil
|
||||
})
|
||||
|
||||
type DiskUpdateOptions struct {
|
||||
ID string `help:"ID or name of disk"`
|
||||
Name string `help:"New name of disk"`
|
||||
@@ -300,7 +259,7 @@ func init() {
|
||||
return nil
|
||||
})
|
||||
|
||||
R(&DiskDetailOptions{}, "disk-change-owner-candidate-domains", "Get change owner candidate domain list", func(s *mcclient.ClientSession, args *DiskDetailOptions) error {
|
||||
R(&compute_options.DiskIdOptions{}, "disk-change-owner-candidate-domains", "Get change owner candidate domain list", func(s *mcclient.ClientSession, args *compute_options.DiskIdOptions) error {
|
||||
result, err := modules.Disks.GetSpecific(s, args.ID, "change-owner-candidate-domains", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -87,6 +87,6 @@ type CachedimageListInput struct {
|
||||
// valid cachedimage
|
||||
Valid bool `json:"valid"`
|
||||
|
||||
// enum: [public, private]
|
||||
// enum: ["public", "private"]
|
||||
CloudEnv string `json:"cloud_env"`
|
||||
}
|
||||
|
||||
@@ -169,6 +169,8 @@ type DiskListInput struct {
|
||||
|
||||
// 根据是否绑定快照策略过滤
|
||||
BindingSnapshotpolicy *bool `json:"binding_snapshotpolicy"`
|
||||
// 根据是否磁盘所在虚拟机是否绑定主机快照策略
|
||||
BindingServerSnapshotpolicy *bool `json:"binding_server_snapshotpolicy"`
|
||||
}
|
||||
|
||||
type DiskResourceInput struct {
|
||||
@@ -213,13 +215,22 @@ type SimpleGuest struct {
|
||||
Bps int `json:"bps"`
|
||||
// 计费类型
|
||||
BillingType string `json:"billing_type"`
|
||||
|
||||
// 磁盘绑定的快照策略列表
|
||||
Snapshotpolicy []SimpleSnapshotPolicy `json:"snapshotpolicy"`
|
||||
}
|
||||
|
||||
type SimpleSnapshotPolicy struct {
|
||||
Id string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
RepeatWeekdays []int `json:"repeat_weekdays"`
|
||||
TimePoints []int `json:"time_points"`
|
||||
// 快照策略ID
|
||||
Id string `json:"id"`
|
||||
// 快照策略名称
|
||||
Name string `json:"name"`
|
||||
// 快照策略类型
|
||||
ResourceType string `json:"resource_type"`
|
||||
// 快照策略重复周期
|
||||
RepeatWeekdays []int `json:"repeat_weekdays"`
|
||||
// 快照策略时间点
|
||||
TimePoints []int `json:"time_points"`
|
||||
}
|
||||
|
||||
type DiskDetails struct {
|
||||
@@ -239,11 +250,11 @@ type DiskDetails struct {
|
||||
GuestStatus string `json:"guest_status"`
|
||||
// 所挂载虚拟机计费类型
|
||||
GuestBillingType string `json:"guest_billing_type"`
|
||||
// 磁盘所在虚拟机绑定的主机快照策略数量
|
||||
GuestSnapshotpolicyCount int `json:"guest_snapshotpolicy_count"`
|
||||
|
||||
// 自动清理时间
|
||||
AutoDeleteAt time.Time `json:"auto_delete_at"`
|
||||
// 自动快照策略状态
|
||||
SnapshotpolicyStatus string `json:"snapshotpolicy_status,allowempty"`
|
||||
|
||||
// 自动快照策略
|
||||
Snapshotpolicies []SimpleSnapshotPolicy `json:"snapshotpolicies"`
|
||||
@@ -351,6 +362,7 @@ type DiskChagneStorageTypeInput struct {
|
||||
}
|
||||
|
||||
type DiskSnapshotpolicyInput struct {
|
||||
// 快照策略ID
|
||||
SnapshotpolicyId string `json:"snapshotpolicy_id"`
|
||||
}
|
||||
|
||||
|
||||
@@ -134,6 +134,14 @@ type ServerListInput struct {
|
||||
|
||||
// 根据是否绑定快照策略过滤
|
||||
BindingSnapshotpolicy *bool `json:"binding_snapshotpolicy"`
|
||||
// 根据虚机关联的磁盘是否绑定快照策略过滤
|
||||
BindingDisksSnapshotpolicy *bool `json:"binding_disks_snapshotpolicy"`
|
||||
}
|
||||
|
||||
// 主机快照策略绑定/设置接口入参
|
||||
type ServerSnapshotpolicyInput struct {
|
||||
// 快照策略ID
|
||||
SnapshotpolicyId string `json:"snapshotpolicy_id"`
|
||||
}
|
||||
|
||||
func (input *ServerListInput) AfterUnmarshal() {
|
||||
@@ -183,6 +191,11 @@ type ServerDetails struct {
|
||||
// 磁盘概要
|
||||
Disks string `json:"disks"`
|
||||
|
||||
// 主机快照策略数量
|
||||
SnapshotpolicyCount int `json:"snapshotpolicy_count"`
|
||||
// 磁盘快照策略数量
|
||||
DisksSnapshotpolicyCount int `json:"disks_snapshotpolicy_count"`
|
||||
|
||||
// 磁盘详情
|
||||
DisksInfo []GuestDiskInfo `json:"disks_info"`
|
||||
// 虚拟机Ip列表
|
||||
|
||||
@@ -218,6 +218,16 @@ func (manager *SDiskManager) ListItemFilter(
|
||||
q = q.NotIn("id", spjsq)
|
||||
}
|
||||
}
|
||||
if query.BindingServerSnapshotpolicy != nil {
|
||||
guestDisks := GuestdiskManager.Query("disk_id")
|
||||
sq := SnapshotPolicyResourceManager.Query("resource_id").Equals("resource_type", api.SNAPSHOT_POLICY_TYPE_SERVER).SubQuery()
|
||||
gdsq := guestDisks.Join(sq, sqlchemy.Equals(guestDisks.Field("guest_id"), sq.Field("resource_id"))).SubQuery()
|
||||
if *query.BindingServerSnapshotpolicy {
|
||||
q = q.In("id", gdsq)
|
||||
} else {
|
||||
q = q.NotIn("id", gdsq)
|
||||
}
|
||||
}
|
||||
|
||||
guestId := query.ServerId
|
||||
if len(guestId) > 0 {
|
||||
@@ -2550,11 +2560,12 @@ func (manager *SDiskManager) FetchCustomizeColumns(
|
||||
return rows
|
||||
}
|
||||
|
||||
guests := map[string][]api.SimpleGuest{}
|
||||
guests, guestIds := map[string][]api.SimpleGuest{}, []string{}
|
||||
for _, guest := range guestInfo {
|
||||
_, ok := guests[guest.DiskId]
|
||||
if !ok {
|
||||
guests[guest.DiskId] = []api.SimpleGuest{}
|
||||
guestIds = append(guestIds, guest.Id)
|
||||
}
|
||||
guests[guest.DiskId] = append(guests[guest.DiskId], api.SimpleGuest{
|
||||
Id: guest.Id,
|
||||
@@ -2571,7 +2582,7 @@ func (manager *SDiskManager) FetchCustomizeColumns(
|
||||
}
|
||||
|
||||
policySQ := SnapshotPolicyManager.Query().SubQuery()
|
||||
dps := SnapshotPolicyResourceManager.Query().Equals("resource_type", api.SNAPSHOT_POLICY_TYPE_DISK).SubQuery()
|
||||
dps := SnapshotPolicyResourceManager.Query().SubQuery()
|
||||
|
||||
q = policySQ.Query(
|
||||
policySQ.Field("id"),
|
||||
@@ -2579,8 +2590,9 @@ func (manager *SDiskManager) FetchCustomizeColumns(
|
||||
policySQ.Field("time_points"),
|
||||
policySQ.Field("repeat_weekdays"),
|
||||
dps.Field("resource_id"),
|
||||
dps.Field("resource_type"),
|
||||
).Join(dps, sqlchemy.Equals(dps.Field("snapshotpolicy_id"), policySQ.Field("id"))).
|
||||
Filter(sqlchemy.In(dps.Field("resource_id"), diskIds))
|
||||
Filter(sqlchemy.OR(sqlchemy.In(dps.Field("resource_id"), diskIds), sqlchemy.In(dps.Field("resource_id"), guestIds)))
|
||||
|
||||
policyInfo := []struct {
|
||||
Id string
|
||||
@@ -2588,7 +2600,8 @@ func (manager *SDiskManager) FetchCustomizeColumns(
|
||||
Status string
|
||||
TimePoints []int
|
||||
RepeatWeekdays []int
|
||||
DiskId string
|
||||
ResourceId string
|
||||
ResourceType string
|
||||
}{}
|
||||
err = q.All(&policyInfo)
|
||||
if err != nil {
|
||||
@@ -2598,15 +2611,16 @@ func (manager *SDiskManager) FetchCustomizeColumns(
|
||||
|
||||
policies := map[string][]api.SimpleSnapshotPolicy{}
|
||||
for _, policy := range policyInfo {
|
||||
_, ok := policies[policy.DiskId]
|
||||
_, ok := policies[policy.ResourceId]
|
||||
if !ok {
|
||||
policies[policy.DiskId] = []api.SimpleSnapshotPolicy{}
|
||||
policies[policy.ResourceId] = []api.SimpleSnapshotPolicy{}
|
||||
}
|
||||
policies[policy.DiskId] = append(policies[policy.DiskId], api.SimpleSnapshotPolicy{
|
||||
policies[policy.ResourceId] = append(policies[policy.ResourceId], api.SimpleSnapshotPolicy{
|
||||
Id: policy.Id,
|
||||
Name: policy.Name,
|
||||
RepeatWeekdays: policy.RepeatWeekdays,
|
||||
TimePoints: policy.TimePoints,
|
||||
ResourceType: policy.ResourceType,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -2614,12 +2628,15 @@ func (manager *SDiskManager) FetchCustomizeColumns(
|
||||
rows[i].Guests, _ = guests[diskIds[i]]
|
||||
names, status, billingTypes := []string{}, []string{}, []string{}
|
||||
var iops, bps int
|
||||
for _, guest := range rows[i].Guests {
|
||||
for j := range rows[i].Guests {
|
||||
guest := rows[i].Guests[j]
|
||||
names = append(names, guest.Name)
|
||||
status = append(status, guest.Status)
|
||||
iops = guest.Iops
|
||||
bps = guest.Bps
|
||||
billingTypes = append(billingTypes, guest.BillingType)
|
||||
rows[i].Guests[j].Snapshotpolicy, _ = policies[guest.Id]
|
||||
rows[i].GuestSnapshotpolicyCount += len(rows[i].Guests[j].Snapshotpolicy)
|
||||
}
|
||||
rows[i].GuestCount = len(rows[i].Guests)
|
||||
rows[i].Guest = strings.Join(names, ",")
|
||||
@@ -3160,12 +3177,33 @@ func (disk *SDisk) GetUsages() []db.IUsage {
|
||||
}
|
||||
}
|
||||
|
||||
// 绑定磁盘快照策略
|
||||
// 磁盘只能绑定一个快照策略,已绑定时报错
|
||||
// 若磁盘所属主机已绑定主机快照策略,则磁盘不能再绑定快照策略
|
||||
func (disk *SDisk) PerformBindSnapshotpolicy(
|
||||
ctx context.Context,
|
||||
userCred mcclient.TokenCredential,
|
||||
query jsonutils.JSONObject,
|
||||
input *api.DiskSnapshotpolicyInput,
|
||||
) (jsonutils.JSONObject, error) {
|
||||
// 磁盘只能绑定一个快照策略,已绑定时报错
|
||||
cnt, err := SnapshotPolicyResourceManager.GetBindingCount(disk.Id, api.SNAPSHOT_POLICY_TYPE_DISK)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "GetBindingCount")
|
||||
}
|
||||
if cnt > 0 {
|
||||
return nil, httperrors.NewConflictError("disk already bound to a snapshot policy")
|
||||
}
|
||||
// 若磁盘所属主机已绑定主机快照策略,则磁盘不能再绑定快照策略
|
||||
if guest := disk.GetGuest(); guest != nil {
|
||||
guestCnt, err := SnapshotPolicyResourceManager.GetBindingCount(guest.Id, api.SNAPSHOT_POLICY_TYPE_SERVER)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "GetBindingCount for guest")
|
||||
}
|
||||
if guestCnt > 0 {
|
||||
return nil, httperrors.NewConflictError("guest already has server snapshot policy, disk cannot bind snapshot policy")
|
||||
}
|
||||
}
|
||||
spObj, err := validators.ValidateModel(ctx, userCred, SnapshotPolicyManager, &input.SnapshotpolicyId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -3190,6 +3228,52 @@ func (disk *SDisk) PerformBindSnapshotpolicy(
|
||||
return nil, sp.StartBindDisksTask(ctx, userCred, []string{disk.Id})
|
||||
}
|
||||
|
||||
// 设置磁盘快照策略
|
||||
// 可覆盖当前磁盘绑定的快照策略,若磁盘所属主机已绑定主机快照策略,则自动解除主机快照策略
|
||||
func (disk *SDisk) PerformSetSnapshotpolicy(
|
||||
ctx context.Context,
|
||||
userCred mcclient.TokenCredential,
|
||||
query jsonutils.JSONObject,
|
||||
input *api.DiskSnapshotpolicyInput,
|
||||
) (jsonutils.JSONObject, error) {
|
||||
spObj, err := validators.ValidateModel(ctx, userCred, SnapshotPolicyManager, &input.SnapshotpolicyId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sp := spObj.(*SSnapshotPolicy)
|
||||
if sp.Type != api.SNAPSHOT_POLICY_TYPE_DISK {
|
||||
return nil, httperrors.NewBadRequestError("The snapshot policy %s is not a disk snapshot policy", sp.Name)
|
||||
}
|
||||
if len(sp.ManagerId) > 0 {
|
||||
storage, err := disk.GetStorage()
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "GetStorage")
|
||||
}
|
||||
if storage.ManagerId != sp.ManagerId {
|
||||
return nil, httperrors.NewConflictError("The snapshot policy %s and disk account are different", sp.Name)
|
||||
}
|
||||
zone, err := storage.GetZone()
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "GetZone")
|
||||
}
|
||||
if sp.CloudregionId != zone.CloudregionId {
|
||||
return nil, httperrors.NewConflictError("The snapshot policy %s and the disk are in different region", sp.Name)
|
||||
}
|
||||
}
|
||||
// 先解除当前绑定再绑定新策略
|
||||
if err := SnapshotPolicyResourceManager.RemoveByResource(disk.Id, api.SNAPSHOT_POLICY_TYPE_DISK); err != nil {
|
||||
return nil, errors.Wrap(err, "RemoveByResource")
|
||||
}
|
||||
// 若磁盘所属主机已绑定主机快照策略,则磁盘不能再绑定快照策略
|
||||
if guest := disk.GetGuest(); guest != nil {
|
||||
if err := SnapshotPolicyResourceManager.RemoveByResource(guest.Id, api.SNAPSHOT_POLICY_TYPE_SERVER); err != nil {
|
||||
return nil, errors.Wrap(err, "RemoveByResource")
|
||||
}
|
||||
}
|
||||
return nil, sp.StartBindDisksTask(ctx, userCred, []string{disk.Id})
|
||||
}
|
||||
|
||||
// 解绑自动快照策略
|
||||
func (disk *SDisk) PerformUnbindSnapshotpolicy(
|
||||
ctx context.Context,
|
||||
userCred mcclient.TokenCredential,
|
||||
|
||||
@@ -5529,6 +5529,96 @@ func (self *SGuest) PerformUnbindGroups(ctx context.Context, userCred mcclient.T
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// 绑定主机快照策略
|
||||
// 主机只能绑定一个快照策略,已绑定时报错
|
||||
// 若主机下任意磁盘已绑定快照策略则报错
|
||||
func (self *SGuest) PerformBindSnapshotpolicy(ctx context.Context, userCred mcclient.TokenCredential,
|
||||
query jsonutils.JSONObject, input *api.ServerSnapshotpolicyInput) (jsonutils.JSONObject, error) {
|
||||
if len(input.SnapshotpolicyId) == 0 {
|
||||
return nil, httperrors.NewMissingParameterError("snapshotpolicy_id")
|
||||
}
|
||||
spObj, err := validators.ValidateModel(ctx, userCred, SnapshotPolicyManager, &input.SnapshotpolicyId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sp := spObj.(*SSnapshotPolicy)
|
||||
if sp.Type != api.SNAPSHOT_POLICY_TYPE_SERVER {
|
||||
return nil, httperrors.NewBadRequestError("The snapshot policy %s is not a server snapshot policy", sp.Name)
|
||||
}
|
||||
// 主机只能绑定一个快照策略
|
||||
cnt, err := SnapshotPolicyResourceManager.GetBindingCount(self.Id, api.SNAPSHOT_POLICY_TYPE_SERVER)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "GetBindingCount")
|
||||
}
|
||||
if cnt > 0 {
|
||||
return nil, httperrors.NewConflictError("guest already bound to a snapshot policy")
|
||||
}
|
||||
// 若主机下任意磁盘已绑定快照策略,则主机不能再绑定主机快照策略
|
||||
disks, err := self.GetDisks()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "GetDisks")
|
||||
}
|
||||
for _, d := range disks {
|
||||
diskCnt, err := SnapshotPolicyResourceManager.GetBindingCount(d.Id, api.SNAPSHOT_POLICY_TYPE_DISK)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "GetBindingCount for disk")
|
||||
}
|
||||
if diskCnt > 0 {
|
||||
return nil, httperrors.NewConflictError("guest has disk %s bound to snapshot policy, guest cannot bind server snapshot policy", d.Name)
|
||||
}
|
||||
}
|
||||
sr := &SSnapshotPolicyResource{}
|
||||
sr.SetModelManager(SnapshotPolicyResourceManager, sr)
|
||||
sr.SnapshotpolicyId = sp.Id
|
||||
sr.ResourceId = self.Id
|
||||
sr.ResourceType = api.SNAPSHOT_POLICY_TYPE_SERVER
|
||||
if err := SnapshotPolicyResourceManager.TableSpec().Insert(ctx, sr); err != nil {
|
||||
return nil, errors.Wrap(err, "Insert")
|
||||
}
|
||||
logclient.AddActionLogWithContext(ctx, self, logclient.ACT_BIND, input, userCred, true)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// 设置主机快照策略
|
||||
// 可覆盖当前主机绑定的快照策略,若主机下任意磁盘已绑定快照策略,则自动解除磁盘快照策略
|
||||
func (self *SGuest) PerformSetSnapshotpolicy(ctx context.Context, userCred mcclient.TokenCredential,
|
||||
query jsonutils.JSONObject, input *api.ServerSnapshotpolicyInput) (jsonutils.JSONObject, error) {
|
||||
if len(input.SnapshotpolicyId) == 0 {
|
||||
return nil, httperrors.NewMissingParameterError("snapshotpolicy_id")
|
||||
}
|
||||
spObj, err := validators.ValidateModel(ctx, userCred, SnapshotPolicyManager, &input.SnapshotpolicyId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sp := spObj.(*SSnapshotPolicy)
|
||||
if sp.Type != api.SNAPSHOT_POLICY_TYPE_SERVER {
|
||||
return nil, httperrors.NewBadRequestError("The snapshot policy %s is not a server snapshot policy", sp.Name)
|
||||
}
|
||||
if err := SnapshotPolicyResourceManager.RemoveByResource(self.Id, api.SNAPSHOT_POLICY_TYPE_SERVER); err != nil {
|
||||
return nil, errors.Wrap(err, "RemoveByResource")
|
||||
}
|
||||
// 若主机下任意磁盘已绑定快照策略,则主机不能再绑定主机快照策略
|
||||
disks, err := self.GetDisks()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "GetDisks")
|
||||
}
|
||||
for _, d := range disks {
|
||||
if err := SnapshotPolicyResourceManager.RemoveByResource(d.Id, api.SNAPSHOT_POLICY_TYPE_DISK); err != nil {
|
||||
return nil, errors.Wrap(err, "RemoveByResource")
|
||||
}
|
||||
}
|
||||
sr := &SSnapshotPolicyResource{}
|
||||
sr.SetModelManager(SnapshotPolicyResourceManager, sr)
|
||||
sr.SnapshotpolicyId = sp.Id
|
||||
sr.ResourceId = self.Id
|
||||
sr.ResourceType = api.SNAPSHOT_POLICY_TYPE_SERVER
|
||||
if err := SnapshotPolicyResourceManager.TableSpec().Insert(ctx, sr); err != nil {
|
||||
return nil, errors.Wrap(err, "Insert")
|
||||
}
|
||||
logclient.AddActionLogWithContext(ctx, self, logclient.ACT_UPDATE, input, userCred, true)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (self *SGuest) checkGroups(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject,
|
||||
data jsonutils.JSONObject) (sets.String, error) {
|
||||
|
||||
|
||||
@@ -90,6 +90,15 @@ func (manager *SGuestManager) FetchCustomizeColumns(
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(fields) == 0 || fields.Contains("snapshotpolicy") {
|
||||
counts := fetchGuestSnapshotpolicyInfo(guestIds)
|
||||
for i := range rows {
|
||||
rows[i].SnapshotpolicyCount = counts[guestIds[i]]
|
||||
for j := range rows[i].DisksInfo {
|
||||
rows[i].DisksSnapshotpolicyCount += counts[rows[i].DisksInfo[j].Id]
|
||||
}
|
||||
}
|
||||
}
|
||||
/*if len(fields) == 0 || fields.Contains("ips") {
|
||||
gips := fetchGuestIPs(guestIds, tristate.False)
|
||||
if gips != nil {
|
||||
@@ -440,6 +449,34 @@ func fetchGuestDisksInfo(guestIds []string) map[string][]GuestDiskInfo {
|
||||
return ret
|
||||
}
|
||||
|
||||
func fetchGuestSnapshotpolicyInfo(guestIds []string) map[string]int {
|
||||
ret := map[string]int{}
|
||||
disks := GuestdiskManager.Query("disk_id").In("guest_id", guestIds).SubQuery()
|
||||
spq := SnapshotPolicyResourceManager.Query()
|
||||
spq = spq.Filter(sqlchemy.OR(
|
||||
sqlchemy.In(spq.Field("resource_id"), guestIds),
|
||||
sqlchemy.In(spq.Field("resource_id"), disks),
|
||||
))
|
||||
sq := spq.SubQuery()
|
||||
q := sq.Query(
|
||||
sq.Field("resource_id"),
|
||||
sqlchemy.COUNT("count", sq.Field("snapshotpolicy_id")),
|
||||
).GroupBy(sq.Field("resource_id"))
|
||||
counts := []struct {
|
||||
ResourceId string
|
||||
Count int
|
||||
}{}
|
||||
err := q.All(&counts)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
for _, count := range counts {
|
||||
ret[count.ResourceId] = count.Count
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func (guest *SGuest) GetDisksSize() int {
|
||||
return guest.getDiskSize()
|
||||
}
|
||||
|
||||
@@ -738,6 +738,16 @@ func (manager *SGuestManager) ListItemFilter(
|
||||
q = q.NotIn("id", spjsq)
|
||||
}
|
||||
}
|
||||
if query.BindingDisksSnapshotpolicy != nil {
|
||||
guestDisks := GuestdiskManager.Query("guest_id")
|
||||
sq := SnapshotPolicyResourceManager.Query("resource_id").Equals("resource_type", api.SNAPSHOT_POLICY_TYPE_DISK).SubQuery()
|
||||
gdsq := guestDisks.Join(sq, sqlchemy.Equals(guestDisks.Field("disk_id"), sq.Field("resource_id"))).SubQuery()
|
||||
if *query.BindingDisksSnapshotpolicy {
|
||||
q = q.In("id", gdsq)
|
||||
} else {
|
||||
q = q.NotIn("id", gdsq)
|
||||
}
|
||||
}
|
||||
|
||||
return q, nil
|
||||
}
|
||||
|
||||
@@ -91,3 +91,8 @@ func (man *SSnapshotPolicyResourceManager) RemoveBySnapshotpolicy(id string) err
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
// GetBindingCount returns the number of snapshot policies bound to the given resource.
|
||||
func (man *SSnapshotPolicyResourceManager) GetBindingCount(resourceId, resourceType string) (int, error) {
|
||||
return man.Query().Equals("resource_id", resourceId).Equals("resource_type", resourceType).CountWithError()
|
||||
}
|
||||
|
||||
@@ -510,6 +510,12 @@ func (sp *SSnapshotPolicy) PerformBindDisks(
|
||||
return nil, sp.StartBindDisksTask(ctx, userCred, diskIds)
|
||||
}
|
||||
|
||||
// 绑定资源
|
||||
// 目前仅支持绑定主机和磁盘
|
||||
// 磁盘只能绑定一个快照策略,已绑定时报错
|
||||
// 若磁盘所属主机已绑定主机快照策略,则磁盘不能再绑定快照策略
|
||||
// 主机只能绑定一个快照策略,已绑定时报错
|
||||
// 若主机下任意磁盘已绑定快照策略,则主机不能再绑定主机快照策略
|
||||
func (sp *SSnapshotPolicy) PerformBindResources(
|
||||
ctx context.Context,
|
||||
userCred mcclient.TokenCredential,
|
||||
@@ -522,15 +528,63 @@ func (sp *SSnapshotPolicy) PerformBindResources(
|
||||
for i := range input.Resources {
|
||||
switch input.Resources[i].Type {
|
||||
case api.SNAPSHOT_POLICY_TYPE_DISK:
|
||||
_, err := validators.ValidateModel(ctx, userCred, DiskManager, &input.Resources[i].Id)
|
||||
if sp.Type != api.SNAPSHOT_POLICY_TYPE_DISK {
|
||||
return nil, httperrors.NewBadRequestError("The snapshot policy %s is not a disk snapshot policy", sp.Name)
|
||||
}
|
||||
diskObj, err := validators.ValidateModel(ctx, userCred, DiskManager, &input.Resources[i].Id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
disk := diskObj.(*SDisk)
|
||||
// 磁盘只能绑定一个快照策略
|
||||
cnt, err := SnapshotPolicyResourceManager.GetBindingCount(disk.Id, api.SNAPSHOT_POLICY_TYPE_DISK)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "GetBindingCount")
|
||||
}
|
||||
if cnt > 0 {
|
||||
return nil, httperrors.NewConflictError("disk %s already bound to a snapshot policy", disk.Name)
|
||||
}
|
||||
// 若磁盘所属主机已绑定主机快照策略,则磁盘不能再绑定
|
||||
if guest := disk.GetGuest(); guest != nil {
|
||||
guestCnt, err := SnapshotPolicyResourceManager.GetBindingCount(guest.Id, api.SNAPSHOT_POLICY_TYPE_SERVER)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "GetBindingCount for guest")
|
||||
}
|
||||
if guestCnt > 0 {
|
||||
return nil, httperrors.NewConflictError("guest %s already has server snapshot policy, disk cannot bind snapshot policy", guest.Name)
|
||||
}
|
||||
}
|
||||
case api.SNAPSHOT_POLICY_TYPE_SERVER:
|
||||
_, err := validators.ValidateModel(ctx, userCred, GuestManager, &input.Resources[i].Id)
|
||||
if sp.Type != api.SNAPSHOT_POLICY_TYPE_SERVER {
|
||||
return nil, httperrors.NewBadRequestError("The snapshot policy %s is not a server snapshot policy", sp.Name)
|
||||
}
|
||||
guestObj, err := validators.ValidateModel(ctx, userCred, GuestManager, &input.Resources[i].Id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
guest := guestObj.(*SGuest)
|
||||
// 主机只能绑定一个快照策略
|
||||
cnt, err := SnapshotPolicyResourceManager.GetBindingCount(guest.Id, api.SNAPSHOT_POLICY_TYPE_SERVER)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "GetBindingCount")
|
||||
}
|
||||
if cnt > 0 {
|
||||
return nil, httperrors.NewConflictError("guest %s already bound to a snapshot policy", guest.Name)
|
||||
}
|
||||
// 若主机下任意磁盘已绑定快照策略,则主机不能再绑定主机快照策略
|
||||
disks, err := guest.GetDisks()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "guest.GetDisks")
|
||||
}
|
||||
for _, d := range disks {
|
||||
diskCnt, err := SnapshotPolicyResourceManager.GetBindingCount(d.Id, api.SNAPSHOT_POLICY_TYPE_DISK)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "GetBindingCount for disk")
|
||||
}
|
||||
if diskCnt > 0 {
|
||||
return nil, httperrors.NewConflictError("guest %s has disk %s bound to snapshot policy, guest cannot bind server snapshot policy", guest.Name, d.Name)
|
||||
}
|
||||
}
|
||||
default:
|
||||
return nil, httperrors.NewBadRequestError("Invalid resource type: %s", input.Resources[i].Type)
|
||||
}
|
||||
|
||||
@@ -78,30 +78,34 @@ func (o DiskCreateOptions) Params() (*api.DiskCreateInput, error) {
|
||||
return params, nil
|
||||
}
|
||||
|
||||
type DiskMigrateOptions struct {
|
||||
ID string `help:"ID of the server" json:"-"`
|
||||
|
||||
TargetStorageId string `help:"Disk migrate target storage id or name" json:"target_storage_id"`
|
||||
type DiskIdOptions struct {
|
||||
ID string `help:"ID or Name of disk"`
|
||||
}
|
||||
|
||||
func (o *DiskMigrateOptions) GetId() string {
|
||||
func (o *DiskIdOptions) GetId() string {
|
||||
return o.ID
|
||||
}
|
||||
|
||||
func (o *DiskIdOptions) Params() (jsonutils.JSONObject, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
type DiskMigrateOptions struct {
|
||||
DiskIdOptions
|
||||
|
||||
TargetStorageId string `help:"Disk migrate target storage id or name" json:"target_storage_id"`
|
||||
}
|
||||
|
||||
func (o *DiskMigrateOptions) Params() (jsonutils.JSONObject, error) {
|
||||
return options.StructToParams(o)
|
||||
}
|
||||
|
||||
type DiskChangeStorageTypeOptions struct {
|
||||
ID string `help:"ID of the server" json:"-"`
|
||||
DiskIdOptions
|
||||
|
||||
StorageType string `help:"Disk migrate target storage type" json:"storage_type"`
|
||||
}
|
||||
|
||||
func (o *DiskChangeStorageTypeOptions) GetId() string {
|
||||
return o.ID
|
||||
}
|
||||
|
||||
func (o *DiskChangeStorageTypeOptions) Params() (jsonutils.JSONObject, error) {
|
||||
return options.StructToParams(o)
|
||||
}
|
||||
@@ -124,7 +128,9 @@ type DiskListOptions struct {
|
||||
|
||||
SnapshotpolicyId string `help:"snapshotpolicy id"`
|
||||
|
||||
StorageHostId string `help:"filter disk by host"`
|
||||
StorageHostId string `help:"filter disk by host"`
|
||||
BindingServerSnapshotpolicy *bool `help:"filter disk by binding server snapshotpolicy" negative:"no-binding-server-snapshotpolicy"`
|
||||
BindingSnapshotpolicy *bool `help:"filter disk by binding snapshotpolicy" negative:"no-binding-snapshotpolicy"`
|
||||
}
|
||||
|
||||
func (opts *DiskListOptions) Params() (jsonutils.JSONObject, error) {
|
||||
@@ -143,14 +149,10 @@ func (opts *DiskListOptions) Params() (jsonutils.JSONObject, error) {
|
||||
}
|
||||
|
||||
type DiskChangeBillingTypeOptions struct {
|
||||
ID string
|
||||
DiskIdOptions
|
||||
BillingType string `choices:"prepaid|postpaid"`
|
||||
}
|
||||
|
||||
func (o *DiskChangeBillingTypeOptions) GetId() string {
|
||||
return o.ID
|
||||
}
|
||||
|
||||
func (o *DiskChangeBillingTypeOptions) Params() (jsonutils.JSONObject, error) {
|
||||
return jsonutils.Marshal(map[string]string{"billing_type": o.BillingType}), nil
|
||||
}
|
||||
|
||||
@@ -79,8 +79,10 @@ type ServerListOptions struct {
|
||||
|
||||
WithUserMeta *bool `help:"filter by user metadata" negative:"without_user_meta"`
|
||||
|
||||
WithHost *bool `help:"filter guest with host or not" negative:"without_host"`
|
||||
SnapshotpolicyId string `help:"filter guest with snapshotpolicy or not" json:"snapshotpolicy_id"`
|
||||
WithHost *bool `help:"filter guest with host or not" negative:"without_host"`
|
||||
SnapshotpolicyId string `help:"filter guest with snapshotpolicy or not" json:"snapshotpolicy_id"`
|
||||
BindingDisksSnapshotpolicy *bool `help:"filter guest with disks binding snapshotpolicy or not" negative:"no-binding-disks-snapshotpolicy" json:"binding_disks_snapshotpolicy"`
|
||||
BindingSnapshotpolicy *bool `help:"filter guest with binding snapshotpolicy or not" negative:"no-binding-snapshotpolicy" json:"binding_snapshotpolicy"`
|
||||
}
|
||||
|
||||
func (o *ServerListOptions) Params() (jsonutils.JSONObject, error) {
|
||||
|
||||
Reference in New Issue
Block a user