From 206702298a6daf2811077ba2a20ff2039158244f Mon Sep 17 00:00:00 2001 From: Qu Xuan Date: Thu, 21 Oct 2021 12:14:02 +0800 Subject: [PATCH] fix(host): same mountpoint rbd storage --- pkg/apis/compute/hoststorage.go | 9 ++++ pkg/compute/hostdrivers/base.go | 4 +- pkg/compute/hostdrivers/kvm.go | 30 +++++------ pkg/compute/models/hostdrivers.go | 2 +- pkg/compute/models/hoststorages.go | 51 +++++++------------ pkg/hostman/storageman/core.go | 28 ++++++++-- .../storagehandler/storagehandler.go | 28 +++++----- 7 files changed, 86 insertions(+), 66 deletions(-) diff --git a/pkg/apis/compute/hoststorage.go b/pkg/apis/compute/hoststorage.go index 772ca71190..52a3d5a7c3 100644 --- a/pkg/apis/compute/hoststorage.go +++ b/pkg/apis/compute/hoststorage.go @@ -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"` +} diff --git a/pkg/compute/hostdrivers/base.go b/pkg/compute/hostdrivers/base.go index 99d7a464c2..d5565b18f8 100644 --- a/pkg/compute/hostdrivers/base.go +++ b/pkg/compute/hostdrivers/base.go @@ -43,8 +43,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 { diff --git a/pkg/compute/hostdrivers/kvm.go b/pkg/compute/hostdrivers/kvm.go index 8e5698016f..7d84cb2e3f 100644 --- a/pkg/compute/hostdrivers/kvm.go +++ b/pkg/compute/hostdrivers/kvm.go @@ -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 } diff --git a/pkg/compute/models/hostdrivers.go b/pkg/compute/models/hostdrivers.go index 208b64644a..8d8049b58c 100644 --- a/pkg/compute/models/hostdrivers.go +++ b/pkg/compute/models/hostdrivers.go @@ -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 diff --git a/pkg/compute/models/hoststorages.go b/pkg/compute/models/hoststorages.go index 509a4ef958..8ebf9d6d5d 100644 --- a/pkg/compute/models/hoststorages.go +++ b/pkg/compute/models/hoststorages.go @@ -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" @@ -137,42 +138,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) { diff --git a/pkg/hostman/storageman/core.go b/pkg/hostman/storageman/core.go index a35cf4ceb9..b4a36554a9 100644 --- a/pkg/hostman/storageman/core.go +++ b/pkg/hostman/storageman/core.go @@ -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 { diff --git a/pkg/hostman/storageman/storagehandler/storagehandler.go b/pkg/hostman/storageman/storagehandler/storagehandler.go index 852af631d6..659161f573 100644 --- a/pkg/hostman/storageman/storagehandler/storagehandler.go +++ b/pkg/hostman/storageman/storagehandler/storagehandler.go @@ -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 }