yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/qcloud/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 qcloud 16 17 import ( 18 "fmt" 19 "strings" 20 "time" 21 22 "yunion.io/x/log" 23 "yunion.io/x/pkg/errors" 24 "yunion.io/x/pkg/utils" 25 26 api "yunion.io/x/cloudmux/pkg/apis/compute" 27 "yunion.io/x/cloudmux/pkg/cloudprovider" 28 "yunion.io/x/cloudmux/pkg/multicloud" 29 ) 30 31 type InstanceChargeType string 32 33 const ( 34 PrePaidInstanceChargeType InstanceChargeType = "PREPAID" 35 PostPaidInstanceChargeType InstanceChargeType = "POSTPAID_BY_HOUR" 36 CdhPaidInstanceChargeType InstanceChargeType = "CDHPAID" 37 DefaultInstanceChargeType = PostPaidInstanceChargeType 38 ) 39 40 type SZone struct { 41 multicloud.SResourceBase 42 QcloudTags 43 region *SRegion 44 45 iwires []cloudprovider.ICloudWire 46 47 host *SHost 48 49 istorages []cloudprovider.ICloudStorage 50 51 instanceTypes []string 52 refreshTime time.Time 53 localstorages []string 54 cloudstorages []string 55 56 Zone string 57 ZoneName string 58 ZoneState string 59 } 60 61 func (self *SZone) GetId() string { 62 return self.Zone 63 } 64 65 func (self *SZone) GetName() string { 66 return self.ZoneName 67 } 68 69 func (self *SZone) GetI18n() cloudprovider.SModelI18nTable { 70 en := self.ZoneName 71 table := cloudprovider.SModelI18nTable{} 72 table["name"] = cloudprovider.NewSModelI18nEntry(self.GetName()).CN(self.GetName()).EN(en) 73 return table 74 } 75 76 func (self *SZone) GetGlobalId() string { 77 return fmt.Sprintf("%s/%s", self.region.GetGlobalId(), self.Zone) 78 } 79 80 func (self *SZone) IsEmulated() bool { 81 return false 82 } 83 84 func (self *SZone) Refresh() error { 85 // do nothing 86 return nil 87 } 88 89 func (self *SZone) GetStatus() string { 90 if self.ZoneState == "AVAILABLE" { 91 return api.ZONE_ENABLE 92 } 93 return api.ZONE_SOLDOUT 94 } 95 96 func (self *SZone) GetIHostById(id string) (cloudprovider.ICloudHost, error) { 97 host := self.getHost() 98 if host.GetGlobalId() == id { 99 return host, nil 100 } 101 return nil, cloudprovider.ErrNotFound 102 } 103 104 func (self *SZone) GetIHosts() ([]cloudprovider.ICloudHost, error) { 105 return []cloudprovider.ICloudHost{self.getHost()}, nil 106 } 107 108 func (self *SZone) getHost() *SHost { 109 if self.host == nil { 110 self.host = &SHost{zone: self} 111 } 112 return self.host 113 } 114 115 func (self *SZone) GetIRegion() cloudprovider.ICloudRegion { 116 return self.region 117 } 118 119 type SDiskConfigSet struct { 120 Available bool 121 DeviceClass string 122 DiskChargeType string 123 DiskType string 124 DiskUsage string 125 InstanceFamily string 126 MaxDiskSize int 127 MinDiskSize int 128 Zone string 129 } 130 131 func (self *SRegion) GetDiskConfigSet(zoneName string) ([]SDiskConfigSet, error) { 132 params := map[string]string{} 133 params["Region"] = self.Region 134 params["Zones.0"] = zoneName 135 params["InquiryType"] = "INQUIRY_CBS_CONFIG" 136 body, err := self.cbsRequest("DescribeDiskConfigQuota", params) 137 if err != nil { 138 return nil, err 139 } 140 diskConfigSet := []SDiskConfigSet{} 141 return diskConfigSet, body.Unmarshal(&diskConfigSet, "DiskConfigSet") 142 } 143 144 func (self *SZone) fetchStorages() error { 145 self.istorages = []cloudprovider.ICloudStorage{} 146 diskConfigSet, err := self.region.GetDiskConfigSet(self.Zone) 147 if err != nil { 148 return err 149 } 150 self.cloudstorages = []string{} 151 for _, diskConfig := range diskConfigSet { 152 if !utils.IsInStringArray(strings.ToUpper(diskConfig.DiskType), self.cloudstorages) { 153 self.cloudstorages = append(self.cloudstorages, strings.ToUpper(diskConfig.DiskType)) 154 storage := SStorage{zone: self, storageType: diskConfig.DiskType, available: diskConfig.Available} 155 self.istorages = append(self.istorages, &storage) 156 } 157 } 158 for _, storageType := range []string{"CLOUD_PREMIUM", "CLOUD_SSD", "CLOUD_BASIC"} { 159 if !utils.IsInStringArray(storageType, self.cloudstorages) { 160 self.cloudstorages = append(self.cloudstorages, storageType) 161 storage := SStorage{zone: self, storageType: storageType, available: false} 162 self.istorages = append(self.istorages, &storage) 163 } 164 } 165 self.localstorages, err = self.region.GetZoneLocalStorages(self.Zone) 166 if err != nil { 167 log.Errorf("falied to fetch local storage for zone %s", self.Zone) 168 } 169 for _, localstorageType := range self.localstorages { 170 storage := SLocalStorage{zone: self, storageType: localstorageType, available: true} 171 self.istorages = append(self.istorages, &storage) 172 } 173 for _, storageType := range QCLOUD_LOCAL_STORAGE_TYPES { 174 if !utils.IsInStringArray(storageType, self.localstorages) { 175 storage := SLocalStorage{zone: self, storageType: storageType, available: false} 176 self.istorages = append(self.istorages, &storage) 177 } 178 } 179 return nil 180 } 181 182 func (self *SZone) GetIStorages() ([]cloudprovider.ICloudStorage, error) { 183 if self.istorages == nil { 184 err := self.fetchStorages() 185 if err != nil { 186 return nil, errors.Wrapf(err, "fetchStorages") 187 } 188 } 189 return self.istorages, nil 190 } 191 192 func (self *SZone) getLocalStorageByCategory(category string) (*SLocalStorage, error) { 193 if len(self.localstorages) == 0 { 194 err := self.fetchStorages() 195 if err != nil { 196 return nil, errors.Wrap(err, "fetchStorages") 197 } 198 } 199 if utils.IsInStringArray(strings.ToUpper(category), self.localstorages) { 200 return &SLocalStorage{zone: self, storageType: strings.ToUpper(category)}, nil 201 } 202 return nil, fmt.Errorf("No such storage %s", category) 203 } 204 205 func (self *SZone) validateStorageType(category string) error { 206 if len(self.localstorages) == 0 || len(self.cloudstorages) == 0 { 207 err := self.fetchStorages() 208 if err != nil { 209 return errors.Wrap(err, "fetchStorages") 210 } 211 } 212 if utils.IsInStringArray(strings.ToUpper(category), self.localstorages) || utils.IsInStringArray(strings.ToUpper(category), self.cloudstorages) { 213 return nil 214 } 215 return fmt.Errorf("No such storage %s", category) 216 } 217 218 func (self *SZone) getStorageByCategory(category string) (*SStorage, error) { 219 storages, err := self.GetIStorages() 220 if err != nil { 221 return nil, err 222 } 223 for i := 0; i < len(storages); i++ { 224 if utils.IsInStringArray(storages[i].GetStorageType(), self.localstorages) { 225 continue 226 //return &SStorage{zone: self, storageType: strings.ToUpper(storages[i].GetStorageType())}, nil 227 } 228 storage := storages[i].(*SStorage) 229 if strings.ToLower(storage.storageType) == strings.ToLower(category) { 230 return storage, nil 231 } 232 } 233 return nil, fmt.Errorf("No such storage %s", category) 234 } 235 236 func (self *SZone) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { 237 if self.istorages == nil { 238 err := self.fetchStorages() 239 if err != nil { 240 return nil, errors.Wrapf(err, "fetchStorages") 241 } 242 } 243 for i := 0; i < len(self.istorages); i += 1 { 244 if self.istorages[i].GetGlobalId() == id { 245 return self.istorages[i], nil 246 } 247 } 248 return nil, cloudprovider.ErrNotFound 249 } 250 251 func (self *SZone) addWire(wire *SWire) { 252 if self.iwires == nil { 253 self.iwires = make([]cloudprovider.ICloudWire, 0) 254 } 255 self.iwires = append(self.iwires, wire) 256 } 257 258 func (self *SZone) GetIWires() ([]cloudprovider.ICloudWire, error) { 259 return self.iwires, nil 260 } 261 262 func (self *SZone) getNetworkById(networkId string) *SNetwork { 263 log.Debugf("Search in wires %d", len(self.iwires)) 264 for i := 0; i < len(self.iwires); i += 1 { 265 log.Debugf("Search in wire %s", self.iwires[i].GetName()) 266 wire := self.iwires[i].(*SWire) 267 net := wire.getNetworkById(networkId) 268 if net != nil { 269 return net 270 } 271 } 272 return nil 273 } 274 275 func (self *SZone) fetchInstanceTypes() { 276 self.instanceTypes = []string{} 277 params := map[string]string{} 278 params["Region"] = self.region.Region 279 params["Filters.0.Name"] = "zone" 280 params["Filters.0.Values.0"] = self.Zone 281 if body, err := self.region.cvmRequest("DescribeInstanceTypeConfigs", params, true); err != nil { 282 log.Errorf("DescribeInstanceTypeConfigs error: %v", err) 283 } else if configSet, err := body.GetArray("InstanceTypeConfigSet"); err != nil { 284 log.Errorf("Get InstanceTypeConfigSet error: %v", err) 285 } else { 286 for _, config := range configSet { 287 if instanceType, err := config.GetString("InstanceType"); err == nil && !utils.IsInStringArray(instanceType, self.instanceTypes) { 288 self.instanceTypes = append(self.instanceTypes, instanceType) 289 } 290 } 291 self.refreshTime = time.Now() 292 } 293 } 294 295 func (self *SZone) getAvaliableInstanceTypes() []string { 296 if self.instanceTypes == nil || len(self.instanceTypes) == 0 || time.Now().Sub(self.refreshTime).Hours() > refreshHours() { 297 self.fetchInstanceTypes() 298 } 299 return self.instanceTypes 300 } 301 302 func refreshHours() float64 { 303 return 5 304 } 305 306 func (self *SZone) getCosEndpoint() string { 307 return fmt.Sprintf("cos.%s.myqcloud.com", self.GetId()) 308 } 309 310 func (self *SZone) getCosWebsiteEndpoint() string { 311 return fmt.Sprintf("cos-website.%s.myqcloud.com", self.GetId()) 312 }