mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-06-25 11:27:17 +08:00
- instance snapshot
- instance clone - create form snapshot don't reset passwd
This commit is contained in:
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
|
||||
51
pkg/compute/models/instance_snapshot_joint.go
Normal file
51
pkg/compute/models/instance_snapshot_joint.go
Normal 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)
|
||||
}
|
||||
211
pkg/compute/models/instance_snapshots.go
Normal file
211
pkg/compute/models/instance_snapshots.go
Normal 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)
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user