Merge pull request #2672 from Mjoycarry/feature/snapshotpolicy_of_disk_sync

local snapshotpolicy
This commit is contained in:
yunion-ci-robot
2019-09-02 16:12:15 +08:00
committed by GitHub
43 changed files with 2449 additions and 825 deletions

View File

@@ -259,33 +259,6 @@ func init() {
printObject(disk)
return nil
})
type DiskApplySnapshotPolicy struct {
ID string `help:"ID or name of disk" json:"-"`
Snapshotpolicy string `help:"ID or name of snapshot policy"`
}
R(&DiskApplySnapshotPolicy{}, "disk-apply-snapshot-policy", "Set disk snapshot policy", func(s *mcclient.ClientSession, args *DiskApplySnapshotPolicy) error {
params, err := options.StructToParams(args)
if err != nil {
return err
}
disk, err := modules.Disks.PerformAction(s, args.ID, "apply-snapshot-policy", params)
if err != nil {
return err
}
printObject(disk)
return nil
})
type DiskCancelSnapshotPolicy struct {
ID string `help:"ID or name of disk"`
}
R(&DiskCancelSnapshotPolicy{}, "disk-cancel-snapshot-policy", "Cancel disk snapshot policy", func(s *mcclient.ClientSession, args *DiskCancelSnapshotPolicy) error {
disk, err := modules.Disks.PerformAction(s, args.ID, "cancel-snapshot-policy", nil)
if err != nil {
return err
}
printObject(disk)
return nil
})
type DiskChangeOwnerOptions struct {
ID string `help:"Disk to change owner" json:"-"`

View File

@@ -16,6 +16,7 @@ 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"
@@ -51,9 +52,7 @@ func init() {
})
type SnapshotPolicyCreateOptions struct {
NAME string
Manager string `help:"Manager id or name"`
Cloudregion string `help:"Cloudregion id or name"`
NAME string
RetentionDays int `help:"snapshot retention days"`
RepeatWeekdays []int `help:"snapshot create days on week"`
@@ -70,21 +69,36 @@ func init() {
return nil
})
type SnapshotPolicyApplyOptions struct {
ID string `help:"ID or Name of SnapshotPolicy" json:"-"`
Disk []string `help:"Disks id to apply snapshot policy"`
type SnapshotPolicyBindDisksOptions struct {
ID string `help:"ID"`
Disk []string `help:"ids of disk"`
}
R(&SnapshotPolicyApplyOptions{}, "snapshot-policy-apply", "Apply snapshot policy to disks", func(s *mcclient.ClientSession, args *SnapshotPolicyApplyOptions) error {
params, err := options.StructToParams(args)
if err != nil {
return err
}
snapshot, err := modules.SnapshotPoliciy.PerformAction(s, args.ID, "apply-to-disk", params)
if err != nil {
return err
}
printObject(snapshot)
return nil
})
R(&SnapshotPolicyBindDisksOptions{}, "snapshot-policy-bind-disk", "bind snapshotpolicy to disks",
func(s *mcclient.ClientSession, opts *SnapshotPolicyBindDisksOptions) error {
params, err := options.StructToParams(opts)
if err != nil {
return err
}
sp, err := modules.SnapshotPoliciy.PerformAction(s, opts.ID, "bind-disks", params)
if err != nil {
return err
}
printObject(sp)
return nil
})
R(&SnapshotPolicyBindDisksOptions{}, "snapshot-policy-unbind-disk", "bind snapshotpolicy to disks",
func(s *mcclient.ClientSession, opts *SnapshotPolicyBindDisksOptions) error {
params, err := options.StructToParams(opts)
if err != nil {
return err
}
sp, err := modules.SnapshotPoliciy.PerformAction(s, opts.ID, "unbind-disks", params)
if err != nil {
return err
}
printObject(sp)
return nil
})
}

View File

@@ -16,6 +16,7 @@ package shell
import (
"yunion.io/x/jsonutils"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/mcclient/modules"
)
@@ -76,5 +77,4 @@ func init() {
return nil
},
)
}

View File

@@ -254,6 +254,21 @@ paths:
/natsentries/{snatentryId}:
$ref: "./natgateway/snatentry.yaml"
/snapshotpolicies:
$ref: "./snapshotpolicy/snapshotpolicies.yaml"
/snapshotpolicies/{snapshotpolicyId}:
$ref: "./snapshotpolicy/snapshotpolicy.yaml"
/disks/{disk_id}/snapshotpolicies:
$ref: "./snapshotpolicy/snapshotpolicydisk.yaml"
/snapshotpolicies/{snapshotpolicy_id}/disks:
$ref: "./snapshotpolicy/snapshotpolicydisk2.yaml"
/disks/{disk_id}/snapshotpolicies/{snapshotpolicy_id}:
$ref: "./snapshotpolicy/snapshotpolicydisk3.yaml"
/snapshotpolicies/{snapshotpolicyId}/bind-disks:
$ref: "./snapshotpolicy/bind-disk.yaml"
/snapshotpolicies/{snapshotpolicyId}/unbind-disks:
$ref: "./snapshotpolicy/unbind-disk.yaml"
/loadbalancers:
$ref: "./loadbalancer/loadbalancers.yaml"
/loadbalancers/{loadbalancerId}:

View File

