yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/hcso/zone.go (about) 1 // Copyright 2019 Yunion 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package hcso 16 17 import ( 18 "fmt" 19 20 "yunion.io/x/log" 21 "yunion.io/x/pkg/errors" 22 23 api "yunion.io/x/cloudmux/pkg/apis/compute" 24 "yunion.io/x/cloudmux/pkg/cloudprovider" 25 "yunion.io/x/cloudmux/pkg/multicloud" 26 "yunion.io/x/cloudmux/pkg/multicloud/huawei" 27 ) 28 29 var StorageTypes = []string{ 30 api.STORAGE_HUAWEI_SAS, 31 api.STORAGE_HUAWEI_SATA, 32 api.STORAGE_HUAWEI_SSD, 33 } 34 35 type ZoneState struct { 36 Available bool `json:"available"` 37 } 38 39 // https://support.huaweicloud.com/api-ecs/zh-cn_topic_0065817728.html 40 type SZone struct { 41 multicloud.SResourceBase 42 huawei.HuaweiTags 43 region *SRegion 44 ihosts []cloudprovider.ICloudHost 45 46 iwires []cloudprovider.ICloudWire 47 istorages []cloudprovider.ICloudStorage 48 49 ZoneState ZoneState `json:"zoneState"` 50 ZoneName string `json:"zoneName"` 51 52 /* 支持的磁盘种类集合 */ 53 storageTypes []string 54 } 55 56 func (self *SZone) addWire(wire *SWire) { 57 if self.iwires == nil { 58 self.iwires = make([]cloudprovider.ICloudWire, 0) 59 } 60 self.iwires = append(self.iwires, wire) 61 } 62 63 func (self *SZone) getStorageType() { 64 if len(self.storageTypes) == 0 { 65 if sts, err := self.region.GetZoneSupportedDiskTypes(self.GetId()); err == nil { 66 self.storageTypes = sts 67 } else { 68 log.Errorf("GetZoneSupportedDiskTypes %s %s", self.GetId(), err) 69 self.storageTypes = StorageTypes 70 } 71 } 72 } 73 74 func (self *SZone) fetchStorages() error { 75 self.getStorageType() 76 self.istorages = make([]cloudprovider.ICloudStorage, len(self.storageTypes)) 77 78 for i, sc := range self.storageTypes { 79 storage := SStorage{zone: self, storageType: sc} 80 self.istorages[i] = &storage 81 } 82 return nil 83 } 84 85 // 华为私有云没有直接列出host的接口,所有账号下的host都是通过VM反向解析出来的 86 // 当账号下没有虚拟机时,如果没有host,会导致调度找不到可用的HOST。 87 // 因此,为了避免上述情况始终会在每个zone下返回一台虚拟的host 88 func (self *SZone) getEmulatedHost() SHost { 89 return SHost{ 90 zone: self, 91 vms: nil, 92 IsFake: true, 93 projectId: self.region.client.projectId, 94 Id: fmt.Sprintf("%s-%s", self.region.client.cpcfg.Id, self.GetId()), 95 Name: fmt.Sprintf("%s-%s", self.region.client.cpcfg.Name, self.GetId()), 96 } 97 } 98 99 func (self *SZone) getHosts() ([]cloudprovider.ICloudHost, error) { 100 if self.ihosts != nil { 101 return self.ihosts, nil 102 } 103 104 vms, err := self.region.GetInstances() 105 if err != nil { 106 return nil, errors.Wrap(err, "GetInstances") 107 } 108 109 hosts := map[string]string{} 110 hostVms := map[string][]SInstance{} 111 for i := range vms { 112 vm := vms[i] 113 if vm.OSEXTAZAvailabilityZone == self.GetId() { 114 hosts[vm.HostID] = vm.OSEXTSRVATTRHost 115 if _, ok := hostVms[vm.HostID]; ok { 116 hostVms[vm.HostID] = append(hostVms[vm.HostID], vm) 117 } else { 118 hostVms[vm.HostID] = []SInstance{vm} 119 } 120 } 121 } 122 123 fakeHost := self.getEmulatedHost() 124 ihosts := []cloudprovider.ICloudHost{&fakeHost} 125 for k, _ := range hosts { 126 h := SHost{ 127 zone: self, 128 projectId: self.region.client.projectId, 129 Id: k, 130 Name: hosts[k], 131 } 132 for i := range hostVms[k] { 133 hostVms[k][i].host = &h 134 } 135 136 h.vms = hostVms[k] 137 ihosts = append(ihosts, &h) 138 } 139 140 return ihosts, nil 141 } 142 143 func (self *SZone) GetId() string { 144 return self.ZoneName 145 } 146 147 func (self *SZone) GetName() string { 148 return fmt.Sprintf("%s %s", CLOUD_PROVIDER_HUAWEI_CN, self.ZoneName) 149 } 150 151 func (self *SZone) GetI18n() cloudprovider.SModelI18nTable { 152 en := fmt.Sprintf("%s %s", CLOUD_PROVIDER_HUAWEI_EN, self.ZoneName) 153 table := cloudprovider.SModelI18nTable{} 154 table["name"] = cloudprovider.NewSModelI18nEntry(self.GetName()).CN(self.GetName()).EN(en) 155 return table 156 } 157 158 func (self *SZone) GetGlobalId() string { 159 return fmt.Sprintf("%s/%s", self.region.GetGlobalId(), self.ZoneName) 160 } 161 162 func (self *SZone) GetStatus() string { 163 return "enable" 164 } 165 166 func (self *SZone) Refresh() error { 167 return nil 168 } 169 170 func (self *SZone) IsEmulated() bool { 171 return false 172 } 173 174 func (self *SZone) GetIRegion() cloudprovider.ICloudRegion { 175 return self.region 176 } 177 178 func (self *SZone) GetIHosts() ([]cloudprovider.ICloudHost, error) { 179 return self.getHosts() 180 } 181 182 func (self *SZone) GetIHostById(id string) (cloudprovider.ICloudHost, error) { 183 ihosts, err := self.getHosts() 184 if err != nil { 185 return nil, errors.Wrap(err, "getHosts") 186 } 187 188 for i := range ihosts { 189 if ihosts[i].GetGlobalId() == id { 190 return ihosts[i], nil 191 } 192 } 193 194 return nil, cloudprovider.ErrNotFound 195 } 196 197 func (self *SZone) GetIStorages() ([]cloudprovider.ICloudStorage, error) { 198 if self.istorages == nil { 199 err := self.fetchStorages() 200 if err != nil { 201 return nil, errors.Wrapf(err, "fetchStorages") 202 } 203 } 204 return self.istorages, nil 205 } 206 207 func (self *SZone) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { 208 if self.istorages == nil { 209 err := self.fetchStorages() 210 if err != nil { 211 return nil, errors.Wrapf(err, "fetchStorages") 212 } 213 } 214 for i := 0; i < len(self.istorages); i += 1 { 215 if self.istorages[i].GetGlobalId() == id { 216 return self.istorages[i], nil 217 } 218 } 219 return nil, cloudprovider.ErrNotFound 220 } 221 222 func (self *SZone) GetIWires() ([]cloudprovider.ICloudWire, error) { 223 return self.iwires, nil 224 } 225 226 func (self *SZone) getStorageByCategory(category string) (*SStorage, error) { 227 storages, err := self.GetIStorages() 228 if err != nil { 229 return nil, err 230 } 231 for i := 0; i < len(storages); i += 1 { 232 storage := storages[i].(*SStorage) 233 if storage.storageType == category { 234 return storage, nil 235 } 236 } 237 return nil, fmt.Errorf("No such storage %s", category) 238 } 239 240 func (self *SRegion) getZoneById(id string) (*SZone, error) { 241 izones, err := self.GetIZones() 242 if err != nil { 243 return nil, err 244 } 245 for i := 0; i < len(izones); i += 1 { 246 zone := izones[i].(*SZone) 247 if zone.GetId() == id { 248 return zone, nil 249 } 250 } 251 return nil, fmt.Errorf("no such zone %s", id) 252 } 253 254 func (self *SZone) getNetworkById(networkId string) *SNetwork { 255 for i := 0; i < len(self.iwires); i += 1 { 256 wire := self.iwires[i].(*SWire) 257 net := wire.getNetworkById(networkId) 258 if net != nil { 259 return net 260 } 261 } 262 return nil 263 }