diff --git a/pkg/multicloud/openstack/host.go b/pkg/multicloud/openstack/host.go index b2d57f48a7..a13482ffdd 100644 --- a/pkg/multicloud/openstack/host.go +++ b/pkg/multicloud/openstack/host.go @@ -17,7 +17,6 @@ package openstack import ( "fmt" "strconv" - "strings" "time" "github.com/pkg/errors" @@ -121,25 +120,13 @@ func (host *SHost) GetIStorages() ([]cloudprovider.ICloudStorage, error) { return nil, err } - schedulerPools, err := host.zone.getSchedulerStatsPool() - if err != nil { - return nil, err - } - + storageTypes := host.zone.getAvailableStorages() + storageTypes = append(storageTypes, host.zone.getUnavailableStorage()...) result := []cloudprovider.ICloudStorage{} for _, istorage := range istorages { - if istorage.GetStorageType() == api.STORAGE_OPENSTACK_NOVA { + if utils.IsInStringArray(istorage.GetStorageType(), storageTypes) { result = append(result, istorage) - continue - } - if storage := istorage.(*SStorage); len(storage.ExtraSpecs.VolumeBackendName) > 0 { - for _, pool := range schedulerPools { - if strings.HasPrefix(pool.Name, fmt.Sprintf("%s@%s", host.GetName(), storage.ExtraSpecs.VolumeBackendName)) { - result = append(result, istorage) - break - } - } } } return result, nil @@ -213,12 +200,12 @@ func (host *SHost) CreateVM(desc *cloudprovider.SManagedVMCreateConfig) (cloudpr BlockDeviceMappingV2 := []map[string]interface{}{} if desc.SysDisk.StorageType != api.STORAGE_OPENSTACK_NOVA { //新建volume - storage, err := host.zone.getStorageByCategory(desc.SysDisk.StorageType) + istorage, err := host.zone.GetIStorageById(desc.SysDisk.StorageExternalId) if err != nil { - return nil, err + return nil, errors.Wrapf(err, "GetIStorageById(%s)", desc.SysDisk.StorageExternalId) } - _sysDisk, err := host.zone.region.CreateDisk(desc.ExternalImageId, storage.Name, "", desc.SysDisk.SizeGB, desc.SysDisk.Name) + _sysDisk, err := host.zone.region.CreateDisk(desc.ExternalImageId, istorage.GetName(), "", desc.SysDisk.SizeGB, desc.SysDisk.Name) if err != nil { return nil, err } @@ -234,11 +221,11 @@ func (host *SHost) CreateVM(desc *cloudprovider.SManagedVMCreateConfig) (cloudpr var _disk *SDisk for _, disk := range desc.DataDisks { - storage, err := host.zone.getStorageByCategory(disk.StorageType) + istorage, err := host.zone.GetIStorageById(disk.StorageExternalId) if err != nil { break } - _disk, err = host.zone.region.CreateDisk("", storage.Name, "", disk.SizeGB, disk.Name) + _disk, err = host.zone.region.CreateDisk("", istorage.GetName(), "", disk.SizeGB, disk.Name) if err != nil { break } diff --git a/pkg/multicloud/openstack/shell/storage.go b/pkg/multicloud/openstack/shell/storage.go index f9430d52df..7ea2e90530 100644 --- a/pkg/multicloud/openstack/shell/storage.go +++ b/pkg/multicloud/openstack/shell/storage.go @@ -38,4 +38,23 @@ func init() { printList(storages, 0, 0, 0, []string{}) return nil }) + + type CinderServiceListOptions struct { + REGION string `help:"Region Name"` + ZONE string `help:"Zone Name"` + } + + shellutils.R(&CinderServiceListOptions{}, "cinder-service-list", "List cinder services", func(cli *openstack.SRegion, args *CinderServiceListOptions) error { + izone, err := cli.GetIZoneById(fmt.Sprintf("%s/%s/%s", openstack.CLOUD_PROVIDER_OPENSTACK, args.REGION, args.ZONE)) + if err != nil { + return err + } + zone := izone.(*openstack.SZone) + services, err := zone.GetCinderServices() + if err != nil { + return err + } + printList(services, 0, 0, 0, []string{}) + return nil + }) } diff --git a/pkg/multicloud/openstack/storage.go b/pkg/multicloud/openstack/storage.go index 6277fa86f6..728225bef0 100644 --- a/pkg/multicloud/openstack/storage.go +++ b/pkg/multicloud/openstack/storage.go @@ -20,11 +20,16 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/log" + "yunion.io/x/pkg/utils" api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudprovider" ) +const ( + DEFAULT_STORAGE_TYPE = "scheduler" +) + type SExtraSpecs struct { VolumeBackendName string } @@ -74,7 +79,10 @@ func (storage *SStorage) GetIDisks() ([]cloudprovider.ICloudDisk, error) { } func (storage *SStorage) GetStorageType() string { - return strings.ToLower(storage.Name) + if len(storage.ExtraSpecs.VolumeBackendName) == 0 { + storage.ExtraSpecs.VolumeBackendName = DEFAULT_STORAGE_TYPE + } + return storage.ExtraSpecs.VolumeBackendName } func (storage *SStorage) GetMediumType() string { @@ -94,7 +102,10 @@ func (storage *SStorage) GetStorageConf() jsonutils.JSONObject { } func (storage *SStorage) GetStatus() string { - return api.STORAGE_ONLINE + if utils.IsInStringArray(storage.GetStorageType(), storage.zone.getAvailableStorages()) { + return api.STORAGE_ONLINE + } + return api.STORAGE_OFFLINE } func (storage *SStorage) Refresh() error { diff --git a/pkg/multicloud/openstack/zone.go b/pkg/multicloud/openstack/zone.go index f23f73add2..0236be3c81 100644 --- a/pkg/multicloud/openstack/zone.go +++ b/pkg/multicloud/openstack/zone.go @@ -59,7 +59,9 @@ type SZone struct { cachedHosts map[string][]string - schedulerPools []SPool + schedulerPools []SPool + availableStorages []string + unavailableStorages []string Hosts map[string]map[string]HostState } @@ -175,6 +177,74 @@ func (zone *SZone) fetchStorages() error { return fmt.Errorf("failed to find storage types by cinder service") } +type SCinderService struct { + ActiveBackendId string + // cinder-volume + Binary string + DisabledReason string + Frozen string + Host string + ReplicationStatus string + State string + Status string + UpdatedAt time.Time + Zone string +} + +func (zone *SZone) GetCinderServices() ([]SCinderService, error) { + _, resp, err := zone.region.CinderList("/os-services", "", nil) + if err != nil { + return nil, errors.Wrap(err, "CinderList") + } + services := []SCinderService{} + err = resp.Unmarshal(&services, "services") + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return services, nil +} + +func (zone *SZone) fetchCinderSerivces() error { + services, err := zone.GetCinderServices() + if err != nil { + return errors.Wrap(err, "GetCinderServices") + } + zone.availableStorages = []string{DEFAULT_STORAGE_TYPE, api.STORAGE_OPENSTACK_NOVA} + zone.unavailableStorages = []string{} + for _, service := range services { + if service.Binary == "cinder-volume" && strings.Contains(service.Host, "@") { + hostInfo := strings.Split(service.Host, "@") + storage := hostInfo[len(hostInfo)-1] + if service.State == "up" && service.Status == "enabled" { + zone.availableStorages = append(zone.availableStorages, storage) + continue + } + zone.unavailableStorages = append(zone.unavailableStorages, storage) + } + } + return nil +} + +func (zone *SZone) getAvailableStorages() []string { + if zone.availableStorages == nil { + err := zone.fetchCinderSerivces() + if err != nil { + log.Errorf("fetchCinderSerivces error: %v", err) + } + } + return zone.availableStorages +} + +func (zone *SZone) getUnavailableStorage() []string { + if zone.unavailableStorages == nil { + err := zone.fetchCinderSerivces() + if err != nil { + log.Errorf("fetchCinderSerivces error: %v", err) + } + } + return zone.unavailableStorages +} + func (zone *SZone) GetIStorages() ([]cloudprovider.ICloudStorage, error) { if zone.istorages == nil { zone.fetchStorages()