feat(region,host): create disk from existing path (#14677)

Server create disk from existing path.

Usage:

climc server-create --disk storage=<storage>:existing_path=<path> ...
climc disk-create storage=<storage>:existing_path=<path> DISKNAME

Signed-off-by: wanyaoqi <d3lx.yq@gmail.com>
This commit is contained in:
wanyaoqi
2022-07-19 20:02:10 +08:00
committed by GitHub
parent c98e584641
commit c8c5a28675
9 changed files with 73 additions and 1 deletions
+3
View File
@@ -212,6 +212,9 @@ type DiskConfig struct {
//swagger:ignore
DiskId string `json:"disk_id"`
//swagger:ignore
ExistingPath string `json:"existing_path"`
}
type IsolatedDeviceConfig struct {
+1
View File
@@ -296,6 +296,7 @@ type DiskAllocateInput struct {
Protocol string
SrcDiskId string
SrcPool string
ExistingPath string
// vmware
HostIp string
+2
View File
@@ -63,3 +63,5 @@ const (
DISK_NOT_EXIST = "not_exist"
DISK_EXIST = "exist"
)
const DISK_META_EXISTING_PATH = "disk_existing_path"
+2
View File
@@ -185,6 +185,8 @@ func ParseDiskConfig(diskStr string, idx int) (*compute.DiskConfig, error) {
diskConfig.Storage = str
case "image", "image_id":
diskConfig.ImageId = str
case "existing_path":
diskConfig.ExistingPath = str
default:
return nil, errors.Errorf("invalid disk description %s", p)
}
+28
View File
@@ -461,12 +461,17 @@ func (manager *SDiskManager) ValidateCreateData(ctx context.Context, userCred mc
if err != nil {
return input, err
}
if input.ExistingPath != "" && input.Storage == "" {
return input, httperrors.NewInputParameterError("disk create from existing disk must give storage")
}
input.ProjectId = ownerId.GetProjectId()
input.ProjectDomainId = ownerId.GetProjectDomainId()
var quotaKey quotas.IQuotaKeys
storageID := input.Storage
if storageID != "" {
storageObj, err := StorageManager.FetchByIdOrName(nil, storageID)
if err != nil {
@@ -558,6 +563,13 @@ func (manager *SDiskManager) validateDiskOnStorage(diskConfig *api.DiskConfig, s
if storage.StorageType != diskConfig.Backend {
return httperrors.NewInputParameterError("Storage type[%s] not match backend %s", storage.StorageType, diskConfig.Backend)
}
if diskConfig.ExistingPath != "" {
if !utils.IsInStringArray(storage.StorageType, api.FIEL_STORAGE) {
return httperrors.NewInputParameterError(
"Disk create from existing path, unsupport storage type %s", storage.StorageType)
}
}
if host, _ := storage.GetMasterHost(); host != nil {
//公有云磁盘大小检查。
if err := host.GetHostDriver().ValidateDiskSize(storage, diskConfig.SizeMb>>10); err != nil {
@@ -663,12 +675,24 @@ func getDiskResourceRequirements(ctx context.Context, userCred mcclient.TokenCre
return newData
}*/
func (disk *SDisk) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) {
input := api.DiskCreateInput{}
err := data.Unmarshal(&input)
if err != nil {
log.Errorf("!!!data.Unmarshal api.DiskCreateInput fail %s", err)
}
if input.ExistingPath != "" {
disk.SetMetadata(ctx, api.DISK_META_EXISTING_PATH, input.ExistingPath, userCred)
}
}
func (manager *SDiskManager) OnCreateComplete(ctx context.Context, items []db.IModel, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) {
input := api.DiskCreateInput{}
err := data.Unmarshal(&input)
if err != nil {
log.Errorf("!!!data.Unmarshal api.DiskCreateInput fail %s", err)
}
pendingUsage := getDiskResourceRequirements(ctx, userCred, ownerId, input, len(items))
parentTaskId, _ := data.GetString("parent_task_id")
RunBatchCreateTask(ctx, items, userCred, data, pendingUsage, SRegionQuota{}, "DiskBatchCreateTask", parentTaskId)
@@ -761,6 +785,10 @@ func (self *SDisk) StartAllocate(ctx context.Context, host *SHost, storage *SSto
return errors.Wrap(err, "GetEncryptInfo")
}
}
if ePath := self.GetMetadata(ctx, api.DISK_META_EXISTING_PATH, userCred); ePath != "" {
input.ExistingPath = ePath
}
if rebuild {
return host.GetHostDriver().RequestRebuildDiskOnStorage(ctx, host, storage, self, task, input)
} else {
+4
View File
@@ -3902,6 +3902,10 @@ func (self *SGuest) createDiskOnHost(
if err != nil {
return nil, err
}
if diskConfig.ExistingPath != "" {
disk.SetMetadata(ctx, api.DISK_META_EXISTING_PATH, diskConfig.ExistingPath, userCred)
}
if len(self.BackupHostId) > 0 {
backupHost := HostManager.FetchHostById(self.BackupHostId)
backupStorage, err := self.ChooseHostStorage(backupHost, diskConfig, backupCandidate)
+19 -1
View File
@@ -123,7 +123,7 @@ type IStorage interface {
CreateDiskByDiskinfo(context.Context, interface{}) (jsonutils.JSONObject, error)
SaveToGlance(context.Context, interface{}) (jsonutils.JSONObject, error)
CreateDiskFromSnapshot(context.Context, IDisk, *SDiskCreateByDiskinfo) error
CreateDiskFromExistingPath(context.Context, IDisk, *SDiskCreateByDiskinfo) error
CreateDiskFromBackup(context.Context, IDisk, *SDiskCreateByDiskinfo) error
// GetCloneTargetDiskPath generate target disk path by target disk id
@@ -354,6 +354,8 @@ func (s *SBaseStorage) CreateDiskByDiskinfo(ctx context.Context, params interfac
case createParams.DiskInfo.Backup != nil:
log.Infof("CreateDiskFromBackup %s", createParams)
return s.createDiskFromBackup(ctx, disk, createParams)
case len(createParams.DiskInfo.ExistingPath) > 0:
return s.createDiskFromExistingPath(ctx, disk, createParams)
case createParams.DiskInfo.DiskSizeMb > 0:
log.Infof("CreateRawDisk %s", createParams)
return s.CreateRawDisk(ctx, disk, createParams)
@@ -397,6 +399,22 @@ func (s *SBaseStorage) CreateDiskFromSnpashot(ctx context.Context, disk IDisk, i
return disk.GetDiskDesc(), nil
}
func (s *SBaseStorage) createDiskFromExistingPath(ctx context.Context, disk IDisk, input *SDiskCreateByDiskinfo) (jsonutils.JSONObject, error) {
var storage = input.Storage
if len(input.DiskInfo.ExistingPath) == 0 {
return nil, httperrors.NewMissingParameterError("existing_path")
}
if !strings.HasPrefix(input.DiskInfo.ExistingPath, storage.GetPath()) {
return nil, errors.Errorf("disk %s not in storage %s", input.DiskInfo.ExistingPath, storage.GetPath())
}
err := storage.CreateDiskFromExistingPath(ctx, disk, input)
if err != nil {
return nil, errors.Wrapf(err, "CreateDiskFromExistingPath")
}
return disk.GetDiskDesc(), nil
}
func (s *SBaseStorage) createDiskFromBackup(ctx context.Context, disk IDisk, input *SDiskCreateByDiskinfo) (jsonutils.JSONObject, error) {
var storage = input.Storage
if input.DiskInfo.Backup == nil {
+10
View File
@@ -664,6 +664,16 @@ func (s *SLocalStorage) CreateDiskFromSnapshot(
return httperrors.NewUnsupportOperationError("Unsupport protocol %s for Local storage", info.Protocol)
}
func (s *SLocalStorage) CreateDiskFromExistingPath(
ctx context.Context, disk IDisk, input *SDiskCreateByDiskinfo,
) error {
err := os.Link(input.DiskInfo.ExistingPath, disk.GetPath())
if err != nil {
return errors.Wrap(err, "os.link")
}
return nil
}
func (s *SLocalStorage) GetCloneTargetDiskPath(ctx context.Context, targetDiskId string) string {
return path.Join(s.GetPath(), targetDiskId)
}
+4
View File
@@ -577,6 +577,10 @@ func (s *SRbdStorage) GetBackupDir() string {
return ""
}
func (s *SRbdStorage) CreateDiskFromExistingPath(context.Context, IDisk, *SDiskCreateByDiskinfo) error {
return fmt.Errorf("Not support")
}
func (s *SRbdStorage) CreateDiskFromBackup(ctx context.Context, disk IDisk, input *SDiskCreateByDiskinfo) error {
backup := input.DiskInfo.Backup
pool, _ := s.StorageConf.GetString("pool")