diff --git a/cmd/climc/shell/snapshotpolicy_disk.go b/cmd/climc/shell/snapshotpolicy_disk.go new file mode 100644 index 0000000000..84b7011bea --- /dev/null +++ b/cmd/climc/shell/snapshotpolicy_disk.go @@ -0,0 +1,80 @@ +// 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 shell + +import ( + "yunion.io/x/jsonutils" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/mcclient/modules" +) + +func init() { + type SSnapshotpolicyDiskListOfDiskOption struct { + DISKID string `help:"disk id"` + } + R(&SSnapshotpolicyDiskListOfDiskOption{}, "disk-snapshot-policy-list", "List snapshot policy attached", + func(s *mcclient.ClientSession, opts *SSnapshotpolicyDiskListOfDiskOption) error { + result, err := modules.SnapshotPolicyDisk.ListDescendent(s, opts.DISKID, jsonutils.NewDict()) + if err != nil { + return err + } + printList(result, modules.SnapshotPolicyDisk.GetColumns(s)) + return nil + }, + ) + + type SSnapshotpolicyDiskListOfSnapshotpolicyOption struct { + SNAPSHOTPOLICYID string `help:"snapshot policy id"` + } + R(&SSnapshotpolicyDiskListOfSnapshotpolicyOption{}, "snapshot-policy-disk-list", "List disk attached", + func(s *mcclient.ClientSession, opts *SSnapshotpolicyDiskListOfSnapshotpolicyOption) error { + result, err := modules.SnapshotPolicyDisk.ListDescendent2(s, opts.SNAPSHOTPOLICYID, jsonutils.NewDict()) + if err != nil { + return err + } + printList(result, modules.SnapshotPolicyDisk.GetColumns(s)) + return nil + }, + ) + + type SSnapshotpolicyDiskAttachOption struct { + DISKID string `help:"disk id"` + SNAPSHOTPOLICYID string `help:"snapshot policy id"` + } + R(&SSnapshotpolicyDiskAttachOption{}, "disk-snapshot-policy-attach", "attach snapshot policy to disk", + func(s *mcclient.ClientSession, opts *SSnapshotpolicyDiskAttachOption) error { + _, err := modules.SnapshotPolicyDisk.Attach(s, opts.DISKID, opts.SNAPSHOTPOLICYID, jsonutils.NewDict()) + if err != nil { + return err + } + return nil + }, + ) + + type SSnapshotpolicyDiskDetachOption struct { + DISKID string `help:"disk id"` + SNAPSHOTPOLICYID string `help:"snapshot policy id"` + } + R(&SSnapshotpolicyDiskDetachOption{}, "disk-snapshot-policy-detach", "detach snapshot policy to disk", + func(s *mcclient.ClientSession, opts *SSnapshotpolicyDiskDetachOption) error { + _, err := modules.SnapshotPolicyDisk.Detach(s, opts.DISKID, opts.SNAPSHOTPOLICYID, jsonutils.NewDict()) + if err != nil { + return err + } + return nil + }, + ) + +} diff --git a/pkg/apis/compute/disk_const.go b/pkg/apis/compute/disk_const.go index 62b3dfff8f..07308cf347 100644 --- a/pkg/apis/compute/disk_const.go +++ b/pkg/apis/compute/disk_const.go @@ -42,8 +42,10 @@ const ( DISK_POST_MIGRATE = "post_migrate" DISK_MIGRATING = "migrating" - DISK_START_SNAPSHOT = "start_snapshot" - DISK_SNAPSHOTING = "snapshoting" + DISK_START_SNAPSHOT = "start_snapshot" + DISK_SNAPSHOTING = "snapshoting" + DISK_APPLY_SNAPSHOT_FAIL = "apply_snapshot_failed" + DISK_CALCEL_SNAPSHOT_FAIL = "cancel_snapshot_failed" DISK_TYPE_SYS = "sys" DISK_TYPE_SWAP = "swap" diff --git a/pkg/apis/compute/snapshot.go b/pkg/apis/compute/snapshot.go index ea5e99e656..4977adcde2 100644 --- a/pkg/apis/compute/snapshot.go +++ b/pkg/apis/compute/snapshot.go @@ -48,3 +48,18 @@ type SSnapshotPolicyCreateInput struct { RepeatWeekdays []int `json:"repeat_weekdays"` TimePoints []int `json:"time_points"` } + +type SSnapshotPolicyCreateInternalInput struct { + apis.Meta + + Name string + ProjectId string + DomainId string + + ManagerId string + CloudregionId string + + RetentionDays int + RepeatWeekdays uint8 + TimePoints uint32 +} diff --git a/pkg/appsrv/dispatcher/jointdispatcher.go b/pkg/appsrv/dispatcher/jointdispatcher.go index 2ceb2db783..962cd32d5b 100644 --- a/pkg/appsrv/dispatcher/jointdispatcher.go +++ b/pkg/appsrv/dispatcher/jointdispatcher.go @@ -18,7 +18,6 @@ import ( "context" "fmt" "net/http" - "yunion.io/x/jsonutils" "yunion.io/x/log" diff --git a/pkg/cloudprovider/resources.go b/pkg/cloudprovider/resources.go index 8557f40b5e..f1a96a305c 100644 --- a/pkg/cloudprovider/resources.go +++ b/pkg/cloudprovider/resources.go @@ -80,8 +80,8 @@ type ICloudRegion interface { CreateSnapshotPolicy(*SnapshotPolicyInput) (string, error) DeleteSnapshotPolicy(string) error - ApplySnapshotPolicyToDisks(snapshotPolicyId string, diskIds []string) error - CancelSnapshotPolicyToDisks(diskIds []string) error + ApplySnapshotPolicyToDisks(snapshotPolicyId string, diskId string) error + CancelSnapshotPolicyToDisks(snapshotPolicyId string, diskId string) error GetISnapshotPolicies() ([]ICloudSnapshotPolicy, error) GetISnapshotPolicyById(snapshotPolicyId string) (ICloudSnapshotPolicy, error) @@ -373,7 +373,7 @@ type ICloudDisk interface { GetISnapshot(idStr string) (ICloudSnapshot, error) GetISnapshots() ([]ICloudSnapshot, error) - GetExtSnapshotPolicyId() string + GetExtSnapshotPolicyIds() []string Resize(ctx context.Context, newSizeMB int64) error Reset(ctx context.Context, snapshotId string) (string, error) @@ -393,6 +393,7 @@ type ICloudSnapshot interface { type ICloudSnapshotPolicy interface { IVirtualResource + IsActivated() bool GetRetentionDays() int GetRepeatWeekdays() ([]int, error) GetTimePoints() ([]int, error) diff --git a/pkg/compute/models/disks.go b/pkg/compute/models/disks.go index 52ea2f8b5b..be1f6d279c 100644 --- a/pkg/compute/models/disks.go +++ b/pkg/compute/models/disks.go @@ -40,7 +40,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/quotas" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient" - "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" @@ -95,9 +94,6 @@ type SDisk struct { DiskType string `width:"32" charset:"ascii" nullable:"true" list:"user" update:"admin"` // Column(VARCHAR(32, charset='ascii'), nullable=True) // # is persistent Nonpersistent bool `default:"false" list:"user"` // Column(Boolean, default=False) - - AutoSnapshot bool `default:"false" nullable:"true" get:"user" update:"user"` - SnapshotPolicyId string `width:"128" charset:"ascii" nullable:"true" get:"user" list:"user" update:"user" create:"optional"` } func (manager *SDiskManager) GetContextManagers() [][]db.IModelManager { @@ -759,51 +755,6 @@ func (self *SDisk) PerformResize(ctx context.Context, userCred mcclient.TokenCre return nil, self.StartDiskResizeTask(ctx, userCred, int64(sizeMb), "", &pendingUsage, guest) } -func (self *SDisk) AllowPerformApplySnapshotPolicy(ctx context.Context, - userCred mcclient.TokenCredential, - query jsonutils.JSONObject, - data jsonutils.JSONObject) bool { - return self.IsOwner(userCred) || db.IsAdminAllowPerform(userCred, self, "apply-snapshot-policy") -} - -func (self *SDisk) PerformApplySnapshotPolicy( - ctx context.Context, userCred mcclient.TokenCredential, - query jsonutils.JSONObject, data jsonutils.JSONObject, -) (jsonutils.JSONObject, error) { - spv := validators.NewModelIdOrNameValidator("snapshotpolicy", "snapshotpolicy", userCred) - if err := spv.Validate(data.(*jsonutils.JSONDict)); err != nil { - return nil, err - } - sp := spv.Model.(*SSnapshotPolicy) - return nil, sp.StartApplySnapshotPolicyToDisks(ctx, userCred, []string{self.Id}) -} - -func (self *SDisk) AllowPerformCancelSnapshotPolicy(ctx context.Context, - userCred mcclient.TokenCredential, - query jsonutils.JSONObject, - data jsonutils.JSONObject) bool { - return self.IsOwner(userCred) || db.IsAdminAllowPerform(userCred, self, "cancel-snapshot-policy") -} - -func (self *SDisk) PerformCancelSnapshotPolicy( - ctx context.Context, userCred mcclient.TokenCredential, - query jsonutils.JSONObject, data jsonutils.JSONObject, -) (jsonutils.JSONObject, error) { - if len(self.SnapshotPolicyId) == 0 { - return nil, httperrors.NewBadRequestError("Disk dosen't apply any snapshot policy") - } - return nil, self.StartCancelSnapshotPolicyToDisks(ctx, userCred) -} - -func (self *SDisk) StartCancelSnapshotPolicyToDisks(ctx context.Context, userCred mcclient.TokenCredential) error { - if task, err := taskman.TaskManager.NewTask(ctx, "SnapshotPolicyCancelTask", self, userCred, nil, "", "", nil); err != nil { - return err - } else { - task.ScheduleRun(nil) - } - return nil -} - func (self *SDisk) GetIStorage() (cloudprovider.ICloudStorage, error) { storage := self.GetStorage() if storage == nil { @@ -1210,6 +1161,7 @@ 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 return self.RealDelete(ctx, userCred) } @@ -1256,13 +1208,7 @@ func (self *SDisk) syncWithCloudDisk(ctx context.Context, userCred mcclient.Toke self.CreatedAt = createdAt } - extPolicyId := extDisk.GetExtSnapshotPolicyId() - if len(extPolicyId) > 0 { - isp, _ := db.FetchByExternalId(SnapshotPolicyManager, extPolicyId) - if isp != nil { - self.SnapshotPolicyId = isp.GetId() - } - } + // todo sync disk's snapshotpolicy return nil }) @@ -1311,13 +1257,7 @@ func (manager *SDiskManager) newFromCloudDisk(ctx context.Context, userCred mccl disk.CreatedAt = createAt } - extPolicyId := extDisk.GetExtSnapshotPolicyId() - if len(extPolicyId) > 0 { - isp, _ := db.FetchByExternalId(SnapshotPolicyManager, extPolicyId) - if isp != nil { - disk.SnapshotPolicyId = isp.GetId() - } - } + // todo create new joint model about snapshotpolicy and disk err = manager.TableSpec().Insert(&disk) if err != nil { @@ -1717,14 +1657,6 @@ func (self *SDisk) GetAttachedGuests() []SGuest { return ret } -func (self *SDisk) SetSnapshotPolicy(policyId string) error { - _, err := db.Update(self, func() error { - self.SnapshotPolicyId = policyId - return nil - }) - return err -} - func (self *SDisk) SetDiskReady(ctx context.Context, userCred mcclient.TokenCredential, reason string) { self.SetStatus(userCred, api.DISK_READY, reason) guests := self.GetAttachedGuests() diff --git a/pkg/compute/models/regiondrivers.go b/pkg/compute/models/regiondrivers.go index 5a6e60ab2b..ab63bdb507 100644 --- a/pkg/compute/models/regiondrivers.go +++ b/pkg/compute/models/regiondrivers.go @@ -82,8 +82,9 @@ type IRegionDriver interface { ValidateCreateSnapshotPolicyData(ctx context.Context, userCred mcclient.TokenCredential, data *compute.SSnapshotPolicyCreateInput) 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 - RequestApplySnapshotPolicy(ctx context.Context, userCred mcclient.TokenCredential, sp *SSnapshotPolicy, task taskman.ITask, diskIds []string) error - RequestCancelSnapshotPolicy(ctx context.Context, userCred mcclient.TokenCredential, region cloudprovider.ICloudRegion, task taskman.ITask, diskIds []string) error + + // Region Driver Snapshot Policy joint Disk Apis + ValidateCreateSnapshopolicyDiskData(ctx context.Context, userCred mcclient.TokenCredential, diskID string) error // Region Driver Snapshot Apis ValidateSnapshotDelete(ctx context.Context, snapshot *SSnapshot) error @@ -93,6 +94,8 @@ 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 } var regionDrivers map[string]IRegionDriver diff --git a/pkg/compute/models/snapshotpolicy.go b/pkg/compute/models/snapshotpolicy.go index 786c4a9116..326285a136 100644 --- a/pkg/compute/models/snapshotpolicy.go +++ b/pkg/compute/models/snapshotpolicy.go @@ -17,7 +17,6 @@ package models import ( "context" "fmt" - "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/util/compare" @@ -31,6 +30,7 @@ import ( "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/bitmap" ) type SSnapshotPolicyManager struct { @@ -46,9 +46,9 @@ type SSnapshotPolicy struct { RetentionDays int `nullable:"false" list:"user" get:"user" create:"required"` - // {repeat_weekdays: [1,2,3,4,5,6,7], time_points: [0...23]} - RepeatWeekdays string `charset:"utf8" list:"user" get:"user" create:"required"` - TimePoints string `charset:"utf8" list:"user" get:"user" create:"required"` + RepeatWeekdays uint8 `charset:"utf8" create:"required"` + TimePoints uint32 `charset:"utf8" create:"required"` + IsActivated bool `list:"user" get:"user" create:"optional" default:"true"` } var SnapshotPolicyManager *SSnapshotPolicyManager @@ -97,10 +97,31 @@ func (manager *SSnapshotPolicyManager) ValidateCreateData(ctx context.Context, u if err != nil { return nil, err } - data = input.JSON(input) + internalInput := manager.sSnapshotPolicyCreateInputToInternal(input) + data = internalInput.JSON(internalInput) return data, 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) } @@ -131,9 +152,26 @@ func (self *SSnapshotPolicy) StartSnapshotPolicyDeleteTask(ctx context.Context, 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 { @@ -146,34 +184,25 @@ func (self *SSnapshotPolicy) GetIRegion() (cloudprovider.ICloudRegion, error) { return provider.GetIRegionById(region.ExternalId) } -func (self *SSnapshotPolicy) GenerateCreateSpParams() (*cloudprovider.SnapshotPolicyInput, error) { - idays, err := jsonutils.ParseString(self.RepeatWeekdays) - if err != nil { - return nil, fmt.Errorf("SnapshotPolicy %s Parse repeat weekdays error %s", self.Name, err) - } - weekdays := idays.(*jsonutils.JSONArray) - intWeekdays := make([]int, weekdays.Length()) - for i, v := range weekdays.Value() { - t, err := v.Int() - if err != nil { - return nil, fmt.Errorf("parse weekdays error %s", weekdays) - } - intWeekdays[i] = int(t) - } +func (self *SSnapshotPolicyManager) RepeatWeekdaysParseIntArray(nums []int) uint8 { + return uint8(bitmap.IntArray2Uint(nums)) +} - idays, err = jsonutils.ParseString(self.TimePoints) - if err != nil { - return nil, fmt.Errorf("SnapshotPolicy %s Parse time points error %s", self.Name, err) - } - timePoints := idays.(*jsonutils.JSONArray) - intTimePoints := make([]int, timePoints.Length()) - for i, v := range timePoints.Value() { - t, err := v.Int() - if err != nil { - return nil, fmt.Errorf("parse weekdays error %s", timePoints) - } - intTimePoints[i] = int(t) - } +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, @@ -271,19 +300,20 @@ func (self *SSnapshotPolicy) SyncWithCloudSnapshotPolicy(ctx context.Context, us if err != nil { return err } - self.RepeatWeekdays = jsonutils.Marshal(arw).String() + self.RepeatWeekdays = SnapshotPolicyManager.RepeatWeekdaysParseIntArray(arw) atp, err := ext.GetTimePoints() if err != nil { return err } - self.TimePoints = jsonutils.Marshal(atp).String() + 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, @@ -307,12 +337,12 @@ func (manager *SSnapshotPolicyManager) newFromCloudSnapshotPolicy( if err != nil { return nil, err } - snapshotPolicy.RepeatWeekdays = jsonutils.Marshal(arw).String() + snapshotPolicy.RepeatWeekdays = SnapshotPolicyManager.RepeatWeekdaysParseIntArray(arw) atp, err := ext.GetTimePoints() if err != nil { return nil, err } - snapshotPolicy.TimePoints = jsonutils.Marshal(atp).String() + snapshotPolicy.TimePoints = SnapshotPolicyManager.TimePointsParseIntArray(atp) err = manager.TableSpec().Insert(&snapshotPolicy) if err != nil { @@ -354,24 +384,6 @@ func (self *SSnapshotPolicy) StartApplySnapshotPolicyToDisks(ctx context.Context return nil } -// func (self *SSnapshotPolicy) AllowPerformCancelToDisks(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) PerformCancelToDisks( -// 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.StartCancelSnapshotPolicyToDisks(ctx, userCred, diskIds) -// } - func (self *SSnapshotPolicy) preCheck( ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject, @@ -404,4 +416,4 @@ func (self *SSnapshotPolicy) preCheck( return nil, httperrors.NewNotFoundError("Disks %v not found", notFoundDisks) } return diskIds, nil -} +} \ No newline at end of file diff --git a/pkg/compute/models/snapshotpolicydisks.go b/pkg/compute/models/snapshotpolicydisks.go new file mode 100644 index 0000000000..c8cfee5809 --- /dev/null +++ b/pkg/compute/models/snapshotpolicydisks.go @@ -0,0 +1,133 @@ +// 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" + "yunion.io/x/onecloud/pkg/cloudcommon/validators" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + "yunion.io/x/onecloud/pkg/cloudcommon/db" + "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" + "yunion.io/x/onecloud/pkg/mcclient" +) + +type SSnapshotPolicyDiskManager struct { + db.SVirtualJointResourceBaseManager +} + +func (manager *SSnapshotPolicyDiskManager) GetMasterFieldName() string { + return "disk_id" +} + +func (manager *SSnapshotPolicyDiskManager) GetSlaveFieldName() string { + return "snapshotpolicy_id" +} + +var SnapshotPolicyDiskManager *SSnapshotPolicyDiskManager + +func init() { + db.InitManager(func() { + SnapshotPolicyDiskManager = &SSnapshotPolicyDiskManager{ + SVirtualJointResourceBaseManager: db.NewVirtualJointResourceBaseManager( + SSnapshotPolicyDisk{}, + "snapshotpolicydisks_tbl", + "snapshotpolicydisk", + "snapshotpolicydisks", + DiskManager, + SnapshotPolicyManager, + ), + } + SnapshotPolicyDiskManager.SetVirtualObject(SnapshotPolicyDiskManager) + }) + +} + +type SSnapshotPolicyDisk struct { + db.SVirtualJointResourceBase + + 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"` +} + +func (self *SSnapshotPolicyDisk) Detach(ctx context.Context, userCred mcclient.TokenCredential) error { + return db.DetachJoint(ctx, userCred, self) +} + +func (self *SSnapshotPolicyDiskManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) { + cloudregionV := validators.NewModelIdOrNameValidator("cloudregion", "cloudregion", ownerId) + err := cloudregionV.Validate(data) + if err != nil { + return nil, err + } + cloudregion := cloudregionV.Model.(*SCloudregion) + diskId, _ := data.GetString(self.GetMasterManager().Keyword()) + err = cloudregion.GetDriver().ValidateCreateSnapshopolicyDiskData(ctx, userCred, diskId) + if err != nil { + return nil, err + } + return data, nil +} + +func (self *SSnapshotPolicyDiskManager) FetchAllSnapshotPolicyOfDisk(ctx context.Context, userCred mcclient.TokenCredential, diskID string) ([]SSnapshotPolicyDisk, error) { + q := self.Query() + q.Equals(self.GetMasterFieldName(), diskID) + ret := make([]SSnapshotPolicyDisk, 0) + err := db.FetchModelObjects(self, 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) + } + 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) + if err != nil { + log.Errorf("SnapshotPolicyApplyTask newTask error %s", err) + } else { + task.ScheduleRun(nil) + } +} + +func (self *SSnapshotPolicyDisk) CustomizeDelete(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) error { + diskID := self.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 + taskData := jsonutils.NewDict() + taskData.Add(jsonutils.NewString(snapshotPolicyID), "snapshot_policy_id") + task, err := taskman.TaskManager.NewTask(ctx, "SnapshotPolicyCancelTask", disk, userCred, taskData, "", "", nil) + if err != nil { + return errors.Wrapf(err, "SnapshotPolicyCancelTask newTask error %s", err) + } else { + task.ScheduleRun(nil) + } + return nil +} diff --git a/pkg/compute/regiondrivers/aliyun.go b/pkg/compute/regiondrivers/aliyun.go index 99755418c9..b5143c22d3 100644 --- a/pkg/compute/regiondrivers/aliyun.go +++ b/pkg/compute/regiondrivers/aliyun.go @@ -823,27 +823,25 @@ func daysValidate(days []int, min, max int) ([]int, error) { 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.") + } + return nil +} + func (self *SAliyunRegionDriver) ValidateCreateSnapshotPolicyData(ctx context.Context, userCred mcclient.TokenCredential, data *compute.SSnapshotPolicyCreateInput) error { - var err error + err := self.SManagedVirtualizationRegionDriver.ValidateCreateSnapshotPolicyData(ctx, userCred, data) + if err != nil { + return err + } if data.RetentionDays < -1 || data.RetentionDays == 0 || data.RetentionDays > 65535 { return httperrors.NewInputParameterError("Retention days must in 1~65535 or -1") } - - if len(data.RepeatWeekdays) == 0 { - return httperrors.NewMissingParameterError("repeat_weekdays") - } - data.RepeatWeekdays, err = daysValidate(data.RepeatWeekdays, 1, 7) - if err != nil { - return httperrors.NewInputParameterError(err.Error()) - } - - if len(data.TimePoints) == 0 { - return httperrors.NewInputParameterError("time_points") - } - data.TimePoints, err = daysValidate(data.TimePoints, 0, 23) - if err != nil { - return httperrors.NewInputParameterError(err.Error()) - } return nil } diff --git a/pkg/compute/regiondrivers/base.go b/pkg/compute/regiondrivers/base.go index 47a11e0520..b4f12f3396 100644 --- a/pkg/compute/regiondrivers/base.go +++ b/pkg/compute/regiondrivers/base.go @@ -138,11 +138,11 @@ func (self *SBaseRegionDriver) RequestDeleteSnapshotPolicy(ctx context.Context, return fmt.Errorf("Not Implement RequestDeleteSnapshotPolicy") } -func (self *SBaseRegionDriver) RequestApplySnapshotPolicy(ctx context.Context, userCred mcclient.TokenCredential, sp *models.SSnapshotPolicy, task taskman.ITask, diskIds []string) error { +func (self *SBaseRegionDriver) RequestApplySnapshotPolicy(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, region cloudprovider.ICloudRegion, task taskman.ITask, diskIds []string) error { +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") } @@ -173,3 +173,7 @@ func (self *SBaseRegionDriver) GetDiskResetParams(snapshot *models.SSnapshot) *j func (self *SBaseRegionDriver) OnDiskReset(ctx context.Context, userCred mcclient.TokenCredential, disk *models.SDisk, snapshot *models.SSnapshot, data *jsonutils.JSONObject) error { 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") +} diff --git a/pkg/compute/regiondrivers/managedvirtual.go b/pkg/compute/regiondrivers/managedvirtual.go index 2dc73d1fd3..d2becc1dc3 100644 --- a/pkg/compute/regiondrivers/managedvirtual.go +++ b/pkg/compute/regiondrivers/managedvirtual.go @@ -25,6 +25,7 @@ import ( "yunion.io/x/pkg/errors" "yunion.io/x/pkg/utils" + "yunion.io/x/onecloud/pkg/apis/compute" api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" @@ -1087,13 +1088,13 @@ func (self *SManagedVirtualizationRegionDriver) RequestDeleteSnapshotPolicy(ctx return nil } -func (self *SManagedVirtualizationRegionDriver) RequestApplySnapshotPolicy(ctx context.Context, userCred mcclient.TokenCredential, sp *models.SSnapshotPolicy, task taskman.ITask, diskIds []string) 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(), diskIds) + err = iRegion.ApplySnapshotPolicyToDisks(sp.GetExternalId(), diskId) if err != nil { return nil, err } @@ -1102,9 +1103,13 @@ func (self *SManagedVirtualizationRegionDriver) RequestApplySnapshotPolicy(ctx c return nil } -func (self *SManagedVirtualizationRegionDriver) RequestCancelSnapshotPolicy(ctx context.Context, userCred mcclient.TokenCredential, region cloudprovider.ICloudRegion, task taskman.ITask, diskIds []string) error { +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) { - err := region.CancelSnapshotPolicyToDisks(diskIds) + iRegion, err := sp.GetIRegion() + if err != nil { + return nil, err + } + err = iRegion.CancelSnapshotPolicyToDisks(sp.GetExternalId(), diskId) if err != nil { return nil, err } @@ -1183,3 +1188,28 @@ func (self *SManagedVirtualizationRegionDriver) OnDiskReset(ctx context.Context, } return iDisk.Refresh() } + +func (self *SManagedVirtualizationRegionDriver) ValidateCreateSnapshotPolicyData(ctx context.Context, userCred mcclient.TokenCredential, data *compute.SSnapshotPolicyCreateInput) error { + var err error + + if len(data.RepeatWeekdays) == 0 { + return httperrors.NewMissingParameterError("repeat_weekdays") + } + data.RepeatWeekdays, err = daysValidate(data.RepeatWeekdays, 1, 7) + if err != nil { + return httperrors.NewInputParameterError(err.Error()) + } + + if len(data.TimePoints) == 0 { + return httperrors.NewInputParameterError("time_points") + } + data.TimePoints, err = daysValidate(data.TimePoints, 0, 23) + if err != nil { + return httperrors.NewInputParameterError(err.Error()) + } + return nil +} + +func (self *SManagedVirtualizationRegionDriver) ValidateCreateSnapshopolicyDiskData(ctx context.Context, userCred mcclient.TokenCredential, diskID string) error { + return nil +} diff --git a/pkg/compute/regiondrivers/qcloud.go b/pkg/compute/regiondrivers/qcloud.go index 569b22e644..02e0d04e8a 100644 --- a/pkg/compute/regiondrivers/qcloud.go +++ b/pkg/compute/regiondrivers/qcloud.go @@ -20,16 +20,17 @@ import ( "regexp" "yunion.io/x/jsonutils" - "yunion.io/x/onecloud/pkg/cloudcommon/validators" - "yunion.io/x/onecloud/pkg/util/rand" + "yunion.io/x/onecloud/pkg/apis/compute" api "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/validators" "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" + "yunion.io/x/onecloud/pkg/util/rand" ) type SQcloudRegionDriver struct { @@ -743,3 +744,14 @@ func (self *SQcloudRegionDriver) ValidateCreateLoadbalancerBackendData(ctx conte data.Set("cloudregion_id", jsonutils.NewString(lb.CloudregionId)) return data, nil } + +func (self *SQcloudRegionDriver) ValidateCreateSnapshotPolicyData(ctx context.Context, userCred mcclient.TokenCredential, data *compute.SSnapshotPolicyCreateInput) error { + err := self.SManagedVirtualizationRegionDriver.ValidateCreateSnapshotPolicyData(ctx, userCred, data) + if err != nil { + return err + } + if data.RetentionDays < -1 || data.RetentionDays == 0 || data.RetentionDays > 65535 { + return httperrors.NewInputParameterError("Retention days must in 1~65535 or -1") + } + return nil +} diff --git a/pkg/compute/service/handlers.go b/pkg/compute/service/handlers.go index 49f8bad6b4..703bca5c8d 100644 --- a/pkg/compute/service/handlers.go +++ b/pkg/compute/service/handlers.go @@ -153,6 +153,7 @@ func InitHandlers(app *appsrv.Application) { models.CloudproviderRegionManager, models.DBInstanceNetworkManager, models.NetworkinterfacenetworkManager, + models.SnapshotPolicyDiskManager, } { db.RegisterModelManager(manager) handler := db.NewJointModelHandler(manager) diff --git a/pkg/compute/tasks/snapshotpolicy_create_task.go b/pkg/compute/tasks/snapshotpolicy_create_task.go index bbc0c1efc7..3e82c1a4ce 100644 --- a/pkg/compute/tasks/snapshotpolicy_create_task.go +++ b/pkg/compute/tasks/snapshotpolicy_create_task.go @@ -19,6 +19,7 @@ import ( "fmt" "yunion.io/x/jsonutils" + "yunion.io/x/log" "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" @@ -81,86 +82,51 @@ type SnapshotPolicyApplyTask struct { taskman.STask } -func (self *SnapshotPolicyApplyTask) taskFail(ctx context.Context, sp *models.SSnapshotPolicy, reason string) { - stringIds, _ := getDiskIds(self) - disks := make([]models.SDisk, 0) - q := models.DiskManager.Query().In("id", stringIds) - err := db.FetchModelObjects(models.DiskManager, q, &disks) - if err == nil { - for i := 0; i < len(disks); i++ { - db.OpsLog.LogEvent(&disks[i], db.ACT_APPLY_SNAPSHOT_POLICY_FAILED, reason, self.UserCred) - logclient.AddActionLogWithStartable(self, &disks[i], logclient.ACT_APPLY_SNAPSHOT_POLICY, reason, self.UserCred, false) - } +func (self *SnapshotPolicyApplyTask) taskFail(ctx context.Context, disk *models.SDisk, snapshotPolicyId, reason string) { + jointModel, err := db.FetchJointByIds(models.SnapshotPolicyDiskManager, self.Id, snapshotPolicyId, jsonutils.JSONNull) + if err != nil { + log.Errorf("Fetch SnapshotPolicy %s Disk %s joint model failed, need to delete", self.Id, snapshotPolicyId) + 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 getDiskIds(task *SnapshotPolicyApplyTask) ([]string, error) { - diskIds, err := task.Params.GetArray("disk_ids") - if err != nil { - return nil, fmt.Errorf("Missing parasm disk_ids") - } - stringIds := make([]string, len(diskIds)) - for i := 0; i < len(diskIds); i++ { - stringIds[i], _ = diskIds[i].GetString() - } - return stringIds, nil -} - func (self *SnapshotPolicyApplyTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { - snapshotPolicy := obj.(*models.SSnapshotPolicy) + disk := obj.(*models.SDisk) + snapshotPolicyID, _ := self.Params.GetString("snapshot_policy_id") - region := snapshotPolicy.GetRegion() - if region == nil { - self.taskFail(ctx, snapshotPolicy, fmt.Sprintf("failed to find region for snapshot policy %s", snapshotPolicy.Name)) - return - } - - stringIds, err := getDiskIds(self) + iregion, err := disk.GetIRegion() if err != nil { - self.taskFail(ctx, snapshotPolicy, err.Error()) + self.taskFail(ctx, disk, snapshotPolicyID, fmt.Sprintf("failed to find iregion for snapshot policy %s: %s", disk.Id, err.Error())) return } - diskExt, err := models.DiskManager.Query("external_id").In("id", stringIds).AllStringMap() + // fetch disk model by diksID + model, err := models.SnapshotPolicyManager.FetchById(snapshotPolicyID) if err != nil { - self.taskFail(ctx, snapshotPolicy, fmt.Sprintf("Fetch disks external_id failed %s", err)) + self.taskFail(ctx, disk, snapshotPolicyID, fmt.Sprintf("failed to fetch disk by id %s: %s", snapshotPolicyID, err.Error())) return } - diskExtIds := make([]string, 0) - for i := 0; i < len(diskExt); i++ { - val, ok := diskExt[i]["external_id"] - if ok { - diskExtIds = append(diskExtIds, val) - } - } - + snapshotPolicy := model.(*models.SSnapshotPolicy) self.SetStage("OnSnapshotPolicyApply", nil) - if err := region.GetDriver().RequestApplySnapshotPolicy(ctx, self.GetUserCred(), snapshotPolicy, self, diskExtIds); err != nil { - self.taskFail(ctx, snapshotPolicy, err.Error()) + if err := iregion.ApplySnapshotPolicyToDisks(snapshotPolicy.ExternalId, 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, sp *models.SSnapshotPolicy, data jsonutils.JSONObject) { - stringIds, _ := getDiskIds(self) - disks := make([]models.SDisk, 0) - q := models.DiskManager.Query().In("id", stringIds) - err := db.FetchModelObjects(models.DiskManager, q, &disks) - if err != nil { - self.taskFail(ctx, sp, fmt.Sprintf("Fetch disks failed %s", err)) - return - } - for i := 0; i < len(disks); i++ { - disks[i].SetSnapshotPolicy(sp.Id) - db.OpsLog.LogEvent(&disks[i], db.ACT_APPLY_SNAPSHOT_POLICY, nil, self.UserCred) - logclient.AddActionLogWithStartable(self, &disks[i], logclient.ACT_APPLY_SNAPSHOT_POLICY, nil, self.UserCred, true) - } + 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) -} -func (self *SnapshotPolicyApplyTask) OnSnapshotPolicyApplyFailed(ctx context.Context, sp *models.SSnapshotPolicy, data jsonutils.JSONObject) { - self.taskFail(ctx, sp, data.String()) } // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- @@ -169,7 +135,18 @@ type SnapshotPolicyCancelTask struct { taskman.STask } -func (self *SnapshotPolicyCancelTask) taskFail(ctx context.Context, disk *models.SDisk, reason string) { +func (self *SnapshotPolicyCancelTask) taskFail(ctx context.Context, disk *models.SDisk, snapshotPolicyId, reason string) { + jointModel, err := db.FetchJointByIds(models.SnapshotPolicyDiskManager, self.Id, snapshotPolicyId, jsonutils.JSONNull) + if err != nil { + log.Errorf("Fetch SnapshotPolicy %s Disk %s joint model failed, need to mark undelete", self.Id, snapshotPolicyId) + 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) @@ -177,42 +154,28 @@ func (self *SnapshotPolicyCancelTask) taskFail(ctx context.Context, disk *models func (self *SnapshotPolicyCancelTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { disk := obj.(*models.SDisk) - storage := disk.GetStorage() - if storage == nil { - self.taskFail(ctx, disk, fmt.Sprintf("failed to find storage for disk %s", disk.Name)) - return - } - region := storage.GetRegion() - if region == nil { - self.taskFail(ctx, disk, fmt.Sprintf("failed to find region for disk %s", disk.Name)) + snapshotPolicyID, _ := self.GetParams().GetString("snapshot_policy_id") + + // get region + iregion, err := disk.GetIRegion() + if err != nil { + self.taskFail(ctx, disk, snapshotPolicyID, fmt.Sprintf("failed to find iregion for disk %s: %s", disk.Name, err.Error())) return } - iSnapshotPolicy, err := models.SnapshotPolicyManager.FetchById(disk.SnapshotPolicyId) + model, err := models.SnapshotPolicyManager.FetchById(snapshotPolicyID) if err != nil { - self.taskFail(ctx, disk, fmt.Sprintf("failed to find snapshot policy for disk %s, %s", disk.Name, err)) + self.taskFail(ctx, disk, snapshotPolicyID, fmt.Sprintf("failed to fetch disk by id %s: %s", snapshotPolicyID, err.Error())) return } - snapshotPolicy := iSnapshotPolicy.(*models.SSnapshotPolicy) - iRegion, err := snapshotPolicy.GetIRegion() - if err != nil { - self.taskFail(ctx, disk, fmt.Sprintf("failed to find region for snapshot policy %s", snapshotPolicy.Name)) - return - } - self.SetStage("OnSnapshotPolicyCancel", nil) - if err := region.GetDriver().RequestCancelSnapshotPolicy( - ctx, self.GetUserCred(), iRegion, self, []string{disk.ExternalId}); err != nil { - self.taskFail(ctx, disk, err.Error()) - } -} -func (self *SnapshotPolicyCancelTask) OnSnapshotPolicyCancel(ctx context.Context, disk *models.SDisk, data jsonutils.JSONObject) { - disk.SetSnapshotPolicy("") + snapshotPolicy := model.(*models.SSnapshotPolicy) + self.SetStage("OnSnapshotPolicyApply", nil) + if err := iregion.CancelSnapshotPolicyToDisks(snapshotPolicy.ExternalId, 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())) + } + 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) } - -func (self *SnapshotPolicyCancelTask) OnSnapshotPolicyCancelFailed(ctx context.Context, disk *models.SDisk, data jsonutils.JSONObject) { - self.taskFail(ctx, disk, data.String()) -} diff --git a/pkg/mcclient/modules/mod_snapshotpolicydisk.go b/pkg/mcclient/modules/mod_snapshotpolicydisk.go new file mode 100644 index 0000000000..27eabd6d55 --- /dev/null +++ b/pkg/mcclient/modules/mod_snapshotpolicydisk.go @@ -0,0 +1,30 @@ +// 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 modules + +var ( + SnapshotPolicyDisk JointResourceManager +) + +func init() { + SnapshotPolicyDisk = NewJointComputeManager( + "snapshotpolicydisk", + "snapshotpolicydisks", + []string{"Disk_ID", "Snapshotpolicy_ID"}, + []string{}, + &Disks, + &SnapshotPoliciy) + registerCompute(&SnapshotPolicyDisk) +} diff --git a/pkg/multicloud/aliyun/disk.go b/pkg/multicloud/aliyun/disk.go index f4048098ab..e6940a1446 100644 --- a/pkg/multicloud/aliyun/disk.go +++ b/pkg/multicloud/aliyun/disk.go @@ -405,8 +405,8 @@ func (self *SDisk) GetCreatedAt() time.Time { return self.CreationTime } -func (self *SDisk) GetExtSnapshotPolicyId() string { - return self.AutoSnapshotPolicyId +func (self *SDisk) GetExtSnapshotPolicyIds() []string { + return []string{self.AutoSnapshotPolicyId} } func (self *SDisk) GetExpiredAt() time.Time { diff --git a/pkg/multicloud/aliyun/shell/snapshot_policy.go b/pkg/multicloud/aliyun/shell/snapshot_policy.go new file mode 100644 index 0000000000..5e51fb474f --- /dev/null +++ b/pkg/multicloud/aliyun/shell/snapshot_policy.go @@ -0,0 +1,95 @@ +// 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 shell + +import ( + "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/multicloud/aliyun" + "yunion.io/x/onecloud/pkg/util/shellutils" +) + +func init() { + type SSnapshotPolicyListOptions struct { + PolicyId string `help:"snapshot policy id"` + Offset int `help:"offset"` + Limit int `help:"limit"` + } + + shellutils.R(&SSnapshotPolicyListOptions{}, "snapshot-policy-list", "list snapshot policy", + func(cli *aliyun.SRegion, args *SSnapshotPolicyListOptions) error { + snapshotPolicis, num, err := cli.GetSnapshotPolicies(args.PolicyId, args.Offset, args.Limit) + if err != nil { + return err + } + printList(snapshotPolicis, num, args.Offset, args.Limit, []string{}) + return nil + }, + ) + + type SSnapshotPolicyDeleteOptions struct { + ID string `help:"snapshot id"` + } + shellutils.R(&SSnapshotPolicyDeleteOptions{}, "snapshot-policy-delete", "delete snapshot policy", + func(cli *aliyun.SRegion, args *SSnapshotPolicyDeleteOptions) error { + err := cli.DeleteSnapshotPolicy(args.ID) + return err + }, + ) + + type SSnapshotPolicyCreateOptions struct { + Name string `help:"snapshot name"` + + RetentionDays int `help:"retention days"` + RepeatWeekdays []int `help:"auto snapshot which days of the week"` + TimePoints []int `help:"auto snapshot which hours of the day"` + } + shellutils.R(&SSnapshotPolicyCreateOptions{}, "snapshot-policy-create", "create snapshot policy", + func(cli *aliyun.SRegion, args *SSnapshotPolicyCreateOptions) error { + input := cloudprovider.SnapshotPolicyInput{ + RetentionDays: args.RetentionDays, + RepeatWeekdays: args.RepeatWeekdays, + TimePoints: args.TimePoints, + PolicyName: args.Name, + } + _, err := cli.CreateSnapshotPolicy(&input) + if err != nil { + return err + } + return nil + }, + ) + + type SSnapshotPolicyApplyOptions struct { + SNAPSHOTPOLICYID string `help:"snapshot policy id"` + DISKID string `help:"disk id"` + } + shellutils.R(&SSnapshotPolicyApplyOptions{}, "snapshot-policy-apply", "apply snapshot policy", + func(cli *aliyun.SRegion, args *SSnapshotPolicyApplyOptions) error { + err := cli.ApplySnapshotPolicyToDisks(args.SNAPSHOTPOLICYID, args.DISKID) + return err + }, + ) + + type SSnapshotPolicyCancelOptions struct { + SNAPSHOTPOLICYID string `help:"snapshot policy id"` + DISKID string `help":disk id"` + } + shellutils.R(&SSnapshotPolicyCancelOptions{}, "snapshot-policy-cancel", "cancel snapshot policy", + func(cli *aliyun.SRegion, args *SSnapshotPolicyCancelOptions) error { + err := cli.CancelSnapshotPolicyToDisks(args.SNAPSHOTPOLICYID, args.DISKID) + return err + }, + ) +} diff --git a/pkg/multicloud/aliyun/snapshot_policy.go b/pkg/multicloud/aliyun/snapshot_policy.go index 8dfa178dee..74274c5358 100644 --- a/pkg/multicloud/aliyun/snapshot_policy.go +++ b/pkg/multicloud/aliyun/snapshot_policy.go @@ -135,6 +135,10 @@ func (self *SSnapshotPolicy) GetTimePoints() ([]int, error) { return parsePolicy(self.TimePoints) } +func (self *SSnapshotPolicy) IsActivated() bool { + return true +} + func (self *SRegion) GetISnapshotPolicies() ([]cloudprovider.ICloudSnapshotPolicy, error) { snapshotPolicies, total, err := self.GetSnapshotPolicies("", 0, 50) if err != nil { @@ -159,8 +163,10 @@ func (self *SRegion) GetSnapshotPolicies(policyId string, offset int, limit int) params := make(map[string]string) params["RegionId"] = self.RegionId - params["PageSize"] = fmt.Sprintf("%d", limit) - params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) + if limit != 0 { + params["PageSize"] = fmt.Sprintf("%d", limit) + params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) + } if len(policyId) > 0 { params["AutoSnapshotPolicyId"] = policyId @@ -253,10 +259,11 @@ func (self *SRegion) UpdateSnapshotPolicy( return nil } -func (self *SRegion) ApplySnapshotPolicyToDisks(snapshotPolicyId string, diskIds []string) error { +func (self *SRegion) ApplySnapshotPolicyToDisks(snapshotPolicyId string, diskId string) error { params := make(map[string]string) params["RegionId"] = self.RegionId params["autoSnapshotPolicyId"] = snapshotPolicyId + diskIds := []string{diskId} params["diskIds"] = jsonutils.Marshal(diskIds).String() _, err := self.ecsRequest("ApplyAutoSnapshotPolicy", params) if err != nil { @@ -265,9 +272,10 @@ func (self *SRegion) ApplySnapshotPolicyToDisks(snapshotPolicyId string, diskIds return nil } -func (self *SRegion) CancelSnapshotPolicyToDisks(diskIds []string) error { +func (self *SRegion) CancelSnapshotPolicyToDisks(snapshotPolicyId string, diskId string) error { params := make(map[string]string) params["RegionId"] = self.RegionId + diskIds := []string{diskId} params["diskIds"] = jsonutils.Marshal(diskIds).String() _, err := self.ecsRequest("CancelAutoSnapshotPolicy", params) if err != nil { diff --git a/pkg/multicloud/aws/snapshot_policy.go b/pkg/multicloud/aws/snapshot_policy.go new file mode 100644 index 0000000000..aaf76f4d7a --- /dev/null +++ b/pkg/multicloud/aws/snapshot_policy.go @@ -0,0 +1,15 @@ +// 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 aws diff --git a/pkg/multicloud/disk_base.go b/pkg/multicloud/disk_base.go index e5b12195da..e7290691ef 100644 --- a/pkg/multicloud/disk_base.go +++ b/pkg/multicloud/disk_base.go @@ -16,8 +16,8 @@ package multicloud type SDisk struct{} -func (self *SDisk) GetExtSnapshotPolicyId() string { - return "" +func (self *SDisk) GetExtSnapshotPolicyIds() []string { + return []string{""} } func (self *SDisk) GetIStorageId() string { diff --git a/pkg/multicloud/objectstore/objectstore.go b/pkg/multicloud/objectstore/objectstore.go index 8473c04811..791a5b8122 100644 --- a/pkg/multicloud/objectstore/objectstore.go +++ b/pkg/multicloud/objectstore/objectstore.go @@ -186,11 +186,11 @@ func (cli *SObjectStoreClient) DeleteSnapshotPolicy(string) error { return cloudprovider.ErrNotSupported } -func (cli *SObjectStoreClient) ApplySnapshotPolicyToDisks(snapshotPolicyId string, diskIds []string) error { +func (cli *SObjectStoreClient) ApplySnapshotPolicyToDisks(snapshotPolicyId string, diskId string) error { return cloudprovider.ErrNotSupported } -func (cli *SObjectStoreClient) CancelSnapshotPolicyToDisks(diskIds []string) error { +func (cli *SObjectStoreClient) CancelSnapshotPolicyToDisks(snapshotPolicyId string, diskId string) error { return cloudprovider.ErrNotSupported } diff --git a/pkg/multicloud/qcloud/shell/snapshot_policy.go b/pkg/multicloud/qcloud/shell/snapshot_policy.go new file mode 100644 index 0000000000..7a1e120004 --- /dev/null +++ b/pkg/multicloud/qcloud/shell/snapshot_policy.go @@ -0,0 +1,96 @@ +// 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 shell + +import ( + "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/multicloud/qcloud" + "yunion.io/x/onecloud/pkg/util/shellutils" +) + +func init() { + type SSnapshotPolicyListOptions struct { + PolicyId string `help:"snapshot policy id"` + Offset int `help:"offset"` + Limit int `help:"limit"` + } + + shellutils.R(&SSnapshotPolicyListOptions{}, "snapshot-policy-list", "list snapshot policy", + func(cli *qcloud.SRegion, args *SSnapshotPolicyListOptions) error { + snapshotPolicis, num, err := cli.GetSnapshotPolicies(args.PolicyId, args.Offset, args.Limit) + if err != nil { + return err + } + + printList(snapshotPolicis, num, args.Offset, args.Limit, []string{}) + return nil + }, + ) + + type SSnapshotPolicyDeleteOptions struct { + ID string `help:"snapshot id"` + } + shellutils.R(&SSnapshotPolicyDeleteOptions{}, "snapshot-policy-delete", "delete snapshot policy", + func(cli *qcloud.SRegion, args *SSnapshotPolicyDeleteOptions) error { + err := cli.DeleteSnapshotPolicy(args.ID) + return err + }, + ) + + type SSnapshotPolicyCreateOptions struct { + Name string `help:"snapshot name"` + + RetentionDays int `help:"retention days"` + RepeatWeekdays []int `help:"auto snapshot which days of the week"` + TimePoints []int `help:"auto snapshot which hours of the day"` + } + shellutils.R(&SSnapshotPolicyCreateOptions{}, "snapshot-policy-create", "create snapshot policy", + func(cli *qcloud.SRegion, args *SSnapshotPolicyCreateOptions) error { + input := cloudprovider.SnapshotPolicyInput{ + RetentionDays: args.RetentionDays, + RepeatWeekdays: args.RepeatWeekdays, + TimePoints: args.TimePoints, + PolicyName: args.Name, + } + _, err := cli.CreateSnapshotPolicy(&input) + if err != nil { + return err + } + return nil + }, + ) + + type SSnapshotPolicyApplyOptions struct { + SNAPSHOTPOLICYID string `help:"snapshot policy id"` + DISKID string `help:"disk id"` + } + shellutils.R(&SSnapshotPolicyApplyOptions{}, "snapshot-policy-apply", "apply snapshot policy", + func(cli *qcloud.SRegion, args *SSnapshotPolicyApplyOptions) error { + err := cli.ApplySnapshotPolicyToDisks(args.SNAPSHOTPOLICYID, args.DISKID) + return err + }, + ) + + type SSnapshotPolicyCancelOptions struct { + SNAPSHOTPOLICYID string `help:"snapshot policy id"` + DISKID string `help:"disk id"` + } + shellutils.R(&SSnapshotPolicyCancelOptions{}, "snapshot-policy-cancel", "cancel snapshot policy", + func(cli *qcloud.SRegion, args *SSnapshotPolicyCancelOptions) error { + err := cli.CancelSnapshotPolicyToDisks(args.SNAPSHOTPOLICYID, args.DISKID) + return err + }, + ) +} diff --git a/pkg/multicloud/qcloud/snapshot_policy.go b/pkg/multicloud/qcloud/snapshot_policy.go new file mode 100644 index 0000000000..d941e933c5 --- /dev/null +++ b/pkg/multicloud/qcloud/snapshot_policy.go @@ -0,0 +1,240 @@ +// 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 qcloud + +import ( + "fmt" + "strconv" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/onecloud/pkg/apis/compute" + "yunion.io/x/onecloud/pkg/cloudprovider" +) + +const ( + NORMAL = "NORMAL" + UNKOWN = "ISOLATED" +) + +type SPolicy struct { + DayOfWeek []int + Hour []int +} + +type SSnapshotPolicy struct { + region *SRegion + + AutoSnapshotPolicyName string + AutoSnapshotPolicyId string + AutoSnapshotPolicyState string + RetentionDays int + Policy []SPolicy + Activated bool `json:"is_activated"` + IsPermanent bool +} + +func (self *SSnapshotPolicy) GetId() string { + return self.AutoSnapshotPolicyId +} + +func (self *SSnapshotPolicy) GetName() string { + return self.AutoSnapshotPolicyName +} + +func (self *SSnapshotPolicy) GetGlobalId() string { + return self.GetId() +} + +func (self *SSnapshotPolicy) GetStatus() string { + if self.AutoSnapshotPolicyState == NORMAL { + return api.SNAPSHOT_POLICY_READY + } + return api.SNAPSHOT_POLICY_UNKNOWN +} + +func (self *SSnapshotPolicy) Refresh() error { + if snapshotPolicies, total, err := self.region.GetSnapshotPolicies(self.AutoSnapshotPolicyId, 0, 1); err != nil { + return err + } else if total != 1 { + return cloudprovider.ErrNotFound + } else if err := jsonutils.Update(self, snapshotPolicies[0]); err != nil { + return err + } + return nil +} + +func (self *SSnapshotPolicy) IsEmulated() bool { + return false +} + +func (self *SSnapshotPolicy) GetMetadata() *jsonutils.JSONDict { + return nil +} + +func (self *SSnapshotPolicy) GetProjectId() string { + return "" +} + +func (self *SSnapshotPolicy) GetRetentionDays() int { + return self.RetentionDays +} + +func (self *SSnapshotPolicy) GetRepeatWeekdays() ([]int, error) { + if len(self.Policy) == 0 { + return nil, errors.Error("Policy Set Empty") + } + return self.Policy[0].DayOfWeek, nil +} + +func (self *SSnapshotPolicy) GetTimePoints() ([]int, error) { + if len(self.Policy) == 0 { + return nil, errors.Error("Policy Set Empty") + } + return self.Policy[0].Hour, nil +} + +func (self *SSnapshotPolicy) IsActivated() bool { + return self.Activated +} + +func (self *SRegion) GetISnapshotPolicies() ([]cloudprovider.ICloudSnapshotPolicy, error) { + snapshotPolicies, total, err := self.GetSnapshotPolicies("", 0, 50) + if err != nil { + return nil, err + } + for len(snapshotPolicies) < total { + var parts []SSnapshotPolicy + parts, total, err = self.GetSnapshotPolicies("", len(snapshotPolicies), 50) + if err != nil { + return nil, err + } + snapshotPolicies = append(snapshotPolicies, parts...) + } + ret := make([]cloudprovider.ICloudSnapshotPolicy, len(snapshotPolicies)) + for i := 0; i < len(snapshotPolicies); i += 1 { + ret[i] = &snapshotPolicies[i] + } + return ret, nil +} + +func (self *SRegion) GetSnapshotPolicies(policyId string, offset int, limit int) ([]SSnapshotPolicy, int, error) { + params := make(map[string]string) + if len(policyId) > 0 { + params["AutoSnapshotPolicyIds.0"] = policyId + } + if limit != 0 { + params["Limit"] = strconv.Itoa(limit) + params["Offset"] = strconv.Itoa(offset) + } + body, err := self.cbsRequest("DescribeAutoSnapshotPolicies", params) + if err != nil { + return nil, 0, errors.Wrap(err, "Get Snapshot Policies failed") + } + snapshotPolicies := make([]SSnapshotPolicy, 0, 1) + if err := body.Unmarshal(&snapshotPolicies, "AutoSnapshotPolicySet"); err != nil { + return nil, 0, errors.Wrap(err, "Unmarshal snapshot policies detail failed") + } + return snapshotPolicies, len(snapshotPolicies), nil +} + +func (self *SSnapshotPolicy) Delete() error { + if self.region == nil { + return fmt.Errorf("Not init region for snapshotPolicy %s", self.GetId()) + } + return self.region.DeleteSnapshotPolicy(self.GetId()) +} + +func (self *SRegion) DeleteSnapshotPolicy(snapshotPolicyId string) error { + params := make(map[string]string) + params["AutoSnapshotPolicyIds.0"] = snapshotPolicyId + _, err := self.cbsRequest("DeleteAutoSnapshotPolicies", params) + if err != nil { + return errors.Wrapf(err, "delete auto snapshot policy %s failed", snapshotPolicyId) + } + return nil +} + +func (self *SRegion) GetISnapshotPolicyById(snapshotPolicyId string) (cloudprovider.ICloudSnapshotPolicy, error) { + policies, _, err := self.GetSnapshotPolicies(snapshotPolicyId, 0, 1) + if err != nil { + return nil, err + } + if len(policies) == 0 { + return nil, cloudprovider.ErrNotFound + } + return &policies[0], nil +} + +func (self *SRegion) CreateSnapshotPolicy(input *cloudprovider.SnapshotPolicyInput) (string, error) { + if input.RepeatWeekdays == nil { + return "", fmt.Errorf("Can't create snapshot policy with nil repeatWeekdays") + } + if input.TimePoints == nil { + return "", fmt.Errorf("Can't create snapshot policy with nil timePoints") + } + params := make(map[string]string) + params["RetentionDays"] = strconv.Itoa(input.RetentionDays) + dayOfWeekPrefix, hourPrefix := "Policy.0.DayOfWeek.", "Policy.0.Hour." + for index, day := range input.RepeatWeekdays { + if day == 0 { + day = 7 + } + params[dayOfWeekPrefix+strconv.Itoa(index)] = strconv.Itoa(day) + } + if len(input.PolicyName) > 0 { + params["AutoSnapshotPolicyName"] = input.PolicyName + } + for index, hour := range input.TimePoints { + params[hourPrefix+strconv.Itoa(index)] = strconv.Itoa(hour) + } + body, err := self.cbsRequest("CreateAutoSnapshotPolicy", params) + if err != nil { + return "", errors.Wrap(err, "create auto snapshot policy failed") + } + id, _ := body.GetString("AutoSnapshotPolicyId") + return id, nil +} + +func (self *SRegion) UpdateSnapshotPolicy( + snapshotPolicyId string, retentionDays *int, + repeatWeekdays, timePoints *jsonutils.JSONArray, policyName string, +) error { + // not implement + return nil +} + +func (self *SRegion) ApplySnapshotPolicyToDisks(snapshotPolicyId string, diskId string) error { + params := make(map[string]string) + params["AutoSnapshotPolicyId"] = snapshotPolicyId + params["DiskIds.0"] = diskId + _, err := self.cbsRequest("BindAutoSnapshotPolicy", params) + if err != nil { + return errors.Wrapf(err, "Bind AutoSnapshotPolicy %s to Disk failed", snapshotPolicyId) + } + return nil +} + +func (self *SRegion) CancelSnapshotPolicyToDisks(snapshotPolicyId string, diskId string) error { + params := make(map[string]string) + params["AutoSnapshotPolicyId"] = snapshotPolicyId + params["DiskIds.0"] = diskId + _, err := self.cbsRequest("UnbindAutoSnapshotPolicy", params) + if err != nil { + return errors.Wrapf(err, "Unbind AutoSnapshotPolicy %s of Disk failed", snapshotPolicyId) + } + return nil +} diff --git a/pkg/multicloud/region_base.go b/pkg/multicloud/region_base.go index 614d8013ce..13855e4ad7 100644 --- a/pkg/multicloud/region_base.go +++ b/pkg/multicloud/region_base.go @@ -38,11 +38,11 @@ func (self *SRegion) DeleteSnapshotPolicy(string) error { return fmt.Errorf("DeleteSnapshotPolicy not implement") } -func (self *SRegion) ApplySnapshotPolicyToDisks(snapshotPolicyId string, diskIds []string) error { +func (self *SRegion) ApplySnapshotPolicyToDisks(snapshotPolicyId string, diskId string) error { return fmt.Errorf("ApplySnapshotPolicyToDisks not implement") } -func (self *SRegion) CancelSnapshotPolicyToDisks(diskIds []string) error { +func (self *SRegion) CancelSnapshotPolicyToDisks(snapshotPolicyId string, diskId string) error { return fmt.Errorf("ApplySnapshotPolicyToDisks not implement") } diff --git a/pkg/util/bitmap/bitmap.go b/pkg/util/bitmap/bitmap.go new file mode 100644 index 0000000000..5a80cf9c86 --- /dev/null +++ b/pkg/util/bitmap/bitmap.go @@ -0,0 +1,36 @@ +// 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 bitmap + +func Uint2IntArray(n uint32) []int { + ret := make([]int, 0, 2) + var i uint = 0 + for n != 0 { + if n&(1<