mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-10-28 03:23:25 +08:00
Merge pull request #3493 from wanyaoqi/bugfix/wyq/fix-isolated-device-attach
region: gpu&instance_snapshot bugfix
This commit is contained in:
@@ -116,6 +116,7 @@ var (
|
||||
STORAGE_LIMITED_TYPES = []string{STORAGE_LOCAL, STORAGE_BAREMETAL, STORAGE_NAS, STORAGE_RBD, STORAGE_NFS, STORAGE_GPFS}
|
||||
|
||||
SHARED_FILE_STORAGE = []string{STORAGE_NFS, STORAGE_GPFS}
|
||||
FIEL_STORAGE = []string{STORAGE_LOCAL, STORAGE_NFS, STORAGE_GPFS}
|
||||
|
||||
// 目前来说只支持这些
|
||||
SHARED_STORAGE = []string{STORAGE_NFS, STORAGE_GPFS, STORAGE_RBD}
|
||||
|
||||
@@ -607,7 +607,7 @@ func (self *SDisk) StartAllocate(ctx context.Context, host *SHost, storage *SSto
|
||||
content.Add(jsonutils.NewInt(int64(self.DiskSize)), "size")
|
||||
if len(snapshot) > 0 {
|
||||
content.Add(jsonutils.NewString(snapshot), "snapshot")
|
||||
if utils.IsInStringArray(storage.StorageType, []string{api.STORAGE_LOCAL, api.STORAGE_GPFS, api.STORAGE_NFS}) {
|
||||
if utils.IsInStringArray(storage.StorageType, api.FIEL_STORAGE) {
|
||||
SnapshotManager.AddRefCount(self.SnapshotId, 1)
|
||||
self.SetMetadata(ctx, "merge_snapshot", jsonutils.JSONTrue, userCred)
|
||||
}
|
||||
@@ -1989,8 +1989,7 @@ func (disk *SDisk) validateDiskAutoCreateSnapshot() error {
|
||||
if len(guests) == 0 {
|
||||
return fmt.Errorf("Disks %s not attach guest, can't create snapshot", disk.GetName())
|
||||
}
|
||||
if len(guests) == 1 && utils.IsInStringArray(disk.GetStorage().StorageType,
|
||||
[]string{api.STORAGE_LOCAL, api.STORAGE_GPFS, api.STORAGE_NFS}) {
|
||||
if len(guests) == 1 && utils.IsInStringArray(disk.GetStorage().StorageType, api.FIEL_STORAGE) {
|
||||
if !utils.IsInStringArray(guests[0].Status, []string{api.VM_RUNNING, api.VM_READY}) {
|
||||
return fmt.Errorf("Guest(%s) in status(%s) cannot do disk snapshot", guests[0].Id, guests[0].Status)
|
||||
}
|
||||
|
||||
@@ -1582,14 +1582,34 @@ func (self *SGuest) PerformDetachIsolatedDevice(ctx context.Context, userCred mc
|
||||
logclient.AddActionLogWithContext(ctx, self, logclient.ACT_GUEST_DETACH_ISOLATED_DEVICE, msg, userCred, false)
|
||||
return nil, httperrors.NewInvalidStatusError(msg)
|
||||
}
|
||||
device, err := data.GetString("device")
|
||||
if err != nil {
|
||||
msg := "Missing isolated device"
|
||||
logclient.AddActionLogWithContext(ctx, self, logclient.ACT_GUEST_DETACH_ISOLATED_DEVICE, msg, userCred, false)
|
||||
return nil, httperrors.NewBadRequestError(msg)
|
||||
var detachAllDevice = jsonutils.QueryBoolean(data, "detach_all", false)
|
||||
if !detachAllDevice {
|
||||
device, err := data.GetString("device")
|
||||
if err != nil {
|
||||
msg := "Missing isolated device"
|
||||
logclient.AddActionLogWithContext(ctx, self, logclient.ACT_GUEST_DETACH_ISOLATED_DEVICE, msg, userCred, false)
|
||||
return nil, httperrors.NewBadRequestError(msg)
|
||||
}
|
||||
err = self.startDetachIsolateDevice(ctx, userCred, device)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
devs := self.GetIsolatedDevices()
|
||||
host := self.GetHost()
|
||||
lockman.LockObject(ctx, host)
|
||||
defer lockman.ReleaseObject(ctx, host)
|
||||
for i := 0; i < len(devs); i++ {
|
||||
err := self.detachIsolateDevice(ctx, userCred, &devs[i])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
err = self.startDetachIsolateDevice(ctx, userCred, device)
|
||||
return nil, err
|
||||
if jsonutils.QueryBoolean(data, "auto_start", false) {
|
||||
return self.PerformStart(ctx, userCred, query, data)
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (self *SGuest) startDetachIsolateDevice(ctx context.Context, userCred mcclient.TokenCredential, device string) error {
|
||||
@@ -1637,10 +1657,10 @@ func (self *SGuest) PerformAttachIsolatedDevice(ctx context.Context, userCred mc
|
||||
logclient.AddActionLogWithContext(ctx, self, logclient.ACT_GUEST_ATTACH_ISOLATED_DEVICE, msg, userCred, false)
|
||||
return nil, httperrors.NewInvalidStatusError(msg)
|
||||
}
|
||||
var err error
|
||||
if data.Contains("device") {
|
||||
device, _ := data.GetString("device")
|
||||
err := self.startAttachIsolatedDevice(ctx, userCred, device)
|
||||
return nil, err
|
||||
err = self.startAttachIsolatedDevice(ctx, userCred, device)
|
||||
} else if data.Contains("model") {
|
||||
vmodel, _ := data.GetString("model")
|
||||
var count int64 = 1
|
||||
@@ -1650,10 +1670,18 @@ func (self *SGuest) PerformAttachIsolatedDevice(ctx context.Context, userCred mc
|
||||
if count < 1 {
|
||||
return nil, httperrors.NewBadRequestError("guest attach gpu count must > 0")
|
||||
}
|
||||
err := self.startAttachIsolatedDevices(ctx, userCred, vmodel, int(count))
|
||||
err = self.startAttachIsolatedDevices(ctx, userCred, vmodel, int(count))
|
||||
} else {
|
||||
return nil, httperrors.NewMissingParameterError("device||model")
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil, httperrors.NewMissingParameterError("device||model")
|
||||
if jsonutils.QueryBoolean(data, "auto_start", false) {
|
||||
return self.PerformStart(ctx, userCred, query, data)
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (self *SGuest) startAttachIsolatedDevices(ctx context.Context, userCred mcclient.TokenCredential, gpuModel string, count int) error {
|
||||
@@ -1767,6 +1795,9 @@ func (self *SGuest) PerformSetIsolatedDevice(ctx context.Context, userCred mccli
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if jsonutils.QueryBoolean(data, "auto_start", false) {
|
||||
return self.PerformStart(ctx, userCred, query, data)
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@@ -3922,12 +3953,20 @@ func (self *SGuest) validateCreateInstanceSnapshot(
|
||||
return nil, httperrors.NewInvalidStatusError("guest can't do snapshot in status %s", self.Status)
|
||||
}
|
||||
|
||||
var name string
|
||||
ownerId := self.GetOwnerId()
|
||||
dataDict := data.(*jsonutils.JSONDict)
|
||||
name, err := dataDict.GetString("name")
|
||||
if err != nil || len(name) == 0 {
|
||||
nameHint, err := dataDict.GetString("generate_name")
|
||||
if err == nil {
|
||||
name, err = db.GenerateName(InstanceSnapshotManager, ownerId, nameHint)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dataDict.Set("name", jsonutils.NewString(name))
|
||||
} else if name, err = dataDict.GetString("name"); err != nil {
|
||||
return nil, httperrors.NewMissingParameterError("name")
|
||||
}
|
||||
|
||||
err = db.NewNameValidator(InstanceSnapshotManager, ownerId, name, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -3935,12 +3974,14 @@ func (self *SGuest) validateCreateInstanceSnapshot(
|
||||
|
||||
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)
|
||||
if storage := disks[i].GetDisk().GetStorage(); utils.IsInStringArray(storage.StorageType, api.FIEL_STORAGE) {
|
||||
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()
|
||||
@@ -3958,12 +3999,14 @@ func (self *SGuest) validateCreateInstanceSnapshot(
|
||||
func (self *SGuest) PerformInstanceSnapshot(
|
||||
ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject,
|
||||
) (jsonutils.JSONObject, error) {
|
||||
ownerId := self.GetOwnerId()
|
||||
lockman.LockClass(ctx, InstanceSnapshotManager, ownerId.GetProjectId())
|
||||
defer lockman.ReleaseClass(ctx, InstanceSnapshotManager, ownerId.GetProjectId())
|
||||
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(
|
||||
@@ -4050,10 +4093,6 @@ func (self *SGuest) PerformSnapshotAndClone(
|
||||
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 {
|
||||
@@ -4130,6 +4169,11 @@ func (manager *SGuestManager) CreateGuestFromInstanceSnapshot(
|
||||
return nil, nil, err
|
||||
}
|
||||
guest := iGuest.(*SGuest)
|
||||
if isp.ServerMetadata != nil {
|
||||
metadata := make(map[string]interface{}, 0)
|
||||
isp.ServerMetadata.Unmarshal(metadata)
|
||||
guest.SetAllMetadata(ctx, metadata, userCred)
|
||||
}
|
||||
return guest, guestParams, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -48,8 +48,9 @@ func init() {
|
||||
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"`
|
||||
GuestId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"required" index:"true"`
|
||||
ServerConfig jsonutils.JSONObject `nullable:"true" list:"user"`
|
||||
ServerMetadata jsonutils.JSONObject `nullable:"true" list:"user"`
|
||||
}
|
||||
|
||||
type SInstanceSnapshotManager struct {
|
||||
@@ -163,7 +164,24 @@ func (manager *SInstanceSnapshotManager) CreateInstanceSnapshot(
|
||||
guestSchedInput.Networks[i].Address6 = ""
|
||||
}
|
||||
instanceSnapshot.ServerConfig = jsonutils.Marshal(guestSchedInput.ServerConfig)
|
||||
|
||||
serverMetadata := jsonutils.NewDict()
|
||||
if loginAccount := guest.GetMetadata("login_account", nil); len(loginAccount) > 0 {
|
||||
serverMetadata.Set("login_account", jsonutils.NewString(loginAccount))
|
||||
serverMetadata.Set("login_key", jsonutils.NewString(guest.GetMetadata("login_key", nil)))
|
||||
}
|
||||
if osArch := guest.GetMetadata("os_arch", nil); len(osArch) > 0 {
|
||||
serverMetadata.Set("os_arch", jsonutils.NewString(osArch))
|
||||
}
|
||||
if osDist := guest.GetMetadata("os_distribution", nil); len(osDist) > 0 {
|
||||
serverMetadata.Set("os_distribution", jsonutils.NewString(osDist))
|
||||
}
|
||||
if osName := guest.GetMetadata("os_name", nil); len(osName) > 0 {
|
||||
serverMetadata.Set("os_name", jsonutils.NewString(osName))
|
||||
}
|
||||
if osVersion := guest.GetMetadata("os_version", nil); len(osVersion) > 0 {
|
||||
serverMetadata.Set("os_version", jsonutils.NewString(osVersion))
|
||||
}
|
||||
instanceSnapshot.ServerMetadata = serverMetadata
|
||||
err := manager.TableSpec().Insert(instanceSnapshot)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -612,7 +612,7 @@ func (manager *SIsolatedDeviceManager) DeleteDevicesByHost(ctx context.Context,
|
||||
|
||||
func (manager *SIsolatedDeviceManager) GetDevsOnHost(hostId string, model string, count int) ([]SIsolatedDevice, error) {
|
||||
devs := make([]SIsolatedDevice, 0)
|
||||
q := manager.Query().Equals("host_id", hostId).Equals("model", model).IsEmpty("guest_id").Limit(count)
|
||||
q := manager.Query().Equals("host_id", hostId).Equals("model", model).IsNullOrEmpty("guest_id").Limit(count)
|
||||
err := db.FetchModelObjects(manager, q, &devs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -177,13 +177,6 @@ func (self *SSnapshot) getMoreDetails(extra *jsonutils.JSONDict) *jsonutils.JSON
|
||||
if IStorage, _ := StorageManager.FetchById(self.StorageId); IStorage != nil {
|
||||
storage := IStorage.(*SStorage)
|
||||
extra.Add(jsonutils.NewString(storage.StorageType), "storage_type")
|
||||
// if provider := storage.GetCloudprovider(); provider != nil {
|
||||
// extra.Add(jsonutils.NewString(provider.Name), "provider")
|
||||
// }
|
||||
} else {
|
||||
// if cloudprovider := self.GetCloudprovider(); cloudprovider != nil {
|
||||
// extra.Add(jsonutils.NewString(cloudprovider.Provider), "provider")
|
||||
// }
|
||||
}
|
||||
disk, _ := self.GetDisk()
|
||||
if disk != nil {
|
||||
|
||||
@@ -118,7 +118,7 @@ func (self *InstanceSnapshotAndCloneTask) doGuestCreate(
|
||||
var errStr string
|
||||
for i := 0; i < count; i++ {
|
||||
newGuest, input, err := models.GuestManager.CreateGuestFromInstanceSnapshot(
|
||||
ctx, self.UserCred, dictParmas.DeepCopy().(*jsonutils.JSONDict), isp, i+1)
|
||||
ctx, self.UserCred, dictParmas.DeepCopy().(*jsonutils.JSONDict), isp, i)
|
||||
if err != nil {
|
||||
log.Errorln(err)
|
||||
errStr += err.Error() + "\n"
|
||||
|
||||
@@ -18,17 +18,17 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/pkg/util/timeutils"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/apis/compute"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/notifyclient"
|
||||
"yunion.io/x/onecloud/pkg/compute/models"
|
||||
"yunion.io/x/onecloud/pkg/util/logclient"
|
||||
"yunion.io/x/onecloud/pkg/util/rand"
|
||||
"yunion.io/x/onecloud/pkg/util/rbacutils"
|
||||
)
|
||||
|
||||
@@ -107,9 +107,19 @@ func (self *InstanceSnapshotCreateTask) GuestDiskCreateSnapshot(
|
||||
return
|
||||
}
|
||||
|
||||
lockman.LockClass(ctx, models.SnapshotManager, self.UserCred.GetProjectId())
|
||||
defer lockman.ReleaseClass(ctx, models.SnapshotManager, self.UserCred.GetProjectId())
|
||||
|
||||
snapshotName, err := db.GenerateName(models.SnapshotManager, self.UserCred,
|
||||
fmt.Sprintf("%s-%s", isp.Name, rand.String(8)))
|
||||
if err != nil {
|
||||
self.taskFail(ctx, isp, guest, fmt.Sprintf("Generate snapshot name %s", err))
|
||||
return
|
||||
}
|
||||
|
||||
snapshot, err := models.SnapshotManager.CreateSnapshot(
|
||||
ctx, self.UserCred, compute.SNAPSHOT_MANUAL, disks[diskIndex].DiskId, guest.Id,
|
||||
"", fmt.Sprintf("%s-snapshot-%s", guest.Name, timeutils.CompactTime(time.Now())), -1)
|
||||
ctx, self.UserCred, compute.SNAPSHOT_MANUAL, disks[diskIndex].DiskId,
|
||||
guest.Id, "", snapshotName, -1)
|
||||
if err != nil {
|
||||
self.taskFail(ctx, isp, guest, err.Error())
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user