aliyun snapshot sync, create, delete; disk reset

This commit is contained in:
wanyaoqi
2018-09-17 22:15:21 +08:00
parent ad3544901a
commit bd7010b9e2
15 changed files with 509 additions and 149 deletions
+7
View File
@@ -35,7 +35,9 @@ type ICloudRegion interface {
GetIZones() ([]ICloudZone, error)
GetIVpcs() ([]ICloudVpc, error)
GetIEips() ([]ICloudEIP, error)
GetISnapshots() ([]ICloudSnapshot, error)
GetISnapshotById(snapshotId string) (ICloudSnapshot, error)
GetIZoneById(id string) (ICloudZone, error)
GetIVpcById(id string) (ICloudVpc, error)
GetIHostById(id string) (ICloudHost, error)
@@ -242,11 +244,16 @@ type ICloudDisk interface {
GetISnapshots() ([]ICloudSnapshot, error)
Resize(newSize int64) error
Reset(snapshotId string) error
}
type ICloudSnapshot interface {
ICloudResource
GetManagerId() string
GetSize() int32
GetDiskId() string
Delete() error
GetRegionId() string
}
type ICloudVpc interface {
+23
View File
@@ -654,3 +654,26 @@ func (self *SAliyunGuestDriver) RequestStartOnHost(ctx context.Context, guest *m
task.ScheduleRun(nil)
return nil
}*/
func (self *SAliyunGuestDriver) RequestDiskSnapshot(ctx context.Context, guest *models.SGuest, task taskman.ITask, snapshotId, diskId string) error {
iDisk, _ := models.DiskManager.FetchById(diskId)
disk := iDisk.(*models.SDisk)
providerDisk, err := disk.GetIDisk()
if err != nil {
return err
}
iSnapshot, _ := models.SnapshotManager.FetchById(snapshotId)
snapshot := iSnapshot.(*models.SSnapshot)
taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
cloudSnapshot, err := providerDisk.CreateISnapshot(snapshot.Name, "")
if err != nil {
return nil, err
}
res := jsonutils.NewDict()
res.Set("snapshot_id", jsonutils.NewString(cloudSnapshot.GetId()))
res.Set("manager_id", jsonutils.NewString(cloudSnapshot.GetManagerId()))
res.Set("cloudregion_id", jsonutils.NewString(cloudSnapshot.GetRegionId()))
return res, nil
})
return nil
}
-9
View File
@@ -47,15 +47,6 @@ func (self *SKVMGuestDriver) DoGuestCreateDisksTask(ctx context.Context, guest *
return nil
}
func (self *SKVMGuestDriver) StartGuestDiskSnapshotTask(ctx context.Context, userCred mcclient.TokenCredential, guest *models.SGuest, params *jsonutils.JSONDict) error {
task, err := taskman.TaskManager.NewTask(ctx, "GuestDiskSnapshotTask", guest, userCred, params, "", "", nil)
if err != nil {
return err
}
task.ScheduleRun(nil)
return nil
}
func (self *SKVMGuestDriver) RequestDiskSnapshot(ctx context.Context, guest *models.SGuest, task taskman.ITask, snapshotId, diskId string) error {
url := fmt.Sprintf("/servers/%s/snapshot", guest.Id)
body := jsonutils.NewDict()
@@ -203,3 +203,12 @@ func (self *SVirtualizedGuestDriver) StartGuestSaveImage(ctx context.Context, us
}
return nil
}
func (self *SVirtualizedGuestDriver) StartGuestDiskSnapshotTask(ctx context.Context, userCred mcclient.TokenCredential, guest *models.SGuest, params *jsonutils.JSONDict) error {
task, err := taskman.TaskManager.NewTask(ctx, "GuestDiskSnapshotTask", guest, userCred, params, "", "", nil)
if err != nil {
return err
}
task.ScheduleRun(nil)
return nil
}
+17 -2
View File
@@ -6,11 +6,11 @@ import (
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
"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/cloudcommon/db/lockman"
)
type SAliyunHostDriver struct {
@@ -37,7 +37,6 @@ func (self *SAliyunHostDriver) CheckAndSetCacheImage(ctx context.Context, host *
osType, _ := params.GetString("os_type")
osDist, _ := params.GetString("os_distribution")
isForce := jsonutils.QueryBoolean(params, "is_force", false)
userCred := task.GetUserCred()
taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
@@ -189,3 +188,19 @@ func (self *SAliyunHostDriver) RequestResizeDiskOnHost(host *models.SHost, stora
}
return nil
}
func (self *SAliyunHostDriver) RequestResetDisk(ctx context.Context, host *models.SHost, disk *models.SDisk, params *jsonutils.JSONDict, task taskman.ITask) error {
iDisk, err := disk.GetIDisk()
if err != nil {
return err
}
snapshotId, err := params.GetString("snapshot_id")
if err != nil {
return err
}
taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
err := iDisk.Reset(snapshotId)
return nil, err
})
return nil
}
+2 -2
View File
@@ -1245,11 +1245,11 @@ func (manager *SDiskManager) AutoDiskSnapshot(ctx context.Context, userCred mccl
continue
}
if !utils.IsInStringArray(guests[0].Status, []string{VM_RUNNING, VM_READY}) {
log.Errorln("Guest(%s) in status(%s) cannot do snapshot action", guests[0].Id, guests[0].Status)
log.Errorf("Guest(%s) in status(%s) cannot do snapshot action", guests[0].Id, guests[0].Status)
continue
}
// name
name := disk.Name + time.Now().Format("2006-01-02#15:04:05")
name := guests[0].Name + time.Now().Format("2006-01-02#15:04:05")
snap, err := SnapshotManager.CreateSnapshot(ctx, userCred, AUTO, disk.Id, guests[0].Id, "", name)
if err != nil {
log.Errorln(err)
+1 -1
View File
@@ -13,12 +13,12 @@ import (
"yunion.io/x/sqlchemy"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
"yunion.io/x/onecloud/pkg/cloudcommon/db/quotas"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
)
const (
+33 -21
View File
@@ -82,6 +82,7 @@ const (
VM_START_SNAPSHOT = "snapshot_start"
VM_SNAPSHOT = "snapshot"
VM_SNAPSHOT_DELETE = "snapshot_delete"
VM_SNAPSHOT_STREAM = "block_stream"
VM_SNAPSHOT_SUCC = "snapshot_succ"
VM_SNAPSHOT_FAILED = "snapshot_failed"
@@ -3866,39 +3867,50 @@ func (self *SGuest) PerformDiskSnapshot(ctx context.Context, userCred mcclient.T
}
diskId, err := data.GetString("disk_id")
if err != nil {
return nil, err
return nil, httperrors.NewBadRequestError(err.Error())
}
name, err := data.GetString("name")
if err != nil {
return nil, err
return nil, httperrors.NewBadRequestError(err.Error())
}
// if self.GetHypervisor() == HYPERVISOR_ALIYUN && strings.HasPrefix(name, "auto") {
// }
if self.GetGuestDisk(diskId) == nil {
return nil, httperrors.NewNotFoundError("Guest disk %s not found", diskId)
}
snapshots := SnapshotManager.GetDiskSnapshotsByCreate(diskId, MANUAL)
if snapshots != nil {
if len(snapshots) >= options.Options.DefaultMaxManualSnapshotCount {
return nil, httperrors.NewBadRequestError("Disk %s snapshot full, cannot take any more", diskId)
}
for _, snapshot := range snapshots {
if snapshot.Name == name {
return nil, httperrors.NewBadRequestError("Name Conflict")
if self.GetHypervisor() == HYPERVISOR_KVM {
snapshots := SnapshotManager.GetDiskSnapshotsByCreate(diskId, MANUAL)
if snapshots != nil {
if len(snapshots) >= options.Options.DefaultMaxManualSnapshotCount {
return nil, httperrors.NewBadRequestError("Disk %s snapshot full, cannot take any more", diskId)
}
for _, snapshot := range snapshots {
if snapshot.Name == name {
return nil, httperrors.NewBadRequestError("Name Conflict")
}
}
}
}
pendingUsage := &SQuota{Snapshot: 1}
err = QuotaManager.CheckSetPendingQuota(ctx, userCred, self.ProjectId, pendingUsage)
if err != nil {
return nil, httperrors.NewBadRequestError("Check set pending quota error %s", err)
}
snapshot, err := SnapshotManager.CreateSnapshot(ctx, userCred, MANUAL, diskId, self.Id, "", name)
QuotaManager.CancelPendingUsage(ctx, userCred, self.ProjectId, nil, pendingUsage)
if err != nil {
pendingUsage := &SQuota{Snapshot: 1}
err = QuotaManager.CheckSetPendingQuota(ctx, userCred, self.ProjectId, pendingUsage)
if err != nil {
return nil, httperrors.NewBadRequestError("Check set pending quota error %s", err)
}
snapshot, err := SnapshotManager.CreateSnapshot(ctx, userCred, MANUAL, diskId, self.Id, "", name)
QuotaManager.CancelPendingUsage(ctx, userCred, self.ProjectId, nil, pendingUsage)
if err != nil {
return nil, err
}
err = self.StartDiskSnapshot(ctx, userCred, diskId, snapshot.Id)
return nil, err
} else {
snapshot, err := SnapshotManager.CreateSnapshot(ctx, userCred, MANUAL, diskId, self.Id, "", name)
if err != nil {
return nil, err
}
err = self.StartDiskSnapshot(ctx, userCred, diskId, snapshot.Id)
return nil, err
}
err = self.StartDiskSnapshot(ctx, userCred, diskId, snapshot.Id)
return nil, err
}
func (self *SGuest) StartDiskSnapshot(ctx context.Context, userCred mcclient.TokenCredential, diskId, snapshotId string) error {
+145 -12
View File
@@ -7,10 +7,13 @@ import (
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/util/compare"
"yunion.io/x/pkg/utils"
"yunion.io/x/sqlchemy"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"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"
@@ -21,9 +24,11 @@ const (
MANUAL = "manual"
AUTO = "auto"
SNAPSHOT_CREATING = "creating"
SNAPSHOT_FAILED = "create_failed"
SNAPSHOT_READY = "ready"
SNAPSHOT_DELETING = "deleting"
SNAPSHOT_UNKNOWN = "unknown"
)
type SSnapshotManager struct {
@@ -32,13 +37,17 @@ type SSnapshotManager struct {
type SSnapshot struct {
db.SVirtualResourceBase
DiskId string `width:"36" charset:"ascii" nullable:"false" create:"required" key_index:"true" list:"user"`
SManagedResourceBase
DiskId string `width:"36" charset:"ascii" nullable:"true" create:"required" key_index:"true" list:"user"`
StorageId string `width:"36" charset:"ascii" nullable:"true" list:"admin"`
CreatedBy string `width:"36" charset:"ascii" nullable:"false" default:"manual" list:"admin"`
Location string `charset:"ascii" nullable:"false" list:"admin"`
Location string `charset:"ascii" nullable:"true" list:"admin"`
Size int `nullable:"false" list:"user"` // MB
OutOfChain bool `nullable:"false" default:"false" index:"true" list:"admin"`
FakeDeleted bool `nullable:"false" default:"false" index:"true"`
CloudregionId string `width:"36" charset:"ascii" nullable:"true" list:"user"`
}
var SnapshotManager *SSnapshotManager
@@ -180,6 +189,7 @@ func (self *SSnapshotManager) CreateSnapshot(ctx context.Context, userCred mccli
snapshot.Location = location
snapshot.CreatedBy = createdBy
snapshot.Name = name
snapshot.Status = SNAPSHOT_CREATING
err = SnapshotManager.TableSpec().Insert(snapshot)
if err != nil {
return nil, err
@@ -211,21 +221,29 @@ func (self *SSnapshot) ValidateDeleteCondition(ctx context.Context) error {
func (self *SSnapshot) CustomizeDelete(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
if self.Status == SNAPSHOT_DELETING {
return fmt.Errorf("Cannot delete snapshot in status %s", self.Status)
} else if self.Status == VM_SNAPSHOT_FAILED {
}
if self.Status == SNAPSHOT_UNKNOWN {
return self.RealDelete(ctx, userCred)
}
if self.CreatedBy == MANUAL {
if !self.FakeDeleted {
return self.FakeDelete()
} else {
_, err := SnapshotManager.GetConvertSnapshot(self)
if err != nil {
return fmt.Errorf("Cannot delete snapshot: %s, disk need at least one of snapshot as backing file", err.Error())
if len(self.ExternalId) == 0 {
if utils.IsInStringArray(self.Status, []string{SNAPSHOT_FAILED}) {
return self.RealDelete(ctx, userCred)
}
if self.CreatedBy == MANUAL {
if !self.FakeDeleted {
return self.FakeDelete()
} else {
_, err := SnapshotManager.GetConvertSnapshot(self)
if err != nil {
return fmt.Errorf("Cannot delete snapshot: %s, disk need at least one of snapshot as backing file", err.Error())
}
return self.StartSnapshotDeleteTask(ctx, userCred, false, "")
}
return self.StartSnapshotDeleteTask(ctx, userCred, false, "")
} else {
return fmt.Errorf("Cannot delete snapshot created by %s", self.CreatedBy)
}
} else {
return fmt.Errorf("Cannot delete snapshot created by %s", self.CreatedBy)
return self.StartSnapshotDeleteTask(ctx, userCred, false, "")
}
}
@@ -324,3 +342,118 @@ func totalSnapshotCount(projectId string) int {
count := q.Equals("tenant_id", projectId).Equals("fake_deleted", false).Count()
return count
}
// Only sync snapshot status
func (self *SSnapshot) SyncWithCloudSnapshot(userCred mcclient.TokenCredential, ext cloudprovider.ICloudSnapshot) error {
_, err := self.GetModelManager().TableSpec().Update(self, func() error {
self.Status = ext.GetStatus()
return nil
})
if err != nil {
log.Errorf("SyncWithCloudSnapshot fail %s", err)
}
return err
}
func (manager *SSnapshotManager) newFromCloudSnapshot(userCred mcclient.TokenCredential, extSnapshot cloudprovider.ICloudSnapshot, region *SCloudregion) (*SSnapshot, error) {
snapshot := SSnapshot{}
snapshot.SetModelManager(manager)
snapshot.Name = extSnapshot.GetName()
snapshot.Status = extSnapshot.GetStatus()
snapshot.ExternalId = extSnapshot.GetGlobalId()
if len(extSnapshot.GetDiskId()) > 0 {
disk, err := DiskManager.FetchByExternalId(extSnapshot.GetDiskId())
if err != nil {
log.Errorf("snapshot %s missing disk?", snapshot.Name)
} else {
snapshot.DiskId = disk.GetId()
}
}
snapshot.Size = int(extSnapshot.GetSize()) * 1024
snapshot.ManagerId = extSnapshot.GetManagerId()
snapshot.CloudregionId = region.Id
snapshot.ProjectId = userCred.GetProjectId()
err := manager.TableSpec().Insert(&snapshot)
if err != nil {
log.Errorf("newFromCloudEip fail %s", err)
return nil, err
}
return &snapshot, nil
}
func (manager *SSnapshotManager) getProviderSnapshotsByRegion(region *SCloudregion, provider *SCloudprovider) ([]SSnapshot, error) {
if region == nil || provider == nil {
return nil, fmt.Errorf("Region is nil or provider is nil")
}
snapshots := make([]SSnapshot, 0)
q := manager.Query().Equals("cloudregion_id", region.Id).Equals("manager_id", provider.Id).NotEquals("status", SNAPSHOT_UNKNOWN)
err := db.FetchModelObjects(manager, q, &snapshots)
if err != nil {
return nil, err
}
return snapshots, nil
}
func (manager *SSnapshotManager) SyncSnapshots(ctx context.Context, userCred mcclient.TokenCredential, provider *SCloudprovider, region *SCloudregion, snapshots []cloudprovider.ICloudSnapshot) compare.SyncResult {
syncResult := compare.SyncResult{}
dbSnapshots, err := manager.getProviderSnapshotsByRegion(region, provider)
if err != nil {
syncResult.Error(err)
return syncResult
}
removed := make([]SSnapshot, 0)
commondb := make([]SSnapshot, 0)
commonext := make([]cloudprovider.ICloudSnapshot, 0)
added := make([]cloudprovider.ICloudSnapshot, 0)
err = compare.CompareSets(dbSnapshots, snapshots, &removed, &commondb, &commonext, &added)
if err != nil {
syncResult.Error(err)
return syncResult
}
for i := 0; i < len(removed); i += 1 {
err = removed[i].SetStatus(userCred, SNAPSHOT_UNKNOWN, "sync to delete")
if err != nil {
syncResult.DeleteError(err)
} else {
syncResult.Delete()
}
}
for i := 0; i < len(commondb); i += 1 {
err = commondb[i].SyncWithCloudSnapshot(userCred, commonext[i])
if err != nil {
syncResult.UpdateError(err)
} else {
syncResult.Update()
}
}
for i := 0; i < len(added); i += 1 {
_, err := manager.newFromCloudSnapshot(userCred, added[i], region)
if err != nil {
syncResult.AddError(err)
} else {
syncResult.Add()
}
}
return syncResult
}
func (self *SSnapshot) GetRegion() *SCloudregion {
return CloudregionManager.FetchRegionById(self.CloudregionId)
}
func (self *SSnapshot) GetISnapshotRegion() (cloudprovider.ICloudRegion, error) {
provider, err := self.GetDriver()
if err != nil {
return nil, err
}
region := self.GetRegion()
if region == nil {
return nil, fmt.Errorf("fail to find region for snapshot")
}
return provider.GetIRegionById(region.GetExternalId())
}
@@ -108,7 +108,6 @@ func syncCloudProviderInfo(ctx context.Context, provider *models.SCloudprovider,
if len(syncRange.Region) > 0 && !utils.IsInStringArray(localRegions[i].Id, syncRange.Region) {
continue
}
syncRegionEips(ctx, provider, task, &localRegions[i], remoteRegions[i])
localZones, remoteZones := syncRegionZones(ctx, provider, task, &localRegions[i], remoteRegions[i])
@@ -125,9 +124,29 @@ func syncCloudProviderInfo(ctx context.Context, provider *models.SCloudprovider,
syncZoneHosts(ctx, provider, task, &localZones[j], remoteZones[j], syncRange)
}
}
syncRegionSnapshots(ctx, provider, task, &localRegions[i], remoteRegions[i])
}
}
func syncRegionSnapshots(ctx context.Context, provider *models.SCloudprovider, task *CloudProviderSyncInfoTask, localRegion *models.SCloudregion, remoteRegion cloudprovider.ICloudRegion) {
snapshots, err := remoteRegion.GetISnapshots()
if err != nil {
msg := fmt.Sprintf("GetISnapshots for region %s failed %s", remoteRegion.GetName(), err)
log.Errorf(msg)
logSyncFailed(provider, task, msg)
return
}
result := models.SnapshotManager.SyncSnapshots(ctx, task.GetUserCred(), provider, localRegion, snapshots)
msg := result.Result()
log.Infof("SyncSnapshots for region %s result: %s", localRegion.Name, msg)
if result.IsError() {
logSyncFailed(provider, task, msg)
return
}
db.OpsLog.LogEvent(provider, db.ACT_SYNC_HOST_COMPLETE, msg, task.GetUserCred())
}
func syncRegionEips(ctx context.Context, provider *models.SCloudprovider, task *CloudProviderSyncInfoTask, localRegion *models.SCloudregion, remoteRegion cloudprovider.ICloudRegion) {
eips, err := remoteRegion.GetIEips()
if err != nil {
@@ -405,7 +424,7 @@ func syncHostVMs(ctx context.Context, provider *models.SCloudprovider, task *Clo
for i := 0; i < len(localVMs); i += 1 {
syncVMNics(ctx, provider, task, localHost, &localVMs[i], remoteVMs[i])
syncVMDisks(ctx, provider, task, localHost, &localVMs[i], remoteVMs[i])
syncVMEip(ctx, provider, task, &localVMs[i], remoteVMs[i])
syncVMEip(ctx, provider, task, &localVMs[i], remoteVMs[i])
}
}
@@ -465,4 +484,4 @@ func syncVMEip(ctx context.Context, provider *models.SCloudprovider, task *Cloud
return
}
db.OpsLog.LogEvent(provider, db.ACT_SYNC_HOST_COMPLETE, msg, task.UserCred)
}
}
+15 -9
View File
@@ -45,11 +45,15 @@ func (self *DiskResetTask) RequestResetDisk(ctx context.Context, disk *models.SD
iSnapshot, _ := models.SnapshotManager.FetchById(snapshotId)
snapshot := iSnapshot.(*models.SSnapshot)
params := jsonutils.NewDict()
params.Set("snapshot_id", jsonutils.NewString(snapshot.Id))
if snapshot.OutOfChain {
params.Set("out_of_chain", jsonutils.JSONTrue)
if len(snapshot.ExternalId) == 0 {
params.Set("snapshot_id", jsonutils.NewString(snapshot.Id))
if snapshot.OutOfChain {
params.Set("out_of_chain", jsonutils.JSONTrue)
} else {
params.Set("out_of_chain", jsonutils.JSONFalse)
}
} else {
params.Set("out_of_chain", jsonutils.JSONFalse)
params.Set("snapshot_id", jsonutils.NewString(snapshot.ExternalId))
}
self.SetStage("OnRequestResetDisk", nil)
err = host.GetHostDriver().RequestResetDisk(ctx, host, disk, params, self)
@@ -71,11 +75,13 @@ func (self *DiskResetTask) OnRequestResetDisk(ctx context.Context, disk *models.
log.Errorln(err)
}
}
err := disk.CleanUpDiskSnapshots(ctx, self.UserCred, snapshot)
if err != nil {
log.Errorln(err)
self.SetStageFailed(ctx, fmt.Sprintf("OnRequestResetDisk %s", err.Error()))
return
if len(snapshot.ExternalId) == 0 {
err := disk.CleanUpDiskSnapshots(ctx, self.UserCred, snapshot)
if err != nil {
log.Errorln(err)
self.SetStageFailed(ctx, fmt.Sprintf("OnRequestResetDisk %s", err.Error()))
return
}
}
self.SetStageComplete(ctx, nil)
}
+86 -36
View File
@@ -3,12 +3,14 @@ package tasks
import (
"context"
"database/sql"
"time"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/compute/models"
)
@@ -49,19 +51,35 @@ func (self *GuestDiskSnapshotTask) DoDiskSnapshot(ctx context.Context, guest *mo
func (self *GuestDiskSnapshotTask) OnDiskSnapshotComplete(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
res := data.(*jsonutils.JSONDict)
location, err := res.GetString("location")
if err != nil {
log.Infof("OnDiskSnapshotComplete called with data no location")
return
if guest.Hypervisor == models.HYPERVISOR_KVM {
location, err := res.GetString("location")
if err != nil {
log.Infof("OnDiskSnapshotComplete called with data no location")
return
}
snapshotId, _ := self.Params.GetString("snapshot_id")
iSnapshot, _ := models.SnapshotManager.FetchById(snapshotId)
snapshot := iSnapshot.(*models.SSnapshot)
models.SnapshotManager.TableSpec().Update(snapshot, func() error {
snapshot.Location = location
snapshot.Status = models.SNAPSHOT_READY
return nil
})
} else {
snapshotId, _ := self.Params.GetString("snapshot_id")
iSnapshot, _ := models.SnapshotManager.FetchById(snapshotId)
snapshot := iSnapshot.(*models.SSnapshot)
extSnapshotId, _ := data.GetString("snapshot_id")
cloudregionId, _ := data.GetString("cloudregion_id")
managerId, _ := data.GetString("manager_id")
models.SnapshotManager.TableSpec().Update(snapshot, func() error {
snapshot.CloudregionId = cloudregionId
snapshot.ExternalId = extSnapshotId
snapshot.Status = models.SNAPSHOT_READY
snapshot.ManagerId = managerId
return nil
})
}
snapshotId, _ := self.Params.GetString("snapshot_id")
iSnapshot, _ := models.SnapshotManager.FetchById(snapshotId)
snapshot := iSnapshot.(*models.SSnapshot)
models.SnapshotManager.TableSpec().Update(snapshot, func() error {
snapshot.Location = location
snapshot.Status = models.SNAPSHOT_READY
return nil
})
guest.SetStatus(self.UserCred, models.VM_SNAPSHOT_SUCC, "")
self.TaskComplete(ctx, guest, nil)
}
@@ -108,6 +126,16 @@ type SnapshotDeleteTask struct {
func (self *SnapshotDeleteTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
snapshot := obj.(*models.SSnapshot)
if len(snapshot.ExternalId) > 0 {
err := self.deleteExternalSnapshot(ctx, snapshot)
if err != nil {
self.SetStageFailed(ctx, err.Error())
} else {
snapshot.RealDelete(ctx, self.GetUserCred())
self.SetStageComplete(ctx, nil)
}
return
}
guest, err := snapshot.GetGuest()
if err != nil {
if err != sql.ErrNoRows {
@@ -126,6 +154,22 @@ func (self *SnapshotDeleteTask) OnInit(ctx context.Context, obj db.IStandaloneMo
}
}
func (self *SnapshotDeleteTask) deleteExternalSnapshot(ctx context.Context, snapshot *models.SSnapshot) error {
cloudRegion, err := snapshot.GetISnapshotRegion()
if err != nil {
log.Errorln(err, cloudRegion, snapshot.CloudregionId)
return err
}
cloudSnapshot, err := cloudRegion.GetISnapshotById(snapshot.ExternalId)
if err != nil {
log.Errorln(err, cloudSnapshot)
return err
}
cloudSnapshot.Delete()
err = cloudprovider.WaitDeleted(cloudSnapshot, 10*time.Second, 300*time.Second)
return err
}
func (self *SnapshotDeleteTask) StartReloadDisk(ctx context.Context, snapshot *models.SSnapshot, guest *models.SGuest) {
self.SetStage("OnReloadDiskSnapshot", nil)
guest.SetStatus(self.UserCred, models.VM_SNAPSHOT, "Start Reload Snapshot")
@@ -139,6 +183,7 @@ func (self *SnapshotDeleteTask) StartReloadDisk(ctx context.Context, snapshot *m
func (self *SnapshotDeleteTask) StartDeleteSnapshot(ctx context.Context, snapshot *models.SSnapshot, guest *models.SGuest) {
snapshot.SetStatus(self.UserCred, models.SNAPSHOT_DELETING, "On SnapshotDeleteTask StartDeleteSnapshot")
params := jsonutils.NewDict()
convertSnapshot, err := models.SnapshotManager.GetConvertSnapshot(snapshot)
if err != nil {
self.TaskFailed(ctx, snapshot, err.Error())
@@ -148,7 +193,6 @@ func (self *SnapshotDeleteTask) StartDeleteSnapshot(ctx context.Context, snapsho
self.TaskFailed(ctx, snapshot, "snapshot dose not have convert snapshot")
return
}
params := jsonutils.NewDict()
params.Set("delete_snapshot", jsonutils.NewString(snapshot.Id))
params.Set("disk_id", jsonutils.NewString(snapshot.DiskId))
if !snapshot.OutOfChain {
@@ -161,9 +205,9 @@ func (self *SnapshotDeleteTask) StartDeleteSnapshot(ctx context.Context, snapsho
} else {
params.Set("auto_deleted", jsonutils.JSONTrue)
}
guest.SetStatus(self.UserCred, models.VM_SNAPSHOT_DELETE, "Start Delete Snapshot")
self.SetStage("OnDeleteSnapshot", nil)
guest.SetStatus(self.UserCred, models.VM_SNAPSHOT, "Start Delete Snapshot")
err = guest.GetDriver().RequestDeleteSnapshot(ctx, guest, self, params)
if err != nil {
self.TaskFailed(ctx, snapshot, err.Error())
@@ -180,30 +224,36 @@ func (self *SnapshotDeleteTask) DeleteStaticSnapshot(ctx context.Context, snapsh
}
func (self *SnapshotDeleteTask) OnDeleteSnapshot(ctx context.Context, snapshot *models.SSnapshot, data jsonutils.JSONObject) {
if !jsonutils.QueryBoolean(data, "deleted", false) {
log.Infof("OnDeleteSnapshot with no deleted")
return
}
snapshot.SetStatus(self.UserCred, models.SNAPSHOT_READY, "OnDeleteSnapshot")
if snapshot.OutOfChain {
if len(snapshot.ExternalId) == 0 {
if !jsonutils.QueryBoolean(data, "deleted", false) {
log.Infof("OnDeleteSnapshot with no deleted")
return
}
snapshot.SetStatus(self.UserCred, models.SNAPSHOT_READY, "OnDeleteSnapshot")
if snapshot.OutOfChain {
snapshot.RealDelete(ctx, self.UserCred)
self.TaskComplete(ctx, snapshot, nil)
} else {
guest, _ := snapshot.GetGuest()
var FakeDelete = false
if snapshot.CreatedBy == models.MANUAL && snapshot.FakeDeleted == false {
FakeDelete = true
}
if FakeDelete {
models.SnapshotManager.TableSpec().Update(snapshot, func() error {
snapshot.OutOfChain = true
return nil
})
} else {
snapshot.RealDelete(ctx, self.UserCred)
}
self.SetStage("TaskComplete", nil)
guest.StartSyncstatus(ctx, self.UserCred, "")
}
} else {
snapshot.SetStatus(self.UserCred, models.SNAPSHOT_READY, "OnDeleteSnapshot")
snapshot.RealDelete(ctx, self.UserCred)
self.TaskComplete(ctx, snapshot, nil)
} else {
guest, _ := snapshot.GetGuest()
var FakeDelete = false
if snapshot.CreatedBy == models.MANUAL && snapshot.FakeDeleted == false {
FakeDelete = true
}
if FakeDelete {
models.SnapshotManager.TableSpec().Update(snapshot, func() error {
snapshot.OutOfChain = true
return nil
})
} else {
snapshot.RealDelete(ctx, self.UserCred)
}
self.SetStage("TaskComplete", nil)
guest.StartSyncstatus(ctx, self.UserCred, "")
}
}
+19 -39
View File
@@ -271,6 +271,19 @@ func (self *SRegion) resizeDisk(diskId string, size int64) error {
return nil
}
func (self *SRegion) resetDisk(diskId, snapshotId string) error {
params := make(map[string]string)
params["DiskId"] = diskId
params["SnapshotId"] = snapshotId
_, err := self.ecsRequest("ResetDisk", params)
if err != nil {
log.Errorf("ResetDisk %s to snapshot %s fail %s", diskId, snapshotId, err)
return err
}
return nil
}
func (self *SDisk) CreateISnapshot(name, desc string) (cloudprovider.ICloudSnapshot, error) {
if snapshotId, err := self.storage.zone.region.CreateSnapshot(self.DiskId, name, desc); err != nil {
log.Errorf("createSnapshot fail %s", err)
@@ -278,8 +291,8 @@ func (self *SDisk) CreateISnapshot(name, desc string) (cloudprovider.ICloudSnaps
} else if snapshot, err := self.getSnapshot(snapshotId); err != nil {
return nil, err
} else {
snapshot.disk = self
if err := cloudprovider.WaitStatus(snapshot, string(SnapshotStatusAccoplished), 15*time.Second, 3600*time.Second); err != nil {
snapshot.region = self.storage.zone.region
if err := cloudprovider.WaitStatus(snapshot, models.SNAPSHOT_READY, 15*time.Second, 3600*time.Second); err != nil {
return nil, err
}
return snapshot, nil
@@ -305,7 +318,7 @@ func (self *SDisk) GetISnapshot(snapshotId string) (cloudprovider.ICloudSnapshot
if snapshot, err := self.getSnapshot(snapshotId); err != nil {
return nil, err
} else {
snapshot.disk = self
snapshot.region = self.storage.zone.region
return snapshot, nil
}
}
@@ -335,47 +348,14 @@ func (self *SDisk) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) {
}
isnapshots := make([]cloudprovider.ICloudSnapshot, len(snapshots))
for i := 0; i < len(snapshots); i++ {
snapshots[i].disk = self
snapshots[i].region = self.storage.zone.region
isnapshots[i] = &snapshots[i]
}
return isnapshots, nil
}
func (self *SRegion) GetSnapshots(instanceId string, diskId string, snapshotName string, snapshotIds []string, offset int, limit int) ([]SSnapshot, int, error) {
if limit > 50 || limit <= 0 {
limit = 50
}
params := make(map[string]string)
params["RegionId"] = self.RegionId
params["PageSize"] = fmt.Sprintf("%d", limit)
params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1)
if len(instanceId) > 0 {
params["InstanceId"] = instanceId
}
if len(diskId) > 0 {
params["diskId"] = diskId
}
if len(snapshotName) > 0 {
params["SnapshotName"] = snapshotName
}
if snapshotIds != nil && len(snapshotIds) > 0 {
params["SnapshotIds"] = jsonutils.Marshal(snapshotIds).String()
}
if body, err := self.ecsRequest("DescribeSnapshots", params); err != nil {
log.Errorf("GetSnapshots fail %s", err)
return nil, 0, err
} else {
snapshots := make([]SSnapshot, 0)
if err := body.Unmarshal(&snapshots, "Snapshots", "Snapshot"); err != nil {
log.Errorf("Unmarshal snapshot details fail %s", err)
return nil, 0, err
}
total, _ := body.Int("TotalCount")
return snapshots, int(total), nil
}
func (self *SDisk) Reset(snapshotId string) error {
return self.storage.zone.region.resetDisk(self.DiskId, snapshotId)
}
+21 -1
View File
@@ -571,6 +571,26 @@ func (self *SRegion) UpdateInstancePassword(instId string, passwd string) error
return self.updateInstance(instId, "", "", passwd, "")
}
// func (self *SRegion) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) {
// eips, total, err := self.GetSnapshots("", 0, 50)
// if err != nil {
// return nil, err
// }
// for len(eips) < total {
// var parts []SEipAddress
// parts, total, err = self.GetEips("", len(eips), 50)
// if err != nil {
// return nil, err
// }
// eips = append(eips, parts...)
// }
// ret := make([]cloudprovider.ICloudEIP, len(eips))
// for i := 0; i < len(eips); i += 1 {
// ret[i] = &eips[i]
// }
// return ret, nil
// }
func (self *SRegion) GetIEips() ([]cloudprovider.ICloudEIP, error) {
eips, total, err := self.GetEips("", 0, 50)
if err != nil {
@@ -603,4 +623,4 @@ func (self *SRegion) GetIEipById(eipId string) (cloudprovider.ICloudEIP, error)
return nil, cloudprovider.ErrDuplicateId
}
return &eips[0], nil
}
}
+109 -14
View File
@@ -4,17 +4,22 @@ import (
"fmt"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/compute/models"
)
type SnapshotStatusType string
const (
SnapshotStatusAccoplished SnapshotStatusType = "accomplished"
SnapshotStatusProgress SnapshotStatusType = "progressing"
SnapshotStatusAccomplished SnapshotStatusType = "accomplished"
SnapshotStatusProgress SnapshotStatusType = "progressing"
SnapshotStatusFailed SnapshotStatusType = "failed"
)
type SSnapshot struct {
disk *SDisk
region *SRegion
Progress string
SnapshotId string
SnapshotName string
@@ -34,13 +39,37 @@ func (self *SSnapshot) GetName() string {
}
func (self *SSnapshot) GetStatus() string {
return string(self.Status)
if self.Status == SnapshotStatusAccomplished {
return models.SNAPSHOT_READY
} else if self.Status == SnapshotStatusProgress {
return models.SNAPSHOT_CREATING
} else { // if self.Status == SnapshotStatusFailed
return models.SNAPSHOT_FAILED
}
}
func (self *SSnapshot) GetManagerId() string {
return self.region.client.providerId
}
func (self *SSnapshot) GetRegionId() string {
return self.region.GetId()
}
func (self *SSnapshot) GetSize() int32 {
return self.SourceDiskSize
}
func (self *SSnapshot) GetDiskId() string {
return self.SourceDiskId
}
func (self *SSnapshot) Refresh() error {
if snapshot, err := self.disk.getSnapshot(self.SnapshotId); err != nil {
if snapshots, total, err := self.region.GetSnapshots("", "", "", []string{self.SnapshotId}, 0, 1); err != nil {
return err
} else if err := jsonutils.Update(self, snapshot); err != nil {
} else if total != 1 {
return cloudprovider.ErrNotFound
} else if err := jsonutils.Update(self, snapshots[0]); err != nil {
return err
}
return nil
@@ -54,20 +83,86 @@ func (self *SSnapshot) IsEmulated() bool {
return false
}
func (self *SRegion) DeleteSnapshot(snapshotId string) error {
params := make(map[string]string)
params["SnapshotId"] = snapshotId
_, err := self.ecsRequest("DeleteSnapshot", params)
return err
func (self *SRegion) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) {
snapshots, total, err := self.GetSnapshots("", "", "", []string{}, 0, 50)
if err != nil {
return nil, err
}
for len(snapshots) < total {
var parts []SSnapshot
parts, total, err = self.GetSnapshots("", "", "", []string{}, len(snapshots), 50)
if err != nil {
return nil, err
}
snapshots = append(snapshots, parts...)
}
ret := make([]cloudprovider.ICloudSnapshot, len(snapshots))
for i := 0; i < len(snapshots); i += 1 {
ret[i] = &snapshots[i]
}
return ret, nil
}
func (self *SSnapshot) Delete() error {
if self.disk == nil {
return fmt.Errorf("not init disk for snapshot %s", self.SnapshotId)
if self.region == nil {
return fmt.Errorf("not init region for snapshot %s", self.SnapshotId)
}
return self.disk.storage.zone.region.DeleteSnapshot(self.SnapshotId)
params := make(map[string]string)
params["SnapshotId"] = self.SnapshotId
_, err := self.region.ecsRequest("DeleteSnapshot", params)
return err
}
func (self *SSnapshot) GetMetadata() *jsonutils.JSONDict {
return nil
}
func (self *SRegion) GetSnapshots(instanceId string, diskId string, snapshotName string, snapshotIds []string, offset int, limit int) ([]SSnapshot, int, error) {
if limit > 50 || limit <= 0 {
limit = 50
}
params := make(map[string]string)
params["RegionId"] = self.RegionId
params["PageSize"] = fmt.Sprintf("%d", limit)
params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1)
if len(instanceId) > 0 {
params["InstanceId"] = instanceId
}
if len(diskId) > 0 {
params["diskId"] = diskId
}
if len(snapshotName) > 0 {
params["SnapshotName"] = snapshotName
}
if snapshotIds != nil && len(snapshotIds) > 0 {
params["SnapshotIds"] = jsonutils.Marshal(snapshotIds).String()
}
body, err := self.ecsRequest("DescribeSnapshots", params)
if err != nil {
log.Errorf("GetSnapshots fail %s", err)
return nil, 0, err
}
snapshots := make([]SSnapshot, 0)
if err := body.Unmarshal(&snapshots, "Snapshots", "Snapshot"); err != nil {
log.Errorf("Unmarshal snapshot details fail %s", err)
return nil, 0, err
}
total, _ := body.Int("TotalCount")
for i := 0; i < len(snapshots); i += 1 {
snapshots[i].region = self
}
return snapshots, int(total), nil
}
func (self *SRegion) GetISnapshotById(snapshotId string) (cloudprovider.ICloudSnapshot, error) {
if snapshots, total, err := self.GetSnapshots("", "", "", []string{snapshotId}, 0, 1); err != nil {
return nil, err
} else if total != 1 {
return nil, cloudprovider.ErrNotFound
} else {
return &snapshots[0], nil
}
}