diff --git a/cmd/climc/shell/storages.go b/cmd/climc/shell/storages.go index 7ec51ebca4..cf87838007 100644 --- a/cmd/climc/shell/storages.go +++ b/cmd/climc/shell/storages.go @@ -94,7 +94,7 @@ func init() { ZONE string `help:"Zone id of storage"` Capacity int64 `help:"Capacity of the Storage"` MediumType string `help:"Medium type, either ssd or rotate" choices:"ssd|rotate"` - StorageType string `help:"Storage type" choices:"local|nas|vsan|rbd|nfs|baremetal"` + StorageType string `help:"Storage type" choices:"local|nas|vsan|rbd|nfs|gpfs|baremetal"` MonHost string `help:"Ceph mon_host config"` Key string `help:"Ceph key config"` Pool string `help:"Ceph Poll Name"` diff --git a/pkg/apis/compute/storage_const.go b/pkg/apis/compute/storage_const.go index bd8cadc65d..5344998192 100644 --- a/pkg/apis/compute/storage_const.go +++ b/pkg/apis/compute/storage_const.go @@ -23,6 +23,7 @@ const ( STORAGE_NAS = "nas" STORAGE_VSAN = "vsan" STORAGE_NFS = "nfs" + STORAGE_GPFS = "gpfs" STORAGE_PUBLIC_CLOUD = "cloud" STORAGE_CLOUD_EFFICIENCY = "cloud_efficiency" @@ -87,7 +88,7 @@ var ( STORAGE_ALL_TYPES = []string{ STORAGE_LOCAL, STORAGE_BAREMETAL, STORAGE_SHEEPDOG, STORAGE_RBD, STORAGE_DOCKER, STORAGE_NAS, STORAGE_VSAN, - STORAGE_NFS, + STORAGE_NFS, STORAGE_GPFS, } STORAGE_TYPES = []string{STORAGE_LOCAL, STORAGE_BAREMETAL, STORAGE_SHEEPDOG, STORAGE_RBD, STORAGE_DOCKER, STORAGE_NAS, STORAGE_VSAN, STORAGE_NFS, @@ -98,8 +99,14 @@ var ( STORAGE_HUAWEI_SSD, STORAGE_HUAWEI_SAS, STORAGE_HUAWEI_SATA, STORAGE_OPENSTACK_ISCSI, STORAGE_UCLOUD_CLOUD_NORMAL, STORAGE_UCLOUD_CLOUD_SSD, STORAGE_UCLOUD_LOCAL_NORMAL, STORAGE_UCLOUD_LOCAL_SSD, STORAGE_UCLOUD_EXCLUSIVE_LOCAL_DISK, - STORAGE_ZSTACK_LOCAL_STORAGE, STORAGE_ZSTACK_CEPH, + STORAGE_ZSTACK_LOCAL_STORAGE, STORAGE_ZSTACK_CEPH, STORAGE_GPFS, } - STORAGE_LIMITED_TYPES = []string{STORAGE_LOCAL, STORAGE_BAREMETAL, STORAGE_NAS, STORAGE_RBD, STORAGE_NFS} + STORAGE_LIMITED_TYPES = []string{STORAGE_LOCAL, STORAGE_BAREMETAL, STORAGE_NAS, STORAGE_RBD, STORAGE_NFS, STORAGE_GPFS} + + SHARED_FILE_STORAGE = []string{STORAGE_NFS, STORAGE_GPFS} + + // 目前来说只支持这些 + SHARED_STORAGE = []string{STORAGE_NFS, STORAGE_GPFS, STORAGE_RBD} + ATTACHABLE_STORAGE = []string{STORAGE_NFS, STORAGE_GPFS, STORAGE_RBD, STORAGE_LOCAL} ) diff --git a/pkg/cloudcommon/cmdline/parser.go b/pkg/cloudcommon/cmdline/parser.go index e90383dbe2..62a6f6c39f 100644 --- a/pkg/cloudcommon/cmdline/parser.go +++ b/pkg/cloudcommon/cmdline/parser.go @@ -109,6 +109,8 @@ func ParseDiskConfig(diskStr string, idx int) (*compute.DiskConfig, error) { diskConfig.Mountpoint = p } else if p == "autoextend" { diskConfig.SizeMb = -1 + } else if utils.IsInStringArray(p, compute.STORAGE_ALL_TYPES) { + diskConfig.Backend = p } else if strings.HasPrefix(p, "snapshot-") { // HACK: use snapshot creat disk format snapshot-id // example: snapshot-3140cecb-ccc4-4865-abae-3a5ba8c69d9b diff --git a/pkg/cloudcommon/db/opslog.go b/pkg/cloudcommon/db/opslog.go index e128c78cc9..3784e54bd4 100644 --- a/pkg/cloudcommon/db/opslog.go +++ b/pkg/cloudcommon/db/opslog.go @@ -33,16 +33,18 @@ import ( ) const ( - ACT_CREATE = "create" - ACT_DELETE = "delete" - ACT_UPDATE = "update" - ACT_FETCH = "fetch" - ACT_ENABLE = "enable" - ACT_DISABLE = "disable" - ACT_OFFLINE = "offline" - ACT_ONLINE = "online" - ACT_ATTACH = "attach" - ACT_DETACH = "detach" + ACT_CREATE = "create" + ACT_DELETE = "delete" + ACT_UPDATE = "update" + ACT_FETCH = "fetch" + ACT_ENABLE = "enable" + ACT_DISABLE = "disable" + ACT_OFFLINE = "offline" + ACT_ONLINE = "online" + ACT_ATTACH = "attach" + ACT_DETACH = "detach" + ACT_ATTACH_FAIL = "attach_fail" + ACT_DETACH_FAIL = "detach_fail" ACT_SYNC_UPDATE = "sync_update" ACT_SYNC_CREATE = "sync_create" diff --git a/pkg/compute/hostdrivers/kvm.go b/pkg/compute/hostdrivers/kvm.go index 113d7e1ab4..6edaf05a95 100644 --- a/pkg/compute/hostdrivers/kvm.go +++ b/pkg/compute/hostdrivers/kvm.go @@ -52,7 +52,7 @@ func (self *SKVMHostDriver) GetHypervisor() string { } func (self *SKVMHostDriver) ValidateAttachStorage(host *models.SHost, storage *models.SStorage, data *jsonutils.JSONDict) error { - if !utils.IsInStringArray(storage.StorageType, []string{api.STORAGE_LOCAL, api.STORAGE_RBD, api.STORAGE_NFS}) { + if !utils.IsInStringArray(storage.StorageType, api.ATTACHABLE_STORAGE) { return httperrors.NewUnsupportOperationError("Unsupport attach %s storage for %s host", storage.StorageType, host.HostType) } if storage.StorageType == api.STORAGE_RBD { @@ -61,7 +61,7 @@ func (self *SKVMHostDriver) ValidateAttachStorage(host *models.SHost, storage *m } pool, _ := storage.StorageConf.GetString("pool") data.Set("mount_point", jsonutils.NewString(fmt.Sprintf("rbd:%s", pool))) - } else if storage.StorageType == api.STORAGE_NFS { + } else if utils.IsInStringArray(storage.StorageType, api.SHARED_FILE_STORAGE) { if host.HostStatus != api.HOST_ONLINE { return httperrors.NewInvalidStatusError("Attach nfs storage require host status is online") } @@ -71,7 +71,7 @@ func (self *SKVMHostDriver) ValidateAttachStorage(host *models.SHost, storage *m 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 utils.IsInStringArray(storage.StorageType, []string{api.STORAGE_NFS, api.STORAGE_RBD}) { + if utils.IsInStringArray(storage.StorageType, api.ATTACHABLE_STORAGE) { 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()) @@ -99,7 +99,7 @@ func (self *SKVMHostDriver) RequestAttachStorage(ctx context.Context, hoststorag 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 utils.IsInStringArray(storage.StorageType, []string{api.STORAGE_NFS, api.STORAGE_RBD}) && host.HostStatus == api.HOST_ONLINE { + if utils.IsInStringArray(storage.StorageType, api.ATTACHABLE_STORAGE) && host.HostStatus == api.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()) diff --git a/pkg/compute/models/disks.go b/pkg/compute/models/disks.go index 47a84588c7..7b3260328a 100644 --- a/pkg/compute/models/disks.go +++ b/pkg/compute/models/disks.go @@ -647,6 +647,11 @@ func (self *SDisk) PerformCreateSnapshot(ctx context.Context, userCred mcclient. if len(guests) != 1 { return nil, httperrors.NewBadRequestError("Disk dosen't attach guest??") } + storage := self.GetStorage() + if guests[0].Hypervisor == api.HYPERVISOR_KVM && storage.StorageType != api.STORAGE_LOCAL { + return nil, httperrors.NewBadRequestError("storage %s not support snapshot", storage.StorageType) + } + dataDict := data.(*jsonutils.JSONDict) dataDict.Set("disk_id", jsonutils.NewString(self.Id)) return guests[0].PerformDiskSnapshot(ctx, userCred, query, dataDict) diff --git a/pkg/compute/models/guests.go b/pkg/compute/models/guests.go index 1655beaad8..ec9de21e1e 100644 --- a/pkg/compute/models/guests.go +++ b/pkg/compute/models/guests.go @@ -4143,7 +4143,9 @@ func (self *SGuest) FillDiskSchedDesc(desc *api.ServerConfigs) { for i := 0; i < len(guestDisks); i++ { diskConf := guestDisks[i].ToDiskConfig() // HACK: storage used by self, so earse it - diskConf.Storage = "" + if diskConf.DiskType == api.STORAGE_LOCAL { + diskConf.Storage = "" + } desc.Disks = append(desc.Disks, diskConf) } } diff --git a/pkg/compute/models/hosts.go b/pkg/compute/models/hosts.go index 33d0f9c66a..260b3ccd33 100644 --- a/pkg/compute/models/hosts.go +++ b/pkg/compute/models/hosts.go @@ -982,6 +982,9 @@ func parseDiskDriverSpec(driver string, adapterSpecs api.DiskAdapterSpec) []stri } func ConvertStorageInfo2BaremetalStorages(storageInfo jsonutils.JSONObject) []*baremetal.BaremetalStorage { + if storageInfo == nil { + return nil + } storages := []baremetal.BaremetalStorage{} err := storageInfo.Unmarshal(&storages) if err != nil { diff --git a/pkg/compute/models/storages.go b/pkg/compute/models/storages.go index e44ee5595a..559880b798 100644 --- a/pkg/compute/models/storages.go +++ b/pkg/compute/models/storages.go @@ -304,6 +304,7 @@ func (self *SStorage) PerformEnable(ctx context.Context, userCred mcclient.Token return nil, err } db.OpsLog.LogEvent(self, db.ACT_ENABLE, "", userCred) + self.ClearSchedDescCache() } return nil, nil } @@ -323,6 +324,7 @@ func (self *SStorage) PerformDisable(ctx context.Context, userCred mcclient.Toke return nil, err } db.OpsLog.LogEvent(self, db.ACT_DISABLE, "", userCred) + self.ClearSchedDescCache() } return nil, nil } @@ -338,6 +340,7 @@ func (self *SStorage) PerformOnline(ctx context.Context, userCred mcclient.Token return nil, err } db.OpsLog.LogEvent(self, db.ACT_ONLINE, "", userCred) + self.ClearSchedDescCache() } return nil, nil } @@ -353,6 +356,7 @@ func (self *SStorage) PerformOffline(ctx context.Context, userCred mcclient.Toke return nil, err } db.OpsLog.LogEvent(self, db.ACT_OFFLINE, "", userCred) + self.ClearSchedDescCache() } return nil, nil } @@ -385,7 +389,7 @@ func (self *SStorage) IsLocal() bool { } func (self *SStorage) GetStorageCachePath(mountPoint, imageCachePath string) string { - if self.StorageType == api.STORAGE_NFS { + if utils.IsInStringArray(self.StorageType, api.SHARED_FILE_STORAGE) { return path.Join(mountPoint, imageCachePath) } else { return imageCachePath @@ -569,6 +573,8 @@ func (self *SStorage) SyncStatusWithHosts() { status = self.Status if online == 0 { status = api.STORAGE_OFFLINE + } else { + status = api.STORAGE_ONLINE } } else if online > 0 { status = api.STORAGE_ONLINE diff --git a/pkg/compute/options/options.go b/pkg/compute/options/options.go index 63d733a9f6..e6d8074c60 100644 --- a/pkg/compute/options/options.go +++ b/pkg/compute/options/options.go @@ -84,7 +84,7 @@ type ComputeOptions struct { ConvertEsxiDefaultTemplate string `help:"ESXI baremetal convert option"` ConvertKubeletDockerVolumeSize string `default:"256g" help:"Docker volume size"` - NfsDefaultImageCacheDir string `default:"image_cache"` + DefaultImageCacheDir string `default:"image_cache"` SnapshotCreateDiskProtocol string `help:"Snapshot create disk protocol" choices:"url|fuse" default:"fuse"` diff --git a/pkg/compute/storagedrivers/gpfs.go b/pkg/compute/storagedrivers/gpfs.go new file mode 100644 index 0000000000..c5be759c5f --- /dev/null +++ b/pkg/compute/storagedrivers/gpfs.go @@ -0,0 +1,52 @@ +package storagedrivers + +import ( + "context" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + api "yunion.io/x/onecloud/pkg/apis/compute" + "yunion.io/x/onecloud/pkg/cloudcommon/db" + "yunion.io/x/onecloud/pkg/compute/models" + "yunion.io/x/onecloud/pkg/compute/options" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/pkg/util/timeutils" +) + +type SGpfsStorageDriver struct { + SBaseStorageDriver +} + +func init() { + driver := SGpfsStorageDriver{} + models.RegisterStorageDriver(&driver) +} + +func (self *SGpfsStorageDriver) GetStorageType() string { + return api.STORAGE_GPFS +} + +func (self *SGpfsStorageDriver) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) { + return data, nil +} + +func (self *SGpfsStorageDriver) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, storage *models.SStorage, data jsonutils.JSONObject) { + sc := &models.SStoragecache{} + sc.Path = options.Options.DefaultImageCacheDir + sc.ExternalId = storage.Id + timeutils.IsoTime(time.Now()) + sc.Name = "gpfs-" + storage.Name + timeutils.IsoTime(time.Now()) + if err := models.StoragecacheManager.TableSpec().Insert(sc); err != nil { + log.Errorf("insert storagecache for storage %s error: %v", storage.Name, err) + return + } + _, err := db.Update(storage, func() error { + storage.StoragecacheId = sc.Id + storage.Status = api.STORAGE_ONLINE + return nil + }) + if err != nil { + log.Errorf("update storagecache info for storage %s error: %v", storage.Name, err) + } +} diff --git a/pkg/compute/storagedrivers/nfs.go b/pkg/compute/storagedrivers/nfs.go index d9c7a3e9f4..79fc76a5e1 100644 --- a/pkg/compute/storagedrivers/nfs.go +++ b/pkg/compute/storagedrivers/nfs.go @@ -59,7 +59,7 @@ func (self *SNfsStorageDriver) ValidateCreateData(ctx context.Context, userCred func (self *SNfsStorageDriver) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, storage *models.SStorage, data jsonutils.JSONObject) { sc := &models.SStoragecache{} - sc.Path = options.Options.NfsDefaultImageCacheDir + sc.Path = options.Options.DefaultImageCacheDir sc.ExternalId = storage.Id sc.Name = "nfs-" + storage.Name + time.Now().Format("2006-01-02 15:04:05") if err := models.StoragecacheManager.TableSpec().Insert(sc); err != nil { diff --git a/pkg/compute/tasks/host_storage_attach_task.go b/pkg/compute/tasks/host_storage_attach_task.go index b8eb35c3c8..0406264c9c 100644 --- a/pkg/compute/tasks/host_storage_attach_task.go +++ b/pkg/compute/tasks/host_storage_attach_task.go @@ -23,6 +23,7 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/compute/models" + "yunion.io/x/onecloud/pkg/util/logclient" ) type HostStorageAttachTask struct { @@ -38,7 +39,8 @@ func (self *HostStorageAttachTask) taskFail(ctx context.Context, host *models.SH storage := hoststorage.GetStorage() hoststorage.Detach(ctx, self.GetUserCred()) note := fmt.Sprintf("attach host %s failed: %s", host.Name, reason) - db.OpsLog.LogEvent(storage, db.ACT_ATTACH, note, self.GetUserCred()) + db.OpsLog.LogEvent(storage, db.ACT_ATTACH_FAIL, note, self.GetUserCred()) + logclient.AddActionLogWithContext(ctx, storage, logclient.ACT_ATTACH_HOST, note, self.GetUserCred(), false) } self.SetStageFailed(ctx, reason) } @@ -70,6 +72,11 @@ func (self *HostStorageAttachTask) OnInit(ctx context.Context, obj db.IStandalon } func (self *HostStorageAttachTask) OnAttachStorageComplete(ctx context.Context, host *models.SHost, data jsonutils.JSONObject) { + storageId, _ := self.GetParams().GetString("storage_id") + storage := models.StorageManager.FetchStorageById(storageId) + db.OpsLog.LogEvent(storage, db.ACT_ATTACH, "", self.GetUserCred()) + logclient.AddActionLogWithContext(ctx, storage, logclient.ACT_ATTACH_HOST, + fmt.Sprintf("Attach host %s success", host.Name), self.GetUserCred(), true) self.SetStageComplete(ctx, nil) } diff --git a/pkg/scheduler/algorithm/predicates/disk_schedtag_predicate.go b/pkg/scheduler/algorithm/predicates/disk_schedtag_predicate.go index 1cf30b6f4d..add59ba20e 100644 --- a/pkg/scheduler/algorithm/predicates/disk_schedtag_predicate.go +++ b/pkg/scheduler/algorithm/predicates/disk_schedtag_predicate.go @@ -74,6 +74,10 @@ func (p *DiskSchedtagPredicate) GetResources(c core.Candidater) []ISchedtagCandi func (p *DiskSchedtagPredicate) IsResourceFitInput(u *core.Unit, c core.Candidater, res ISchedtagCandidateResource, input ISchedtagCustomer) error { storage := res.(*api.CandidateStorage) + if storage.Status == computeapi.STORAGE_OFFLINE || !storage.Enabled { + return fmt.Errorf("Storage status is %s, enable is %v", storage.Status, storage.Enabled) + } + d := input.(*diskW) if d.Storage != "" { if storage.Id != d.Storage && storage.Name != d.Storage { diff --git a/pkg/util/logclient/logclient.go b/pkg/util/logclient/logclient.go index 6dd0c9d154..1ccca9bcfc 100644 --- a/pkg/util/logclient/logclient.go +++ b/pkg/util/logclient/logclient.go @@ -140,6 +140,7 @@ const ( ACT_DELETE_BACKUP = "删除备份机" ACT_APPLY_SNAPSHOT_POLICY = "绑定快照策略" ACT_CANCEL_SNAPSHOT_POLICY = "取消快照策略" + ACT_ATTACH_HOST = "关联宿主机" ACT_IMAGE_SAVE = "上传镜像" ACT_IMAGE_PROBE = "镜像检测"