yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/qcloud/provider/provider.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 provider 16 17 import ( 18 "context" 19 "fmt" 20 "strings" 21 22 "yunion.io/x/jsonutils" 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/onecloud/pkg/httperrors" 29 "yunion.io/x/onecloud/pkg/mcclient" 30 "yunion.io/x/cloudmux/pkg/multicloud/qcloud" 31 ) 32 33 type SQcloudProviderFactory struct { 34 cloudprovider.SPublicCloudBaseProviderFactory 35 } 36 37 func (self *SQcloudProviderFactory) GetId() string { 38 return qcloud.CLOUD_PROVIDER_QCLOUD 39 } 40 41 func (self *SQcloudProviderFactory) GetName() string { 42 return qcloud.CLOUD_PROVIDER_QCLOUD_CN 43 } 44 45 func (self *SQcloudProviderFactory) IsCloudeventRegional() bool { 46 return true 47 } 48 49 func (self *SQcloudProviderFactory) GetMaxCloudEventSyncDays() int { 50 return 7 51 } 52 53 func (self *SQcloudProviderFactory) GetMaxCloudEventKeepDays() int { 54 return 30 55 } 56 57 func (self *SQcloudProviderFactory) IsSupportCloudIdService() bool { 58 return true 59 } 60 61 func (self *SQcloudProviderFactory) IsSupportCreateCloudgroup() bool { 62 return true 63 } 64 65 func (self *SQcloudProviderFactory) IsSupportSAMLAuth() bool { 66 return true 67 } 68 69 func (self *SQcloudProviderFactory) IsSupportCrossCloudEnvVpcPeering() bool { 70 return false 71 } 72 73 func (self *SQcloudProviderFactory) IsSupportCrossRegionVpcPeering() bool { 74 return true 75 } 76 77 func (self *SQcloudProviderFactory) IsSupportVpcPeeringVpcCidrOverlap() bool { 78 return false 79 } 80 81 func (self *SQcloudProviderFactory) ValidateCrossRegionVpcPeeringBandWidth(bandwidth int) error { 82 validatedBandwidths := []int{10, 20, 50, 100, 200, 500, 1000} 83 ok, _ := utils.InArray(bandwidth, validatedBandwidths) 84 if ok { 85 return nil 86 } 87 return httperrors.NewInputParameterError("require validated qcloud cross region vpcPeering bandwidth values:[10, 20, 50, 100, 200, 500, 1000],unit Mbps") 88 } 89 90 func (self *SQcloudProviderFactory) GetSupportedDnsZoneTypes() []cloudprovider.TDnsZoneType { 91 return []cloudprovider.TDnsZoneType{ 92 cloudprovider.PublicZone, 93 } 94 } 95 96 func (self *SQcloudProviderFactory) GetSupportedDnsTypes() map[cloudprovider.TDnsZoneType][]cloudprovider.TDnsType { 97 return map[cloudprovider.TDnsZoneType][]cloudprovider.TDnsType{ 98 cloudprovider.PublicZone: []cloudprovider.TDnsType{ 99 cloudprovider.DnsTypeA, 100 cloudprovider.DnsTypeAAAA, 101 cloudprovider.DnsTypeCNAME, 102 cloudprovider.DnsTypeMX, 103 cloudprovider.DnsTypeNS, 104 cloudprovider.DnsTypeSRV, 105 cloudprovider.DnsTypeTXT, 106 cloudprovider.DnsTypePTR, 107 }, 108 } 109 } 110 111 func (self *SQcloudProviderFactory) GetSupportedDnsPolicyTypes() map[cloudprovider.TDnsZoneType][]cloudprovider.TDnsPolicyType { 112 return map[cloudprovider.TDnsZoneType][]cloudprovider.TDnsPolicyType{ 113 cloudprovider.PublicZone: []cloudprovider.TDnsPolicyType{ 114 cloudprovider.DnsPolicyTypeSimple, 115 cloudprovider.DnsPolicyTypeByCarrier, 116 cloudprovider.DnsPolicyTypeByGeoLocation, 117 cloudprovider.DnsPolicyTypeBySearchEngine, 118 cloudprovider.DnsPolicyTypeWeighted, 119 }, 120 } 121 } 122 123 func (self *SQcloudProviderFactory) GetSupportedDnsPolicyValues() map[cloudprovider.TDnsPolicyType][]cloudprovider.TDnsPolicyValue { 124 return map[cloudprovider.TDnsPolicyType][]cloudprovider.TDnsPolicyValue{ 125 cloudprovider.DnsPolicyTypeByCarrier: []cloudprovider.TDnsPolicyValue{ 126 cloudprovider.DnsPolicyValueUnicom, 127 cloudprovider.DnsPolicyValueTelecom, 128 cloudprovider.DnsPolicyValueChinaMobile, 129 cloudprovider.DnsPolicyValueCernet, 130 }, 131 cloudprovider.DnsPolicyTypeByGeoLocation: []cloudprovider.TDnsPolicyValue{ 132 cloudprovider.DnsPolicyValueOversea, 133 cloudprovider.DnsPolicyValueMainland, 134 }, 135 cloudprovider.DnsPolicyTypeBySearchEngine: []cloudprovider.TDnsPolicyValue{ 136 cloudprovider.DnsPolicyValueBaidu, 137 cloudprovider.DnsPolicyValueBing, 138 cloudprovider.DnsPolicyValueGoogle, 139 cloudprovider.DnsPolicyValueYoudao, 140 cloudprovider.DnsPolicyValueSousou, 141 cloudprovider.DnsPolicyValueSougou, 142 cloudprovider.DnsPolicyValueQihu360, 143 }, 144 } 145 } 146 147 // https://buy.cloud.tencent.com/cns?from=gobuy&domain=example4.com 148 func (self *SQcloudProviderFactory) GetTTLRange(zoneType cloudprovider.TDnsZoneType, productType cloudprovider.TDnsProductType) cloudprovider.TTlRange { 149 if len(productType) > 0 { 150 switch productType { 151 case cloudprovider.DnsProductEnterpriseUltimate: 152 return cloudprovider.TtlRangeQcloudEnterpriseUltimate 153 case cloudprovider.DnsProductEnterpriseStandard: 154 return cloudprovider.TtlRangeQcloudEnterpriseStandard 155 case cloudprovider.DnsProductEnterpriseBasic: 156 return cloudprovider.TtlRangeQcloudEnterpriseBasic 157 case cloudprovider.DnsProductPersonalProfessional: 158 return cloudprovider.TtlRangeQcloudPersonalProfessional 159 case cloudprovider.DnsProductFree: 160 return cloudprovider.TtlRangeQcloudFree 161 default: 162 return cloudprovider.TtlRangeQcloudFree 163 } 164 } 165 return cloudprovider.TtlRangeQcloudFree 166 } 167 168 func (self *SQcloudProviderFactory) ValidateChangeBandwidth(instanceId string, bandwidth int64) error { 169 if len(instanceId) == 0 { 170 return fmt.Errorf("Only changes to the binding machine's EIP bandwidth are supported") 171 } 172 return nil 173 } 174 175 func (self *SQcloudProviderFactory) ValidateCreateCloudaccountData(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential) (cloudprovider.SCloudaccount, error) { 176 output := cloudprovider.SCloudaccount{} 177 if len(input.AppId) == 0 { 178 return output, errors.Wrap(httperrors.ErrMissingParameter, "app_id") 179 } 180 if len(input.SecretId) == 0 { 181 return output, errors.Wrap(httperrors.ErrMissingParameter, "secret_id") 182 } 183 if len(input.SecretKey) == 0 { 184 return output, errors.Wrap(httperrors.ErrMissingParameter, "secret_key") 185 } 186 output.Account = fmt.Sprintf("%s/%s", input.SecretId, input.AppId) 187 output.Secret = input.SecretKey 188 return output, nil 189 } 190 191 func (self *SQcloudProviderFactory) ValidateUpdateCloudaccountCredential(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential, cloudaccount string) (cloudprovider.SCloudaccount, error) { 192 output := cloudprovider.SCloudaccount{} 193 if len(input.AppId) == 0 { 194 accountInfo := strings.Split(cloudaccount, "/") 195 if len(accountInfo) < 2 { 196 return output, errors.Wrap(httperrors.ErrMissingParameter, "app_id") 197 } 198 input.AppId = accountInfo[1] 199 } 200 if len(input.SecretId) == 0 { 201 return output, errors.Wrap(httperrors.ErrMissingParameter, "secret_id") 202 } 203 if len(input.SecretKey) == 0 { 204 return output, errors.Wrap(httperrors.ErrMissingParameter, "secret_key") 205 } 206 output = cloudprovider.SCloudaccount{ 207 Account: fmt.Sprintf("%s/%s", input.SecretId, input.AppId), 208 Secret: input.SecretKey, 209 } 210 return output, nil 211 } 212 213 func (self *SQcloudProviderFactory) GetProvider(cfg cloudprovider.ProviderConfig) (cloudprovider.ICloudProvider, error) { 214 secretId := cfg.Account 215 appId := "" 216 if tmp := strings.Split(cfg.Account, "/"); len(tmp) == 2 { 217 secretId = tmp[0] 218 appId = tmp[1] 219 } 220 client, err := qcloud.NewQcloudClient( 221 qcloud.NewQcloudClientConfig( 222 secretId, cfg.Secret, 223 ).AppId(appId).CloudproviderConfig(cfg), 224 ) 225 if err != nil { 226 return nil, err 227 } 228 return &SQcloudProvider{ 229 SBaseProvider: cloudprovider.NewBaseProvider(self), 230 client: client, 231 }, nil 232 } 233 234 func (self *SQcloudProviderFactory) GetClientRC(info cloudprovider.SProviderInfo) (map[string]string, error) { 235 secretId := info.Account 236 appId := "" 237 if tmp := strings.Split(info.Account, "/"); len(tmp) == 2 { 238 secretId = tmp[0] 239 appId = tmp[1] 240 } 241 return map[string]string{ 242 "QCLOUD_APPID": appId, 243 "QCLOUD_SECRET_ID": secretId, 244 "QCLOUD_SECRET_KEY": info.Secret, 245 "QCLOUD_REGION": qcloud.QCLOUD_DEFAULT_REGION, 246 }, nil 247 } 248 249 func init() { 250 factory := SQcloudProviderFactory{} 251 cloudprovider.RegisterFactory(&factory) 252 } 253 254 type SQcloudProvider struct { 255 cloudprovider.SBaseProvider 256 client *qcloud.SQcloudClient 257 } 258 259 func (self *SQcloudProvider) GetSysInfo() (jsonutils.JSONObject, error) { 260 regions := self.client.GetIRegions() 261 info := jsonutils.NewDict() 262 info.Add(jsonutils.NewInt(int64(len(regions))), "region_count") 263 info.Add(jsonutils.NewString(qcloud.QCLOUD_API_VERSION), "api_version") 264 return info, nil 265 } 266 267 func (self *SQcloudProvider) GetVersion() string { 268 return qcloud.QCLOUD_API_VERSION 269 } 270 271 func (self *SQcloudProvider) GetSubAccounts() ([]cloudprovider.SSubAccount, error) { 272 return self.client.GetSubAccounts() 273 } 274 275 func (self *SQcloudProvider) GetAccountId() string { 276 return self.client.GetAccountId() 277 } 278 279 func (self *SQcloudProvider) GetIamLoginUrl() string { 280 return self.client.GetIamLoginUrl() 281 } 282 283 func (self *SQcloudProvider) GetIRegions() []cloudprovider.ICloudRegion { 284 return self.client.GetIRegions() 285 } 286 287 func (self *SQcloudProvider) GetIRegionById(id string) (cloudprovider.ICloudRegion, error) { 288 return self.client.GetIRegionById(id) 289 } 290 291 func (self *SQcloudProvider) GetBalance() (float64, string, error) { 292 balance, err := self.client.QueryAccountBalance() 293 if err != nil { 294 return 0.0, api.CLOUD_PROVIDER_HEALTH_UNKNOWN, err 295 } 296 status := api.CLOUD_PROVIDER_HEALTH_NORMAL 297 if balance.AvailableAmount < 0.0 { 298 status = api.CLOUD_PROVIDER_HEALTH_ARREARS 299 } 300 return balance.AvailableAmount, status, nil 301 } 302 303 func (self *SQcloudProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) { 304 return self.client.GetIProjects() 305 } 306 307 func (self *SQcloudProvider) CreateIProject(name string) (cloudprovider.ICloudProject, error) { 308 return self.client.CreateIProject(name) 309 } 310 311 func (self *SQcloudProvider) GetStorageClasses(regionId string) []string { 312 return []string{ 313 "STANDARD", "STANDARD_IA", "ARCHIVE", 314 } 315 } 316 317 func (self *SQcloudProvider) GetBucketCannedAcls(regionId string) []string { 318 return []string{ 319 string(cloudprovider.ACLPrivate), 320 string(cloudprovider.ACLAuthRead), 321 string(cloudprovider.ACLPublicRead), 322 } 323 } 324 325 func (self *SQcloudProvider) GetObjectCannedAcls(regionId string) []string { 326 return []string{ 327 string(cloudprovider.ACLPrivate), 328 string(cloudprovider.ACLAuthRead), 329 string(cloudprovider.ACLPublicRead), 330 } 331 } 332 333 func (self *SQcloudProvider) GetCapabilities() []string { 334 return self.client.GetCapabilities() 335 } 336 337 func (self *SQcloudProvider) CreateIClouduser(conf *cloudprovider.SClouduserCreateConfig) (cloudprovider.IClouduser, error) { 338 return self.client.CreateIClouduser(conf) 339 } 340 341 func (self *SQcloudProvider) GetICloudusers() ([]cloudprovider.IClouduser, error) { 342 return self.client.GetICloudusers() 343 } 344 345 func (self *SQcloudProvider) GetICloudgroups() ([]cloudprovider.ICloudgroup, error) { 346 return self.client.GetICloudgroups() 347 } 348 349 func (self *SQcloudProvider) GetICloudgroupByName(name string) (cloudprovider.ICloudgroup, error) { 350 return self.client.GetICloudgroupByName(name) 351 } 352 353 func (self *SQcloudProvider) CreateICloudgroup(name, desc string) (cloudprovider.ICloudgroup, error) { 354 return self.client.CreateICloudgroup(name, desc) 355 } 356 357 func (self *SQcloudProvider) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { 358 return self.client.GetISystemCloudpolicies() 359 } 360 361 func (self *SQcloudProvider) GetICustomCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { 362 return self.client.GetICustomCloudpolicies() 363 } 364 365 func (self *SQcloudProvider) GetIClouduserByName(name string) (cloudprovider.IClouduser, error) { 366 return self.client.GetIClouduserByName(name) 367 } 368 369 func (self *SQcloudProvider) CreateICloudpolicy(opts *cloudprovider.SCloudpolicyCreateOptions) (cloudprovider.ICloudpolicy, error) { 370 return self.client.CreateICloudpolicy(opts) 371 } 372 373 func (self *SQcloudProvider) GetSamlEntityId() string { 374 return cloudprovider.SAML_ENTITY_ID_QCLOUD 375 } 376 377 func (self *SQcloudProvider) GetICloudDnsZones() ([]cloudprovider.ICloudDnsZone, error) { 378 return self.client.GetICloudDnsZones() 379 } 380 381 func (self *SQcloudProvider) GetICloudDnsZoneById(id string) (cloudprovider.ICloudDnsZone, error) { 382 domain, err := self.client.GetDomain(id) 383 if err != nil { 384 return nil, err 385 } 386 return domain, nil 387 } 388 389 func (self *SQcloudProvider) CreateICloudDnsZone(opts *cloudprovider.SDnsZoneCreateOptions) (cloudprovider.ICloudDnsZone, error) { 390 return self.client.CreateICloudDnsZone(opts) 391 } 392 393 func (self *SQcloudProvider) CreateICloudSAMLProvider(opts *cloudprovider.SAMLProviderCreateOptions) (cloudprovider.ICloudSAMLProvider, error) { 394 saml, err := self.client.CreateSAMLProvider(opts.Name, opts.Metadata.String(), "") 395 if err != nil { 396 return nil, errors.Wrap(err, "CreateSAMLProvider") 397 } 398 return saml, nil 399 } 400 401 func (self *SQcloudProvider) GetICloudSAMLProviders() ([]cloudprovider.ICloudSAMLProvider, error) { 402 return self.client.GetICloudSAMLProviders() 403 } 404 405 func (self *SQcloudProvider) CreateICloudrole(opts *cloudprovider.SRoleCreateOptions) (cloudprovider.ICloudrole, error) { 406 if len(opts.SAMLProvider) > 0 { 407 document := fmt.Sprintf(`{"version":"2.0","statement":[{"action":"name/sts:AssumeRoleWithSAML","effect":"allow","principal":{"federated":["qcs::cam::uin/%s:saml-provider/%s"]},"condition":{}}]}`, self.client.GetAccountId(), opts.SAMLProvider) 408 role, err := self.client.CreateRole(opts.Name, document, opts.Desc) 409 if err != nil { 410 return nil, errors.Wrapf(err, "CreateRole") 411 } 412 return role, nil 413 } 414 role, err := self.client.CreateRole(opts.Name, "", opts.Desc) 415 if err != nil { 416 return nil, errors.Wrapf(err, "") 417 } 418 return role, nil 419 } 420 421 func (self *SQcloudProvider) GetICloudroles() ([]cloudprovider.ICloudrole, error) { 422 return self.client.GetICloudroles() 423 } 424 425 func (self *SQcloudProvider) GetICloudroleByName(name string) (cloudprovider.ICloudrole, error) { 426 role, err := self.client.GetRole(name) 427 if err != nil { 428 return nil, errors.Wrapf(err, "GetRole(%s)", name) 429 } 430 return role, nil 431 } 432 433 func (self *SQcloudProvider) GetICloudroleById(id string) (cloudprovider.ICloudrole, error) { 434 return self.GetICloudroleByName(id) 435 } 436 437 func (self *SQcloudProvider) GetICloudInterVpcNetworks() ([]cloudprovider.ICloudInterVpcNetwork, error) { 438 return self.client.GetICloudInterVpcNetworks() 439 } 440 441 func (self *SQcloudProvider) GetICloudInterVpcNetworkById(id string) (cloudprovider.ICloudInterVpcNetwork, error) { 442 return self.client.GetICloudInterVpcNetworkById(id) 443 } 444 445 func (self *SQcloudProvider) CreateICloudInterVpcNetwork(opts *cloudprovider.SInterVpcNetworkCreateOptions) (cloudprovider.ICloudInterVpcNetwork, error) { 446 return self.client.CreateICloudInterVpcNetwork(opts) 447 } 448 449 func (self *SQcloudProvider) GetICloudCDNDomains() ([]cloudprovider.ICloudCDNDomain, error) { 450 return self.client.GetICloudCDNDomains() 451 } 452 453 func (self *SQcloudProvider) GetICloudCDNDomainByName(name string) (cloudprovider.ICloudCDNDomain, error) { 454 return self.client.GetICloudCDNDomainByName(name) 455 } 456 457 func (self *SQcloudProvider) CreateICloudCDNDomain(opts *cloudprovider.CdnCreateOptions) (cloudprovider.ICloudCDNDomain, error) { 458 return self.client.CreateCDNDomain(opts) 459 } 460 461 func (self *SQcloudProvider) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { 462 return self.client.GetMetrics(opts) 463 }