@@ -0,0 +1,28 @@
snapshotpolicyId:
name: snapshotpolicyId
required: true
in: path
description: 自动快照策略的ID
diskId:
name: diskId
in: path
description: 磁盘的ID
retention_days:
name: retention_days
in: query
type: integer
description: 快照的保存时间(永久保存选-1
repeat_weekdays:
name: repeat_weekdays
in: query
type: array
items:
type: integer
description: 做快照的时间(周几)
time_points:
name: time_points
in: query
type: array
items:
type: integer
description: 做快照的时间(每天几点)

View File

@@ -0,0 +1,189 @@
CanDelete:
type: string
example: true
description: 可否删除
CanUpdate:
type: string
example: false
description: 可否更新
CreatedAt:
type: string
example: 2019-05-30T08:46:12.000000Z
description: 资源创建时间
UpdatedAt:
type: string
example: 2019-05-30T08:46:12.000000Z
description: 资源最近一次更新时间
SnapshotPolicy:
type: object
description: 自动快照策略
properties:
id:
type: string
example: ea27c0ce-5870-49f3-8d57-f53e63f40361
description: 自动快照策略ID
readOnly: true
name:
type: string
description: 自动快照策略名称
example: snapshotpolicy-jo5pskhg
retention_days:
type: integer
example: 10
description: 快照保存的时间(-1为永久保存)
repeat_weekdays:
type: array
items:
type: integer
example: [1, 2]
description: 做快照的时间(每周的周几)
time_points:
type: array
items:
type: integer
example: [2]
description: 做快照的时间(每天的几点)
is_activated:
type: boolean
example: true
description: 是否启用快照策略
binding_disk_count:
type: integer
example: 3
description: 自动快照策略绑定的磁盘数量
can_delete:
$ref: '#/CanDelete'
can_update:
$ref: '#/CanUpdate'
created_at:
$ref: '#/CreatedAt'
updated_at:
$ref: '#/UpdatedAt'
is_emulated:
type: boolean
example: false
description: 是否是虚拟出来的实例
status:
type: string
example: init
description: 状态
update_version:
type: integer
example: 2
description: 资源被更新的次数
SnapshotPolicyCreate:
type: object
properties:
snapshotpolicy:
type: object
required:
- name
- retention_days
- repeat_weekdays
- time_points
- is_activated
properties:
name:
type: string
example: snapshotpolicy-jo5pskhg
description: 自动快照策略名称
retention_days:
type: integer
example: 10
description: 快照保存的时间(-1为永久保存)
repeat_weekdays:
type: array
items:
type: integer
example: [1, 2]
description: 做快照的时间(每周的周几)
time_points:
type: array
items:
type: integer
example: [2]
description: 做快照的时间(每天的几点)
is_activated:
type: boolean
example: true
description: 是否启用快照策略
SnapshotPolicyListResponse:
type: object
properties:
limit:
type: integer
example: 20
total:
type: integer
example: 12
snapshotpolicies:
type: array
items:
$ref: '#/SnapshotPolicy'
SnapshotPolicyResponse:
type: object
properties:
snapshotpolicy:
type: object
$ref: '#/SnapshotPolicy'
SnapshotPolicyDisk:
type: object
properties:
can_delete:
$ref: '#/CanDelete'
can_update:
$ref: '#/CanUpdate'
created_at:
$ref: '#/CreatedAt'
updated_at:
$ref: '#/UpdatedAt'
status:
type: string
example: init
description: 状态
snapshotpolicy_id:
type: string
example: -be8b-4f0f-8885-797930266c6539210785
description: 自动快照策略ID
disk_id:
type: string
example: f7749379-34b1-4219-8835-257615cf34f6
description: 磁盘ID
SnapshotPolicyDiskResponse:
type: object
properties:
snapshotpolicydisk:
type: object
$ref: '#/SnapshotPolicyDisk'
SnapshotPolicyDiskListResponse:
type: object
properties:
total:
type: integer
example: 20
snapshotpolicydisks:
type: array
items:
$ref: '#/SnapshotPolicyDisk'
SnapshotPolicyBindDisk:
type: object
required:
- disk.0
properties:
disk.0:
type: string
example: vv100455-79ef-43a3-8fc3-23adc74b8b87
description: 待绑定的disk的ID
disk.1:
type: string
example: dd100399-79ef-43a3-8fc3-23adc74b8b87
description: 待绑定的disk的ID

View File

@@ -0,0 +1,16 @@
post:
summary: 批量绑定磁盘
parameters:
- $ref: '../parameters/snapshotpolicy.yaml#/snapshotpolicyId'
- in: body
name: disks
required: true
schema:
$ref: '../schemas/snapshotpolicy.yaml#/SnapshotPolicyBindDisk'
responses:
200:
description: 自动快照策略
schema:
$ref: '../schemas/snapshotpolicy.yaml#/SnapshotPolicyResponse'
tags:
- snapshotpolicy

View File

@@ -0,0 +1,32 @@
get:
summary: 按指定条件列出快照策略
parameters:
- $ref: "../parameters/common.yaml#/offset"
- $ref: "../parameters/common.yaml#/limit"
- $ref: "../parameters/snapshotpolicy.yaml#/retention_days"
- $ref: "../parameters/snapshotpolicy.yaml#/repeat_weekdays"
- $ref: "../parameters/snapshotpolicy.yaml#/time_points"
responses:
200:
description: 快照策略列表信息
schema:
$ref: "../schemas/snapshotpolicy.yaml#/SnapshotPolicyListResponse"
tags:
- snapshotpolicy
post:
summary: 创建自动快照策略
parameters:
- in: body
name: snapshotpolicy
required: true
schema:
$ref: '../schemas/snapshotpolicy.yaml#/SnapshotPolicyCreate'
responses:
200:
description: 新建自动快照策略的信息
schema:
$ref: '../schemas/snapshotpolicy.yaml#/SnapshotPolicyResponse'
tags:
- snapshotpolicy

View File

@@ -0,0 +1,22 @@
get:
summary: 获取指定自动快照策略信息
parameters:
- $ref: "../parameters/snapshotpolicy.yaml#/snapshotpolicyId"
responses:
200:
description: 自动快照策略信息
schema:
$ref: "../schemas/snapshotpolicy.yaml#/SnapshotPolicyResponse"
tags:
- snapshotpolicy
delete:
summary: 删除指定自动快照
parameters:
- $ref: '../parameters/snapshotpolicy.yaml#/snapshotpolicyId'
responses:
200:
schema:
$ref: '../schemas/snapshotpolicy.yaml#/SnapshotPolicyResponse'
tags:
- snapshotpolicy

View File

@@ -0,0 +1,11 @@
get:
summary: 列出指定磁盘下所有绑定的自动快照策略
parameters:
- $ref: '../parameters/snapshotpolicy.yaml#/diskId'
responses:
200:
description: 自动快照策略ID列表
schema:
$ref: '../schemas/snapshotpolicy.yaml#/SnapshotPolicyDiskListResponse'
tags:
- snapshotpolicy

View File

@@ -0,0 +1,11 @@
get:
summary: 列出指定自动快照策略所有绑定的磁盘
parameters:
- $ref: '../parameters/snapshotpolicy.yaml#/snapshotpolicyId'
responses:
200:
description: 自动快照策略ID列表
schema:
$ref: '../schemas/snapshotpolicy.yaml#/SnapshotPolicyDiskListResponse'
tags:
- snapshotpolicy

View File

@@ -0,0 +1,23 @@
post:
summary: 绑定指定磁盘和自动快照策略
parameters:
- $ref: '../parameters/snapshotpolicy.yaml#/diskId'
- $ref: '../parameters/snapshotpolicy.yaml#/snapshotpolicyId'
responses:
200:
schema:
$ref: '../schemas/snapshotpolicy.yaml#/SnapshotPolicyDiskResponse'
tags:
- snapshotpolicy
delete:
summary: 解绑指定磁盘和自动快照策略
parameters:
- $ref: '../parameters/snapshotpolicy.yaml#/diskId'
- $ref: '../parameters/snapshotpolicy.yaml#/snapshotpolicyId'
responses:
200:
schema:
$ref: '../schemas/snapshotpolicy.yaml#/SnapshotPolicyDiskResponse'
tags:
- snapshotpolicy

View File

@@ -0,0 +1,16 @@
post:
summary: 批量解绑磁盘
parameters:
- $ref: '../parameters/snapshotpolicy.yaml#/snapshotpolicyId'
- in: body
name: disks
required: true
schema:
$ref: '../schemas/snapshotpolicy.yaml#/SnapshotPolicyBindDisk'
responses:
200:
description: 自动快照策略
schema:
$ref: '../schemas/snapshotpolicy.yaml#/SnapshotPolicyResponse'
tags:
- snapshotpolicy

View File

@@ -41,9 +41,6 @@ type SSnapshotPolicyCreateInput struct {
ProjectId string `json:"project_id"`
DomainId string `json:"domain_id"`
ManagerId string `json:"manager_id"`
CloudregionId string `json:"cloudregion_id"`
RetentionDays int `json:"retention_days"`
RepeatWeekdays []int `json:"repeat_weekdays"`
TimePoints []int `json:"time_points"`
@@ -56,9 +53,6 @@ type SSnapshotPolicyCreateInternalInput struct {
ProjectId string
DomainId string
ManagerId string
CloudregionId string
RetentionDays int
RepeatWeekdays uint8
TimePoints uint32

View File

@@ -26,10 +26,20 @@ const (
SNAPSHOT_DELETING = "deleting"
SNAPSHOT_UNKNOWN = "unknown"
SNAPSHOT_POLICY_CREATING = "creating"
SNAPSHOT_POLICY_CREATING = "creating"
SNAPSHOT_POLICY_READY = "ready"
SNAPSHOT_POLICY_CREATE_FAILED = "create_failed"
SNAPSHOT_POLICY_UPDATING = "updating"
SNAPSHOT_POLICY_UNKNOWN = "unknown"
SNAPSHOT_POLICY_DELETING = "deleting"
SNAPSHOT_POLICY_DELETE_FAILED = "delete_failed"
SNAPSHOT_POLICY_APPLY = "applying"
SNAPSHOT_POLICY_APPLY_FAILED = "apply_failed"
SNAPSHOT_POLICY_CANCEL = "canceling"
SNAPSHOT_POLICY_CANCEL_FAILED = "cancel_failed"
SNAPSHOT_POLICY_DISK_READY = "ready"
SNAPSHOT_POLICY_DISK_DELETING = "deleting"
SNAPSHOT_POLICY_DISK_DELETE_FAILED = "delete_failed"
)

View File

@@ -79,6 +79,7 @@ type ICloudRegion interface {
GetISnapshotById(snapshotId string) (ICloudSnapshot, error)
CreateSnapshotPolicy(*SnapshotPolicyInput) (string, error)
UpdateSnapshotPolicy(*SnapshotPolicyInput, string) error
DeleteSnapshotPolicy(string) error
ApplySnapshotPolicyToDisks(snapshotPolicyId string, diskId string) error
CancelSnapshotPolicyToDisks(snapshotPolicyId string, diskId string) error
@@ -373,7 +374,7 @@ type ICloudDisk interface {
GetISnapshot(idStr string) (ICloudSnapshot, error)
GetISnapshots() ([]ICloudSnapshot, error)
GetExtSnapshotPolicyIds() []string
GetExtSnapshotPolicyIds() ([]string, error)
Resize(ctx context.Context, newSizeMB int64) error
Reset(ctx context.Context, snapshotId string) (string, error)

View File

@@ -24,6 +24,7 @@ import (
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/tristate"
"yunion.io/x/pkg/util/compare"
"yunion.io/x/pkg/util/fileutils"
@@ -340,6 +341,14 @@ func (self *SDisk) GetRuningGuestCount() (int, error) {
Filter(sqlchemy.Equals(guests.Field("status"), api.VM_RUNNING)).CountWithError()
}
func (self *SDisk) DetachAfterDelete(ctx context.Context, userCred mcclient.TokenCredential) error {
err := SnapshotPolicyDiskManager.SyncDetachByDisk(ctx, userCred, nil, self)
if err != nil {
return errors.Wrap(err, "detach after delete failed")
}
return nil
}
func (self *SDisk) CustomizeCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
input := new(api.DiskCreateInput)
if err := data.Unmarshal(input); err != nil {
@@ -1191,7 +1200,11 @@ func (self *SDisk) syncRemoveCloudDisk(ctx context.Context, userCred mcclient.To
self.SetStatus(userCred, api.DISK_UNKNOWN, "missing original disk after sync")
return err
}
// todo detach joint modle about snapshotpolicy and disk
// detach joint modle aboutsnapshotpolicy and disk
err = SnapshotPolicyDiskManager.SyncDetachByDisk(ctx, userCred, nil, self)
if err != nil {
return err
}
return self.RealDelete(ctx, userCred)
}
@@ -1238,8 +1251,6 @@ func (self *SDisk) syncWithCloudDisk(ctx context.Context, userCred mcclient.Toke
self.CreatedAt = createdAt
}
// todo sync disk's snapshotpolicy
return nil
})
if err != nil {
@@ -1247,6 +1258,15 @@ func (self *SDisk) syncWithCloudDisk(ctx context.Context, userCred mcclient.Toke
return err
}
// sync disk's snapshotpolicy
snapshotpolicies, err := extDisk.GetExtSnapshotPolicyIds()
if err != nil {
return errors.Wrapf(err, "Get snapshot policies of ICloudDisk %s.", extDisk.GetId())
}
err = SnapshotPolicyDiskManager.SyncByDisk(ctx, userCred, snapshotpolicies, syncOwnerId, self, storage)
if err != nil {
return err
}
db.OpsLog.LogSyncUpdate(self, diff, userCred)
SyncCloudProject(userCred, self, syncOwnerId, extDisk, storage.ManagerId)
@@ -1287,14 +1307,22 @@ func (manager *SDiskManager) newFromCloudDisk(ctx context.Context, userCred mccl
disk.CreatedAt = createAt
}
// todo create new joint model about snapshotpolicy and disk
err = manager.TableSpec().Insert(&disk)
if err != nil {
log.Errorf("newFromCloudZone fail %s", err)
return nil, err
}
// create new joint model aboutsnapshotpolicy and disk
snapshotpolicies, err := extDisk.GetExtSnapshotPolicyIds()
if err != nil {
return nil, errors.Wrapf(err, "Get snapshot policies of ICloudDisk %s.", extDisk.GetId())
}
err = SnapshotPolicyDiskManager.SyncAttachDiskExt(ctx, userCred, snapshotpolicies, syncOwnerId, &disk, storage)
if err != nil {
return nil, err
}
SyncCloudProject(userCred, &disk, syncOwnerId, extDisk, storage.ManagerId)
db.OpsLog.LogEvent(&disk, db.ACT_CREATE, disk.GetShortDesc(ctx), userCred)
@@ -1544,7 +1572,12 @@ func (self *SDisk) RealDelete(ctx context.Context, userCred mcclient.TokenCreden
guestdisk.Detach(ctx, userCred)
}
}
return self.SSharableVirtualResourceBase.Delete(ctx, userCred)
err := self.SSharableVirtualResourceBase.Delete(ctx, userCred)
if err != nil {
return err
}
return self.DetachAfterDelete(ctx, userCred)
}
func (self *SDisk) AllowPerformPurge(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
@@ -1587,7 +1620,9 @@ func (self *SDisk) CustomizeDelete(ctx context.Context, userCred mcclient.TokenC
jsonutils.QueryBoolean(query, "override_pending_delete", false))
}
func (self *SDisk) getMoreDetails(extra *jsonutils.JSONDict) *jsonutils.JSONDict {
func (self *SDisk) getMoreDetails(ctx context.Context, userCred mcclient.TokenCredential,
extra *jsonutils.JSONDict) *jsonutils.
JSONDict {
if cloudprovider := self.GetCloudprovider(); cloudprovider != nil {
extra.Add(jsonutils.NewString(cloudprovider.Provider), "provider")
}
@@ -1623,6 +1658,39 @@ func (self *SDisk) getMoreDetails(extra *jsonutils.JSONDict) *jsonutils.JSONDict
pendingDeletedAt := self.PendingDeletedAt.Add(time.Second * time.Duration(options.Options.PendingDeleteExpireSeconds))
extra.Add(jsonutils.NewString(timeutils.FullIsoTime(pendingDeletedAt)), "auto_delete_at")
}
// the binded snapshot policy list
sds, err := SnapshotPolicyDiskManager.FetchAllByDiskID(ctx, userCred, self.Id)
if err != nil {
return extra
}
spIds := make([]string, len(sds))
for i := range sds {
spIds[i] = sds[i].SnapshotpolicyId
}
sps, err := SnapshotPolicyManager.FetchAllByIds(spIds)
if err != nil {
return extra
}
if len(sps) == 0 {
extra.Add(jsonutils.NewString(""), "snapshotpolicy_status")
} else {
extra.Add(jsonutils.NewString(sds[0].Status), "snapshotpolicy_status")
}
// check status
// construction for snapshotpolicies attached to disk
snapshotpoliciesJson := jsonutils.NewArray()
for i := range sps {
spsJson := jsonutils.Marshal(sps[i])
spsDict := spsJson.(*jsonutils.JSONDict)
repeatWeekdays := SnapshotPolicyManager.RepeatWeekdaysToIntArray(sps[i].RepeatWeekdays)
timePoints := SnapshotPolicyManager.TimePointsToIntArray(sps[i].TimePoints)
spsDict.Remove("repeat_weekdays")
spsDict.Remove("time_points")
spsDict.Add(jsonutils.Marshal(repeatWeekdays), "repeat_weekdays")
spsDict.Add(jsonutils.Marshal(timePoints), "time_points")
snapshotpoliciesJson.Add(spsDict)
}
extra.Add(snapshotpoliciesJson, "snapshotpolicies")
return extra
}
@@ -1631,12 +1699,12 @@ func (self *SDisk) GetExtraDetails(ctx context.Context, userCred mcclient.TokenC
if err != nil {
return nil, err
}
return self.getMoreDetails(extra), nil
return self.getMoreDetails(ctx, userCred, extra), nil
}
func (self *SDisk) GetCustomizeColumns(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) *jsonutils.JSONDict {
extra := self.SSharableVirtualResourceBase.GetCustomizeColumns(ctx, userCred, query)
return self.getMoreDetails(extra)
return self.getMoreDetails(ctx, userCred, extra)
}
func (self *SDisk) StartDiskResizeTask(ctx context.Context, userCred mcclient.TokenCredential, sizeMb int64, parentTaskId string, pendingUsage quotas.IQuota) error {

View File

@@ -625,14 +625,16 @@ func (snapshot *SSnapshot) purge(ctx context.Context, userCred mcclient.TokenCre
return snapshot.RealDelete(ctx, userCred)
}
func (manager *SSnapshotPolicyManager) purgeAll(ctx context.Context, userCred mcclient.TokenCredential, providerId string) error {
sps := make([]SSnapshotPolicy, 0)
err := fetchByManagerId(manager, providerId, &sps)
func (manager *SSnapshotPolicyCacheManager) purgeAll(ctx context.Context, userCred mcclient.TokenCredential,
providerId string) error {
// delete snapshot policy cache belong to manager
spCaches := make([]SSnapshotPolicyCache, 0)
err := fetchByManagerId(SnapshotPolicyCacheManager, providerId, &spCaches)
if err != nil {
return err
}
for i := range sps {
err := sps[i].purge(ctx, userCred)
for i := range spCaches {
err := spCaches[i].purge(ctx, userCred)
if err != nil {
return err
}
@@ -640,15 +642,19 @@ func (manager *SSnapshotPolicyManager) purgeAll(ctx context.Context, userCred mc
return nil
}
func (sp *SSnapshotPolicy) purge(ctx context.Context, userCred mcclient.TokenCredential) error {
lockman.LockObject(ctx, sp)
defer lockman.ReleaseObject(ctx, sp)
err := sp.ValidateDeleteCondition(ctx)
func (spc *SSnapshotPolicyCache) purge(ctx context.Context, userCred mcclient.TokenCredential) error {
lockman.LockObject(ctx, spc)
defer lockman.LockObject(ctx, spc)
err := spc.ValidateDeleteCondition(ctx)
if err != nil {
return err
}
return sp.RealDelete(ctx, userCred)
return spc.RealDetele(ctx, userCred)
}
func (manager *SSnapshotPolicyManager) purgeAll(ctx context.Context, userCred mcclient.TokenCredential, providerId string) error {
// delete snapshot policy cache belong to manager
return SnapshotPolicyCacheManager.purgeAll(ctx, userCred, providerId)
}
func (manager *SStoragecacheManager) purgeAll(ctx context.Context, userCred mcclient.TokenCredential, providerId string) error {

View File

@@ -20,7 +20,6 @@ import (
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/cloudprovider"
@@ -79,12 +78,14 @@ type IRegionDriver interface {
ValidateCreateEipData(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error)
// Region Driver Snapshot Policy Apis
ValidateCreateSnapshotPolicyData(context.Context, mcclient.TokenCredential, *compute.SSnapshotPolicyCreateInput, mcclient.IIdentityProvider, *jsonutils.JSONDict) error
RequestCreateSnapshotPolicy(ctx context.Context, userCred mcclient.TokenCredential, sp *SSnapshotPolicy, task taskman.ITask) error
RequestDeleteSnapshotPolicy(ctx context.Context, userCred mcclient.TokenCredential, sp *SSnapshotPolicy, task taskman.ITask) error
//ValidateCreateSnapshotPolicyData(context.Context, mcclient.TokenCredential, *compute.SSnapshotPolicyCreateInput, mcclient.IIdentityProvider, *jsonutils.JSONDict) error
RequestUpdateSnapshotPolicy(ctx context.Context, userCred mcclient.TokenCredential, sp *SSnapshotPolicy, input cloudprovider.SnapshotPolicyInput, task taskman.ITask) error
RequestApplySnapshotPolicy(ctx context.Context, userCred mcclient.TokenCredential, task taskman.ITask, disk *SDisk, sp *SSnapshotPolicy, data jsonutils.JSONObject) error
RequestCancelSnapshotPolicy(ctx context.Context, userCred mcclient.TokenCredential, task taskman.ITask, disk *SDisk, sp *SSnapshotPolicy, data jsonutils.JSONObject) error
RequestPreSnapshotPolicyApply(ctx context.Context, userCred mcclient.TokenCredential, task taskman.ITask, disk *SDisk, sp *SSnapshotPolicy, data jsonutils.JSONObject) error
// Region Driver Snapshot Policy joint Disk Apis
ValidateCreateSnapshopolicyDiskData(ctx context.Context, userCred mcclient.TokenCredential, diskID string) error
ValidateCreateSnapshopolicyDiskData(ctx context.Context, userCred mcclient.TokenCredential, disk *SDisk, snapshotPolicy *SSnapshotPolicy) error
// Region Driver Snapshot Apis
ValidateSnapshotDelete(ctx context.Context, snapshot *SSnapshot) error
@@ -94,8 +95,6 @@ type IRegionDriver interface {
SnapshotIsOutOfChain(disk *SDisk) bool
GetDiskResetParams(snapshot *SSnapshot) *jsonutils.JSONDict
OnDiskReset(ctx context.Context, userCred mcclient.TokenCredential, disk *SDisk, snapshot *SSnapshot, data jsonutils.JSONObject) error
RequestApplySnapshotPolicy(ctx context.Context, userCred mcclient.TokenCredential, sp *SSnapshotPolicy, task taskman.ITask, diskId string) error
RequestCancelSnapshotPolicy(ctx context.Context, userCred mcclient.TokenCredential, sp *SSnapshotPolicy, task taskman.ITask, diskId string) error
OnSnapshotDelete(ctx context.Context, snapshot *SSnapshot, task taskman.ITask, data jsonutils.JSONObject) error
//Nat gateway

View File

@@ -17,23 +17,23 @@ package models
import (
"context"
"fmt"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/tristate"
"yunion.io/x/pkg/util/compare"
"yunion.io/x/pkg/utils"
"yunion.io/x/sqlchemy"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/cloudcommon/validators"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/compute/options"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/util/bitmap"
"yunion.io/x/onecloud/pkg/util/validate"
)
type SSnapshotPolicyManager struct {
@@ -42,10 +42,10 @@ type SSnapshotPolicyManager struct {
type SSnapshotPolicy struct {
db.SVirtualResourceBase
db.SExternalizedResourceBase
SManagedResourceBase
SCloudregionResourceBase
//db.SExternalizedResourceBase
//
//SManagedResourceBase
//SCloudregionResourceBase
RetentionDays int `nullable:"false" list:"user" get:"user" create:"required"`
@@ -70,360 +70,36 @@ func init() {
SnapshotPolicyManager.SetVirtualObject(SnapshotPolicyManager)
}
func (manager *SSnapshotPolicyManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
func (manager *SSnapshotPolicyManager) ValidateListConditions(ctx context.Context, userCred mcclient.TokenCredential,
query *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
input := &api.SSnapshotPolicyCreateInput{}
err := data.Unmarshal(input)
err := query.Unmarshal(input)
if err != nil {
return nil, httperrors.NewInputParameterError("Unmarshal input failed %s", err)
}
input.ProjectId = ownerId.GetProjectId()
input.DomainId = ownerId.GetProjectDomainId()
err = db.NewNameValidator(manager, ownerId, input.Name)
if err != nil {
return nil, err
if query.Contains("repeat_weekdays") {
query.Remove("repeat_weekdays")
query.Add(jsonutils.NewInt(int64(manager.RepeatWeekdaysParseIntArray(input.RepeatWeekdays))), "repeat_weekdays")
}
cloudregionV := validators.NewModelIdOrNameValidator("cloudregion", "cloudregion", ownerId)
err = cloudregionV.Validate(data)
if err != nil {
return nil, err
if query.Contains("time_points") {
query.Remove("time_points")
query.Add(jsonutils.NewInt(int64(manager.RepeatWeekdaysParseIntArray(input.RepeatWeekdays))), "time_points")
}
cloudregion := cloudregionV.Model.(*SCloudregion)
input.CloudregionId = cloudregion.GetId()
err = cloudregion.GetDriver().ValidateCreateSnapshotPolicyData(ctx, userCred, input, ownerId, data)
if err != nil {
return nil, err
}
internalInput := manager.sSnapshotPolicyCreateInputToInternal(input)
data = internalInput.JSON(internalInput)
return data, nil
return query, nil
}
func (manager *SSnapshotPolicyManager) sSnapshotPolicyCreateInputToInternal(input *api.SSnapshotPolicyCreateInput) *api.SSnapshotPolicyCreateInternalInput {
ret := api.SSnapshotPolicyCreateInternalInput{
Meta: input.Meta,
Name: input.Name,
ProjectId: input.ProjectId,
DomainId: input.DomainId,
ManagerId: input.ManagerId,
CloudregionId: input.CloudregionId,
RetentionDays: input.RetentionDays,
}
ret.RepeatWeekdays = manager.RepeatWeekdaysParseIntArray(input.RepeatWeekdays)
ret.TimePoints = manager.TimePointsParseIntArray(input.TimePoints)
return &ret
}
func (manager *SSnapshotPolicyManager) sSnapshotPolicyCreateInputFromInternal(input *api.SSnapshotPolicyCreateInternalInput) *api.SSnapshotPolicyCreateInput {
return nil
}
func (self *SSnapshotPolicy) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) {
self.StartCreateSnapshotPolicy(ctx, userCred, ownerId, query, data)
}
func (self *SSnapshotPolicy) StartCreateSnapshotPolicy(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
if task, err := taskman.TaskManager.NewTask(ctx, "SnapshotPolicyCreateTask", self, userCred, nil, "", "", nil); err != nil {
return err
} else {
task.ScheduleRun(nil)
}
return nil
}
func (self *SSnapshotPolicy) CustomizeDelete(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
self.SetStatus(userCred, api.SNAPSHOT_POLICY_DELETING, "")
return self.StartSnapshotPolicyDeleteTask(ctx, userCred, jsonutils.NewDict(), "")
}
func (self *SSnapshotPolicy) StartSnapshotPolicyDeleteTask(ctx context.Context, userCred mcclient.TokenCredential, params *jsonutils.JSONDict, parentTaskId string) error {
task, err := taskman.TaskManager.NewTask(ctx, "SnapshotPolicyDeleteTask", self, userCred, params, parentTaskId, "", nil)
if err != nil {
return err
}
task.ScheduleRun(nil)
return nil
}
func (self *SSnapshotPolicy) GetCustomizeColumns(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) *jsonutils.JSONDict {
ret := self.SCloudregionResourceBase.GetCustomizeColumns(ctx, userCred, query)
ret.Update(self.SVirtualResourceBase.GetCustomizeColumns(ctx, userCred, query))
// more
weekdays := SnapshotPolicyManager.RepeatWeekdaysToIntArray(self.RepeatWeekdays)
timePoints := SnapshotPolicyManager.TimePointsToIntArray(self.TimePoints)
ret.Add(jsonutils.Marshal(weekdays), "repeat_weekdays")
ret.Add(jsonutils.Marshal(timePoints), "time_points")
return ret
}
func (self *SSnapshotPolicy) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (*jsonutils.JSONDict, error) {
ret := jsonutils.NewDict()
// more
weekdays := SnapshotPolicyManager.RepeatWeekdaysToIntArray(self.RepeatWeekdays)
timePoints := SnapshotPolicyManager.TimePointsToIntArray(self.TimePoints)
ret.Add(jsonutils.Marshal(weekdays), "repeat_weekdays")
ret.Add(jsonutils.Marshal(timePoints), "time_points")
return ret, nil
}
func (self *SSnapshotPolicy) GetIRegion() (cloudprovider.ICloudRegion, error) {
provider, err := self.GetDriver()
if err != nil {
return nil, fmt.Errorf("No cloudprovider for sp %s: %s", self.Name, err)
}
region := self.GetRegion()
if region == nil {
return nil, fmt.Errorf("failed to find region for sp %s", self.Name)
}
return provider.GetIRegionById(region.ExternalId)
}
func (self *SSnapshotPolicyManager) RepeatWeekdaysParseIntArray(nums []int) uint8 {
return uint8(bitmap.IntArray2Uint(nums))
}
func (self *SSnapshotPolicyManager) RepeatWeekdaysToIntArray(n uint8) []int {
return bitmap.Uint2IntArray(uint32(n))
}
func (self *SSnapshotPolicyManager) TimePointsParseIntArray(nums []int) uint32 {
return bitmap.IntArray2Uint(nums)
}
func (self *SSnapshotPolicyManager) TimePointsToIntArray(n uint32) []int {
return bitmap.Uint2IntArray(n)
}
func (self *SSnapshotPolicy) GenerateCreateSpParams() (*cloudprovider.SnapshotPolicyInput, error) {
intWeekdays := SnapshotPolicyManager.RepeatWeekdaysToIntArray(self.RepeatWeekdays)
intTimePoints := SnapshotPolicyManager.TimePointsToIntArray(self.TimePoints)
return &cloudprovider.SnapshotPolicyInput{
RetentionDays: self.RetentionDays,
RepeatWeekdays: intWeekdays,
TimePoints: intTimePoints,
PolicyName: self.Name,
}, nil
}
func (manager *SSnapshotPolicyManager) SyncSnapshotPolicies(ctx context.Context, userCred mcclient.TokenCredential, provider *SCloudprovider, region *SCloudregion, snapshots []cloudprovider.ICloudSnapshotPolicy, syncOwnerId mcclient.IIdentityProvider) compare.SyncResult {
lockman.LockClass(ctx, manager, db.GetLockClassKey(manager, syncOwnerId))
defer lockman.ReleaseClass(ctx, manager, db.GetLockClassKey(manager, syncOwnerId))
syncResult := compare.SyncResult{}
dbSnapshotPolicies, err := manager.getProviderSnapshotPolicies(region, provider)
if err != nil {
syncResult.Error(err)
return syncResult
}
removed := make([]SSnapshotPolicy, 0)
commondb := make([]SSnapshotPolicy, 0)
commonext := make([]cloudprovider.ICloudSnapshotPolicy, 0)
added := make([]cloudprovider.ICloudSnapshotPolicy, 0)
err = compare.CompareSets(dbSnapshotPolicies, snapshots, &removed, &commondb, &commonext, &added)
if err != nil {
syncResult.Error(err)
return syncResult
}
for i := 0; i < len(removed); i += 1 {
err = removed[i].syncRemoveCloudSnapshot(ctx, userCred)
if err != nil {
syncResult.DeleteError(err)
} else {
syncResult.Delete()
}
}
for i := 0; i < len(commondb); i += 1 {
err = commondb[i].SyncWithCloudSnapshotPolicy(ctx, userCred, commonext[i], syncOwnerId, region)
if err != nil {
syncResult.UpdateError(err)
} else {
syncMetadata(ctx, userCred, &commondb[i], commonext[i])
syncResult.Update()
}
}
for i := 0; i < len(added); i += 1 {
local, err := manager.newFromCloudSnapshotPolicy(ctx, userCred, added[i], region, syncOwnerId, provider)
if err != nil {
syncResult.AddError(err)
} else {
syncMetadata(ctx, userCred, local, added[i])
syncResult.Add()
}
}
return syncResult
}
func (manager *SSnapshotPolicyManager) getProviderSnapshotPolicies(region *SCloudregion, provider *SCloudprovider) ([]SSnapshotPolicy, error) {
if region == nil || provider == nil {
return nil, fmt.Errorf("Region is nil or provider is nil")
}
snapshotPolicies := make([]SSnapshotPolicy, 0)
q := manager.Query().Equals("cloudregion_id", region.Id).Equals("manager_id", provider.Id)
err := db.FetchModelObjects(manager, q, &snapshotPolicies)
if err != nil {
return nil, err
}
return snapshotPolicies, nil
}
func (self *SSnapshotPolicy) syncRemoveCloudSnapshot(ctx context.Context, userCred mcclient.TokenCredential) error {
lockman.LockObject(ctx, self)
defer lockman.ReleaseObject(ctx, self)
err := self.ValidateDeleteCondition(ctx)
if err != nil {
err = self.SetStatus(userCred, api.SNAPSHOT_POLICY_UNKNOWN, "sync to delete")
} else {
err = self.RealDelete(ctx, userCred)
}
return err
}
func (self *SSnapshotPolicy) RealDelete(ctx context.Context, userCred mcclient.TokenCredential) error {
return db.DeleteModel(ctx, userCred, self)
}
func (self *SSnapshotPolicy) SyncWithCloudSnapshotPolicy(ctx context.Context, userCred mcclient.TokenCredential, ext cloudprovider.ICloudSnapshotPolicy, ownerId mcclient.IIdentityProvider, region *SCloudregion) error {
diff, err := db.UpdateWithLock(ctx, self, func() error {
self.Name = ext.GetName()
self.Status = ext.GetStatus()
self.RetentionDays = ext.GetRetentionDays()
arw, err := ext.GetRepeatWeekdays()
if err != nil {
return err
}
self.RepeatWeekdays = SnapshotPolicyManager.RepeatWeekdaysParseIntArray(arw)
atp, err := ext.GetTimePoints()
if err != nil {
return err
}
self.TimePoints = SnapshotPolicyManager.TimePointsParseIntArray(atp)
return nil
})
db.OpsLog.LogSyncUpdate(self, diff, userCred)
SyncCloudProject(userCred, self, ownerId, ext, self.ManagerId)
return err
}
func (manager *SSnapshotPolicyManager) newFromCloudSnapshotPolicy(
ctx context.Context, userCred mcclient.TokenCredential,
ext cloudprovider.ICloudSnapshotPolicy, region *SCloudregion,
syncOwnerId mcclient.IIdentityProvider, provider *SCloudprovider,
) (*SSnapshotPolicy, error) {
snapshotPolicy := SSnapshotPolicy{}
snapshotPolicy.SetModelManager(manager, &snapshotPolicy)
newName, err := db.GenerateName(manager, syncOwnerId, ext.GetName())
if err != nil {
return nil, err
}
snapshotPolicy.Name = newName
snapshotPolicy.Status = ext.GetStatus()
snapshotPolicy.ExternalId = ext.GetGlobalId()
snapshotPolicy.ManagerId = provider.Id
snapshotPolicy.CloudregionId = region.Id
snapshotPolicy.RetentionDays = ext.GetRetentionDays()
arw, err := ext.GetRepeatWeekdays()
if err != nil {
return nil, err
}
snapshotPolicy.RepeatWeekdays = SnapshotPolicyManager.RepeatWeekdaysParseIntArray(arw)
atp, err := ext.GetTimePoints()
if err != nil {
return nil, err
}
snapshotPolicy.TimePoints = SnapshotPolicyManager.TimePointsParseIntArray(atp)
err = manager.TableSpec().Insert(&snapshotPolicy)
if err != nil {
log.Errorf("newFromCloudEip fail %s", err)
return nil, err
}
SyncCloudProject(userCred, &snapshotPolicy, syncOwnerId, ext, snapshotPolicy.ManagerId)
db.OpsLog.LogEvent(&snapshotPolicy, db.ACT_CREATE, snapshotPolicy.GetShortDesc(ctx), userCred)
return &snapshotPolicy, nil
}
func (self *SSnapshotPolicy) AllowPerformApplyToDisks(ctx context.Context,
userCred mcclient.TokenCredential,
query jsonutils.JSONObject,
data jsonutils.JSONObject) bool {
return self.IsOwner(userCred) || db.IsAdminAllowPerform(userCred, self, "apply-to-disks")
}
func (self *SSnapshotPolicy) PerformApplyToDisks(
ctx context.Context, userCred mcclient.TokenCredential,
query jsonutils.JSONObject, data jsonutils.JSONObject,
) (jsonutils.JSONObject, error) {
diskIds, err := self.preCheck(ctx, userCred, query, data)
if err != nil {
return nil, err
}
return nil, self.StartApplySnapshotPolicyToDisks(ctx, userCred, diskIds)
}
func (self *SSnapshotPolicy) StartApplySnapshotPolicyToDisks(ctx context.Context, userCred mcclient.TokenCredential, diskIds []string) error {
params := jsonutils.NewDict()
params.Set("disk_ids", jsonutils.Marshal(diskIds))
if task, err := taskman.TaskManager.NewTask(ctx, "SnapshotPolicyApplyTask", self, userCred, params, "", "", nil); err != nil {
return err
} else {
task.ScheduleRun(nil)
}
return nil
}
func (self *SSnapshotPolicy) preCheck(
ctx context.Context, userCred mcclient.TokenCredential,
query jsonutils.JSONObject, data jsonutils.JSONObject,
) ([]string, error) {
if self.Status != api.SNAPSHOT_POLICY_READY {
return nil, httperrors.NewInvalidStatusError("Snapshot policy status %s can't do apply", self.Status)
}
jsonDiskIds, err := data.Get("disks")
if err != nil {
return nil, httperrors.NewMissingParameterError("disks")
}
ids, ok := jsonDiskIds.(*jsonutils.JSONArray)
if !ok {
return nil, httperrors.NewInputParameterError("disk_ids %s", jsonDiskIds)
}
diskIds := ids.GetStringArray()
disks := make([]string, 0)
err = DiskManager.Query("id").Equals("cloudregion_id", self.CloudregionId).
Equals("manager_id", self.ManagerId).In("id", diskIds).All(&disks)
if err != nil {
return nil, httperrors.NewInternalServerError("Query disks error %s", err)
}
if len(disks) < len(diskIds) {
notFoundDisks := make([]string, 0)
for _, id := range diskIds {
if !utils.IsInStringArray(id, disks) {
notFoundDisks = append(notFoundDisks, id)
}
}
return nil, httperrors.NewNotFoundError("Disks %v not found", notFoundDisks)
}
return diskIds, nil
func (sp *SSnapshotPolicy) AllowUpdateItem(ctx context.Context, userCred mcclient.TokenCredential) bool {
return false
}
// ==================================================== fetch ==========================================================
func (manager *SSnapshotPolicyManager) GetSnapshotPoliciesAt(week, timePoint uint32) ([]string, error) {
q := manager.Query("id")
q = q.Filter(sqlchemy.Equals(sqlchemy.AND_Val("", q.Field("repeat_weekdays"), 1<<week), 1<<week))
q = q.Filter(sqlchemy.Equals(sqlchemy.AND_Val("", q.Field("time_points"), 1<<timePoint), 1<<timePoint))
q = q.Equals("is_activated", true)
q.DebugQuery()
sps := make([]SSnapshotPolicy, 0)
err := q.All(&sps)
@@ -448,3 +124,560 @@ func (manager *SSnapshotPolicyManager) FetchSnapshotPolicyById(spId string) *SSn
}
return sp.(*SSnapshotPolicy)
}
func (manager *SSnapshotPolicyManager) FetchAllByIds(spIds []string) ([]SSnapshotPolicy, error) {
if spIds == nil || len(spIds) == 0 {
return []SSnapshotPolicy{}, nil
}
q := manager.Query().In("id", spIds)
sps := make([]SSnapshotPolicy, 0, 1)
err := db.FetchModelObjects(manager, q, &sps)
if err != nil {
return nil, err
}
return sps, nil
}
// ==================================================== create =========================================================
func (manager *SSnapshotPolicyManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential,
ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
input := &api.SSnapshotPolicyCreateInput{}
err := data.Unmarshal(input)
if err != nil {
return nil, httperrors.NewInputParameterError("Unmarshal input failed %s", err)
}
input.ProjectId = ownerId.GetProjectId()
input.DomainId = ownerId.GetProjectDomainId()
err = db.NewNameValidator(manager, ownerId, input.Name)
if err != nil {
return nil, err
}
if input.RetentionDays < -1 || input.RetentionDays == 0 || input.RetentionDays > options.Options.RetentionDaysLimit {
return nil, httperrors.NewInputParameterError("Retention days must in 1~%d or -1", options.Options.RetentionDaysLimit)
}
if len(input.RepeatWeekdays) == 0 {
return nil, httperrors.NewMissingParameterError("repeat_weekdays")
}
if len(input.RepeatWeekdays) > options.Options.RepeatWeekdaysLimit {
return nil, httperrors.NewInputParameterError("repeat_weekdays only contains %d days at most",
options.Options.RepeatWeekdaysLimit)
}
input.RepeatWeekdays, err = validate.DaysCheck(input.RepeatWeekdays, 1, 7)
if err != nil {
return nil, httperrors.NewInputParameterError(err.Error())
}
if len(input.TimePoints) == 0 {
return nil, httperrors.NewMissingParameterError("time_points")
}
if len(input.TimePoints) > options.Options.TimePointsLimit {
return nil, httperrors.NewInputParameterError("time_points only contains %d points at most", options.Options.TimePointsLimit)
}
input.TimePoints, err = validate.DaysCheck(input.TimePoints, 0, 23)
if err != nil {
return nil, httperrors.NewInputParameterError(err.Error())
}
internalInput := manager.sSnapshotPolicyCreateInputToInternal(input)
data = internalInput.JSON(internalInput)
return data, nil
}
// ==================================================== update =========================================================
func (self *SSnapshotPolicy) AllowPerformUpdate(ctx context.Context, userCred mcclient.TokenCredential,
query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
// no fo now
return false
//return self.IsOwner(userCred) || db.IsAdminAllowPerform(userCred, self, "update")
}
func (self *SSnapshotPolicy) PerformUpdate(ctx context.Context, userCred mcclient.TokenCredential,
query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
//check param
input := &api.SSnapshotPolicyCreateInput{}
err := data.Unmarshal(input)
if err != nil {
return nil, httperrors.NewInputParameterError("Unmarshel input failed %s", err)
}
err = self.UpdateParamCheck(input)
if err != nil {
return nil, err
}
return nil, self.StartSnapshotPolicyUpdateTask(ctx, userCred, input)
}
func (self *SSnapshotPolicy) StartSnapshotPolicyUpdateTask(ctx context.Context, userCred mcclient.TokenCredential,
input *api.SSnapshotPolicyCreateInput) error {
params := jsonutils.NewDict()
params.Add(jsonutils.Marshal(input), "input")
self.SetStatus(userCred, api.SNAPSHOT_POLICY_UPDATING, "")
if task, err := taskman.TaskManager.NewTask(ctx, "SnapshotPolicyUpdateTask", self, userCred, params,
"", "", nil); err == nil {
return err
} else {
task.ScheduleRun(nil)
}
return nil
}
// UpdateParamCheck check if update parameters are correct and need to update
func (self *SSnapshotPolicy) UpdateParamCheck(input *api.SSnapshotPolicyCreateInput) error {
var err error
updateNum := 0
if input.RetentionDays != 0 {
if input.RetentionDays < -1 || input.RetentionDays > 65535 {
return httperrors.NewInputParameterError("Retention days must in 1~65535 or -1")
}
if input.RetentionDays != self.RetentionDays {
updateNum++
}
}
if input.RepeatWeekdays != nil && len(input.RepeatWeekdays) != 0 {
input.RepeatWeekdays, err = validate.DaysCheck(input.RepeatWeekdays, 1, 7)
if err != nil {
return httperrors.NewInputParameterError(err.Error())
}
if self.RepeatWeekdays != SnapshotPolicyManager.RepeatWeekdaysParseIntArray(input.RepeatWeekdays) {
updateNum++
}
}
if input.TimePoints != nil && len(input.TimePoints) != 0 {
input.TimePoints, err = validate.DaysCheck(input.TimePoints, 0, 23)
if err != nil {
return httperrors.NewInputParameterError(err.Error())
}
if self.TimePoints != SnapshotPolicyManager.TimePointsParseIntArray(input.TimePoints) {
updateNum++
}
}
if updateNum == 0 {
return httperrors.NewInputParameterError("Do not need to update")
}
return nil
}
// ==================================================== delete =========================================================
func (self *SSnapshotPolicy) DetachAfterDelete(ctx context.Context, userCred mcclient.TokenCredential) error {
err := SnapshotPolicyDiskManager.SyncDetachBySnapshotpolicy(ctx, userCred, nil, self)
if err != nil {
return errors.Wrap(err, "detach after delete failed")
}
return nil
}
func (self *SSnapshotPolicy) CustomizeDelete(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.
JSONObject, data jsonutils.JSONObject) error {
// check if self bind to some disks
sds, err := SnapshotPolicyDiskManager.FetchAllBySnapshotpolicyID(ctx, userCred, self.GetId())
if err != nil {
return errors.Wrap(err, "fetch bind info failed")
}
if len(sds) != 0 {
return httperrors.NewBadRequestError("Couldn't delete snapshot policy binding to disks")
}
self.SetStatus(userCred, api.SNAPSHOT_POLICY_DELETING, "")
return self.StartSnapshotPolicyDeleteTask(ctx, userCred, jsonutils.NewDict(), "")
}
func (self *SSnapshotPolicy) StartSnapshotPolicyDeleteTask(ctx context.Context, userCred mcclient.TokenCredential,
params *jsonutils.JSONDict, parentTaskId string) error {
task, err := taskman.TaskManager.NewTask(ctx, "SnapshotPolicyDeleteTask", self, userCred, params,
parentTaskId, "", nil)
if err != nil {
return err
}
task.ScheduleRun(nil)
return nil
}
func (self *SSnapshotPolicy) GetCustomizeColumns(ctx context.Context, userCred mcclient.TokenCredential,
query jsonutils.JSONObject) *jsonutils.JSONDict {
ret, _ := self.getMoreDetails(ctx, userCred, query)
return ret
}
func (self *SSnapshotPolicy) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential,
query jsonutils.JSONObject) (*jsonutils.JSONDict, error) {
return self.getMoreDetails(ctx, userCred, query)
}
func (self *SSnapshotPolicy) getMoreDetails(ctx context.Context, userCred mcclient.TokenCredential,
query jsonutils.JSONObject) (*jsonutils.JSONDict, error) {
ret := query.(*jsonutils.JSONDict)
// more
weekdays := SnapshotPolicyManager.RepeatWeekdaysToIntArray(self.RepeatWeekdays)
timePoints := SnapshotPolicyManager.TimePointsToIntArray(self.TimePoints)
ret.Add(jsonutils.Marshal(weekdays), "repeat_weekdays")
ret.Add(jsonutils.Marshal(timePoints), "time_points")
count, err := SnapshotPolicyDiskManager.FetchDiskCountBySPID(self.Id)
if err != nil {
return ret, err
}
ret.Add(jsonutils.NewInt(int64(count)), "binding_disk_count")
return ret, nil
}
// ==================================================== sync ===========================================================
func (manager *SSnapshotPolicyManager) SyncSnapshotPolicies(ctx context.Context, userCred mcclient.TokenCredential,
provider *SCloudprovider, region *SCloudregion, cloudSPs []cloudprovider.ICloudSnapshotPolicy,
syncOwnerId mcclient.IIdentityProvider) compare.SyncResult {
lockman.LockClass(ctx, manager, db.GetLockClassKey(manager, syncOwnerId))
defer lockman.ReleaseClass(ctx, manager, db.GetLockClassKey(manager, syncOwnerId))
syncResult := compare.SyncResult{}
// Fetch allsnapshotpolicy caches
spCaches, err := SnapshotPolicyCacheManager.FetchAllByRegionProvider(region.GetId(), provider.GetId())
if err != nil {
syncResult.Error(err)
return syncResult
}
spIdSet, spIds := make(map[string]struct{}), make([]string, 0, 2)
for _, spCache := range spCaches {
if _, ok := spIdSet[spCache.SnapshotpolicyId]; !ok {
spIds = append(spIds, spCache.SnapshotpolicyId)
spIdSet[spCache.SnapshotpolicyId] = struct{}{}
}
}
// Fetch allsnapshotpolicy of caches above
snapshotPolicies, err := manager.FetchAllByIds(spIds)
if err != nil {
syncResult.Error(err)
return syncResult
}
// structure two sets (externalID, snapshotpolicyCache), (snapshotPolicyID, snapshotPolicy)
spSet, spCacheSet := make(map[string]*SSnapshotPolicy), make(map[string]*SSnapshotPolicyCache)
for i := range snapshotPolicies {
spSet[snapshotPolicies[i].GetId()] = &snapshotPolicies[i]
}
for i := range spCaches {
externalId := spCaches[i].ExternalId
if len(externalId) != 0 {
spCacheSet[spCaches[i].ExternalId] = &spCaches[i]
}
}
// start sync
// add forsnapshotpolicy and cache
// delete forsnapshotpolicy cache
added := make([]cloudprovider.ICloudSnapshotPolicy, 0, 1)
removed := make([]*SSnapshotPolicyCache, 0, 1)
for _, cloudSP := range cloudSPs {
spCache, ok := spCacheSet[cloudSP.GetGlobalId()]
if !ok {
added = append(added, cloudSP)
continue
}
snapshotPolicy := spSet[spCache.SnapshotpolicyId]
if !snapshotPolicy.Equals(cloudSP) {
removed = append(removed, spCache)
added = append(added, cloudSP)
}
}
for i := range removed {
// changesnapshotpolicy cache
err := removed[i].RealDetele(ctx, userCred)
if err != nil {
syncResult.DeleteError(err)
}
}
for i := range added {
locol, err := manager.newFromCloudSnapshotPolicy(ctx, userCred, added[i], region, syncOwnerId, provider)
if err != nil {
syncResult.AddError(err)
} else {
syncMetadata(ctx, userCred, locol, added[i])
syncResult.Add()
}
}
return compare.SyncResult{}
}
func (manager *SSnapshotPolicyManager) newFromCloudSnapshotPolicy(
ctx context.Context, userCred mcclient.TokenCredential,
ext cloudprovider.ICloudSnapshotPolicy, region *SCloudregion,
syncOwnerId mcclient.IIdentityProvider, provider *SCloudprovider,
) (*SSnapshotPolicy, error) {
snapshotPolicy := SSnapshotPolicy{}
snapshotPolicy.SetModelManager(manager, &snapshotPolicy)
newName, err := db.GenerateName(manager, syncOwnerId, ext.GetName())
if err != nil {
return nil, err
}
snapshotPolicy.Name = newName
snapshotPolicy.Status = ext.GetStatus()
snapshotPolicy.RetentionDays = ext.GetRetentionDays()
arw, err := ext.GetRepeatWeekdays()
if err != nil {
return nil, err
}
snapshotPolicy.RepeatWeekdays = SnapshotPolicyManager.RepeatWeekdaysParseIntArray(arw)
atp, err := ext.GetTimePoints()
if err != nil {
return nil, err
}
snapshotPolicy.TimePoints = SnapshotPolicyManager.TimePointsParseIntArray(atp)
snapshotPolicy.IsActivated = tristate.NewFromBool(ext.IsActivated())
err = manager.TableSpec().Insert(&snapshotPolicy)
if err != nil {
log.Errorf("newFromCloudEip fail %s", err)
return nil, err
}
// add cache
_, err = SnapshotPolicyCacheManager.NewCacheWithExternalId(ctx, userCred, snapshotPolicy.GetId(),
ext.GetGlobalId(), region.GetId(), provider.GetId())
if err != nil {
//snapshotpolicy has been exist so that created is successful although cache created is fail.
// disk will be sync aftersnapshotpolicy sync, cache must be right so that this sync is fail
log.Errorf("snapshotpolicy %s created successfully but corresponding cache created fail", snapshotPolicy.GetId())
return nil, errors.Wrapf(err, "snapshotpolicy %s created successfully but corresponding cache created fail",
snapshotPolicy.GetId())
}
SyncCloudProject(userCred, &snapshotPolicy, syncOwnerId, ext, provider.GetId())
db.OpsLog.LogEvent(&snapshotPolicy, db.ACT_CREATE, snapshotPolicy.GetShortDesc(ctx), userCred)
return &snapshotPolicy, nil
}
func (self *SSnapshotPolicy) Equals(cloudSP cloudprovider.ICloudSnapshotPolicy) bool {
rws, err := cloudSP.GetRepeatWeekdays()
if err != nil {
return false
}
tps, err := cloudSP.GetTimePoints()
if err != nil {
return false
}
repeatWeekdays := SnapshotPolicyManager.RepeatWeekdaysParseIntArray(rws)
timePoints := SnapshotPolicyManager.TimePointsParseIntArray(tps)
return self.RetentionDays == cloudSP.GetRetentionDays() && self.RepeatWeekdays == repeatWeekdays && self.
TimePoints == timePoints && self.IsActivated.Bool() == cloudSP.IsActivated()
}
func (manager *SSnapshotPolicyManager) getProviderSnapshotPolicies(region *SCloudregion, provider *SCloudprovider) ([]SSnapshotPolicy, error) {
if region == nil && provider == nil {
return nil, fmt.Errorf("Region is nil or provider is nil")
}
snapshotPolicies := make([]SSnapshotPolicy, 0)
q := manager.Query().Equals("cloudregion_id", region.Id).Equals("manager_id", provider.Id)
err := db.FetchModelObjects(manager, q, &snapshotPolicies)
if err != nil {
return nil, err
}
return snapshotPolicies, nil
}
func (self *SSnapshotPolicy) syncRemoveCloudSnapshot(ctx context.Context, userCred mcclient.TokenCredential) error {
lockman.LockObject(ctx, self)
defer lockman.ReleaseObject(ctx, self)
err := self.ValidateDeleteCondition(ctx)
if err != nil {
err = self.SetStatus(userCred, api.SNAPSHOT_POLICY_UNKNOWN, "sync to delete")
} else {
err = self.RealDelete(ctx, userCred)
}
return err
}
func (self *SSnapshotPolicy) Delete(ctx context.Context, userCred mcclient.TokenCredential) error {
return nil
}
func (self *SSnapshotPolicy) RealDelete(ctx context.Context, userCred mcclient.TokenCredential) error {
return db.DeleteModel(ctx, userCred, self)
}
// ==================================================== utils ==========================================================
func (manager *SSnapshotPolicyManager) sSnapshotPolicyCreateInputToInternal(input *api.SSnapshotPolicyCreateInput,
) *api.SSnapshotPolicyCreateInternalInput {
ret := api.SSnapshotPolicyCreateInternalInput{
Meta: input.Meta,
Name: input.Name,
ProjectId: input.ProjectId,
DomainId: input.DomainId,
RetentionDays: input.RetentionDays,
}
ret.RepeatWeekdays = manager.RepeatWeekdaysParseIntArray(input.RepeatWeekdays)
ret.TimePoints = manager.TimePointsParseIntArray(input.TimePoints)
return &ret
}
func (manager *SSnapshotPolicyManager) sSnapshotPolicyCreateInputFromInternal(input *api.
SSnapshotPolicyCreateInternalInput) *api.SSnapshotPolicyCreateInput {
return nil
}
func (self *SSnapshotPolicyManager) RepeatWeekdaysParseIntArray(nums []int) uint8 {
return uint8(bitmap.IntArray2Uint(nums))
}
func (self *SSnapshotPolicyManager) RepeatWeekdaysToIntArray(n uint8) []int {
return bitmap.Uint2IntArray(uint32(n))
}
func (self *SSnapshotPolicyManager) TimePointsParseIntArray(nums []int) uint32 {
return bitmap.IntArray2Uint(nums)
}
func (self *SSnapshotPolicyManager) TimePointsToIntArray(n uint32) []int {
return bitmap.Uint2IntArray(n)
}
func (self *SSnapshotPolicy) GenerateCreateSpParams() *cloudprovider.SnapshotPolicyInput {
intWeekdays := SnapshotPolicyManager.RepeatWeekdaysToIntArray(self.RepeatWeekdays)
intTimePoints := SnapshotPolicyManager.TimePointsToIntArray(self.TimePoints)
return &cloudprovider.SnapshotPolicyInput{
RetentionDays: self.RetentionDays,
RepeatWeekdays: intWeekdays,
TimePoints: intTimePoints,
PolicyName: self.Name,
}
}
// ==================================================== action =========================================================
func (manager *SSnapshotPolicy) AllowPerformBindDisks(ctx context.Context, userCred mcclient.TokenCredential,
query jsonutils.JSONObject) bool {
return manager.IsOwner(userCred) || db.IsAdminAllowPerform(userCred, manager, "bind-disks")
}
func (sp *SSnapshotPolicy) PerformBindDisks(ctx context.Context, userCred mcclient.TokenCredential,
query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
disks := jsonutils.GetArrayOfPrefix(data, "disk")
if len(disks) == 0 {
return nil, httperrors.NewMissingParameterError("disk.0 disk.1 ... ")
}
//database
diskSlice := make([]*SDisk, len(disks))
for i := range disks {
diskId, _ := disks[i].GetString()
disk := DiskManager.FetchDiskById(diskId)
if disk == nil {
return nil, httperrors.NewInputParameterError("no such disk %s", diskId)
}
disk.SetModelManager(DiskManager, disk)
diskSlice[i] = disk
}
taskDisk := make([]*SDisk, 0, len(diskSlice))
taskSpd := make([]*SSnapshotPolicyDisk, 0, len(diskSlice))
for _, disk := range diskSlice {
spd, err := SnapshotPolicyDiskManager.newSnapshotpolicyDisk(ctx, userCred, sp, disk)
if err == ErrExistSD {
if spd.Status == "init" {
taskDisk = append(taskDisk, disk)
taskSpd = append(taskSpd, spd)
}
continue
}
if err != nil {
return nil, fmt.Errorf("oper for database error")
}
taskDisk = append(taskDisk, disk)
taskSpd = append(taskSpd, spd)
}
for i := range taskDisk {
// field 'need_detach' is not needed, because the the subject is snapshot policy not disk
taskdata := jsonutils.NewDict()
taskdata.Add(jsonutils.Marshal(taskSpd[i]), "snapshotPolicyDisk")
taskdata.Add(jsonutils.Marshal(sp), "snapshotPolicy")
if task, err := taskman.TaskManager.NewTask(ctx, "SnapshotPolicyApplyTask", taskDisk[i], userCred, nil,
"", "", nil); err != nil {
continue
} else {
task.ScheduleRun(taskdata)
}
}
return nil, nil
}
func (manager *SSnapshotPolicy) AllowPerformUnbindDisks(ctx context.Context, userCred mcclient.TokenCredential,
query jsonutils.JSONObject) bool {
return manager.IsOwner(userCred) || db.IsAdminAllowPerform(userCred, manager, "bind-disks")
}
func (sp *SSnapshotPolicy) PerformUnbindDisks(ctx context.Context, userCred mcclient.TokenCredential,
query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
disks := jsonutils.GetArrayOfPrefix(data, "disk")
if len(disks) == 0 {
return nil, httperrors.NewMissingParameterError("disk.0 disk.1 ... ")
}
diskSlice := make([]*SDisk, len(disks))
for i := range disks {
diskId, _ := disks[i].GetString()
disk := DiskManager.FetchDiskById(diskId)
if disk == nil {
return nil, httperrors.NewInputParameterError("no such disk %s", diskId)
}
disk.SetModelManager(DiskManager, disk)
diskSlice[i] = disk
}
taskDisk := make([]*SDisk, 0, len(diskSlice))
taskSpd := make([]*SSnapshotPolicyDisk, 0, len(diskSlice))
for _, disk := range diskSlice {
spd, err := SnapshotPolicyDiskManager.FetchBySnapshotPolicyDisk(sp.Id, disk.GetId())
if err != nil {
continue
}
if spd == nil {
continue
}
taskSpd = append(taskSpd, spd)
taskDisk = append(taskDisk, disk)
}
for i := range taskDisk {
taskdata := jsonutils.NewDict()
taskdata.Add(jsonutils.NewString(sp.Id), "snapshot_policy_id")
taskdata.Add(jsonutils.Marshal(taskSpd[i]), "snapshotPolicyDisk")
taskSpd[i].SetStatus(userCred, api.SNAPSHOT_POLICY_DISK_DELETING, "")
if task, err := taskman.TaskManager.NewTask(ctx, "SnapshotPolicyCancelTask", taskDisk[i], userCred, nil, "", "",
nil); err != nil {
continue
} else {
task.ScheduleRun(taskdata)
}
}
return nil, nil
}

View File

@@ -0,0 +1,415 @@
// Copyright 2019 Yunion
//
// 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.
package models
import (
"context"
"database/sql"
"fmt"
"strings"
"time"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/util/stringutils"
"yunion.io/x/sqlchemy"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/appsrv"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
)
type SSnapshotPolicyCacheManager struct {
db.SResourceBaseManager
}
type SSnapshotPolicyCache struct {
db.SResourceBase
SManagedResourceBase
Id string `width:"128" charset:"ascii" primary:"true" list:"user"`
SnapshotpolicyId string `width:"128" charset:"ascii" create:"required"`
CloudregionId string `width:"128" charset:"ascii" create:"required"`
ExternalId string `width:"256" charset:"utf8" index:"true" list:"admin" create:"admin_optional"`
}
var SnapshotPolicyCacheManager *SSnapshotPolicyCacheManager
func init() {
SnapshotPolicyCacheManager = &SSnapshotPolicyCacheManager{
db.NewResourceBaseManager(
SSnapshotPolicyCache{},
"snapshotpolicycache_tbl",
"snapshotpolicycache",
"snapshotpolicycaches",
),
}
SnapshotPolicyCacheManager.SetVirtualObject(SnapshotPolicyCacheManager)
}
func (spc *SSnapshotPolicyCache) BeforeInsert() {
if len(spc.Id) == 0 {
spc.Id = stringutils.UUID4()
}
}
func (spcm *SSnapshotPolicyCacheManager) FilterById(q *sqlchemy.SQuery, idStr string) *sqlchemy.SQuery {
return q.Equals("id", idStr)
}
func (spcm *SSnapshotPolicyCacheManager) GetIStandaloneModelManager() db.IStandaloneModelManager {
return spcm.GetVirtualObject().(db.IStandaloneModelManager)
}
func (spc *SSnapshotPolicyCache) GetIStandaloneModel() db.IStandaloneModel {
return spc.GetVirtualObject().(db.IStandaloneModel)
}
func (spc *SSnapshotPolicyCache) ClearSchedDescCache() error {
return nil
}
func (spcm *SSnapshotPolicyCacheManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential,
query jsonutils.JSONObject) (*sqlchemy.SQuery, error) {
q, err := spcm.SResourceBaseManager.ListItemFilter(ctx, q, userCred, query)
if err != nil {
return nil, err
}
if defsecgroup, _ := query.GetString("snapshotpolicy"); len(defsecgroup) > 0 {
secgroup, err := SecurityGroupManager.FetchByIdOrName(userCred, defsecgroup)
if err != nil {
if err == sql.ErrNoRows {
return nil, httperrors.NewResourceNotFoundError2(SecurityGroupManager.Keyword(), defsecgroup)
} else {
return nil, httperrors.NewGeneralError(err)
}
}
q = q.Equals("snapshotpolicy_id", secgroup.GetId())
}
return q, nil
}
func (spc *SSnapshotPolicyCache) GetIRegion() (cloudprovider.ICloudRegion, error) {
provider, err := spc.GetDriver()
if err != nil {
return nil, err
}
if region := CloudregionManager.FetchRegionById(spc.CloudregionId); region != nil {
return provider.GetIRegionById(region.ExternalId)
}
return nil, fmt.Errorf("failed to find iregion for snapshotpolicycache %s: cloudregion %s manager %s", spc.Id,
spc.CloudregionId, spc.ManagerId)
}
func (spc *SSnapshotPolicyCache) GetSnapshotPolicy() (*SSnapshotPolicy, error) {
model, err := SnapshotPolicyManager.FetchById(spc.SnapshotpolicyId)
if err != nil {
return nil, fmt.Errorf("failed to fetchsnapshotpolicy by %s", spc.SnapshotpolicyId)
}
return model.(*SSnapshotPolicy), nil
}
func (spc *SSnapshotPolicyCache) SetExternalId(userCred mcclient.TokenCredential, externalId string) error {
diff, err := db.Update(spc, func() error {
spc.ExternalId = externalId
return nil
})
if err != nil {
return err
}
db.OpsLog.LogEvent(spc, db.ACT_UPDATE, diff, userCred)
return nil
}
func (spc SSnapshotPolicyCache) GetExternalId() string {
return spc.ExternalId
}
// =============================================== detach and delete ===================================================
func (spc *SSnapshotPolicyCache) RealDetele(ctx context.Context, userCred mcclient.TokenCredential) error {
return db.DeleteModel(ctx, userCred, spc)
}
// ================================================= new and regist ====================================================
func (spcm *SSnapshotPolicyCacheManager) NewCache(ctx context.Context, userCred mcclient.TokenCredential,
snapshotPolicyId, regionId, providerId string) (*SSnapshotPolicyCache, error) {
snapshotPolicyCache := SSnapshotPolicyCache{
SnapshotpolicyId: snapshotPolicyId,
CloudregionId: regionId,
}
snapshotPolicyCache.ManagerId = providerId
err := snapshotPolicyCache.CreateCloudSnapshotPolicy()
if err != nil {
return nil, err
}
// should have lock
if err := spcm.TableSpec().Insert(&snapshotPolicyCache); err != nil {
return nil, errors.Wrapf(err, "insert snapshotpolicycache failed")
}
return &snapshotPolicyCache, nil
}
func (spcm *SSnapshotPolicyCacheManager) NewCacheWithExternalId(ctx context.Context, userCred mcclient.TokenCredential,
snapshotPolicyId, externalId, regionId, providerId string) (*SSnapshotPolicyCache, error) {
snapshotPolicyCache := SSnapshotPolicyCache{
SnapshotpolicyId: snapshotPolicyId,
CloudregionId: regionId,
ExternalId: externalId,
}
snapshotPolicyCache.ManagerId = providerId
// should have lock
if err := spcm.TableSpec().Insert(&snapshotPolicyCache); err != nil {
return nil, errors.Wrapf(err, "insert snapshotpolicycache failed")
}
return &snapshotPolicyCache, nil
}
func (spcm *SSnapshotPolicyCacheManager) Register(ctx context.Context, userCred mcclient.TokenCredential, snapshotPolicyId,
regionId string, providerId string) (*SSnapshotPolicyCache, error) {
// Many request about same snapshot policy with same region and provider coming will cause many same cache
// building without lock, so we must Lock.
lockman.LockRawObject(ctx, snapshotPolicyId, regionId+providerId)
defer lockman.ReleaseRawObject(ctx, snapshotPolicyId, regionId+providerId)
snapshotPolicyCache, err := spcm.FetchSnapshotPolicyCache(snapshotPolicyId, regionId, providerId)
// error
if err != nil {
return nil, err
}
// no cache
if snapshotPolicyCache != nil {
return snapshotPolicyCache, nil
}
return spcm.NewCache(ctx, userCred, snapshotPolicyId, regionId, providerId)
}
func (spcm *SSnapshotPolicyCacheManager) RegisterWithExternalID(ctx context.Context, userCred mcclient.TokenCredential,
snapshotPolicyId, externalId, regionId, providerId string) (*SSnapshotPolicyCache, error) {
snapshotPolicyCache, err := spcm.FetchSnapshotPolicyCache(snapshotPolicyId, regionId, providerId)
// error
if err != nil {
return nil, err
}
// no cache
if snapshotPolicyCache != nil {
return snapshotPolicyCache, nil
}
return spcm.NewCacheWithExternalId(ctx, userCred, snapshotPolicyId, externalId, regionId, providerId)
}
// ==================================================== fetch =========================================================
func (spcm *SSnapshotPolicyCacheManager) FetchSnapshotpolicyCaheById(cacheId string) (*SSnapshotPolicyCache, error) {
q := spcm.FilterById(spcm.Query(), cacheId)
return spcm.fetchByQuery(q)
}
func (spcm *SSnapshotPolicyCacheManager) FetchSnapshotPolicyCache(snapshotPolicyId, regionId, providerId string) (*SSnapshotPolicyCache, error) {
q := spcm.Query()
q.Filter(sqlchemy.AND(sqlchemy.Equals(q.Field("snapshotpolicy_id"), snapshotPolicyId),
sqlchemy.Equals(q.Field("cloudregion_id"), regionId),
sqlchemy.Equals(q.Field("manager_id"), providerId)))
return spcm.fetchByQuery(q)
}
func (spcm *SSnapshotPolicyCacheManager) FetchSnapshotPolicyCacheByExtId(externalId, regionId,
providerId string) (*SSnapshotPolicyCache, error) {
q := spcm.Query()
q.Filter(sqlchemy.AND(sqlchemy.Equals(q.Field("external_id"), externalId),
sqlchemy.Equals(q.Field("cloudregion_id"), regionId),
sqlchemy.Equals(q.Field("manager_id"), providerId)))
return spcm.fetchByQuery(q)
}
func (spcm *SSnapshotPolicyCacheManager) FetchAllByExtIds(externalIds []string, regionId,
providerId string) ([]SSnapshotPolicyCache, error) {
q := spcm.Query().In("external_id", externalIds).Equals("cloudregion_id", regionId).Equals("manager_id", providerId)
return spcm.fetchAllByQuery(q)
}
func (spcm *SSnapshotPolicyCacheManager) FetchAllBySnpId(snapshotPolicyId string) ([]SSnapshotPolicyCache, error) {
q := spcm.Query().Equals("snapshotpolicy_id", snapshotPolicyId)
return spcm.fetchAllByQuery(q)
}
func (spcm *SSnapshotPolicyCacheManager) FetchAllByRegionProvider(cloudregionId,
managerId string) ([]SSnapshotPolicyCache, error) {
q := spcm.Query().Equals("cloudregion_id", cloudregionId).Equals("manager_id", managerId)
return spcm.fetchAllByQuery(q)
}
func (spcm *SSnapshotPolicyCacheManager) fetchAllByQuery(q *sqlchemy.SQuery) ([]SSnapshotPolicyCache, error) {
caches := make([]SSnapshotPolicyCache, 0, 1)
if err := db.FetchModelObjects(spcm, q, &caches); err != nil {
return nil, err
}
return caches, nil
}
func (spcm *SSnapshotPolicyCacheManager) fetchByQuery(q *sqlchemy.SQuery) (*SSnapshotPolicyCache, error) {
count, err := q.CountWithError()
if err != nil {
return nil, err
}
if count == 0 {
return nil, nil
}
snapshotPolicyCache := SSnapshotPolicyCache{}
// if exist, only one
q.First(&snapshotPolicyCache)
snapshotPolicyCache.SetModelManager(spcm, &snapshotPolicyCache)
return &snapshotPolicyCache, nil
}
// ============================================== cloud operation ======================================================
// This function should call in the task.
type sOperaResult struct {
err error
snapshotPolicyId string
}
func (spcm *SSnapshotPolicyCacheManager) UpdateCloudSnapshotPolicy(snapshotPolicyId string,
input *cloudprovider.SnapshotPolicyInput) error {
//todo maybe
return fmt.Errorf("Not implement")
}
func (spcm *SSnapshotPolicyCacheManager) DeleteCloudSnapshotPolices(ctx context.Context,
userCred mcclient.TokenCredential, snapshotPolicyId string) error {
spCaches, err := spcm.FetchAllBySnpId(snapshotPolicyId)
if err != nil {
return errors.Wrapf(err, "fetch all snapshotPolicyCaches ofsnapshotpolicy %s failed", snapshotPolicyId)
}
if len(spCaches) == 0 {
return nil
}
wm := appsrv.NewWorkerManager("delete-cloud-snapshotpolices", len(spCaches), 1, false)
retChan := make(chan sOperaResult)
for i := range spCaches {
spc := spCaches[i]
wm.Run(func() {
err := spc.DeleteCloudSnapshotPolicy()
if err != nil {
retChan <- sOperaResult{err, spc.GetId()}
return
}
err = spc.RealDetele(ctx, userCred)
if err != nil {
retChan <- sOperaResult{errors.Wrap(err, "delete cache in database failed"), spc.GetId()}
return
}
retChan <- sOperaResult{nil, spc.GetId()}
}, nil, func(e error) {
retChan <- sOperaResult{e, spc.GetId()}
})
}
failedRecord := make([]string, 0)
for i := 0; i < len(spCaches); i++ {
ret := <-retChan
if ret.err != nil {
failedRecord = append(failedRecord, fmt.Sprintf("%s failed because that %s", ret.snapshotPolicyId,
ret.err.Error()))
}
}
if len(failedRecord) != 0 {
return fmt.Errorf("delete: " + strings.Join(failedRecord, "; "))
}
return nil
}
func (spc *SSnapshotPolicyCache) CreateCloudSnapshotPolicy() error {
// create correspondingsnapshotpolicy in cloud
iregion, err := spc.GetIRegion()
if err != nil {
return err
}
snapshotPolicy, err := spc.GetSnapshotPolicy()
if err != nil {
return err
}
externalId, err := iregion.CreateSnapshotPolicy(snapshotPolicy.GenerateCreateSpParams())
if err != nil {
return errors.Wrap(err, "createsnapshotpolicy failed")
}
spc.ExternalId = externalId
iPolicy, err := iregion.GetISnapshotPolicyById(externalId)
if err != nil {
return err
}
err = cloudprovider.WaitStatus(iPolicy, api.SNAPSHOT_POLICY_READY, 10*time.Second, 300*time.Second)
if err != nil {
return err
}
return nil
}
func (spc *SSnapshotPolicyCache) DeleteCloudSnapshotPolicy() error {
if len(spc.ExternalId) > 0 {
iregion, err := spc.GetIRegion()
if err != nil {
return err
}
return iregion.DeleteSnapshotPolicy(spc.ExternalId)
}
return nil
}
func (spc *SSnapshotPolicyCache) UpdateCloudSnapshotPolicy(input *cloudprovider.SnapshotPolicyInput) error {
iregion, err := spc.GetIRegion()
if err != nil {
return err
}
err = iregion.UpdateSnapshotPolicy(input, spc.ExternalId)
if err != nil {
return errors.Wrap(err, "createsnapshotpolicy failed")
}
return nil
}

View File

@@ -15,14 +15,21 @@
package models
import (
"bytes"
"context"
"database/sql"
"fmt"
"strings"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
)
@@ -30,11 +37,11 @@ type SSnapshotPolicyDiskManager struct {
db.SVirtualJointResourceBaseManager
}
func (manager *SSnapshotPolicyDiskManager) GetMasterFieldName() string {
func (m *SSnapshotPolicyDiskManager) GetMasterFieldName() string {
return "disk_id"
}
func (manager *SSnapshotPolicyDiskManager) GetSlaveFieldName() string {
func (m *SSnapshotPolicyDiskManager) GetSlaveFieldName() string {
return "snapshotpolicy_id"
}
@@ -62,66 +69,382 @@ type SSnapshotPolicyDisk struct {
SnapshotpolicyId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"required" index:"true"`
DiskId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"required" index:"true"`
Status string `width:"36" charset:"ascii" nullable:"false" default:"init" list:"user" create:"optional"`
}
func (self *SSnapshotPolicyDisk) Detach(ctx context.Context, userCred mcclient.TokenCredential) error {
return db.DetachJoint(ctx, userCred, self)
func (sd *SSnapshotPolicyDisk) SetStatus(userCred mcclient.TokenCredential, status string, reason string) error {
if sd.Status == status {
return nil
}
oldStatus := sd.Status
_, err := db.Update(sd, func() error {
sd.Status = status
return nil
})
if err != nil {
return err
}
if userCred != nil {
notes := fmt.Sprintf("%s=>%s", oldStatus, status)
if len(reason) > 0 {
notes = fmt.Sprintf("%s: %s", notes, reason)
}
db.OpsLog.LogEvent(sd, db.ACT_UPDATE_STATUS, notes, userCred)
}
return nil
}
func (self *SSnapshotPolicyDiskManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
diskId, _ := data.GetString(self.GetMasterFieldName())
disk := DiskManager.FetchDiskById(diskId)
err := disk.GetStorage().GetRegion().GetDriver().ValidateCreateSnapshopolicyDiskData(ctx, userCred, diskId)
func (self *SSnapshotPolicyDisk) GetCustomizeColumns(ctx context.Context, userCred mcclient.TokenCredential,
query jsonutils.JSONObject) *jsonutils.JSONDict {
ret, _ := self.getMoreDetails(ctx, userCred, query)
return ret
}
func (self *SSnapshotPolicyDisk) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential,
query jsonutils.JSONObject) (*jsonutils.JSONDict, error) {
return self.getMoreDetails(ctx, userCred, query)
}
func (self *SSnapshotPolicyDisk) getMoreDetails(ctx context.Context, userCred mcclient.TokenCredential,
query jsonutils.JSONObject) (*jsonutils.JSONDict, error) {
disk := DiskManager.FetchDiskById(self.DiskId)
ret := jsonutils.NewDict()
ret.Add(jsonutils.Marshal(disk), "disk")
return ret, nil
}
// ==================================================== fetch ==========================================================
func (m *SSnapshotPolicyDiskManager) FetchBySnapshotPolicyDisk(spId, diskId string) (*SSnapshotPolicyDisk, error) {
q := m.Query().Equals("snapshotpolicy_id", spId).Equals("disk_id", diskId)
ret := make([]SSnapshotPolicyDisk, 0, 1)
err := db.FetchModelObjects(m, q, &ret)
if err != nil {
return nil, err
}
return data, nil
if len(ret) == 0 {
return nil, fmt.Errorf("Not Found")
}
return &ret[0], nil
}
func (self *SSnapshotPolicyDiskManager) FetchAllSnapshotPolicyOfDisk(ctx context.Context, userCred mcclient.TokenCredential, diskID string) ([]SSnapshotPolicyDisk, error) {
q := self.Query()
q.Equals(self.GetMasterFieldName(), diskID)
func (m *SSnapshotPolicyDiskManager) FetchAllByDiskID(ctx context.Context, userCred mcclient.TokenCredential,
diskID string) ([]SSnapshotPolicyDisk, error) {
return m.fetchAll(ctx, userCred, m.GetMasterFieldName(), diskID)
}
func (m *SSnapshotPolicyDiskManager) FetchAllBySnapshotpolicyID(ctx context.Context, userCred mcclient.TokenCredential,
snapshotPolicyID string) ([]SSnapshotPolicyDisk, error) {
return m.fetchAll(ctx, userCred, m.GetSlaveFieldName(), snapshotPolicyID)
}
func (m *SSnapshotPolicyDiskManager) FetchDiskCountBySPID(snapshotpolicyID string) (int, error) {
q := m.Query().Equals("snapshotpolicy_id", snapshotpolicyID)
return q.CountWithError()
}
func (m *SSnapshotPolicyDiskManager) fetchAll(ctx context.Context, userCred mcclient.TokenCredential,
fieldName string, fieldValue string) ([]SSnapshotPolicyDisk, error) {
q := m.Query()
q.Equals(fieldName, fieldValue)
ret := make([]SSnapshotPolicyDisk, 0)
err := db.FetchModelObjects(self, q, &ret)
err := db.FetchModelObjects(m, q, &ret)
if err != nil {
return nil, err
}
return ret, nil
}
func (self *SSnapshotPolicyDisk) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) {
diskID := self.DiskId
model, err := DiskManager.FetchById(diskID)
if err != nil {
log.Errorf("Fetch disk by ID %s failed", diskID)
// ==================================================== sync ===========================================================
// SyncDetachByDisk will detach all snapshot policies fo cloudRelations
// if cloudRelations is nil, it will detach all shapshot policies which has been attached to disk.
func (m *SSnapshotPolicyDiskManager) SyncDetachByDisk(ctx context.Context, userCred mcclient.TokenCredential,
cloudRelations []SSnapshotPolicyDisk, disk *SDisk) error {
snapshotPolicyDisks := cloudRelations
var err error
if snapshotPolicyDisks == nil {
snapshotPolicyDisks, err = m.FetchAllByDiskID(ctx, userCred, disk.GetId())
if err != nil {
return errors.Wrapf(err, "Fetach allsnapshotpolicy of disk %s in database", disk.GetId())
}
}
disk := model.(*SDisk)
snapshotPolicyID := self.SnapshotpolicyId
taskData := jsonutils.NewDict()
taskData.Add(jsonutils.NewString(snapshotPolicyID), "snapshot_policy_id")
task, err := taskman.TaskManager.NewTask(ctx, "SnapshotPolicyApplyTask", disk, userCred, taskData, "", "", nil)
failResult := make([]string, 0, 1)
for i := range snapshotPolicyDisks {
err = snapshotPolicyDisks[i].DetachByDisk(ctx, userCred, disk)
if err != nil {
failResult = append(failResult, snapshotPolicyDisks[i].GetId())
}
}
if len(failResult) != 0 {
errInfo := "detach failed which IDs are: "
return errors.Error(errInfo + strings.Join(failResult, ", "))
}
return nil
}
// SyncDetachBySnapshotpolicy detach all sn
func (m *SSnapshotPolicyDiskManager) SyncDetachBySnapshotpolicy(ctx context.Context,
userCred mcclient.TokenCredential, cloudRelations []SSnapshotPolicyDisk, snapshotPolicy *SSnapshotPolicy) error {
snapshotPolicyDisks := cloudRelations
var err error
if snapshotPolicyDisks == nil {
snapshotPolicyDisks, err = m.FetchAllBySnapshotpolicyID(ctx, userCred, snapshotPolicy.GetId())
if err != nil {
return errors.Wrapf(err, "Fetach all bysnapshotpolicy %s in database", snapshotPolicy.GetId())
}
}
failResult := make([]string, 0, 1)
for i := range snapshotPolicyDisks {
err = snapshotPolicyDisks[i].DetachBySnapshotpolicy(ctx, userCred, snapshotPolicy)
if err != nil {
failResult = append(failResult, snapshotPolicyDisks[i].GetId())
}
}
if len(failResult) != 0 {
errInfo := "detach failed which IDs are "
return errors.Error(errInfo + strings.Join(failResult, ", "))
}
return nil
}
func (m *SSnapshotPolicyDiskManager) SyncByDisk(ctx context.Context, userCred mcclient.TokenCredential,
extSnapshotpolicies []string, syncOwnerID mcclient.IIdentityProvider, disk *SDisk, storage *SStorage) error {
sds, err := m.FetchAllByDiskID(ctx, userCred, disk.GetId())
if err != nil {
return errors.Wrapf(err, "Fetach allsnapshotpolicy of disk %s in database", disk.GetId())
}
//fetch snapshotPolicy Cache to find the snapshotpolicyID corresponding to extSnapshotpolicyID
spCaches, err := SnapshotPolicyCacheManager.FetchAllByExtIds(extSnapshotpolicies, storage.GetRegion().GetId(),
storage.ManagerId)
if err != nil {
return errors.Wrapf(err, "fetachsnapshotpolicy caches failed")
}
cloudRelationsSet := make(map[string]struct{})
for i := range spCaches {
cloudRelationsSet[spCaches[i].SnapshotpolicyId] = struct{}{}
}
removed := make([]SSnapshotPolicyDisk, 0, 1)
added := make([]string, 0, 1)
for i := range sds {
if _, ok := cloudRelationsSet[sds[i].SnapshotpolicyId]; !ok {
removed = append(removed, sds[i])
}
delete(cloudRelationsSet, sds[i].SnapshotpolicyId)
}
for k := range cloudRelationsSet {
added = append(added, k)
}
err = m.SyncDetachByDisk(ctx, userCred, removed, disk)
if err != nil {
return err
}
err = m.SyncAttachDisk(ctx, userCred, added, syncOwnerID, disk)
if err != nil {
return err
}
return nil
}
func (m *SSnapshotPolicyDiskManager) SyncAttachDisk(ctx context.Context, userCred mcclient.TokenCredential,
Snapshotpolicies []string, syncOwnerID mcclient.IIdentityProvider, disk *SDisk) error {
lockman.LockClass(ctx, m, db.GetLockClassKey(m, syncOwnerID))
defer lockman.ReleaseClass(ctx, m, db.GetLockClassKey(m, syncOwnerID))
failRecord := make([]string, 0, 1)
for _, spId := range Snapshotpolicies {
snapshotpolicyDisk, err := db.FetchJointByIds(m, disk.GetId(), spId, jsonutils.JSONNull)
if err != nil && err != sql.ErrNoRows {
failRecord = append(failRecord,
fmt.Sprintf("Get SnapshotpolicyDisk whose diskid %s snapshotpolicyid %s failed",
disk.GetId(), spId))
continue
}
if snapshotpolicyDisk != nil {
continue
}
sd := SSnapshotPolicyDisk{}
sd.DiskId = disk.GetId()
sd.SnapshotpolicyId = spId
sd.Status = compute.SNAPSHOT_POLICY_DISK_READY
err = m.TableSpec().Insert(&sd)
if err != nil {
failRecord = append(failRecord, fmt.Sprintf("attachsnapshotpolicy %s to disk %s failed",
spId, disk.GetId()))
continue
}
}
if len(failRecord) == 0 {
return nil
}
buf := bytes.NewBufferString("sync attach extSnapshotpolicies to disk ")
buf.WriteString(disk.GetId())
buf.WriteString("failed because that ")
for i := range failRecord {
buf.WriteString(failRecord[i])
buf.WriteString(", ")
}
buf.Truncate(buf.Len() - 2)
return errors.Error(buf.String())
}
//
func (m *SSnapshotPolicyDiskManager) SyncAttachDiskExt(ctx context.Context, userCred mcclient.TokenCredential,
extSnapshotpolicies []string, syncOwnerID mcclient.IIdentityProvider, disk *SDisk, storage *SStorage) error {
//fetch snapshotPolicy Cache to find the snapshotpolicyID corresponding to extSnapshotpolicyID
spCaches, err := SnapshotPolicyCacheManager.FetchAllByExtIds(extSnapshotpolicies, storage.GetRegion().GetId(),
storage.ManagerId)
if err != nil {
return errors.Wrapf(err, "fetachsnapshotpolicy caches failed")
}
snapshotPolicie := make([]string, 0, 1)
for i := range spCaches {
snapshotPolicie = append(snapshotPolicie, spCaches[i].SnapshotpolicyId)
}
return m.SyncAttachDisk(ctx, userCred, snapshotPolicie, syncOwnerID, disk)
}
// ==================================================== detach =========================================================
func (sd *SSnapshotPolicyDisk) RealDetach(ctx context.Context, userCred mcclient.TokenCredential) error {
return db.DeleteModel(ctx, userCred, sd)
}
func (sd *SSnapshotPolicyDisk) Delete(ctx context.Context, userCred mcclient.TokenCredential) error {
return nil
}
func (sd *SSnapshotPolicyDisk) Detach(ctx context.Context, userCred mcclient.TokenCredential) error {
return nil
}
// syncDetach should lock before
func (sd *SSnapshotPolicyDisk) DetachByDisk(ctx context.Context, userCred mcclient.TokenCredential, disk *SDisk) error {
snapshotPolicy := SSnapshotPolicy{}
snapshotPolicy.Id = sd.SnapshotpolicyId
snapshotPolicy.SetModelManager(SnapshotPolicyManager, &snapshotPolicy)
lockman.LockJointObject(ctx, disk, &snapshotPolicy)
defer lockman.ReleaseJointObject(ctx, disk, &snapshotPolicy)
// todo call real Detach
return sd.RealDetach(ctx, userCred)
}
func (sd *SSnapshotPolicyDisk) DetachBySnapshotpolicy(ctx context.Context, userCred mcclient.TokenCredential,
snapshotPolicy *SSnapshotPolicy) error {
disk := SDisk{}
disk.Id = sd.DiskId
disk.SetModelManager(DiskManager, &disk)
lockman.LockJointObject(ctx, &disk, snapshotPolicy)
defer lockman.ReleaseJointObject(ctx, &disk, snapshotPolicy)
return sd.RealDetach(ctx, userCred)
}
// ==================================================== create =========================================================
var ErrExistSD = fmt.Errorf("snapshotpolicy disk has been exist")
func (self *SSnapshotPolicyDiskManager) newSnapshotpolicyDisk(ctx context.Context, userCred mcclient.TokenCredential,
sp *SSnapshotPolicy, disk *SDisk) (*SSnapshotPolicyDisk, error) {
q := self.Query().Equals("snapshotpolicy_id", sp.GetId()).Equals("disk_id", disk.GetId())
count, err := q.CountWithError()
if err != nil {
return nil, nil
}
if count > 0 {
spd := SSnapshotPolicyDisk{}
q.First(&spd)
spd.SetModelManager(self, &spd)
return &spd, ErrExistSD
}
spd := SSnapshotPolicyDisk{SnapshotpolicyId: sp.GetId(), DiskId: disk.GetId()}
spd.SetModelManager(self, &spd)
lockman.LockJointObject(ctx, disk, sp)
defer lockman.ReleaseJointObject(ctx, disk, sp)
return &spd, self.TableSpec().Insert(&spd)
}
func (self *SSnapshotPolicyDiskManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
diskId, _ := data.GetString(self.GetMasterFieldName())
snapshotPolicyId, _ := data.GetString(self.GetSlaveFieldName())
disk := DiskManager.FetchDiskById(diskId)
snapshotPolicy := SnapshotPolicyManager.FetchSnapshotPolicyById(snapshotPolicyId)
err := disk.GetStorage().GetRegion().GetDriver().ValidateCreateSnapshopolicyDiskData(ctx, userCred, disk, snapshotPolicy)
if err != nil {
return nil, err
}
//to control that one disk should only bind one snapshot policy
spds, err := SnapshotPolicyDiskManager.FetchAllByDiskID(ctx, userCred, diskId)
if err != nil {
return nil, err
}
if len(spds) > 1 {
return nil, httperrors.NewInputParameterError("disk %s has too many snapshot policy attached", diskId)
}
if len(spds) == 1 {
data.Add(jsonutils.NewString(spds[0].SnapshotpolicyId), "need_detach")
}
// I don't want to request to database again behind
data.Add(jsonutils.Marshal(snapshotPolicy), "snapshotPolicy")
data.Add(jsonutils.Marshal(disk), "disk")
return data, nil
}
func (sd *SSnapshotPolicyDisk) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.
IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) {
taskdata := data.(*jsonutils.JSONDict)
taskdata.Add(jsonutils.Marshal(sd), "snapshotPolicyDisk")
disk := &SDisk{}
data.Unmarshal(disk, "disk")
disk.SetModelManager(DiskManager, disk)
task, err := taskman.TaskManager.NewTask(ctx, "SnapshotPolicyApplyTask", disk, userCred, nil, "", "", nil)
if err != nil {
log.Errorf("SnapshotPolicyApplyTask newTask error %s", err)
} else {
task.ScheduleRun(nil)
task.ScheduleRun(taskdata)
}
}
func (self *SSnapshotPolicyDisk) CustomizeDelete(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
diskID := self.DiskId
// ==================================================== delete =========================================================
func (sd *SSnapshotPolicyDisk) CustomizeDelete(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject,
data jsonutils.JSONObject) error {
diskID := sd.DiskId
model, err := DiskManager.FetchById(diskID)
if err != nil {
return errors.Wrapf(err, "Fetch disk by ID %s failed", diskID)
}
disk := model.(*SDisk)
snapshotPolicyID := self.SnapshotpolicyId
snapshotPolicyID := sd.SnapshotpolicyId
taskData := jsonutils.NewDict()
taskData.Add(jsonutils.NewString(snapshotPolicyID), "snapshot_policy_id")
task, err := taskman.TaskManager.NewTask(ctx, "SnapshotPolicyCancelTask", disk, userCred, taskData, "", "", nil)
taskData.Add(jsonutils.Marshal(sd), "snapshotPolicyDisk")
sd.SetStatus(userCred, compute.SNAPSHOT_POLICY_DISK_DELETING, "")
task, err := taskman.TaskManager.NewTask(ctx, "SnapshotPolicyCancelTask", disk, userCred, nil, "", "", nil)
if err != nil {
return errors.Wrapf(err, "SnapshotPolicyCancelTask newTask error %s", err)
} else {
task.ScheduleRun(nil)
task.ScheduleRun(taskData)
}
return nil
}

View File

@@ -77,6 +77,11 @@ type ComputeOptions struct {
DefaultMaxSnapshotCount int `default:"9" help:"Per Disk max snapshot count, default 9"`
DefaultMaxManualSnapshotCount int `default:"2" help:"Per Disk max manual snapshot count, default 2"`
//snapshot policy options
RetentionDaysLimit int `default:"49" help:"Days of snapshot retention, default 49 days"`
TimePointsLimit int `default:"1" help:"time point of every days, default 1 point"`
RepeatWeekdaysLimit int `default:"7" help:"day point of every weekday, default 7 points"`
// sku sync
SyncSkusDay int `default:"1" help:"Days auto sync skus data, default 1 day"`
SyncSkusHour int `default:"3" help:"What hour start sync skus, default 03:00"`

View File

@@ -18,7 +18,6 @@ import (
"context"
"fmt"
"regexp"
"sort"
"strings"
"time"
@@ -805,34 +804,21 @@ func (self *SAliyunRegionDriver) ValidateUpdateLoadbalancerListenerData(ctx cont
return self.SManagedVirtualizationRegionDriver.ValidateUpdateLoadbalancerListenerData(ctx, userCred, data, lblis, backendGroup)
}
func daysValidate(days []int, min, max int) ([]int, error) {
if len(days) == 0 {
return days, nil
}
sort.Ints(days)
var tmp *int
for i := 0; i < len(days); i++ {
if days[i] < min || days[i] > max {
return days, fmt.Errorf("Day %d out of range", days[i])
}
if tmp != nil && *tmp == days[i] {
return days, fmt.Errorf("Has repeat day %v", days)
} else {
tmp = &days[i]
}
}
return days, nil
}
func (self *SAliyunRegionDriver) ValidateCreateSnapshopolicyDiskData(ctx context.Context, userCred mcclient.TokenCredential, diskID string) error {
ret, err := models.SnapshotPolicyDiskManager.FetchAllSnapshotPolicyOfDisk(ctx, userCred, diskID)
if err != nil {
return err
}
if len(ret) != 0 {
return httperrors.NewBadRequestError("One disk could't attach two snapshot policy in aliyun; please detach last one first.")
}
func (self *SAliyunRegionDriver) ValidateCreateSnapshopolicyDiskData(ctx context.Context,
userCred mcclient.TokenCredential, disk *models.SDisk, snapshotPolicy *models.SSnapshotPolicy) error {
//err := self.SManagedVirtualizationRegionDriver.ValidateCreateSnapshopolicyDiskData(ctx, userCred, disk, snapshotPolicy)
//if err != nil {
// return nil
//}
//// In Aliyun, One disk only apply one snapshot policy
//ret, err := models.SnapshotPolicyDiskManager.FetchAllByDiskID(ctx, userCred, disk.GetId())
//if err != nil {
// return err
//}
//if len(ret) != 0 {
// return httperrors.NewBadRequestError("One disk could't attach two snapshot policy in aliyun; please detach last one first.")
//}
//return nil
return nil
}

View File

@@ -17,14 +17,11 @@ package regiondrivers
import (
"context"
"fmt"
"yunion.io/x/jsonutils"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
)
@@ -127,41 +124,16 @@ func (self *SBaseRegionDriver) RequestDeleteLoadbalancerListenerRule(ctx context
return fmt.Errorf("Not Implement RequestDeleteLoadbalancerListenerRule")
}
func (self *SBaseRegionDriver) ValidateCreateSnapshotPolicyData(ctx context.Context, userCred mcclient.TokenCredential, input *api.SSnapshotPolicyCreateInput, ownerId mcclient.IIdentityProvider, data *jsonutils.JSONDict) error {
var err error
if len(input.RepeatWeekdays) == 0 {
return httperrors.NewMissingParameterError("repeat_weekdays")
}
input.RepeatWeekdays, err = daysValidate(input.RepeatWeekdays, 1, 7)
if err != nil {
return httperrors.NewInputParameterError(err.Error())
}
if len(input.TimePoints) == 0 {
return httperrors.NewInputParameterError("time_points")
}
input.TimePoints, err = daysValidate(input.TimePoints, 0, 23)
if err != nil {
return httperrors.NewInputParameterError(err.Error())
}
return nil
func (self *SBaseRegionDriver) RequestUpdateSnapshotPolicy(ctx context.Context, userCred mcclient.TokenCredential, sp *models.SSnapshotPolicy, input cloudprovider.SnapshotPolicyInput, task taskman.ITask) error {
return fmt.Errorf("Not Implement RequestUpdateSnapshotPolicy")
}
func (self *SBaseRegionDriver) RequestCreateSnapshotPolicy(ctx context.Context, userCred mcclient.TokenCredential, sp *models.SSnapshotPolicy, task taskman.ITask) error {
return fmt.Errorf("Not Implement RequestCreateSnapshotPolicy")
}
func (self *SBaseRegionDriver) RequestDeleteSnapshotPolicy(ctx context.Context, userCred mcclient.TokenCredential, sp *models.SSnapshotPolicy, task taskman.ITask) error {
return fmt.Errorf("Not Implement RequestDeleteSnapshotPolicy")
}
func (self *SBaseRegionDriver) RequestApplySnapshotPolicy(ctx context.Context, userCred mcclient.TokenCredential, sp *models.SSnapshotPolicy, task taskman.ITask, diskId string) error {
func (self *SBaseRegionDriver) RequestApplySnapshotPolicy(ctx context.Context, userCred mcclient.TokenCredential, task taskman.ITask, disk *models.SDisk, sp *models.SSnapshotPolicy, data jsonutils.JSONObject) error {
return fmt.Errorf("Not Implement RequestApplySnapshotPolicy")
}
func (self *SBaseRegionDriver) RequestCancelSnapshotPolicy(ctx context.Context, userCred mcclient.TokenCredential, sp *models.SSnapshotPolicy, task taskman.ITask, diskId string) error {
return fmt.Errorf("Not Implement RequestApplySnapshotPolicy")
func (self *SBaseRegionDriver) RequestCancelSnapshotPolicy(ctx context.Context, userCred mcclient.TokenCredential, task taskman.ITask, disk *models.SDisk, sp *models.SSnapshotPolicy, data jsonutils.JSONObject) error {
return fmt.Errorf("Not Implement RequestCancelSnapshotPolicy")
}
func (self *SBaseRegionDriver) ValidateSnapshotDelete(ctx context.Context, snapshot *models.SSnapshot) error {
@@ -192,8 +164,9 @@ func (self *SBaseRegionDriver) OnDiskReset(ctx context.Context, userCred mcclien
return fmt.Errorf("Not Implement OnDiskReset")
}
func (self *SBaseRegionDriver) ValidateCreateSnapshopolicyDiskData(ctx context.Context, userCred mcclient.TokenCredential, diskID string) error {
return fmt.Errorf("Not Implement ValidateCreateSnapshotpolicyDiskData")
func (self *SBaseRegionDriver) ValidateCreateSnapshopolicyDiskData(ctx context.Context,
userCred mcclient.TokenCredential, disk *models.SDisk, snapshotPolicy *models.SSnapshotPolicy) error {
return nil
}
func (self *SBaseRegionDriver) OnSnapshotDelete(ctx context.Context, snapshot *models.SSnapshot, task taskman.ITask, data jsonutils.JSONObject) error {

View File

@@ -21,7 +21,6 @@ import (
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/onecloud/pkg/util/rand"
"yunion.io/x/pkg/utils"
api "yunion.io/x/onecloud/pkg/apis/compute"
@@ -30,8 +29,10 @@ import (
"yunion.io/x/onecloud/pkg/cloudcommon/validators"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/onecloud/pkg/compute/options"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/util/rand"
)
type SKVMRegionDriver struct {
@@ -774,37 +775,48 @@ func (self *SKVMRegionDriver) OnDiskReset(ctx context.Context, userCred mcclient
return models.GetStorageDriver(storage.StorageType).OnDiskReset(ctx, userCred, disk, snapshot, data)
}
func (self *SKVMRegionDriver) ValidateCreateSnapshotPolicyData(ctx context.Context, userCred mcclient.TokenCredential, input *api.SSnapshotPolicyCreateInput, ownerId mcclient.IIdentityProvider, data *jsonutils.JSONDict) error {
err := self.SBaseRegionDriver.ValidateCreateSnapshotPolicyData(ctx, userCred, input, ownerId, data)
if err != nil {
return err
func (self *SKVMRegionDriver) RequestUpdateSnapshotPolicy(ctx context.Context,
userCred mcclient.TokenCredential, sp *models.SSnapshotPolicy, input cloudprovider.SnapshotPolicyInput,
task taskman.ITask) error {
return nil
}
func (self *SKVMRegionDriver) ValidateCreateSnapshopolicyDiskData(ctx context.Context,
userCred mcclient.TokenCredential, disk *models.SDisk, snapshotPolicy *models.SSnapshotPolicy) error {
if snapshotPolicy.RetentionDays < -1 || snapshotPolicy.RetentionDays == 0 || snapshotPolicy.RetentionDays > options.Options.RetentionDaysLimit {
return httperrors.NewInputParameterError("Retention days must in 1~%d or -1", options.Options.RetentionDaysLimit)
}
// TODO: To be determined
if input.RetentionDays < -1 || input.RetentionDays == 0 || input.RetentionDays > 10 {
return httperrors.NewInputParameterError("Retention days must in 1~10 or -1")
repeatWeekdays := models.SnapshotPolicyManager.RepeatWeekdaysToIntArray(snapshotPolicy.RepeatWeekdays)
timePoints := models.SnapshotPolicyManager.TimePointsToIntArray(snapshotPolicy.TimePoints)
if len(repeatWeekdays) > options.Options.RepeatWeekdaysLimit {
return httperrors.NewInputParameterError("repeat_weekdays only contains %d days at most",
options.Options.RepeatWeekdaysLimit)
}
if len(timePoints) > options.Options.TimePointsLimit {
return httperrors.NewInputParameterError("time_points only contains %d points at most", options.Options.TimePointsLimit)
}
return nil
}
func (self *SKVMRegionDriver) RequestCreateSnapshotPolicy(ctx context.Context, userCred mcclient.TokenCredential, sp *models.SSnapshotPolicy, task taskman.ITask) error {
func (self *SKVMRegionDriver) RequestApplySnapshotPolicy(ctx context.Context, userCred mcclient.TokenCredential, task taskman.ITask, disk *models.SDisk, sp *models.SSnapshotPolicy, data jsonutils.JSONObject) error {
taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
return nil, nil
data := jsonutils.NewDict()
data.Add(jsonutils.NewString(sp.GetId()), "snapshotpolicy_id")
return data, nil
})
return nil
}
func (self *SKVMRegionDriver) ValidateCreateSnapshopolicyDiskData(ctx context.Context, userCred mcclient.TokenCredential, diskID string) error {
return nil
}
func (self *SKVMRegionDriver) RequestApplySnapshotPolicy(ctx context.Context, userCred mcclient.TokenCredential, sp *models.SSnapshotPolicy, task taskman.ITask, diskId string) error {
task.ScheduleRun(nil)
return nil
}
func (self *SKVMRegionDriver) RequestCancelSnapshotPolicy(ctx context.Context, userCred mcclient.TokenCredential, sp *models.SSnapshotPolicy, task taskman.ITask, diskId string) error {
func (self *SKVMRegionDriver) RequestCancelSnapshotPolicy(ctx context.Context, userCred mcclient.TokenCredential, task taskman.ITask, disk *models.SDisk, sp *models.SSnapshotPolicy, data jsonutils.JSONObject) error {
taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
return nil, nil
data := jsonutils.NewDict()
data.Add(jsonutils.NewString(sp.GetId()), "snapshotpolicy_id")
return data, nil
})
return nil
}
@@ -823,3 +835,13 @@ func (self *SKVMRegionDriver) RequestBindIPToNatgateway(ctx context.Context, tas
return nil
}
func (self *SKVMRegionDriver) RequestPreSnapshotPolicyApply(ctx context.Context, userCred mcclient.
TokenCredential, task taskman.ITask, disk *models.SDisk, sp *models.SSnapshotPolicy, data jsonutils.JSONObject) error {
taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
return data, nil
})
return nil
}

View File

@@ -29,7 +29,6 @@ import (
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/cloudcommon/validators"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/onecloud/pkg/httperrors"
@@ -1041,79 +1040,73 @@ func (self *SManagedVirtualizationRegionDriver) ValidateCreateEipData(ctx contex
return data, nil
}
func (self *SManagedVirtualizationRegionDriver) RequestCreateSnapshotPolicy(ctx context.Context, userCred mcclient.TokenCredential, sp *models.SSnapshotPolicy, task taskman.ITask) error {
func (self *SManagedVirtualizationRegionDriver) RequestUpdateSnapshotPolicy(ctx context.Context, userCred mcclient.
TokenCredential, sp *models.SSnapshotPolicy, input cloudprovider.SnapshotPolicyInput, task taskman.ITask) error {
// it's too cumbersome to pass parameters in taskman, so change a simple way for the moment
//spcache, err := models.SnapshotPolicyCacheManager.FetchSnapshotPolicyCache(sp.GetId(), sp.CloudregionId, sp.ManagerId)
//if err != nil {
// return errors.Wrapf(err, "Fetch cache ofsnapshotpolicy %s", sp.GetId())
//}
//return spcache.UpdateCloudSnapshotPolicy(&input)
return nil
}
// RequestApplySnapshotPolicy apply snapshotpolicy for public cloud.
// In our system, one disk only can hava one snapshot policy attached.
// Default, some public cloud such as Aliyun is same with us and this function shoule be used for these public cloud.
// But in Some public cloud such as Qcloud different with us,
// we should wirte a new function in corressponding regiondriver which detach all snapshotpolicy of disk after
// attache new one.
// You can refer to the implementations of function SQcloudRegionDriver.RequestApplySnapshotPolicy().
func (self *SManagedVirtualizationRegionDriver) RequestApplySnapshotPolicy(ctx context.Context,
userCred mcclient.TokenCredential, task taskman.ITask, disk *models.SDisk, sp *models.SSnapshotPolicy,
data jsonutils.JSONObject) error {
taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
iRegion, err := sp.GetIRegion()
spcache, err := models.SnapshotPolicyCacheManager.Register(ctx, userCred, sp.GetId(),
disk.GetStorage().GetRegion().GetId(),
disk.GetStorage().ManagerId)
if err != nil {
return nil, err
return nil, errors.Wrap(err, "registersnapshotpolicy cache failed")
}
input, err := sp.GenerateCreateSpParams()
if err != nil {
return nil, err
}
policyId, err := iRegion.CreateSnapshotPolicy(input)
if err != nil {
return nil, err
}
err = db.SetExternalId(sp, userCred, policyId)
iRegion, err := disk.GetIRegion()
if err != nil {
return nil, err
}
iPolicy, err := iRegion.GetISnapshotPolicyById(policyId)
err = iRegion.ApplySnapshotPolicyToDisks(spcache.GetExternalId(), disk.GetExternalId())
if err != nil {
return nil, err
}
err = cloudprovider.WaitStatus(iPolicy, api.SNAPSHOT_POLICY_READY, 10*time.Second, 300*time.Second)
if err != nil {
return nil, err
}
return nil, nil
data := jsonutils.NewDict()
data.Add(jsonutils.NewString(sp.GetId()), "snapshotpolicy_id")
return data, nil
})
return nil
}
func (self *SManagedVirtualizationRegionDriver) RequestDeleteSnapshotPolicy(ctx context.Context, userCred mcclient.TokenCredential, sp *models.SSnapshotPolicy, task taskman.ITask) error {
taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
iRegion, err := sp.GetIRegion()
if err != nil {
return nil, err
}
err = iRegion.DeleteSnapshotPolicy(sp.GetExternalId())
if err != nil {
return nil, err
}
return nil, nil
})
return nil
}
func (self *SManagedVirtualizationRegionDriver) RequestCancelSnapshotPolicy(ctx context.Context, userCred mcclient.
TokenCredential, task taskman.ITask, disk *models.SDisk, sp *models.SSnapshotPolicy, data jsonutils.JSONObject) error {
func (self *SManagedVirtualizationRegionDriver) RequestApplySnapshotPolicy(ctx context.Context, userCred mcclient.TokenCredential, sp *models.SSnapshotPolicy, task taskman.ITask, diskId string) error {
taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
iRegion, err := sp.GetIRegion()
if err != nil {
return nil, err
}
err = iRegion.ApplySnapshotPolicyToDisks(sp.GetExternalId(), diskId)
if err != nil {
return nil, err
}
return nil, nil
})
return nil
}
spcache, err := models.SnapshotPolicyCacheManager.FetchSnapshotPolicyCache(sp.GetId(),
disk.GetStorage().GetRegion().GetId(), disk.GetStorage().ManagerId)
func (self *SManagedVirtualizationRegionDriver) RequestCancelSnapshotPolicy(ctx context.Context, userCred mcclient.TokenCredential, sp *models.SSnapshotPolicy, task taskman.ITask, diskId string) error {
taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
iRegion, err := sp.GetIRegion()
iRegion, err := spcache.GetIRegion()
if err != nil {
return nil, err
}
err = iRegion.CancelSnapshotPolicyToDisks(sp.GetExternalId(), diskId)
err = iRegion.CancelSnapshotPolicyToDisks(spcache.GetExternalId(), disk.GetExternalId())
if err != nil {
return nil, err
}
return nil, nil
data := jsonutils.NewDict()
data.Add(jsonutils.NewString(sp.GetId()), "snapshotpolicy_id")
return data, nil
})
return nil
}
@@ -1180,7 +1173,9 @@ func (self *SManagedVirtualizationRegionDriver) GetDiskResetParams(snapshot *mod
return params
}
func (self *SManagedVirtualizationRegionDriver) OnDiskReset(ctx context.Context, userCred mcclient.TokenCredential, disk *models.SDisk, snapshot *models.SSnapshot, data jsonutils.JSONObject) error {
func (self *SManagedVirtualizationRegionDriver) OnDiskReset(ctx context.Context, userCred mcclient.TokenCredential,
disk *models.SDisk, snapshot *models.SSnapshot, data jsonutils.JSONObject) error {
externalId, _ := data.GetString("exteranl_disk_id")
if len(externalId) > 0 {
_, err := db.Update(disk, func() error {
@@ -1211,19 +1206,11 @@ func (self *SManagedVirtualizationRegionDriver) OnDiskReset(ctx context.Context,
return nil
}
func (self *SManagedVirtualizationRegionDriver) ValidateCreateSnapshopolicyDiskData(ctx context.Context, userCred mcclient.TokenCredential, diskID string) error {
return nil
}
func (self *SManagedVirtualizationRegionDriver) ValidateCreateSnapshotPolicyData(ctx context.Context, userCred mcclient.TokenCredential, input *api.SSnapshotPolicyCreateInput, ownerId mcclient.IIdentityProvider, data *jsonutils.JSONDict) error {
cloudregionV := validators.NewModelIdOrNameValidator("cloudregion", "cloudregion", ownerId)
err := cloudregionV.Validate(data)
if err != nil {
return err
func (self *SManagedVirtualizationRegionDriver) ValidateCreateSnapshopolicyDiskData(ctx context.Context,
userCred mcclient.TokenCredential, disk *models.SDisk, snapshotPolicy *models.SSnapshotPolicy) error {
if snapshotPolicy.RetentionDays < -1 || snapshotPolicy.RetentionDays == 0 || snapshotPolicy.RetentionDays > 65535 {
return httperrors.NewInputParameterError("Retention days must in 1~65535 or -1")
}
cloudregion := cloudregionV.Model.(*models.SCloudregion)
input.CloudregionId = cloudregion.GetId()
return nil
}
@@ -1243,3 +1230,13 @@ func (self *SManagedVirtualizationRegionDriver) RequestBindIPToNatgateway(ctx co
task.ScheduleRun(nil)
return nil
}
func (self *SManagedVirtualizationRegionDriver) RequestPreSnapshotPolicyApply(ctx context.Context, userCred mcclient.
TokenCredential, task taskman.ITask, disk *models.SDisk, sp *models.SSnapshotPolicy, data jsonutils.JSONObject) error {
taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
return data, nil
})
return nil
}

View File

@@ -18,7 +18,6 @@ import (
"context"
"fmt"
"regexp"
"yunion.io/x/jsonutils"
api "yunion.io/x/onecloud/pkg/apis/compute"
@@ -743,3 +742,27 @@ func (self *SQcloudRegionDriver) ValidateCreateLoadbalancerBackendData(ctx conte
data.Set("cloudregion_id", jsonutils.NewString(lb.CloudregionId))
return data, nil
}
func (self *SQcloudRegionDriver) RequestPreSnapshotPolicyApply(ctx context.Context, userCred mcclient.
TokenCredential, task taskman.ITask, disk *models.SDisk, sp *models.SSnapshotPolicy, data jsonutils.JSONObject) error {
taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
if sp == nil {
return data, nil
}
spcache, err := models.SnapshotPolicyCacheManager.FetchSnapshotPolicyCache(sp.GetId(),
disk.GetStorage().GetRegion().GetId(), disk.GetStorage().ManagerId)
iRegion, err := spcache.GetIRegion()
if err != nil {
return nil, err
}
err = iRegion.CancelSnapshotPolicyToDisks(spcache.GetExternalId(), disk.GetExternalId())
if err != nil {
return nil, err
}
return data, nil
})
return nil
}

View File

@@ -118,7 +118,17 @@ func (self *DiskDeleteTask) OnMasterStorageDeleteDiskCompleteFailed(ctx context.
}
func (self *DiskDeleteTask) startPendingDeleteDisk(ctx context.Context, disk *models.SDisk) {
disk.DoPendingDelete(ctx, self.UserCred)
err := disk.DoPendingDelete(ctx, self.UserCred)
if err != nil {
self.OnGuestDiskDeleteCompleteFailed(ctx, disk, jsonutils.NewString("pending delete disk failed"))
return
}
err = models.SnapshotPolicyDiskManager.SyncDetachByDisk(ctx, self.UserCred, nil, disk)
if err != nil {
self.OnGuestDiskDeleteCompleteFailed(ctx, disk,
jsonutils.NewString("detach all snapshotpolicies of disk failed"))
return
}
self.SetStageComplete(ctx, nil)
}

View File

@@ -16,9 +16,9 @@ package tasks
import (
"context"
"fmt"
"yunion.io/x/jsonutils"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
@@ -45,15 +45,12 @@ func (self *SnapshotPolicyDeleteTask) taskFail(ctx context.Context, sp *models.S
func (self *SnapshotPolicyDeleteTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
sp := obj.(*models.SSnapshotPolicy)
region := sp.GetRegion()
if region == nil {
self.taskFail(ctx, sp, fmt.Sprintf("failed to find region for sp %s", sp.Name))
err := models.SnapshotPolicyCacheManager.DeleteCloudSnapshotPolices(ctx, self.UserCred, sp.GetId())
if err != nil {
self.taskFail(ctx, sp, err.Error())
return
}
self.SetStage("OnSnapshotPolicyDeleteComplete", nil)
if err := region.GetDriver().RequestDeleteSnapshotPolicy(ctx, self.GetUserCred(), sp, self); err != nil {
self.taskFail(ctx, sp, err.Error())
}
self.OnSnapshotPolicyDeleteComplete(ctx, sp, data)
}
func (self *SnapshotPolicyDeleteTask) OnSnapshotPolicyDeleteComplete(ctx context.Context, sp *models.SSnapshotPolicy, data jsonutils.JSONObject) {

View File

@@ -1,173 +0,0 @@
// Copyright 2019 Yunion
//
// 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.
package tasks
import (
"context"
"fmt"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/cloudcommon/notifyclient"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/onecloud/pkg/util/logclient"
)
type SnapshotPolicyCreateTask struct {
taskman.STask
}
func init() {
taskman.RegisterTask(SnapshotPolicyCreateTask{})
taskman.RegisterTask(SnapshotPolicyApplyTask{})
taskman.RegisterTask(SnapshotPolicyCancelTask{})
}
func (self *SnapshotPolicyCreateTask) taskFail(ctx context.Context, sp *models.SSnapshotPolicy, reason string) {
sp.SetStatus(self.UserCred, compute.SNAPSHOT_POLICY_CREATE_FAILED, "")
db.OpsLog.LogEvent(sp, db.ACT_ALLOCATE_FAIL, reason, self.UserCred)
logclient.AddActionLogWithStartable(self, sp, logclient.ACT_CREATE, false, self.UserCred, false)
notifyclient.NotifySystemError(sp.GetId(), sp.Name, compute.SNAPSHOT_POLICY_CREATE_FAILED, reason)
self.SetStageFailed(ctx, reason)
}
func (self *SnapshotPolicyCreateTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
snapshotPolicy := obj.(*models.SSnapshotPolicy)
region := snapshotPolicy.GetRegion()
if region == nil {
self.taskFail(ctx, snapshotPolicy, fmt.Sprintf("failed to find region for snapshot policy %s", snapshotPolicy.Name))
return
}
self.SetStage("OnSnapshotPolicyCreate", nil)
if err := region.GetDriver().RequestCreateSnapshotPolicy(ctx, self.GetUserCred(), snapshotPolicy, self); err != nil {
self.taskFail(ctx, snapshotPolicy, err.Error())
}
}
func (self *SnapshotPolicyCreateTask) OnSnapshotPolicyCreate(
ctx context.Context, sp *models.SSnapshotPolicy, data jsonutils.JSONObject,
) {
sp.SetStatus(self.UserCred, compute.SNAPSHOT_POLICY_READY, "")
db.OpsLog.LogEvent(sp, db.ACT_ALLOCATE, sp.GetShortDesc(ctx), self.UserCred)
logclient.AddActionLogWithStartable(self, sp, logclient.ACT_CREATE, nil, self.UserCred, true)
self.SetStageComplete(ctx, nil)
}
func (self *SnapshotPolicyCreateTask) OnSnapshotPolicyCreateFailed(
ctx context.Context, sp *models.SSnapshotPolicy, data jsonutils.JSONObject,
) {
self.taskFail(ctx, sp, data.String())
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
type SnapshotPolicyApplyTask struct {
taskman.STask
}
func (self *SnapshotPolicyApplyTask) taskFail(ctx context.Context, disk *models.SDisk, snapshotPolicyId, reason string) {
jointModel, err := db.FetchJointByIds(models.SnapshotPolicyDiskManager, disk.Id, snapshotPolicyId, jsonutils.JSONNull)
if err != nil {
log.Errorf("Fetch SnapshotPolicy %s Disk %s joint model failed %s", disk.Id, snapshotPolicyId, reason)
return
}
snapshotPolicyDisk := jointModel.(*models.SSnapshotPolicyDisk)
err = snapshotPolicyDisk.Detach(ctx, self.UserCred)
if err != nil {
log.Errorf("Delete SnapshotPolicy %s Disk %s joint model failed, need to delete", self.Id, snapshotPolicyId)
}
disk.SetStatus(self.UserCred, compute.DISK_APPLY_SNAPSHOT_FAIL, reason)
db.OpsLog.LogEvent(disk, db.ACT_APPLY_SNAPSHOT_POLICY_FAILED, reason, self.UserCred)
logclient.AddActionLogWithStartable(self, disk, logclient.ACT_APPLY_SNAPSHOT_POLICY, reason, self.UserCred, false)
self.SetStageFailed(ctx, reason)
}
func (self *SnapshotPolicyApplyTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
disk := obj.(*models.SDisk)
snapshotPolicyID, _ := self.Params.GetString("snapshot_policy_id")
// fetch disk model by diksID
model, err := models.SnapshotPolicyManager.FetchById(snapshotPolicyID)
if err != nil {
self.taskFail(ctx, disk, snapshotPolicyID, fmt.Sprintf("failed to fetch disk by id %s: %s", snapshotPolicyID, err.Error()))
return
}
snapshotPolicy := model.(*models.SSnapshotPolicy)
self.SetStage("OnSnapshotPolicyApply", nil)
if err := disk.GetStorage().GetRegion().GetDriver().
RequestApplySnapshotPolicy(ctx, self.UserCred, snapshotPolicy, self, disk.ExternalId); err != nil {
self.taskFail(ctx, disk, snapshotPolicyID, fmt.Sprintf("faile to attach snapshot policy %s and disk %s: %s", snapshotPolicy.Id, disk.Id, err.Error()))
}
}
func (self *SnapshotPolicyApplyTask) OnSnapshotPolicyApply(ctx context.Context, disk *models.SDisk, data jsonutils.JSONObject) {
db.OpsLog.LogEvent(disk, db.ACT_APPLY_SNAPSHOT_POLICY, "", self.UserCred)
logclient.AddActionLogWithStartable(self, disk, logclient.ACT_APPLY_SNAPSHOT_POLICY, "", self.UserCred, true)
self.SetStageComplete(ctx, nil)
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
type SnapshotPolicyCancelTask struct {
taskman.STask
}
func (self *SnapshotPolicyCancelTask) taskFail(ctx context.Context, disk *models.SDisk, snapshotPolicyId, reason string) {
jointModel, err := db.FetchJointByIds(models.SnapshotPolicyDiskManager, disk.Id, snapshotPolicyId, jsonutils.JSONNull)
if err != nil {
log.Errorf("Fetch SnapshotPolicy %s Disk %s joint model failed %s", disk.Id, snapshotPolicyId, reason)
return
}
snapshotPolicyDisk := jointModel.(*models.SSnapshotPolicyDisk)
err = snapshotPolicyDisk.MarkUnDelete()
if err != nil {
log.Errorf("Mark undelete joint model snapshotPolicy %s and disk %s failes", snapshotPolicyId, disk.Id)
}
disk.SetStatus(self.UserCred, compute.DISK_CALCEL_SNAPSHOT_FAIL, reason)
db.OpsLog.LogEvent(disk, db.ACT_CANCEL_SNAPSHOT_POLICY_FAILED, reason, self.UserCred)
logclient.AddActionLogWithStartable(self, disk, logclient.ACT_CANCEL_SNAPSHOT_POLICY, reason, self.UserCred, false)
self.SetStageFailed(ctx, reason)
}
func (self *SnapshotPolicyCancelTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
disk := obj.(*models.SDisk)
snapshotPolicyID, _ := self.GetParams().GetString("snapshot_policy_id")
model, err := models.SnapshotPolicyManager.FetchById(snapshotPolicyID)
if err != nil {
self.taskFail(ctx, disk, snapshotPolicyID, fmt.Sprintf("failed to fetch disk by id %s: %s", snapshotPolicyID, err.Error()))
return
}
snapshotPolicy := model.(*models.SSnapshotPolicy)
self.SetStage("OnSnapshotPolicyCancel", nil)
if err := disk.GetStorage().GetRegion().GetDriver().
RequestCancelSnapshotPolicy(ctx, self.UserCred, snapshotPolicy, self, disk.ExternalId); err != nil {
self.taskFail(ctx, disk, snapshotPolicyID, fmt.Sprintf("faile to detach snapshot policy %s and disk %s: %s", snapshotPolicy.Id, disk.Id, err.Error()))
}
}
func (self *SnapshotPolicyCancelTask) OnSnapshotPolicyCancel(ctx context.Context, disk *models.SDisk, data jsonutils.JSONObject) {
db.OpsLog.LogEvent(disk, db.ACT_CANCEL_SNAPSHOT_POLICY, "", self.UserCred)
logclient.AddActionLogWithStartable(self, disk, logclient.ACT_CANCEL_SNAPSHOT_POLICY, "", self.UserCred, true)
self.SetStageComplete(ctx, nil)
}

View File

@@ -0,0 +1,210 @@
// Copyright 2019 Yunion
//
// 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.
package tasks
import (
"context"
"fmt"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/cloudcommon/notifyclient"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/onecloud/pkg/util/logclient"
)
func init() {
taskman.RegisterTask(SnapshotPolicyApplyTask{})
taskman.RegisterTask(SnapshotPolicyCancelTask{})
}
type SnapshotPolicyApplyTask struct {
taskman.STask
}
func (self *SnapshotPolicyApplyTask) taskFail(ctx context.Context, disk *models.SDisk,
spd *models.SSnapshotPolicyDisk, reason string) {
if spd != nil {
err := spd.RealDetach(ctx, self.UserCred)
if err != nil {
log.Errorf("Delete snapshotpolicydisk %s failed, need to delete", spd.GetId())
}
}
disk.SetStatus(self.UserCred, compute.DISK_APPLY_SNAPSHOT_FAIL, reason)
db.OpsLog.LogEvent(disk, db.ACT_APPLY_SNAPSHOT_POLICY_FAILED, reason, self.UserCred)
logclient.AddActionLogWithStartable(self, disk, logclient.ACT_APPLY_SNAPSHOT_POLICY, reason, self.UserCred, false)
notifyclient.NotifySystemError(disk.GetId(), disk.Name, compute.DISK_APPLY_SNAPSHOT_FAIL, reason)
self.SetStageFailed(ctx, reason)
}
func (self *SnapshotPolicyApplyTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
disk := obj.(*models.SDisk)
spd := models.SSnapshotPolicyDisk{}
data.Unmarshal(&spd, "snapshotPolicy")
var snapshotPolicy *models.SSnapshotPolicy
if data.Contains("need_detach") {
snapshotPolicyID, _ := data.GetString("need_detach")
model, err := models.SnapshotPolicyManager.FetchById(snapshotPolicyID)
if err != nil {
self.taskFail(ctx, disk, &spd, err.Error())
return
}
snapshotPolicy = model.(*models.SSnapshotPolicy)
}
self.Params.Add(jsonutils.NewString(spd.GetId()), "snapshotpolicy_id")
self.SetStage("OnPreSnapshotPolicyApplyComplete", nil)
// pass data to next Stage without inserting database through this way
if err := disk.GetStorage().GetRegion().GetDriver().RequestPreSnapshotPolicyApply(ctx, self.UserCred, self, disk, snapshotPolicy,
data); err != nil {
self.taskFail(ctx, disk, &spd, err.Error())
return
}
}
func (self *SnapshotPolicyApplyTask) OnPreSnapshotPolicyApplyCompleteFailed(ctx context.Context, disk *models.SDisk,
reason jsonutils.JSONObject) {
spId, _ := self.Params.GetString("snapshotpolicy_id")
spd, err := models.SnapshotPolicyDiskManager.FetchBySnapshotPolicyDisk(spId, disk.GetId())
if err != nil {
self.taskFail(ctx, disk, nil, reason.String())
return
}
self.taskFail(ctx, disk, spd, reason.String())
}
func (self *SnapshotPolicyApplyTask) OnPreSnapshotPolicyApplyComplete(ctx context.Context, disk *models.SDisk,
data jsonutils.JSONObject) {
if data.Contains("need_detach") {
snapshotPolicyID, _ := data.GetString("need_detach")
spd1, err := models.SnapshotPolicyDiskManager.FetchBySnapshotPolicyDisk(snapshotPolicyID, disk.GetId())
if err != nil {
self.taskFail(ctx, disk, spd1, err.Error())
return
}
if spd1 != nil {
spd1.RealDetach(ctx, self.UserCred)
}
}
snapshotPolicy, spd := models.SSnapshotPolicy{}, models.SSnapshotPolicyDisk{}
data.Unmarshal(&snapshotPolicy, "snapshotPolicy")
data.Unmarshal(&spd, "snapshotPolicyDisk")
self.SetStage("OnSnapshotPolicyApply", nil)
// pass data to next Stage without inserting database through this way
if err := disk.GetStorage().GetRegion().GetDriver().
RequestApplySnapshotPolicy(ctx, self.UserCred, self, disk, &snapshotPolicy, data); err != nil {
self.taskFail(ctx, disk, &spd, err.Error())
}
}
func (self *SnapshotPolicyApplyTask) OnSnapshotPolicyApplyFailed(ctx context.Context, disk *models.SDisk,
reason jsonutils.JSONObject) {
spId, _ := self.Params.GetString("snapshotpolicy_id")
spd, err := models.SnapshotPolicyDiskManager.FetchBySnapshotPolicyDisk(spId, disk.GetId())
if err != nil {
self.taskFail(ctx, disk, nil, reason.String())
return
}
self.taskFail(ctx, disk, spd, reason.String())
}
func (self *SnapshotPolicyApplyTask) OnSnapshotPolicyApply(ctx context.Context, disk *models.SDisk, data jsonutils.JSONObject) {
sp_id, _ := data.GetString("snapshotpolicy_id")
spd, err := models.SnapshotPolicyDiskManager.FetchBySnapshotPolicyDisk(sp_id, disk.GetId())
if err != nil {
log.Errorf("Fechsnapshotpolicy disk failed")
}
spd.SetStatus(self.UserCred, compute.SNAPSHOT_POLICY_DISK_READY, "")
db.OpsLog.LogEvent(disk, db.ACT_APPLY_SNAPSHOT_POLICY, "", self.UserCred)
logclient.AddActionLogWithStartable(self, disk, logclient.ACT_APPLY_SNAPSHOT_POLICY, "", self.UserCred, true)
self.SetStageComplete(ctx, nil)
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
type SnapshotPolicyCancelTask struct {
taskman.STask
}
func (self *SnapshotPolicyCancelTask) taskFail(ctx context.Context, disk *models.SDisk, spd *models.SSnapshotPolicyDisk, reason string) {
if spd != nil {
spd.SetStatus(self.UserCred, compute.SNAPSHOT_POLICY_DISK_DELETE_FAILED, "")
}
disk.SetStatus(self.UserCred, compute.DISK_CALCEL_SNAPSHOT_FAIL, reason)
db.OpsLog.LogEvent(disk, db.ACT_CANCEL_SNAPSHOT_POLICY_FAILED, reason, self.UserCred)
logclient.AddActionLogWithStartable(self, disk, logclient.ACT_CANCEL_SNAPSHOT_POLICY, reason, self.UserCred, false)
self.SetStageFailed(ctx, reason)
}
func (self *SnapshotPolicyCancelTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
disk := obj.(*models.SDisk)
snapshotPolicyID, _ := data.GetString("snapshot_policy_id")
spd := models.SSnapshotPolicyDisk{}
data.Unmarshal(&spd, "snapshotPolicyDisk")
self.Params.Add(jsonutils.NewString(snapshotPolicyID), "snapshotpolicy_id")
model, err := models.SnapshotPolicyManager.FetchById(snapshotPolicyID)
if err != nil {
self.taskFail(ctx, disk, &spd, fmt.Sprintf("failed to fetch disk by id %s: %s", snapshotPolicyID, err.Error()))
return
}
snapshotPolicy := model.(*models.SSnapshotPolicy)
self.SetStage("OnSnapshotPolicyCancel", nil)
if err := disk.GetStorage().GetRegion().GetDriver().RequestCancelSnapshotPolicy(ctx, self.UserCred, self, disk, snapshotPolicy, data); err != nil {
self.taskFail(ctx, disk, &spd, fmt.Sprintf("faile to detach snapshot policy %s and disk %s: %s",
snapshotPolicy.Id, disk.Id, err.Error()))
}
}
func (self *SnapshotPolicyCancelTask) OnSnapshotPolicyCancelFailed(ctx context.Context, disk *models.SDisk,
reason jsonutils.JSONObject) {
spId, _ := self.Params.GetString("snapshotpolicy_id")
spd, err := models.SnapshotPolicyDiskManager.FetchBySnapshotPolicyDisk(spId, disk.GetId())
if err != nil {
self.taskFail(ctx, disk, nil, reason.String())
return
}
self.taskFail(ctx, disk, spd, reason.String())
}
func (self *SnapshotPolicyCancelTask) OnSnapshotPolicyCancel(ctx context.Context, disk *models.SDisk, data jsonutils.JSONObject) {
sp_id, _ := data.GetString("snapshotpolicy_id")
spd, err := models.SnapshotPolicyDiskManager.FetchBySnapshotPolicyDisk(sp_id, disk.GetId())
if err != nil {
log.Errorf("Fechsnapshotpolicy disk failed")
}
//real detach
spd.RealDetach(ctx, self.UserCred)
db.OpsLog.LogEvent(disk, db.ACT_CANCEL_SNAPSHOT_POLICY, "", self.UserCred)
logclient.AddActionLogWithStartable(self, disk, logclient.ACT_CANCEL_SNAPSHOT_POLICY, "", self.UserCred, true)
self.SetStageComplete(ctx, nil)
}

View File

@@ -15,7 +15,8 @@
package modules
var (
SnapshotPolicyDisk JointResourceManager
SnapshotPolicyDisk JointResourceManager
SnapshotPolicyDisk1 JointResourceManager
)
func init() {
@@ -27,4 +28,13 @@ func init() {
&Disks,
&SnapshotPoliciy)
registerCompute(&SnapshotPolicyDisk)
SnapshotPolicyDisk1 = NewJointComputeManager(
"snapshotpolicydisk",
"snapshotpolicydisks",
[]string{"Disk_ID", "Snapshotpolicy_ID"},
[]string{},
&SnapshotPoliciy,
&Disks)
registerCompute(&SnapshotPolicyDisk1)
}

View File

@@ -405,8 +405,11 @@ func (self *SDisk) GetCreatedAt() time.Time {
return self.CreationTime
}
func (self *SDisk) GetExtSnapshotPolicyIds() []string {
return []string{self.AutoSnapshotPolicyId}
func (self *SDisk) GetExtSnapshotPolicyIds() ([]string, error) {
if len(self.AutoSnapshotPolicyId) == 0 {
return []string{}, nil
}
return []string{self.AutoSnapshotPolicyId}, nil
}
func (self *SDisk) GetExpiredAt() time.Time {

View File

@@ -234,23 +234,17 @@ func (self *SRegion) CreateSnapshotPolicy(input *cloudprovider.SnapshotPolicyInp
}
}
func (self *SRegion) UpdateSnapshotPolicy(
snapshotPolicyId string, retentionDays *int,
repeatWeekdays, timePoints *jsonutils.JSONArray, policyName string,
) error {
func (self *SRegion) UpdateSnapshotPolicy(input *cloudprovider.SnapshotPolicyInput, snapshotPolicyId string) error {
params := make(map[string]string)
params["RegionId"] = self.RegionId
if len(policyName) > 0 {
params["autoSnapshotPolicyName"] = policyName
if input.RetentionDays != 0 {
params["retentionDays"] = strconv.Itoa(input.RetentionDays)
}
if retentionDays != nil {
params["retentionDays"] = strconv.Itoa(*retentionDays)
if input.RepeatWeekdays != nil && len(input.RepeatWeekdays) != 0 {
params["repeatWeekdays"] = jsonutils.Marshal(input.GetStringArrayRepeatWeekdays()).String()
}
if repeatWeekdays != nil {
params["repeatWeekdays"] = repeatWeekdays.String()
}
if timePoints != nil {
params["timePoints"] = timePoints.String()
if input.TimePoints != nil && len(input.TimePoints) != 0 {
params["timePoints"] = jsonutils.Marshal(input.GetStringArrayTimePoints()).String()
}
_, err := self.ecsRequest("ModifyAutoSnapshotPolicyEx", params)
if err != nil {
@@ -259,6 +253,31 @@ func (self *SRegion) UpdateSnapshotPolicy(
return nil
}
//func (self *SRegion) UpdateSnapshotPolicy(
// snapshotPolicyId string, retentionDays *int,
// repeatWeekdays, timePoints *jsonutils.JSONArray, policyName string,
//) error {
// params := make(map[string]string)
// params["RegionId"] = self.RegionId
// if len(policyName) > 0 {
// params["autoSnapshotPolicyName"] = policyName
// }
// if retentionDays != nil {
// params["retentionDays"] = strconv.Itoa(*retentionDays)
// }
// if repeatWeekdays != nil {
// params["repeatWeekdays"] = repeatWeekdays.String()
// }
// if timePoints != nil {
// params["timePoints"] = timePoints.String()
// }
// _, err := self.ecsRequest("ModifyAutoSnapshotPolicyEx", params)
// if err != nil {
// return fmt.Errorf("ModifyAutoSnapshotPolicyEx Fail %s", err)
// }
// return nil
//}
func (self *SRegion) ApplySnapshotPolicyToDisks(snapshotPolicyId string, diskId string) error {
params := make(map[string]string)
params["RegionId"] = self.RegionId

View File

@@ -16,8 +16,8 @@ package multicloud
type SDisk struct{}
func (self *SDisk) GetExtSnapshotPolicyIds() []string {
return []string{""}
func (self *SDisk) GetExtSnapshotPolicyIds() ([]string, error) {
return []string{""}, nil
}
func (self *SDisk) GetIStorageId() string {

View File

@@ -348,6 +348,10 @@ func (self *SDisk) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) {
return isnapshots, nil
}
func (self *SDisk) GetExtSnapshotPolicyIds() ([]string, error) {
return self.storage.zone.region.GetSnapshotIdByDiskId(self.GetId())
}
func (self *SDisk) GetTemplateId() string {
//return self.ImageId
return ""

View File

@@ -43,7 +43,7 @@ type SSnapshotPolicy struct {
AutoSnapshotPolicyState string
RetentionDays int
Policy []SPolicy
Activated bool `json:"is_activated"`
Activated bool `json:"IsActivated"`
IsPermanent bool
}
@@ -90,6 +90,9 @@ func (self *SSnapshotPolicy) GetProjectId() string {
}
func (self *SSnapshotPolicy) GetRetentionDays() int {
if self.IsPermanent {
return -1
}
return self.RetentionDays
}
@@ -148,6 +151,9 @@ func (self *SRegion) GetSnapshotPolicies(policyId string, offset int, limit int)
if err := body.Unmarshal(&snapshotPolicies, "AutoSnapshotPolicySet"); err != nil {
return nil, 0, errors.Wrap(err, "Unmarshal snapshot policies detail failed")
}
for i := range snapshotPolicies {
snapshotPolicies[i].region = self
}
return snapshotPolicies, len(snapshotPolicies), nil
}
@@ -187,7 +193,14 @@ func (self *SRegion) CreateSnapshotPolicy(input *cloudprovider.SnapshotPolicyInp
return "", fmt.Errorf("Can't create snapshot policy with nil timePoints")
}
params := make(map[string]string)
params["RetentionDays"] = strconv.Itoa(input.RetentionDays)
// In Qcloud, that IsPermanent is true means that keep snapshot forever,
// In OneCloud, that RetentionDays is -1 means that keep snapshot forever.
if input.RetentionDays == -1 {
params["IsPermanent"] = strconv.FormatBool(true)
} else {
params["RetentionDays"] = strconv.Itoa(input.RetentionDays)
}
dayOfWeekPrefix, hourPrefix := "Policy.0.DayOfWeek.", "Policy.0.Hour."
for index, day := range input.RepeatWeekdays {
if day == 0 {
@@ -209,10 +222,7 @@ func (self *SRegion) CreateSnapshotPolicy(input *cloudprovider.SnapshotPolicyInp
return id, nil
}
func (self *SRegion) UpdateSnapshotPolicy(
snapshotPolicyId string, retentionDays *int,
repeatWeekdays, timePoints *jsonutils.JSONArray, policyName string,
) error {
func (self *SRegion) UpdateSnapshotPolicy(input *cloudprovider.SnapshotPolicyInput, snapshotPolicyId string) error {
// not implement
return nil
}
@@ -238,3 +248,23 @@ func (self *SRegion) CancelSnapshotPolicyToDisks(snapshotPolicyId string, diskId
}
return nil
}
func (self *SRegion) GetSnapshotIdByDiskId(diskID string) ([]string, error) {
params := make(map[string]string)
params["DiskId"] = diskID
rps, err := self.cbsRequest("DescribeDiskAssociatedAutoSnapshotPolicy", params)
if err != nil {
return nil, errors.Wrapf(err, "Get All SnapshotpolicyIDs of Disk %s failed", diskID)
}
snapshotpolicies := make([]SSnapshotPolicy, 0)
if err := rps.Unmarshal(&snapshotpolicies, "AutoSnapshotPolicySet"); err != nil {
return nil, errors.Wrapf(err, "Unmarshal snapshot policies details failed")
}
ret := make([]string, len(snapshotpolicies))
for i := range snapshotpolicies {
ret[i] = snapshotpolicies[i].GetId()
}
return ret, nil
}

View File

@@ -26,6 +26,10 @@ func (r *SRegion) CreateSnapshotPolicy(input *cloudprovider.SnapshotPolicyInput)
return "", fmt.Errorf("CreateSnapshotPolicy not implement")
}
func (r *SRegion) UpdateSnapshotPolicy(input *cloudprovider.SnapshotPolicyInput, snapshotPolicyId string) error {
return fmt.Errorf("UpdateSnapshotPolicy not implement")
}
func (r *SRegion) GetISnapshotPolicyById(snapshotPolicyId string) (cloudprovider.ICloudSnapshotPolicy, error) {
return nil, fmt.Errorf("GetISnapshotPolicyById not implement")
}

View File

@@ -14,6 +14,7 @@
package bitmap
// Uint2IntArray transfer bitmap displayed as n to int array
func Uint2IntArray(n uint32) []int {
ret := make([]int, 0, 2)
var i uint = 0
@@ -27,6 +28,7 @@ func Uint2IntArray(n uint32) []int {
return ret
}
// IntArray2Uint transfer int array nums to bitmap number
func IntArray2Uint(nums []int) uint32 {
var ret uint32 = 0
for _, i := range nums {
@@ -34,3 +36,16 @@ func IntArray2Uint(nums []int) uint32 {
}
return ret
}
// Determine if int slice a euqals b
func IntSliceEqual(a, b []int) bool {
if len(a) != len(b) {
return false
}
for i := 0; i < len(a); i++ {
if a[i] != b[i] {
return false
}
}
return true
}

View File

@@ -35,24 +35,12 @@ func TestUint2IntArray(t *testing.T) {
for _, tc := range testCase {
real := Uint2IntArray(tc.input)
if !sliceEqual(real, tc.want) {
if !IntSliceEqual(real, tc.want) {
t.Fatalf("want %v, but %v\n", tc.want, real)
}
}
}
func sliceEqual(a, b []int) bool {
if len(a) != len(b) {
return false
}
for i := 0; i < len(a); i++ {
if a[i] != b[i] {
return false
}
}
return true
}
func TestIntArray2Uint(t *testing.T) {
oneCase := make([]int, 32)
for i := range oneCase {

39
pkg/util/validate/days.go Normal file
View File

@@ -0,0 +1,39 @@
// Copyright 2019 Yunion
//
// 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.
package validate
import (
"fmt"
"sort"
)
// DaysValidate sort days and check if days is out of range [min, max] or has repeated member
func DaysCheck(days []int, min, max int) ([]int, error) {
if len(days) == 0 {
return days, nil
}
sort.Ints(days)
if days[0] < min || days[len(days)-1] > max {
return days, fmt.Errorf("Out of range")
}
for i := 1; i < len(days); i++ {
if days[i] == days[i-1] {
return days, fmt.Errorf("Has repeat day %v", days)
}
}
return days, nil
}

View File

@@ -0,0 +1,63 @@
// Copyright 2019 Yunion
//
// 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.
package validate
import (
"fmt"
"reflect"
"testing"
)
func TestDaysCheck(t *testing.T) {
tcs := []struct {
input_days []int
input_max int
input_min int
want []int
want_error error
}{
{
[]int{3, 5, 1, 4, 8, 3, 4},
10,
1,
[]int{1, 3, 3, 4, 4, 5, 8},
fmt.Errorf("Has repeat day %v", []int{1, 3, 3, 4, 4, 5, 8}),
},
{
[]int{10, 1},
10,
1,
[]int{1, 10},
nil,
},
{
[]int{10, 3, 5},
3,
5,
[]int{3, 5, 10},
fmt.Errorf("Out of range"),
},
}
for _, tc := range tcs {
days, err := DaysCheck(tc.input_days, tc.input_min, tc.input_max)
if !reflect.DeepEqual(days, tc.want) {
t.Fatalf("want: %v, actual: %v", tc.want, days)
}
if !reflect.DeepEqual(err, tc.want_error) {
t.Fatal("err not correct")
}
}
}