diff --git a/pkg/cloudcommon/db/db_joint_dispatcher.go b/pkg/cloudcommon/db/db_joint_dispatcher.go index fe7ae7caed..46680d1c03 100644 --- a/pkg/cloudcommon/db/db_joint_dispatcher.go +++ b/pkg/cloudcommon/db/db_joint_dispatcher.go @@ -181,6 +181,7 @@ func attachItems(dispatcher *DBJointModelDispatcher, master IStandaloneModel, sl if err != nil { return nil, httperrors.NewGeneralError(err) } + item.PostCreate(ctx, userCred, ownerProjId, query, data) OpsLog.LogAttachEvent(ctx, master, slave, userCred, jsonutils.Marshal(item)) dispatcher.modelManager.OnCreateComplete(ctx, []IModel{item}, userCred, query, data) return getItemDetails(dispatcher.JointModelManager(), item, ctx, userCred, query) diff --git a/pkg/compute/hostdrivers/aliyun.go b/pkg/compute/hostdrivers/aliyun.go index 6b1c4f6776..cc69b7e85f 100644 --- a/pkg/compute/hostdrivers/aliyun.go +++ b/pkg/compute/hostdrivers/aliyun.go @@ -3,9 +3,11 @@ package hostdrivers import ( "fmt" + "yunion.io/x/jsonutils" "yunion.io/x/pkg/utils" "yunion.io/x/onecloud/pkg/compute/models" + "yunion.io/x/onecloud/pkg/httperrors" ) type SAliyunHostDriver struct { @@ -21,6 +23,10 @@ func (self *SAliyunHostDriver) GetHostType() string { return models.HOST_TYPE_ALIYUN } +func (self *SAliyunHostDriver) ValidateAttachStorage(host *models.SHost, storage *models.SStorage, data *jsonutils.JSONDict) error { + return httperrors.NewUnsupportOperationError("Not support attach storage for %s host", self.GetHostType()) +} + func (self *SAliyunHostDriver) ValidateDiskSize(storage *models.SStorage, sizeGb int) error { if utils.IsInStringArray(storage.StorageType, []string{models.STORAGE_CLOUD_EFFICIENCY, models.STORAGE_CLOUD_SSD, models.STORAGE_CLOUD_ESSD}) { if sizeGb < 20 || sizeGb > 32768 { diff --git a/pkg/compute/hostdrivers/aws.go b/pkg/compute/hostdrivers/aws.go index 3654734456..395a866179 100644 --- a/pkg/compute/hostdrivers/aws.go +++ b/pkg/compute/hostdrivers/aws.go @@ -3,9 +3,11 @@ package hostdrivers import ( "fmt" + "yunion.io/x/jsonutils" "yunion.io/x/pkg/utils" "yunion.io/x/onecloud/pkg/compute/models" + "yunion.io/x/onecloud/pkg/httperrors" ) type SAwsHostDriver struct { @@ -21,6 +23,10 @@ func (self *SAwsHostDriver) GetHostType() string { return models.HOST_TYPE_AWS } +func (self *SAwsHostDriver) ValidateAttachStorage(host *models.SHost, storage *models.SStorage, data *jsonutils.JSONDict) error { + return httperrors.NewUnsupportOperationError("Not support attach storage for %s host", self.GetHostType()) +} + func (self *SAwsHostDriver) ValidateDiskSize(storage *models.SStorage, sizeGb int) error { if storage.StorageType == models.STORAGE_GP2_SSD { if sizeGb < 1 || sizeGb > 16384 { diff --git a/pkg/compute/hostdrivers/azure.go b/pkg/compute/hostdrivers/azure.go index 7dca157a16..35e5c054fa 100644 --- a/pkg/compute/hostdrivers/azure.go +++ b/pkg/compute/hostdrivers/azure.go @@ -26,6 +26,10 @@ func (self *SAzureHostDriver) GetHostType() string { return models.HOST_TYPE_AZURE } +func (self *SAzureHostDriver) ValidateAttachStorage(host *models.SHost, storage *models.SStorage, data *jsonutils.JSONDict) error { + return httperrors.NewUnsupportOperationError("Not support attach storage for %s host", self.GetHostType()) +} + func (self *SAzureHostDriver) ValidateUpdateDisk(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) { if data.Contains("name") { return nil, httperrors.NewInputParameterError("cannot support change azure disk name") diff --git a/pkg/compute/hostdrivers/baremetal.go b/pkg/compute/hostdrivers/baremetal.go index 2afc8c086f..fc5a185a83 100644 --- a/pkg/compute/hostdrivers/baremetal.go +++ b/pkg/compute/hostdrivers/baremetal.go @@ -8,6 +8,7 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/compute/models" + "yunion.io/x/onecloud/pkg/httperrors" ) type SBaremetalHostDriver struct { @@ -23,6 +24,10 @@ func (self *SBaremetalHostDriver) GetHostType() string { return models.HOST_TYPE_BAREMETAL } +func (self *SBaremetalHostDriver) ValidateAttachStorage(host *models.SHost, storage *models.SStorage, data *jsonutils.JSONDict) error { + return httperrors.NewUnsupportOperationError("Not support attach storage for %s host", self.GetHostType()) +} + func (self *SBaremetalHostDriver) CheckAndSetCacheImage(ctx context.Context, host *models.SHost, storageCache *models.SStoragecache, task taskman.ITask) error { return fmt.Errorf("not supported") } diff --git a/pkg/compute/hostdrivers/base.go b/pkg/compute/hostdrivers/base.go index e215c3c908..fed7e5ccd0 100644 --- a/pkg/compute/hostdrivers/base.go +++ b/pkg/compute/hostdrivers/base.go @@ -11,6 +11,7 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/compute/baremetal" "yunion.io/x/onecloud/pkg/compute/models" + "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" ) @@ -21,6 +22,18 @@ func (self *SBaseHostDriver) ValidateUpdateDisk(ctx context.Context, userCred mc return data, nil } +func (self *SBaseHostDriver) ValidateAttachStorage(host *models.SHost, storage *models.SStorage, data *jsonutils.JSONDict) error { + return 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 { + return httperrors.NewNotImplementedError("Not Implement RequestAttachStorage") +} + +func (self *SBaseHostDriver) RequestDetachStorage(ctx context.Context, host *models.SHost, storage *models.SStorage, task taskman.ITask) error { + return httperrors.NewNotImplementedError("Not Implement RequestDetachStorage") +} + func (self *SBaseHostDriver) ValidateDiskSize(storage *models.SStorage, sizeGb int) error { return fmt.Errorf("Not Implement ValidateDiskSize") } diff --git a/pkg/compute/hostdrivers/esxi.go b/pkg/compute/hostdrivers/esxi.go index de521f08a6..e2eda6c3c2 100644 --- a/pkg/compute/hostdrivers/esxi.go +++ b/pkg/compute/hostdrivers/esxi.go @@ -10,6 +10,7 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/compute/models" + "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/util/httputils" ) @@ -26,6 +27,10 @@ func (self *SESXiHostDriver) GetHostType() string { return models.HOST_TYPE_ESXI } +func (self *SESXiHostDriver) ValidateAttachStorage(host *models.SHost, storage *models.SStorage, data *jsonutils.JSONDict) error { + return httperrors.NewUnsupportOperationError("Not support attach storage for %s host", self.GetHostType()) +} + func (self *SESXiHostDriver) CheckAndSetCacheImage(ctx context.Context, host *models.SHost, storageCache *models.SStoragecache, task taskman.ITask) error { params := task.GetParams() imageId, err := params.GetString("image_id") diff --git a/pkg/compute/hostdrivers/huawei.go b/pkg/compute/hostdrivers/huawei.go index 27b947e50e..0a9e69075a 100644 --- a/pkg/compute/hostdrivers/huawei.go +++ b/pkg/compute/hostdrivers/huawei.go @@ -3,7 +3,9 @@ package hostdrivers import ( "fmt" + "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/compute/models" + "yunion.io/x/onecloud/pkg/httperrors" ) type SHuaweiHostDriver struct { @@ -19,6 +21,10 @@ func (self *SHuaweiHostDriver) GetHostType() string { return models.HOST_TYPE_HUAWEI } +func (self *SHuaweiHostDriver) ValidateAttachStorage(host *models.SHost, storage *models.SStorage, data *jsonutils.JSONDict) error { + return httperrors.NewUnsupportOperationError("Not support attach storage for %s host", self.GetHostType()) +} + // 系统盘必须至少40G func (self *SHuaweiHostDriver) ValidateDiskSize(storage *models.SStorage, sizeGb int) error { switch storage.StorageType { diff --git a/pkg/compute/hostdrivers/kvm.go b/pkg/compute/hostdrivers/kvm.go index cc14d9cd0b..65e5baea1b 100644 --- a/pkg/compute/hostdrivers/kvm.go +++ b/pkg/compute/hostdrivers/kvm.go @@ -7,11 +7,13 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/log" + "yunion.io/x/pkg/utils" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/compute/baremetal" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/compute/options" + "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/httputils" ) @@ -29,6 +31,66 @@ func (self *SKVMHostDriver) GetHostType() string { return models.HOST_TYPE_HYPERVISOR } +func (self *SKVMHostDriver) ValidateAttachStorage(host *models.SHost, storage *models.SStorage, data *jsonutils.JSONDict) error { + if !utils.IsInStringArray(storage.StorageType, []string{models.STORAGE_LOCAL, models.STORAGE_RBD}) { + return httperrors.NewUnsupportOperationError("Unsupport attach %s storage for %s host", storage.StorageType, host.HostType) + } + if storage.StorageType == models.STORAGE_RBD { + if host.HostStatus != models.HOST_ONLINE { + return 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))) + } + return nil +} + +func (self *SKVMHostDriver) RequestAttachStorage(ctx context.Context, hoststorage *models.SHoststorage, host *models.SHost, storage *models.SStorage, task taskman.ITask) error { + taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) { + if storage.StorageType == models.STORAGE_RBD { + log.Infof("Attach SharedStorage[%s] on host %s ...", storage.Name, host.Name) + url := fmt.Sprintf("%s/storages/attach", host.ManagerUri) + headers := mcclient.GetTokenHeaders(task.GetUserCred()) + data := map[string]interface{}{ + "mount_point": hoststorage.MountPoint, + "name": storage.Name, + "storage_id": storage.Id, + "storage_conf": storage.StorageConf, + "storage_type": storage.StorageType, + } + if len(storage.StoragecacheId) > 0 { + storagecache := models.StoragecacheManager.FetchStoragecacheById(storage.StoragecacheId) + if storagecache != nil { + data["imagecache_path"] = storage.GetStorageCachePath(hoststorage.MountPoint, storagecache.Path) + data["storagecache_id"] = storagecache.Id + } + } + _, resp, err := httputils.JSONRequest(httputils.GetDefaultClient(), ctx, "POST", url, headers, jsonutils.Marshal(data), false) + return resp, err + } + return nil, nil + }) + return nil +} + +func (self *SKVMHostDriver) RequestDetachStorage(ctx context.Context, host *models.SHost, storage *models.SStorage, task taskman.ITask) error { + taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) { + if storage.StorageType == models.STORAGE_RBD && host.HostStatus == models.HOST_ONLINE { + log.Infof("Detach SharedStorage[%s] on host %s ...", storage.Name, host.Name) + url := fmt.Sprintf("%s/storages/detach", host.ManagerUri) + headers := mcclient.GetTokenHeaders(task.GetUserCred()) + body := jsonutils.NewDict() + mountPoint, _ := task.GetParams().GetString("mount_point") + body.Set("mount_point", jsonutils.NewString(mountPoint)) + body.Set("name", jsonutils.NewString(storage.Name)) + _, resp, err := httputils.JSONRequest(httputils.GetDefaultClient(), ctx, "POST", url, headers, body, false) + return resp, err + } + return nil, nil + }) + return nil +} + func (self *SKVMHostDriver) ValidateDiskSize(storage *models.SStorage, sizeGb int) error { return nil } diff --git a/pkg/compute/hostdrivers/openstack.go b/pkg/compute/hostdrivers/openstack.go index aa8cd59169..22972cf356 100644 --- a/pkg/compute/hostdrivers/openstack.go +++ b/pkg/compute/hostdrivers/openstack.go @@ -1,7 +1,9 @@ package hostdrivers import ( + "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/compute/models" + "yunion.io/x/onecloud/pkg/httperrors" ) type SOpenStackHostDriver struct { @@ -17,6 +19,10 @@ func (self *SOpenStackHostDriver) GetHostType() string { return models.HOST_TYPE_OPENSTACK } +func (self *SOpenStackHostDriver) ValidateAttachStorage(host *models.SHost, storage *models.SStorage, data *jsonutils.JSONDict) error { + return httperrors.NewUnsupportOperationError("Not support attach storage for %s host", self.GetHostType()) +} + func (self *SOpenStackHostDriver) ValidateDiskSize(storage *models.SStorage, sizeGb int) error { return nil } diff --git a/pkg/compute/hostdrivers/qcloud.go b/pkg/compute/hostdrivers/qcloud.go index 8244f8b604..455359e6cf 100644 --- a/pkg/compute/hostdrivers/qcloud.go +++ b/pkg/compute/hostdrivers/qcloud.go @@ -4,6 +4,7 @@ import ( "context" "fmt" + "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/httperrors" @@ -22,6 +23,10 @@ func (self *SQcloudHostDriver) GetHostType() string { return models.HOST_TYPE_QCLOUD } +func (self *SQcloudHostDriver) ValidateAttachStorage(host *models.SHost, storage *models.SStorage, data *jsonutils.JSONDict) error { + return httperrors.NewUnsupportOperationError("Not support attach storage for %s host", self.GetHostType()) +} + func (self *SQcloudHostDriver) ValidateDiskSize(storage *models.SStorage, sizeGb int) error { if sizeGb%10 != 0 { return fmt.Errorf("The disk size must be a multiple of 10Gb") diff --git a/pkg/compute/models/hostdrivers.go b/pkg/compute/models/hostdrivers.go index 69735ec906..88fe4e6584 100644 --- a/pkg/compute/models/hostdrivers.go +++ b/pkg/compute/models/hostdrivers.go @@ -43,6 +43,10 @@ type IHostDriver interface { IsReachStoragecacheCapacityLimit(host *SHost, cachedImages []SCachedimage) bool GetStoragecacheQuota(host *SHost) int + + ValidateAttachStorage(host *SHost, storage *SStorage, data *jsonutils.JSONDict) 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 } var hostDrivers map[string]IHostDriver diff --git a/pkg/compute/models/hoststorages.go b/pkg/compute/models/hoststorages.go index dd66d4f53e..236557d720 100644 --- a/pkg/compute/models/hoststorages.go +++ b/pkg/compute/models/hoststorages.go @@ -2,19 +2,17 @@ package models import ( "context" - "fmt" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/tristate" - "yunion.io/x/pkg/utils" "yunion.io/x/sqlchemy" "yunion.io/x/onecloud/pkg/cloudcommon/db" + "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" - "yunion.io/x/onecloud/pkg/util/httputils" ) type SHoststorageManager struct { @@ -91,83 +89,78 @@ func (self *SHoststorage) GetStorage() *SStorage { func (manager *SHoststorageManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerProjId string, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) { storageId, _ := data.GetString("storage_id") if len(storageId) == 0 { - return nil, httperrors.NewInputParameterError("missing storage_id") + return nil, httperrors.NewMissingParameterError("storage_id") } storageTmp, _ := StorageManager.FetchById(storageId) if storageTmp == nil { - return nil, httperrors.NewInputParameterError("invalid storage_id %s", storageId) + return nil, httperrors.NewResourceNotFoundError("failed to find storage %s to attach host", storageId) } storage := storageTmp.(*SStorage) - if storage.StorageType == STORAGE_RBD { - pool, _ := data.GetString("pool") - data.Add(jsonutils.NewString(fmt.Sprintf("rbd:%s", pool)), "mount_point") + + 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(host, storage, data); err != nil { + return nil, err + } + return manager.SJointResourceBaseManager.ValidateCreateData(ctx, userCred, ownerProjId, query, data) } func (self *SHoststorage) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerProjId string, query jsonutils.JSONObject, data jsonutils.JSONObject) { self.SHostJointsBase.PostCreate(ctx, userCred, ownerProjId, query, data) - storage := self.GetStorage() - if !utils.IsInStringArray(storage.StorageType, STORAGE_LOCAL_TYPES) { - host := storage.GetMasterHost() - log.Infof("Attach SharedStorage[%s] on host %s ...", storage.Name, host.Name) - url := fmt.Sprintf("%s/storages/attach", host.ManagerUri) - headers := mcclient.GetTokenHeaders(userCred) - body := jsonutils.NewDict() - body.Set("mount_point", jsonutils.NewString(self.MountPoint)) - body.Set("name", jsonutils.NewString(storage.Name)) - body.Set("storage_id", jsonutils.NewString(storage.Id)) - body.Set("storage_conf", storage.StorageConf) - body.Set("storage_type", jsonutils.NewString(storage.StorageType)) - if len(storage.StoragecacheId) > 0 { - storagecache := StoragecacheManager.FetchStoragecacheById(storage.StoragecacheId) - if storagecache != nil { - body.Set("imagecache_path", jsonutils.NewString( - storage.GetStorageCachePath(self.MountPoint, storagecache.Path))) - body.Set("storagecache_id", jsonutils.NewString(storagecache.Id)) - } - } - _, _, err := httputils.JSONRequest(httputils.GetDefaultClient(), - ctx, "POST", url, headers, body, false) - if err != nil { - log.Errorf("Host Storage Post Create Error: %s", err) - // panic(err) ??? - } - self.SyncStorageStatus() + + if err := self.StartHostStorageAttachTask(ctx, userCred); err != nil { + log.Errorf("failed to attach storage error: %v", err) + self.Detach(ctx, userCred) } } -func (self *SHoststorage) PreDelete(ctx context.Context, userCred mcclient.TokenCredential) { - storage := self.GetStorage() - if !utils.IsInStringArray(storage.StorageType, STORAGE_LOCAL_TYPES) { - host := storage.GetMasterHost() - log.Infof("Attach SharedStorage[%s] on host %s ...", storage.Name, host.Name) - url := fmt.Sprintf("%s/storages/detach", host.ManagerUri) - headers := mcclient.GetTokenHeaders(userCred) - body := jsonutils.NewDict() - body.Set("mount_point", jsonutils.NewString(self.MountPoint)) - body.Set("name", jsonutils.NewString(storage.Name)) - _, _, err := httputils.JSONRequest(httputils.GetDefaultClient(), - ctx, "POST", url, headers, body, false) - if err != nil { - log.Errorf("Host Storage Post Create Error: %s", err) - // panic(err) ??? - } - self.SyncStorageStatus() +func (self *SHoststorage) StartHostStorageAttachTask(ctx context.Context, userCred mcclient.TokenCredential) error { + host := self.GetHost() + params := jsonutils.NewDict() + params.Set("storage_id", jsonutils.NewString(self.StorageId)) + task, err := taskman.TaskManager.NewTask(ctx, "HostStorageAttachTask", host, userCred, params, "", "", nil) + if err != nil { + return err } + task.ScheduleRun(nil) + return nil +} + +func (self *SHoststorage) StartHostStorageDetachTask(ctx context.Context, userCred mcclient.TokenCredential) error { + if host := self.GetHost(); host.HostStatus == HOST_ONLINE { + params := jsonutils.NewDict() + params.Set("storage_id", jsonutils.NewString(self.StorageId)) + params.Set("mount_point", jsonutils.NewString(self.MountPoint)) + task, err := taskman.TaskManager.NewTask(ctx, "HostStorageDetachTask", host, userCred, params, "", "", nil) + if err != nil { + return err + } + task.ScheduleRun(nil) + } + return nil +} + +func (self *SHoststorage) PostDelete(ctx context.Context, userCred mcclient.TokenCredential) { + self.StartHostStorageDetachTask(ctx, userCred) + self.SyncStorageStatus() } func (self *SHoststorage) SyncStorageStatus() { storage := self.GetStorage() - hostQuery := HostManager.Query().SubQuery() - count := HoststorageManager.Query().Join(hostQuery, - sqlchemy.AND(sqlchemy.Equals(hostQuery.Field("id"), self.HostId), - sqlchemy.Equals(hostQuery.Field("host_status"), "online"))).Count() - status := storage.Status - if count >= 1 { - status = STORAGE_ONLINE - } else { - status = STORAGE_OFFLINE + status := STORAGE_OFFLINE + for _, host := range storage.GetAttachedHosts() { + if host.HostStatus == HOST_ONLINE { + status = STORAGE_ONLINE + } } if status != storage.Status { storage.GetModelManager().TableSpec().Update(storage, func() error { diff --git a/pkg/compute/storagedrivers/rbd.go b/pkg/compute/storagedrivers/rbd.go index 540ff93caa..be7fdbc711 100644 --- a/pkg/compute/storagedrivers/rbd.go +++ b/pkg/compute/storagedrivers/rbd.go @@ -51,9 +51,13 @@ func (self *SRbdStorageDriver) ValidateCreateData(ctx context.Context, userCred return nil, httperrors.NewGeneralError(err) } + inputHost, _ := conf.GetString("mon_host") + inputPool, _ := conf.GetString("pool") for i := 0; i < len(storages); i++ { - if conf.Equals(storages[i].StorageConf) { - return nil, httperrors.NewDuplicateResourceError("This RBD Storage[%s/%s] has already exist", storages[i].Name, conf.String()) + host, _ := storages[i].StorageConf.GetString("mon_host") + pool, _ := storages[i].StorageConf.GetString("pool") + if inputHost == host && inputPool == pool { + return nil, httperrors.NewDuplicateResourceError("This RBD Storage[%s/%s] has already exist", storages[i].Name, inputPool) } } @@ -75,7 +79,7 @@ func (self *SRbdStorageDriver) PostCreate(ctx context.Context, userCred mcclient rbdHost, _ := storages[i].StorageConf.GetString("mon_host") rbdKey, _ := storages[i].StorageConf.GetString("key") if newRbdHost == rbdHost && newRbdKey == rbdKey { - _, err := storage.GetModelManager().TableSpec().Update(self, func() error { + _, err := storage.GetModelManager().TableSpec().Update(storage, func() error { storage.StoragecacheId = storages[i].StoragecacheId return nil }) diff --git a/pkg/compute/tasks/host_storage_attach_task.go b/pkg/compute/tasks/host_storage_attach_task.go new file mode 100644 index 0000000000..2b189ea4f3 --- /dev/null +++ b/pkg/compute/tasks/host_storage_attach_task.go @@ -0,0 +1,59 @@ +package tasks + +import ( + "context" + + "yunion.io/x/jsonutils" + "yunion.io/x/onecloud/pkg/cloudcommon/db" + "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" + "yunion.io/x/onecloud/pkg/compute/models" +) + +type HostStorageAttachTask struct { + taskman.STask +} + +func init() { + taskman.RegisterTask(HostStorageAttachTask{}) +} + +func (self *HostStorageAttachTask) taskFail(ctx context.Context, host *models.SHost, reason string) { + if hoststorage := self.getHoststorage(host); hoststorage != nil { + hoststorage.Detach(ctx, self.GetUserCred()) + } + self.SetStageFailed(ctx, reason) +} + +func (self *HostStorageAttachTask) getHoststorage(host *models.SHost) *models.SHoststorage { + storageId, _ := self.GetParams().GetString("storage_id") + hoststorages := host.GetHoststorages() + for _, hoststorage := range hoststorages { + if hoststorage.StorageId == storageId { + return &hoststorage + } + } + return nil +} + +func (self *HostStorageAttachTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { + host := obj.(*models.SHost) + hoststorage := self.getHoststorage(host) + if hoststorage == nil { + self.taskFail(ctx, host, "failed to find hoststorage") + return + } + storage := hoststorage.GetStorage() + self.SetStage("OnAttachStorageComplete", nil) + err := host.GetHostDriver().RequestAttachStorage(ctx, hoststorage, host, storage, self) + if err != nil { + self.taskFail(ctx, host, err.Error()) + } +} + +func (self *HostStorageAttachTask) OnAttachStorageComplete(ctx context.Context, host *models.SHost, data jsonutils.JSONObject) { + self.SetStageComplete(ctx, nil) +} + +func (self *HostStorageAttachTask) OnAttachStorageCompleteFailed(ctx context.Context, host *models.SHost, reason jsonutils.JSONObject) { + self.taskFail(ctx, host, reason.String()) +} diff --git a/pkg/compute/tasks/host_storage_detach_task.go b/pkg/compute/tasks/host_storage_detach_task.go new file mode 100644 index 0000000000..61081a6f13 --- /dev/null +++ b/pkg/compute/tasks/host_storage_detach_task.go @@ -0,0 +1,46 @@ +package tasks + +import ( + "context" + + "yunion.io/x/jsonutils" + "yunion.io/x/onecloud/pkg/cloudcommon/db" + "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" + "yunion.io/x/onecloud/pkg/compute/models" +) + +type HostStorageDetachTask struct { + taskman.STask +} + +func init() { + taskman.RegisterTask(HostStorageDetachTask{}) +} + +func (self *HostStorageDetachTask) taskFail(ctx context.Context, host *models.SHost, reason string) { + self.SetStageFailed(ctx, reason) +} + +func (self *HostStorageDetachTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { + host := obj.(*models.SHost) + storageId, _ := self.GetParams().GetString("storage_id") + _storage, err := models.StorageManager.FetchById(storageId) + if err != nil { + self.taskFail(ctx, host, err.Error()) + return + } + storage := _storage.(*models.SStorage) + self.SetStage("OnDetachStorageComplete", nil) + err = host.GetHostDriver().RequestDetachStorage(ctx, host, storage, self) + if err != nil { + self.taskFail(ctx, host, err.Error()) + } +} + +func (self *HostStorageDetachTask) OnDetachStorageComplete(ctx context.Context, host *models.SHost, data jsonutils.JSONObject) { + self.SetStageComplete(ctx, nil) +} + +func (self *HostStorageDetachTask) OnDetachStorageCompleteFailed(ctx context.Context, host *models.SHost, reason jsonutils.JSONObject) { + self.taskFail(ctx, host, reason.String()) +} diff --git a/pkg/hostman/storageman/storage_rbd.go b/pkg/hostman/storageman/storage_rbd.go index 2991ca2ddd..657d9a0935 100644 --- a/pkg/hostman/storageman/storage_rbd.go +++ b/pkg/hostman/storageman/storage_rbd.go @@ -162,8 +162,6 @@ func (s *SRbdStorage) cloneImage(srcPool string, srcImage string, destPool strin log.Errorf("create snapshot error: %v", err) return nil, err } - names, err := src.GetSnapshotNames() - defer snapshot.Remove() isProtect, err := snapshot.IsProtected() if err != nil { @@ -384,7 +382,7 @@ func (s *SRbdStorage) SaveToGlance(ctx context.Context, params interface{}) (jso rbdImageCache.LoadImageCache(imageId) _, err := hostutils.RemoteStoragecacheCacheImage(ctx, rbdImageCache.GetId(), imageId, "ready", imagePath) if err != nil { - log.Errorf("ail to remote cache image: %v", err) + log.Errorf("Fail to remote cache image: %v", err) } return nil, nil } @@ -482,7 +480,7 @@ func (s *SRbdStorage) saveToGlance(ctx context.Context, imageId, imagePath strin } func (s *SRbdStorage) CreateSnapshotFormUrl(ctx context.Context, snapshotUrl, diskId, snapshotPath string) error { - return nil + return fmt.Errorf("Not support") } func (s *SRbdStorage) DeleteSnapshots(ctx context.Context, params interface{}) (jsonutils.JSONObject, error) { diff --git a/pkg/hostman/storageman/storagehandler.go b/pkg/hostman/storageman/storagehandler.go index f85abd956f..d86b38c7e0 100644 --- a/pkg/hostman/storageman/storagehandler.go +++ b/pkg/hostman/storageman/storagehandler.go @@ -70,11 +70,16 @@ func storageAttach(ctx context.Context, body jsonutils.JSONObject) (interface{}, imagecachePath, _ := body.GetString("imagecache_path") storageManager.InitSharedStorageImageCache(storageType, storagecacheId, imagecachePath, storage) - storageId, _ := body.GetString("id") + storageId, _ := body.GetString("storage_id") storageName, _ := body.GetString("name") storageConf, _ := body.Get("storage_conf") storage.SetStorageInfo(storageId, storageName, storageConf) - return nil, nil + resp, err := storage.SyncStorageInfo() + if err != nil { + return nil, err + } + storageManager.Storages = append(storageManager.Storages, storage) + return resp, nil } func storageDetach(ctx context.Context, body jsonutils.JSONObject) (interface{}, error) {