// Copyright 2019 Yunion // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package zstack import ( "fmt" "net/url" "strings" "yunion.io/x/jsonutils" "yunion.io/x/log" api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudprovider" ) type TStorageType string type TCephPoolType string const ( StorageTypeCeph = TStorageType("Ceph") StorageTypeLocal = TStorageType("LocalStorage") StorageTypeVCenter = TStorageType("VCenter") CephPoolTypeData = TCephPoolType("Data") CephPoolTypeRoot = TCephPoolType("Root") CephPoolTypeImageCache = TCephPoolType("ImageCache") ) type SPool struct { UUID string `json:"uuid"` PrimaryStorageUUID string `json:"primaryStorageUuid"` PoolName string `json:"poolName"` Type TCephPoolType `json:"type"` AvailableCapacity int64 `json:"availableCapacity"` UsedCapacity int64 `json:"usedCapacity"` ReplicatedSize int64 `json:"replicatedSize"` TotalCapacity int64 `json:"totalCapacity"` ZStackTime } type SStorage struct { region *SRegion ZStackBasic VCenterUUID string `json:"VCenterUuid"` Datastore string `json:"datastore"` ZoneUUID string `json:"zoneUuid"` URL string `json:"url"` TotalCapacity int64 `json:"totalCapacity"` AvailableCapacity int `json:"availableCapacity"` TotalPhysicalCapacity int `json:"totalPhysicalCapacity"` AvailablePhysicalCapacity int `json:"availablePhysicalCapacity"` Type TStorageType `json:"type"` State string `json:"state"` Status string `json:"status"` MountPath string `json:"mountPath"` AttachedClusterUUIDs []string `json:"attachedClusterUuids"` Pools []SPool `json:"pools"` ZStackTime } func (region *SRegion) getIStorages(zondId string) ([]cloudprovider.ICloudStorage, error) { primaryStorages, err := region.GetStorages(zondId, "", "") if err != nil { return nil, err } istorage := []cloudprovider.ICloudStorage{} for i := 0; i < len(primaryStorages); i++ { primaryStorage := primaryStorages[i] switch primaryStorage.Type { case StorageTypeLocal: ilocalStorages, err := region.getILocalStorages(primaryStorage.UUID, "") if err != nil { return nil, err } istorage = append(istorage, ilocalStorages...) case StorageTypeCeph: primaryStorage.region = region istorage = append(istorage, &primaryStorage) case StorageTypeVCenter: } } return istorage, nil } func (region *SRegion) GetStorage(storageId string) (*SStorage, error) { if len(storageId) == 0 { return nil, cloudprovider.ErrNotFound } storages, err := region.GetStorages("", "", storageId) if err != nil { return nil, err } if len(storages) == 1 && storages[0].UUID == storageId { storages[0].region = region return &storages[0], nil } if len(storages) == 0 { return nil, cloudprovider.ErrNotFound } return nil, cloudprovider.ErrDuplicateId } func (region *SRegion) GetStorages(zoneId, clusterId, storageId string) ([]SStorage, error) { storages := []SStorage{} params := url.Values{} if len(zoneId) > 0 { params.Add("q", "zone.uuid="+zoneId) } if len(clusterId) > 0 { params.Add("q", "cluster.uuid="+clusterId) } if SkipEsxi { params.Add("q", "type!=VCenter") } if len(storageId) > 0 { params.Add("q", "uuid="+storageId) } return storages, region.client.listAll("primary-storage", params, &storages) } func (storage *SStorage) GetStatus() string { if storage.Status == "Connected" { return api.STORAGE_ONLINE } return api.STORAGE_OFFLINE } func (storage *SStorage) GetMetadata() *jsonutils.JSONDict { return nil } func (storage *SStorage) GetId() string { return storage.UUID } func (storage *SStorage) GetName() string { return storage.Name } func (storage *SStorage) GetGlobalId() string { return storage.GetId() } func (storage *SStorage) IsEmulated() bool { return false } func (storage *SStorage) GetIZone() cloudprovider.ICloudZone { zone, err := storage.region.GetZone(storage.ZoneUUID) if err != nil { log.Errorf("failed to find zone for storage %s(%s)", storage.Name, storage.UUID) return nil } return zone } func (storage *SStorage) GetIDisks() ([]cloudprovider.ICloudDisk, error) { disks, err := storage.region.GetDisks(storage.UUID, []string{}, "") if err != nil { return nil, err } idisks := []cloudprovider.ICloudDisk{} for i := 0; i < len(disks); i++ { disks[i].storage = storage disks[i].region = storage.region idisks = append(idisks, &disks[i]) } return idisks, nil } func (storage *SStorage) GetStorageType() string { return strings.ToLower(string(storage.Type)) } func (storage *SStorage) GetMediumType() string { return api.DISK_TYPE_ROTATE } func (storage *SStorage) GetCapacityMB() int64 { return storage.TotalCapacity / 1024 / 1024 } func (storage *SStorage) GetStorageConf() jsonutils.JSONObject { conf := jsonutils.NewDict() return conf } func (storage *SStorage) Refresh() error { // do nothing return nil } func (storage *SStorage) GetEnabled() bool { return true } func (storage *SStorage) GetIStoragecache() cloudprovider.ICloudStoragecache { return &SStoragecache{ZoneId: storage.ZoneUUID, region: storage.region} } func (storage *SStorage) CreateIDisk(name string, sizeGb int, desc string) (cloudprovider.ICloudDisk, error) { poolName, err := storage.GetDataPoolName() if err != nil { return nil, err } disk, err := storage.region.CreateDisk(name, storage.UUID, "", poolName, sizeGb, desc) if err != nil { return nil, err } disk.storage = storage return disk, nil } func (storage *SStorage) GetIDiskById(diskId string) (cloudprovider.ICloudDisk, error) { disk, err := storage.region.GetDisk(diskId) if err != nil { return nil, err } if disk.PrimaryStorageUUID != storage.UUID { return nil, cloudprovider.ErrNotFound } disk.region = storage.region disk.storage = storage return disk, nil } func (storage *SStorage) GetMountPoint() string { poolName, _ := storage.GetDataPoolName() if len(poolName) > 0 { return fmt.Sprintf("ceph://%s", poolName) } return "" } func (storage *SStorage) IsSysDiskStore() bool { return true } func (storage *SStorage) GetDataPoolName() (string, error) { for _, pool := range storage.Pools { if pool.Type == CephPoolTypeData { return pool.PoolName, nil } } return "", fmt.Errorf("failed to found storage %s(%s) data pool name", storage.Name, storage.UUID) }