- instance snapshot

- instance clone

- create form snapshot don't reset passwd
This commit is contained in:
wanyaoqi
2019-08-29 17:49:24 +08:00
parent 905fb307a8
commit 8fc4b2920a
26 changed files with 1203 additions and 26 deletions

View File

@@ -714,22 +714,21 @@ func (self *SDisk) PerformDiskReset(ctx context.Context, userCred mcclient.Token
autoStart := jsonutils.QueryBoolean(data, "auto_start", false)
snapshotId, _ := data.GetString("snapshot_id")
guests := self.GetGuests()
self.StartResetDisk(ctx, userCred, snapshotId, autoStart, guests)
return nil, nil
return nil, self.StartResetDisk(ctx, userCred, snapshotId, autoStart, &guests[0], "")
}
func (self *SDisk) StartResetDisk(
ctx context.Context, userCred mcclient.TokenCredential,
snapshotId string, autoStart bool, guests []SGuest,
snapshotId string, autoStart bool, guest *SGuest, parentTaskId string,
) error {
self.SetStatus(userCred, api.DISK_RESET, "")
if len(guests) == 1 {
guests[0].SetStatus(userCred, api.VM_DISK_RESET, "disk reset")
if guest != nil {
guest.SetStatus(userCred, api.VM_DISK_RESET, "disk reset")
}
params := jsonutils.NewDict()
params.Set("snapshot_id", jsonutils.NewString(snapshotId))
params.Set("auto_start", jsonutils.NewBool(autoStart))
task, err := taskman.TaskManager.NewTask(ctx, "DiskResetTask", self, userCred, params, "", "", nil)
task, err := taskman.TaskManager.NewTask(ctx, "DiskResetTask", self, userCred, params, parentTaskId, "", nil)
if err != nil {
return err
} else {
@@ -2012,7 +2011,7 @@ func (self *SDisk) CreateSnapshotAuto(
}
db.OpsLog.LogEvent(snap, db.ACT_CREATE, "disk create snapshot auto", userCred)
err = snap.StartSnapshotCreateTask(ctx, userCred, nil)
err = snap.StartSnapshotCreateTask(ctx, userCred, nil, "")
if err != nil {
return errors.Wrap(err, "disk auto snapshot start snapshot task")
}

View File

@@ -3779,3 +3779,237 @@ func (manager *SGuestManager) StartHostGuestsMigrateTask(
task.ScheduleRun(nil)
return nil
}
func (self *SGuest) AllowPerformInstanceSnapshot(ctx context.Context,
userCred mcclient.TokenCredential,
query jsonutils.JSONObject,
data jsonutils.JSONObject) bool {
return self.IsOwner(userCred) || db.IsAdminAllowPerform(userCred, self, "instance-snapshot")
}
func (self *SGuest) validateCreateInstanceSnapshot(
ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject,
) (*SQuota, error) {
if self.Hypervisor != api.HYPERVISOR_KVM {
return nil, httperrors.NewBadRequestError("guest hypervisor %s can't create instance snapshot", self.Hypervisor)
}
if len(self.BackupHostId) > 0 {
return nil, httperrors.NewBadRequestError("Can't do instance snapshot with backup guest")
}
if !utils.IsInStringArray(self.Status, []string{api.VM_RUNNING, api.VM_READY}) {
return nil, httperrors.NewInvalidStatusError("guest can't do snapshot in status %s", self.Status)
}
ownerId := self.GetOwnerId()
dataDict := data.(*jsonutils.JSONDict)
name, err := dataDict.GetString("name")
if err != nil || len(name) == 0 {
return nil, httperrors.NewMissingParameterError("name")
}
err = db.NewNameValidator(InstanceSnapshotManager, ownerId, name, "")
if err != nil {
return nil, err
}
disks := self.GetDisks()
for i := 0; i < len(disks); i++ {
count, err := SnapshotManager.GetDiskManualSnapshotCount(disks[i].DiskId)
if err != nil {
return nil, httperrors.NewInternalServerError(err.Error())
}
if count >= options.Options.DefaultMaxManualSnapshotCount {
return nil, httperrors.NewBadRequestError("guests disk %d snapshot full, can't take anymore", i)
}
}
quotaPlatform := self.GetQuotaPlatformID()
pendingUsage := &SQuota{Snapshot: len(disks)}
err = QuotaManager.CheckSetPendingQuota(ctx, userCred, rbacutils.ScopeProject, ownerId, quotaPlatform, pendingUsage)
if err != nil {
return nil, httperrors.NewOutOfQuotaError("Check set pending quota error %s", err)
}
return pendingUsage, nil
}
// 1. validate guest status, guest hypervisor
// 2. validate every disk manual snapshot count
// 3. validate snapshot quota with disk count
func (self *SGuest) PerformInstanceSnapshot(
ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject,
) (jsonutils.JSONObject, error) {
pendingUsage, err := self.validateCreateInstanceSnapshot(ctx, userCred, query, data)
if err != nil {
return nil, err
}
name, _ := data.GetString("name")
ownerId := self.GetOwnerId()
instanceSnapshot, err := InstanceSnapshotManager.CreateInstanceSnapshot(ctx, ownerId, self, name)
if err != nil {
QuotaManager.CancelPendingUsage(
ctx, userCred, rbacutils.ScopeProject, ownerId, self.GetQuotaPlatformID(), pendingUsage, pendingUsage)
return nil, httperrors.NewInternalServerError("create instance snapshot failed: %s", err)
}
err = self.InstaceCreateSnapshot(ctx, userCred, ownerId, instanceSnapshot, pendingUsage)
if err != nil {
QuotaManager.CancelPendingUsage(
ctx, userCred, rbacutils.ScopeProject, ownerId, self.GetQuotaPlatformID(), pendingUsage, pendingUsage)
return nil, httperrors.NewInternalServerError("start create snapshot task failed: %s", err)
}
return nil, nil
}
func (self *SGuest) InstaceCreateSnapshot(
ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider,
instanceSnapshot *SInstanceSnapshot, pendingUsage *SQuota) error {
self.SetStatus(userCred, api.VM_START_INSTANCE_SNAPSHOT, "instance snapshot")
return instanceSnapshot.StartCreateInstanceSnapshotTask(ctx, userCred, ownerId, pendingUsage, "")
}
func (self *SGuest) AllowPerformInstanceSnapshotReset(ctx context.Context,
userCred mcclient.TokenCredential,
query jsonutils.JSONObject,
data jsonutils.JSONObject) bool {
return self.IsOwner(userCred) || db.IsAdminAllowPerform(userCred, self, "instance-snapshot")
}
func (self *SGuest) PerformInstanceSnapshotReset(
ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject,
) (jsonutils.JSONObject, error) {
if self.Status != api.VM_READY {
return nil, httperrors.NewInvalidStatusError("guest can't do snapshot in status ", self.Status)
}
dataDict := data.(*jsonutils.JSONDict)
instanceSnapshotV := validators.NewModelIdOrNameValidator(
"instance_snapshot", "instance_snapshot", self.GetOwnerId(),
)
err := instanceSnapshotV.Validate(dataDict)
if err != nil {
return nil, err
}
instanceSnapshot := instanceSnapshotV.Model.(*SInstanceSnapshot)
if instanceSnapshot.Status != api.INSTANCE_SNAPSHOT_READY {
return nil, httperrors.NewBadRequestError("Instance sanpshot not ready")
}
err = self.StartSnapshotResetTask(ctx, userCred, instanceSnapshot)
if err != nil {
return nil, httperrors.NewInternalServerError("start snapshot reset failed %s", err)
}
return nil, nil
}
func (self *SGuest) StartSnapshotResetTask(
ctx context.Context, userCred mcclient.TokenCredential, instanceSnapshot *SInstanceSnapshot) error {
self.SetStatus(userCred, api.VM_START_SNAPSHOT_RESET, "start snapshot reset task")
if task, err := taskman.TaskManager.NewTask(
ctx, "InstanceSnapshotResetTask", instanceSnapshot, userCred, nil, "", "", nil,
); err != nil {
return err
} else {
task.ScheduleRun(nil)
}
return nil
}
func (self *SGuest) AllowPerformSnapshotAndClone(
ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject,
) bool {
return self.IsOwner(userCred) || db.IsAdminAllowPerform(userCred, self, "snapshot-and-clone")
}
func (self *SGuest) PerformSnapshotAndClone(
ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject,
) (jsonutils.JSONObject, error) {
newlyGuestName, err := data.GetString("name")
if err != nil {
return nil, httperrors.NewMissingParameterError("name")
}
err = db.NewNameValidator(GuestManager, self.GetOwnerId(), newlyGuestName, "")
if err != nil {
return nil, err
}
pendingUsage, err := self.validateCreateInstanceSnapshot(ctx, userCred, query, data)
if err != nil {
return nil, err
}
lockman.LockClass(ctx, InstanceSnapshotManager, self.ProjectId)
defer lockman.ReleaseClass(ctx, InstanceSnapshotManager, self.ProjectId)
instanceSnapshotName, err := db.GenerateName(InstanceSnapshotManager, self.GetOwnerId(), "Snapshot-For-"+newlyGuestName)
if err != nil {
QuotaManager.CancelPendingUsage(
ctx, userCred, rbacutils.ScopeProject, self.GetOwnerId(),
self.GetQuotaPlatformID(), pendingUsage, pendingUsage)
return nil, httperrors.NewInternalServerError("Generate snapshot name failed %s", err)
}
instanceSnapshot, err := InstanceSnapshotManager.CreateInstanceSnapshot(ctx, self.GetOwnerId(), self, instanceSnapshotName)
if err != nil {
QuotaManager.CancelPendingUsage(
ctx, userCred, rbacutils.ScopeProject, self.GetOwnerId(),
self.GetQuotaPlatformID(), pendingUsage, pendingUsage)
return nil, httperrors.NewInternalServerError("create instance snapshot failed: %s", err)
}
err = self.StartInstanceSnapshotAndCloneTask(
ctx, userCred, newlyGuestName, pendingUsage, instanceSnapshot, data.(*jsonutils.JSONDict))
if err != nil {
QuotaManager.CancelPendingUsage(
ctx, userCred, rbacutils.ScopeProject, self.GetOwnerId(),
self.GetQuotaPlatformID(), pendingUsage, pendingUsage)
return nil, err
}
return nil, nil
}
func (self *SGuest) StartInstanceSnapshotAndCloneTask(
ctx context.Context, userCred mcclient.TokenCredential, newlyGuestName string,
pendingUsage *SQuota, instanceSnapshot *SInstanceSnapshot, data *jsonutils.JSONDict) error {
params := jsonutils.NewDict()
params.Set("guest_params", data)
if task, err := taskman.TaskManager.NewTask(
ctx, "InstanceSnapshotAndCloneTask", instanceSnapshot, userCred, params, "", "", pendingUsage); err != nil {
return err
} else {
self.SetStatus(userCred, api.VM_START_INSTANCE_SNAPSHOT, "instance snapshot")
task.ScheduleRun(nil)
return nil
}
}
func (manager *SGuestManager) CreateGuestFromInstanceSnapshot(
ctx context.Context, userCred mcclient.TokenCredential, guestParams *jsonutils.JSONDict,
isp *SInstanceSnapshot, index int,
) (*SGuest, *jsonutils.JSONDict, error) {
lockman.LockClass(ctx, manager, isp.ProjectId)
defer lockman.ReleaseClass(ctx, manager, isp.ProjectId)
guestName, err := guestParams.GetString("name")
if err != nil {
return nil, nil, fmt.Errorf("No new guest name provider")
}
if err := db.NewNameValidator(manager, isp.GetOwnerId(), guestName, ""); err != nil {
guestName, err = db.GenerateName2(manager, isp.GetOwnerId(), guestName, nil, index)
if err != nil {
return nil, nil, err
}
}
guestParams.Set("name", jsonutils.NewString(guestName))
guestParams.Set("instance_snapshot_id", jsonutils.NewString(isp.Id))
iGuest, err := db.DoCreate(manager, ctx, userCred, nil, guestParams, isp.GetOwnerId())
if err != nil {
return nil, nil, err
}
guest := iGuest.(*SGuest)
return guest, guestParams, nil
}

View File

@@ -868,15 +868,37 @@ func (manager *SGuestManager) BatchPreValidate(
return nil, nil
}
func parseInstanceSnapshot(input *api.ServerCreateInput) (*api.ServerCreateInput, error) {
ispi, err := InstanceSnapshotManager.FetchByIdOrName(nil, input.InstanceSnapshotId)
if err == sql.ErrNoRows {
return nil, httperrors.NewBadRequestError("can't find instance snapshot %s", input.InstanceSnapshotId)
}
if err != nil {
return nil, httperrors.NewInternalServerError("fetch instance snapshot error %s", err)
}
isp := ispi.(*SInstanceSnapshot)
if isp.Status != api.INSTANCE_SNAPSHOT_READY {
return nil, httperrors.NewBadRequestError("Instance snapshot not ready")
}
return isp.ToInstanceCreateInput(input)
}
func (manager *SGuestManager) validateCreateData(
ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider,
query jsonutils.JSONObject, data *jsonutils.JSONDict) (*api.ServerCreateInput, error) {
// TODO: 定义 api.ServerCreateInput 的 Unmarshal 函数,直接通过 data.Unmarshal(input) 解析参数
input, err := cmdline.FetchServerCreateInputByJSON(data)
if err != nil {
return nil, err
}
if len(input.InstanceSnapshotId) > 0 {
input, err = parseInstanceSnapshot(input)
if err != nil {
return nil, err
}
}
resetPassword := true
if input.ResetPassword != nil {
resetPassword = *input.ResetPassword
@@ -1144,8 +1166,6 @@ func (manager *SGuestManager) validateCreateData(
return nil, httperrors.NewResourceNotFoundError("Keypair %s not found", keypairId)
}
input.KeypairId = keypairObj.GetId()
} else {
input.KeypairId = "None" // TODO: ??? None?
}
if input.SecgroupId != "" {
@@ -3225,6 +3245,15 @@ func (self *SGuest) DeleteAllDisksInDB(ctx context.Context, userCred mcclient.To
return nil
}
func (self *SGuest) isNeedDoResetPasswd() bool {
guestdisks := self.GetDisks()
disk := guestdisks[0].GetDisk()
if len(disk.SnapshotId) > 0 {
return false
}
return true
}
func (self *SGuest) GetDeployConfigOnHost(ctx context.Context, userCred mcclient.TokenCredential, host *SHost, params *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
config := jsonutils.NewDict()
@@ -3245,12 +3274,13 @@ func (self *SGuest) GetDeployConfigOnHost(ctx context.Context, userCred mcclient
deployAction = "deploy"
}
// resetPasswd := true
// if deployAction == "deploy" {
resetPasswd := jsonutils.QueryBoolean(params, "reset_password", true)
//}
config.Add(jsonutils.NewBool(jsonutils.QueryBoolean(params, "enable_cloud_init", false)), "enable_cloud_init")
resetPasswd := jsonutils.QueryBoolean(params, "reset_password", true)
if deployAction == "create" && resetPasswd {
resetPasswd = self.isNeedDoResetPasswd()
}
if resetPasswd {
config.Add(jsonutils.JSONTrue, "reset_password")
passwd, _ := params.GetString("password")

View File

@@ -0,0 +1,51 @@
package models
import "yunion.io/x/onecloud/pkg/cloudcommon/db"
func init() {
db.InitManager(func() {
InstanceSnapshotJointManager = &SInstanceSnapshotJointManager{
SVirtualJointResourceBaseManager: db.NewVirtualJointResourceBaseManager(
SInstanceSnapshotJoint{},
"instancesnapshotjoints_tbl",
"instancesnapshotjoint",
"instancesnapshotjoints",
InstanceSnapshotManager,
SnapshotManager,
),
}
InstanceSnapshotJointManager.SetVirtualObject(InstanceSnapshotJointManager)
})
}
type SInstanceSnapshotJoint struct {
db.SVirtualJointResourceBase
InstanceSnapshotId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"required" index:"true"`
SnapshotId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"required" index:"true"`
DiskIndex int8 `nullable:"false" default:"0" list:"user" create:"required"`
}
type SInstanceSnapshotJointManager struct {
db.SVirtualJointResourceBaseManager
}
func (manager *SInstanceSnapshotJointManager) GetMasterFieldName() string {
return "instance_snapshot_id"
}
func (manager *SInstanceSnapshotJointManager) GetSlaveFieldName() string {
return "disk_id"
}
var InstanceSnapshotJointManager *SInstanceSnapshotJointManager
func (manager *SInstanceSnapshotJointManager) CreateJoint(instanceSnapshotId, snapshotId string, diskIndex int8) error {
instanceSnapshotJoint := &SInstanceSnapshotJoint{}
instanceSnapshotJoint.SetModelManager(manager, instanceSnapshotJoint)
instanceSnapshotJoint.InstanceSnapshotId = instanceSnapshotId
instanceSnapshotJoint.SnapshotId = snapshotId
instanceSnapshotJoint.DiskIndex = diskIndex
return manager.TableSpec().Insert(instanceSnapshotJoint)
}

View File

@@ -0,0 +1,211 @@
package models
import (
"context"
"database/sql"
"fmt"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/sqlchemy"
"yunion.io/x/onecloud/pkg/apis/compute"
schedapi "yunion.io/x/onecloud/pkg/apis/scheduler"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/quotas"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
)
func init() {
InstanceSnapshotManager = &SInstanceSnapshotManager{
SVirtualResourceBaseManager: db.NewVirtualResourceBaseManager(
SInstanceSnapshot{},
"instance_snapshots_tbl",
"instance_snapshot",
"instance_snapshots",
),
}
InstanceSnapshotManager.SetVirtualObject(InstanceSnapshotManager)
}
type SInstanceSnapshot struct {
db.SVirtualResourceBase
GuestId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"required" index:"true"`
ServerConfig jsonutils.JSONObject `nullable:"true" list:"user"`
}
type SInstanceSnapshotManager struct {
db.SVirtualResourceBaseManager
}
var InstanceSnapshotManager *SInstanceSnapshotManager
func (manager *SInstanceSnapshotManager) AllowCreateItem(
ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject,
) bool {
return false
}
func (manager *SInstanceSnapshotManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (*sqlchemy.SQuery, error) {
queryDict, ok := query.(*jsonutils.JSONDict)
if !ok {
return nil, fmt.Errorf("invalid querystring format")
}
if guestId, _ := queryDict.GetString("guest_id"); len(guestId) > 0 {
q = q.Equals("guest_id", guestId)
}
return q, nil
}
func (self *SInstanceSnapshot) AllowUpdateItem(ctx context.Context, userCred mcclient.TokenCredential) bool {
return false
}
func (self *SInstanceSnapshot) GetCustomizeColumns(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) *jsonutils.JSONDict {
extra := self.SVirtualResourceBase.GetCustomizeColumns(ctx, userCred, query)
if guest := GuestManager.FetchGuestById(self.GuestId); guest != nil {
extra.Set("guest_status", jsonutils.NewString(guest.Status))
extra.Set("guest_name", jsonutils.NewString(guest.Name))
}
return extra
}
// func (self *SInstanceSnapshot) getMoreDetails()
func (self *SInstanceSnapshot) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (*jsonutils.JSONDict, error) {
extra, err := self.SVirtualResourceBase.GetExtraDetails(ctx, userCred, query)
if err != nil {
return nil, err
}
if guest := GuestManager.FetchGuestById(self.GuestId); guest != nil {
extra.Set("guest_status", jsonutils.NewString(guest.Status))
extra.Set("guest_name", jsonutils.NewString(guest.Name))
}
return extra, nil
}
func (self *SInstanceSnapshot) StartCreateInstanceSnapshotTask(
ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider,
pendingUsage quotas.IQuota, parentTaskId string) error {
if task, err := taskman.TaskManager.NewTask(
ctx, "InstanceSnapshotCreateTask", self, userCred, nil, parentTaskId, "", pendingUsage); err != nil {
return err
} else {
task.ScheduleRun(nil)
}
return nil
}
func (manager *SInstanceSnapshotManager) CreateInstanceSnapshot(
ctx context.Context, ownerId mcclient.IIdentityProvider, guest *SGuest, name string,
) (*SInstanceSnapshot, error) {
instanceSnapshot := &SInstanceSnapshot{}
instanceSnapshot.SetModelManager(manager, instanceSnapshot)
instanceSnapshot.Name = name
instanceSnapshot.ProjectId = ownerId.GetProjectId()
instanceSnapshot.DomainId = ownerId.GetProjectDomainId()
instanceSnapshot.GuestId = guest.Id
guestSchedInput := guest.ToSchedDesc()
for i := 0; i < len(guestSchedInput.Disks); i++ {
guestSchedInput.Disks[i].ImageId = ""
}
guestSchedInput.Name = ""
guestSchedInput.HostId = ""
guestSchedInput.Project = ""
guestSchedInput.Domain = ""
for i := 0; i < len(guestSchedInput.Networks); i++ {
guestSchedInput.Networks[i].Mac = ""
guestSchedInput.Networks[i].Address = ""
guestSchedInput.Networks[i].Address6 = ""
}
instanceSnapshot.ServerConfig = jsonutils.Marshal(guestSchedInput.ServerConfig)
err := manager.TableSpec().Insert(instanceSnapshot)
if err != nil {
return nil, err
}
return instanceSnapshot, nil
}
func (self *SInstanceSnapshot) ToInstanceCreateInput(
sourceInput *compute.ServerCreateInput) (*compute.ServerCreateInput, error) {
serverConfig := new(schedapi.ServerConfig)
if err := self.ServerConfig.Unmarshal(serverConfig); err != nil {
return nil, errors.Wrap(err, "unmarshal sched input")
}
isjs := make([]SInstanceSnapshotJoint, 0)
err := InstanceSnapshotJointManager.Query().Equals("instance_snapshot_id", self.Id).Asc("disk_index").All(&isjs)
if err != nil {
return nil, errors.Wrap(err, "fetch instance snapshots")
}
for i := 0; i < len(serverConfig.Disks); i++ {
serverConfig.Disks[i].SnapshotId = isjs[serverConfig.Disks[i].Index].SnapshotId
}
sourceInput.Disks = serverConfig.Disks
sourceInput.VmemSize = serverConfig.Memory
sourceInput.VcpuCount = serverConfig.Ncpu
sourceInput.Networks = serverConfig.Networks
return sourceInput, nil
}
func (self *SInstanceSnapshot) GetSnapshots() ([]SSnapshot, error) {
isjq := InstanceSnapshotJointManager.Query("snapshot_id").Equals("instance_snapshot_id", self.Id)
snapshots := make([]SSnapshot, 0)
err := SnapshotManager.Query().In("id", isjq).All(&snapshots)
if err != nil && err != sql.ErrNoRows {
return nil, err
} else if err != nil && err == sql.ErrNoRows {
return nil, nil
} else {
for i := 0; i < len(snapshots); i++ {
snapshots[i].SetModelManager(SnapshotManager, &snapshots[i])
}
return snapshots, nil
}
}
func (self *SInstanceSnapshot) GetInstanceSnapshotJointAt(diskIndex int) (*SInstanceSnapshotJoint, error) {
ispj := new(SInstanceSnapshotJoint)
err := InstanceSnapshotJointManager.Query().
Equals("instance_snapshot_id", self.Id).Equals("disk_index", diskIndex).First(ispj)
return ispj, err
}
func (self *SInstanceSnapshot) ValidateDeleteCondition(ctx context.Context) error {
if self.Status == compute.INSTANCE_SNAPSHOT_START_DELETE {
return httperrors.NewBadRequestError("can't delete snapshot in deleting")
}
return nil
}
func (self *SInstanceSnapshot) CustomizeDelete(
ctx context.Context, userCred mcclient.TokenCredential,
query jsonutils.JSONObject, data jsonutils.JSONObject) error {
return self.StartInstanceSnapshotDeleteTask(ctx, userCred, "")
}
func (self *SInstanceSnapshot) StartInstanceSnapshotDeleteTask(
ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error {
task, err := taskman.TaskManager.NewTask(
ctx, "InstanceSnapshotDeleteTask", self, userCred, nil, parentTaskId, "", nil)
if err != nil {
log.Errorf("%s", err)
return err
}
self.SetStatus(userCred, compute.INSTANCE_SNAPSHOT_START_DELETE, "InstanceSnapshotDeleteTask")
task.ScheduleRun(nil)
return nil
}
func (self *SInstanceSnapshot) RealDelete(ctx context.Context, userCred mcclient.TokenCredential) error {
return db.DeleteModel(ctx, userCred, self)
}

View File

@@ -50,7 +50,7 @@ type SSnapshot struct {
SManagedResourceBase
DiskId string `width:"36" charset:"ascii" nullable:"true" create:"required" list:"user"`
DiskId string `width:"36" charset:"ascii" nullable:"true" create:"required" list:"user" index:"true"`
// Only onecloud has StorageId
StorageId string `width:"36" charset:"ascii" nullable:"true" list:"admin" create:"optional"`
@@ -288,11 +288,11 @@ func (self *SSnapshot) CustomizeCreate(ctx context.Context, userCred mcclient.To
func (manager *SSnapshotManager) OnCreateComplete(ctx context.Context, items []db.IModel, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) {
snapshot := items[0].(*SSnapshot)
snapshot.StartSnapshotCreateTask(ctx, userCred, nil)
snapshot.StartSnapshotCreateTask(ctx, userCred, nil, "")
}
func (self *SSnapshot) StartSnapshotCreateTask(ctx context.Context, userCred mcclient.TokenCredential, params *jsonutils.JSONDict) error {
task, err := taskman.TaskManager.NewTask(ctx, "SnapshotCreateTask", self, userCred, params, "", "", nil)
func (self *SSnapshot) StartSnapshotCreateTask(ctx context.Context, userCred mcclient.TokenCredential, params *jsonutils.JSONDict, parentTaskId string) error {
task, err := taskman.TaskManager.NewTask(ctx, "SnapshotCreateTask", self, userCred, params, parentTaskId, "", nil)
if err != nil {
return err
}
@@ -383,6 +383,10 @@ func (self *SSnapshotManager) GetDiskSnapshots(diskId string) []SSnapshot {
return dest
}
func (self *SSnapshotManager) GetDiskManualSnapshotCount(diskId string) (int, error) {
return self.Query().Equals("disk_id", diskId).Equals("fake_deleted", false).CountWithError()
}
func (self *SSnapshotManager) IsDiskSnapshotsNeedConvert(diskId string) (bool, error) {
count, err := self.Query().Equals("disk_id", diskId).
In("status", []string{api.SNAPSHOT_READY, api.SNAPSHOT_DELETING}).
@@ -471,6 +475,13 @@ func (self *SSnapshot) ValidateDeleteCondition(ctx context.Context) error {
if self.Status == api.SNAPSHOT_DELETING {
return httperrors.NewBadRequestError("Cannot delete snapshot in status %s", self.Status)
}
count, err := InstanceSnapshotJointManager.Query().Equals("snapshot_id", self.Id).CountWithError()
if err != nil {
return httperrors.NewInternalServerError("Fetch instance snapshot error %s", err)
}
if count > 0 {
return httperrors.NewBadRequestError("snapshot referenced by instance snapshot")
}
return self.GetRegionDriver().ValidateSnapshotDelete(ctx, self)
}