Merge pull request #12483 from ioito/automated-cherry-pick-of-#12481-upstream-release-3.7

Automated cherry pick of #12481: fix(host): same mountpoint rbd storage
This commit is contained in:
Zexi Li
2021-10-21 17:11:51 +08:00
committed by GitHub
7 changed files with 86 additions and 66 deletions
+9
View File
@@ -16,6 +16,8 @@ package compute
import (
"yunion.io/x/jsonutils"
"yunion.io/x/onecloud/pkg/apis"
)
type HoststorageDetails struct {
@@ -58,3 +60,10 @@ type HoststorageListInput struct {
StorageFilterListInput
}
type HostStorageCreateInput struct {
apis.JoinResourceBaseCreateInput
StorageId string `json:"storage_id"`
HostId string `json:"host_id"`
MountPoint string `json:"mount_point"`
}
+2 -2
View File
@@ -42,8 +42,8 @@ func (self *SBaseHostDriver) ValidateResetDisk(ctx context.Context, userCred mcc
return nil, httperrors.NewNotImplementedError("Not Implement ValidateResetDisk")
}
func (self *SBaseHostDriver) ValidateAttachStorage(ctx context.Context, userCred mcclient.TokenCredential, host *models.SHost, storage *models.SStorage, data *jsonutils.JSONDict) error {
return httperrors.NewNotImplementedError("Not Implement ValidateAttachStorage")
func (self *SBaseHostDriver) ValidateAttachStorage(ctx context.Context, userCred mcclient.TokenCredential, host *models.SHost, storage *models.SStorage, input api.HostStorageCreateInput) (api.HostStorageCreateInput, error) {
return input, httperrors.NewNotImplementedError("Not Implement ValidateAttachStorage")
}
func (self *SBaseHostDriver) RequestAttachStorage(ctx context.Context, hoststorage *models.SHoststorage, host *models.SHost, storage *models.SStorage, task taskman.ITask) error {
+15 -15
View File
@@ -59,48 +59,47 @@ func (self *SKVMHostDriver) GetHypervisor() string {
return api.HYPERVISOR_KVM
}
func (self *SKVMHostDriver) ValidateAttachStorage(ctx context.Context, userCred mcclient.TokenCredential, host *models.SHost, storage *models.SStorage, data *jsonutils.JSONDict) error {
func (self *SKVMHostDriver) ValidateAttachStorage(ctx context.Context, userCred mcclient.TokenCredential, host *models.SHost, storage *models.SStorage, input api.HostStorageCreateInput) (api.HostStorageCreateInput, error) {
if !utils.IsInStringArray(storage.StorageType, append([]string{api.STORAGE_LOCAL}, api.SHARED_STORAGE...)) {
return httperrors.NewUnsupportOperationError("Unsupport attach %s storage for %s host", storage.StorageType, host.HostType)
return input, httperrors.NewUnsupportOperationError("Unsupport attach %s storage for %s host", storage.StorageType, host.HostType)
}
if storage.StorageType == api.STORAGE_RBD {
if host.HostStatus != api.HOST_ONLINE {
return httperrors.NewInvalidStatusError("Attach rbd storage require host status is online")
return input, httperrors.NewInvalidStatusError("Attach rbd storage require host status is online")
}
pool, _ := storage.StorageConf.GetString("pool")
data.Set("mount_point", jsonutils.NewString(fmt.Sprintf("rbd:%s", pool)))
input.MountPoint = fmt.Sprintf("rbd:%s", pool)
} else if utils.IsInStringArray(storage.StorageType, api.SHARED_FILE_STORAGE) {
mountPoint, err := data.GetString("mount_point")
if err != nil {
return httperrors.NewMissingParameterError("mount_point")
if len(input.MountPoint) == 0 {
return input, httperrors.NewMissingParameterError("mount_point")
}
count, err := models.HoststorageManager.Query().Equals("host_id", host.Id).Equals("mount_point", mountPoint).CountWithError()
count, err := models.HoststorageManager.Query().Equals("host_id", host.Id).Equals("mount_point", input.MountPoint).CountWithError()
if err != nil {
return httperrors.NewInternalServerError("Query host storage error %s", err)
return input, httperrors.NewInternalServerError("Query host storage error %s", err)
}
if count > 0 {
return httperrors.NewBadRequestError("Host %s already have mount point %s with other storage", host.Name, mountPoint)
return input, httperrors.NewBadRequestError("Host %s already have mount point %s with other storage", host.Name, input.MountPoint)
}
if host.HostStatus != api.HOST_ONLINE {
return httperrors.NewInvalidStatusError("Attach nfs storage require host status is online")
return input, httperrors.NewInvalidStatusError("Attach nfs storage require host status is online")
}
if storage.StorageType == api.STORAGE_GPFS {
header := http.Header{}
header.Set(mcclient.AUTH_TOKEN, userCred.GetTokenString())
header.Set(mcclient.REGION_VERSION, "v2")
params := jsonutils.NewDict()
params.Set("mount_point", jsonutils.NewString(mountPoint))
params.Set("mount_point", jsonutils.NewString(input.MountPoint))
urlStr := fmt.Sprintf("%s/storages/is-mount-point?%s", host.ManagerUri, params.QueryString())
_, res, err := httputils.JSONRequest(httputils.GetDefaultClient(), ctx, "GET", urlStr, header, nil, false)
if err != nil {
return err
return input, err
}
if !jsonutils.QueryBoolean(res, "is_mount_point", false) {
return httperrors.NewBadRequestError("%s is not mount point %s", mountPoint, res)
return input, httperrors.NewBadRequestError("%s is not mount point %s", input.MountPoint, res)
}
}
}
return nil
return input, nil
}
func (self *SKVMHostDriver) RequestAttachStorage(ctx context.Context, hoststorage *models.SHoststorage, host *models.SHost, storage *models.SStorage, task taskman.ITask) error {
@@ -141,6 +140,7 @@ func (self *SKVMHostDriver) RequestDetachStorage(ctx context.Context, host *mode
mountPoint, _ := task.GetParams().GetString("mount_point")
body.Set("mount_point", jsonutils.NewString(mountPoint))
body.Set("name", jsonutils.NewString(storage.Name))
body.Set("storage_id", jsonutils.NewString(storage.Id))
_, resp, err := httputils.JSONRequest(httputils.GetDefaultClient(), ctx, "POST", url, headers, body, false)
return resp, err
}
+1 -1
View File
@@ -59,7 +59,7 @@ type IHostDriver interface {
IsReachStoragecacheCapacityLimit(host *SHost, cachedImages []SCachedimage) bool
GetStoragecacheQuota(host *SHost) int
ValidateAttachStorage(ctx context.Context, userCred mcclient.TokenCredential, host *SHost, storage *SStorage, data *jsonutils.JSONDict) error
ValidateAttachStorage(ctx context.Context, userCred mcclient.TokenCredential, host *SHost, storage *SStorage, input api.HostStorageCreateInput) (api.HostStorageCreateInput, error)
RequestAttachStorage(ctx context.Context, hoststorage *SHoststorage, host *SHost, storage *SStorage, task taskman.ITask) error
RequestDetachStorage(ctx context.Context, host *SHost, storage *SStorage, task taskman.ITask) error
RequestSyncOnHost(ctx context.Context, host *SHost, task taskman.ITask) error
+19 -32
View File
@@ -27,6 +27,7 @@ import (
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/cloudcommon/validators"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
@@ -146,42 +147,28 @@ func (self *SHoststorage) GetStorage() *SStorage {
return nil
}
func (manager *SHoststorageManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
storageId, _ := data.GetString("storage_id")
if len(storageId) == 0 {
return nil, httperrors.NewMissingParameterError("storage_id")
}
storageTmp, _ := StorageManager.FetchById(storageId)
if storageTmp == nil {
return nil, httperrors.NewResourceNotFoundError("failed to find storage %s to attach host", storageId)
}
storage := storageTmp.(*SStorage)
hostId, _ := data.GetString("host_id")
if len(hostId) == 0 {
return nil, httperrors.NewMissingParameterError("host_id")
}
hostTmp, _ := HostManager.FetchById(hostId)
if hostTmp == nil {
return nil, httperrors.NewResourceNotFoundError("failed to find host %s to attach storage", hostId)
}
host := hostTmp.(*SHost)
if err := host.GetHostDriver().ValidateAttachStorage(ctx, userCred, host, storage, data); err != nil {
return nil, err
}
input := apis.JoinResourceBaseCreateInput{}
err := data.Unmarshal(&input)
func (manager *SHoststorageManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, input api.HostStorageCreateInput) (api.HostStorageCreateInput, error) {
storageObj, err := validators.ValidateModel(userCred, StorageManager, &input.StorageId)
if err != nil {
return nil, httperrors.NewInternalServerError("unmarshal JoinResourceBaseCreateInput fail %s", err)
return input, err
}
input, err = manager.SJointResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input)
storage := storageObj.(*SStorage)
hostObj, err := validators.ValidateModel(userCred, HostManager, &input.HostId)
if err != nil {
return nil, err
return input, err
}
data.Update(jsonutils.Marshal(input))
return data, nil
host := hostObj.(*SHost)
input, err = host.GetHostDriver().ValidateAttachStorage(ctx, userCred, host, storage, input)
if err != nil {
return input, err
}
input.JoinResourceBaseCreateInput, err = manager.SJointResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.JoinResourceBaseCreateInput)
if err != nil {
return input, err
}
return input, nil
}
func (self *SHoststorage) syncLocalStorageShare(ctx context.Context, userCred mcclient.TokenCredential) {
+25 -3
View File
@@ -201,6 +201,19 @@ func (s *SStorageManager) GetStorageDisk(storageId, diskId string) IDisk {
return nil
}
func (s *SStorageManager) GetStoragesByPath(sPath string) ([]IStorage, error) {
ret := []IStorage{}
for i := range s.Storages {
if s.Storages[i].GetPath() == sPath {
ret = append(ret, s.Storages[i])
}
}
if len(ret) == 0 {
return nil, errors.Wrapf(cloudprovider.ErrNotFound, sPath)
}
return ret, nil
}
func (s *SStorageManager) GetStorageByPath(sPath string) (IStorage, error) {
for _, storage := range s.Storages {
if storage.GetPath() == sPath {
@@ -218,11 +231,20 @@ func (s *SStorageManager) GetDiskByPath(diskPath string) (IDisk, error) {
if pos > 0 {
diskId = diskId[:pos]
}
storage, err := s.GetStorageByPath(sPath)
storages, err := s.GetStoragesByPath(sPath)
if err != nil {
return nil, errors.Wrapf(err, "GetStorageByPath")
return nil, errors.Wrapf(err, "GetStoragesByPath")
}
return storage.GetDiskById(diskId)
for i := range storages {
disk, err := storages[i].GetDiskById(diskId)
if err != nil && errors.Cause(err) != cloudprovider.ErrNotFound {
return nil, err
}
if err == nil {
return disk, nil
}
}
return nil, errors.Wrapf(cloudprovider.ErrNotFound, diskId)
}
func (s *SStorageManager) GetTotalCapacity() int {
@@ -24,7 +24,6 @@ import (
"yunion.io/x/pkg/errors"
"yunion.io/x/onecloud/pkg/appsrv"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/hostman/hostutils"
"yunion.io/x/onecloud/pkg/hostman/storageman"
"yunion.io/x/onecloud/pkg/httperrors"
@@ -128,22 +127,25 @@ func storageAttach(ctx context.Context, body jsonutils.JSONObject) (interface{},
}
func storageDetach(ctx context.Context, body jsonutils.JSONObject) (interface{}, error) {
mountPoint, err := body.GetString("mount_point")
info := struct {
MountPoint string
StorageId string
Name string
}{}
err := body.Unmarshal(&info)
if err != nil {
return nil, httperrors.NewMissingParameterError("mount_point")
return nil, errors.Wrapf(err, "body.Unmarshal")
}
storage, err := storageman.GetManager().GetStorageByPath(mountPoint)
if err != nil {
if errors.Cause(err) == cloudprovider.ErrNotFound {
return nil, nil
if len(info.StorageId) == 0 {
return nil, httperrors.NewMissingParameterError("storage_id")
}
storage := storageman.GetManager().GetStorage(info.StorageId)
if storage != nil {
if err := storage.Detach(); err != nil {
log.Errorf("detach storage %s failed: %s", storage.GetPath(), err)
}
return nil, errors.Wrapf(err, "GetStorageByPath(%s)", mountPoint)
storageman.GetManager().Remove(storage)
}
if err := storage.Detach(); err != nil {
log.Errorf("detach storage %s failed: %s", storage.GetPath(), err)
}
storageman.GetManager().Remove(storage)
return nil, nil
}