Merge pull request #3493 from wanyaoqi/bugfix/wyq/fix-isolated-device-attach

region: gpu&instance_snapshot bugfix
This commit is contained in:
Zexi Li
2019-11-07 17:08:23 +08:00
committed by GitHub
8 changed files with 108 additions and 43 deletions
+1
View File
@@ -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}
+2 -3
View File
@@ -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)
}
+68 -24
View File
@@ -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
}
+21 -3
View File
@@ -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
+1 -1
View File
@@ -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
-7
View File
@@ -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