aliyun.go 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092
  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. package aliyun
  15. import (
  16. "bytes"
  17. "fmt"
  18. "io"
  19. "net/http"
  20. "net/url"
  21. "strings"
  22. "sync"
  23. "time"
  24. "github.com/aliyun/alibaba-cloud-sdk-go/sdk"
  25. "github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/credentials"
  26. "github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/signers"
  27. alierr "github.com/aliyun/alibaba-cloud-sdk-go/sdk/errors"
  28. "github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
  29. "github.com/aliyun/aliyun-oss-go-sdk/oss"
  30. "github.com/pkg/errors"
  31. "yunion.io/x/jsonutils"
  32. "yunion.io/x/log"
  33. "yunion.io/x/pkg/gotypes"
  34. "yunion.io/x/pkg/util/httputils"
  35. v "yunion.io/x/pkg/util/version"
  36. "yunion.io/x/pkg/utils"
  37. api "yunion.io/x/cloudmux/pkg/apis/compute"
  38. "yunion.io/x/cloudmux/pkg/cloudprovider"
  39. )
  40. const (
  41. ALIYUN_INTERNATIONAL_CLOUDENV = "InternationalCloud"
  42. ALIYUN_FINANCE_CLOUDENV = "FinanceCloud"
  43. CLOUD_PROVIDER_ALIYUN = api.CLOUD_PROVIDER_ALIYUN
  44. CLOUD_PROVIDER_ALIYUN_CN = "阿里云"
  45. CLOUD_PROVIDER_ALIYUN_EN = "Aliyun"
  46. ALIYUN_DEFAULT_REGION = "cn-hangzhou"
  47. ALIYUN_API_VERSION = "2014-05-26"
  48. ALIYUN_API_VERSION_VPC = "2016-04-28"
  49. ALIYUN_API_VERSION_LB = "2014-05-15"
  50. ALIYUN_API_VERSION_KVS = "2015-01-01"
  51. ALIYUN_API_VERSION_TRIAL = "2020-07-06"
  52. ALIYUN_BSS_API_VERSION = "2017-12-14"
  53. ALIYUN_RAM_API_VERSION = "2015-05-01"
  54. ALIYUN_RDS_API_VERSION = "2014-08-15"
  55. ALIYUN_RM_API_VERSION = "2020-03-31"
  56. ALIYUN_STS_API_VERSION = "2015-04-01"
  57. ALIYUN_PVTZ_API_VERSION = "2018-01-01"
  58. ALIYUN_ALIDNS_API_VERSION = "2015-01-09"
  59. ALIYUN_CBN_API_VERSION = "2017-09-12"
  60. ALIYUN_CDN_API_VERSION = "2018-05-10"
  61. ALIYUN_IMS_API_VERSION = "2019-08-15"
  62. ALIYUN_NAS_API_VERSION = "2017-06-26"
  63. ALIYUN_WAF_API_VERSION = "2019-09-10"
  64. ALIYUN_WAF_V2_API_VERSION = "2021-10-01"
  65. ALIYUN_MONGO_DB_API_VERSION = "2015-12-01"
  66. ALIYUN_ES_API_VERSION = "2017-06-13"
  67. ALIYUN_KAFKA_API_VERSION = "2019-09-16"
  68. ALIYUN_K8S_API_VERSION = "2015-12-15"
  69. ALIYUN_OTS_API_VERSION = "2016-06-20"
  70. ALIYUN_RD_API_VERSION = "2022-04-19"
  71. ALIYUN_CAS_API_VERSION = "2018-07-13"
  72. ALIYUN_SERVICE_ECS = "ecs"
  73. ALIYUN_SERVICE_VPC = "vpc"
  74. ALIYUN_SERVICE_RDS = "rds"
  75. ALIYUN_SERVICE_ES = "es"
  76. ALIYUN_SERVICE_KAFKA = "kafka"
  77. ALIYUN_SERVICE_SLB = "slb"
  78. ALIYUN_SERVICE_KVS = "kvs"
  79. ALIYUN_SERVICE_NAS = "nas"
  80. ALIYUN_SERVICE_CDN = "cdn"
  81. ALIYUN_SERVICE_MONGO_DB = "mongodb"
  82. DefaultAssumeRoleName = "ResourceDirectoryAccountAccessRole"
  83. ALIYUN_API_VERSION_ECS = "2014-05-26"
  84. ALIYUN_API_VERSION_EIP = "2016-04-28"
  85. ALIYUN_API_VERSION_ELB = "2016-04-28"
  86. ALIYUN_API_VERSION_VGW = "2016-04-28"
  87. ALIYUN_API_VERSION_NAS = "2017-06-26"
  88. ALIYUN_API_VERSION_CON = "2018-12-01"
  89. ALIYUN_API_VERSION_VHH = "2019-06-01"
  90. ALIYUN_API_VERSION_BSS = "2017-12-14"
  91. ALIYUN_API_VERSION_FC = "2021-04-06"
  92. ALIYUN_API_VERSION_NLB = "2022-04-30"
  93. ALIYUN_API_VERSION_ALB = "2020-06-16"
  94. ALIYUN_BSS_BILLING_METHOD_PREPAID = "Subscription"
  95. ALIYUN_BSS_BILLING_METHOD_POSTPAID = "PayAsYouGo"
  96. ALIYUN_API_INTERVAL = 5 * time.Second
  97. DEFAULT_SESSION_DURATION_SECONDS = 3600
  98. ALIYUN_SERVICE_ALB = "alb"
  99. ALIYUN_SERVICE_NLB = "nlb"
  100. ALIYUN_SERVICE_OSS = "oss"
  101. ALIYUN_SERVICE_EIP = "eip"
  102. )
  103. var (
  104. // https://help.aliyun.com/document_detail/31837.html?spm=a2c4g.11186623.2.18.675f2b8cu8CN5K#concept-zt4-cvy-5db
  105. OSS_FINANCE_REGION_MAP = map[string]string{
  106. "cn-hzfinance": "cn-hangzhou",
  107. "cn-shanghai-finance-1-pub": "cn-shanghai-finance-1",
  108. "cn-szfinance": "cn-shenzhen-finance-1",
  109. "cn-hzjbp": "cn-hangzhou",
  110. "cn-shanghai-finance-1": "cn-shanghai-finance-1",
  111. "cn-shenzhen-finance-1": "cn-shenzhen-finance-1",
  112. }
  113. )
  114. type AliyunClientConfig struct {
  115. cpcfg cloudprovider.ProviderConfig
  116. cloudEnv string // 服务区域 InternationalCloud | FinanceCloud
  117. accessKey string
  118. accessSecret string
  119. accountId string
  120. debug bool
  121. }
  122. func NewAliyunClientConfig(cloudEnv, accessKey, accessSecret string) *AliyunClientConfig {
  123. cfg := &AliyunClientConfig{
  124. cloudEnv: cloudEnv,
  125. accessKey: accessKey,
  126. accessSecret: accessSecret,
  127. }
  128. return cfg
  129. }
  130. func (cfg *AliyunClientConfig) CloudproviderConfig(cpcfg cloudprovider.ProviderConfig) *AliyunClientConfig {
  131. cfg.cpcfg = cpcfg
  132. return cfg
  133. }
  134. func (cfg *AliyunClientConfig) AccountId(id string) *AliyunClientConfig {
  135. cfg.accountId = id
  136. return cfg
  137. }
  138. func (cfg *AliyunClientConfig) Debug(debug bool) *AliyunClientConfig {
  139. cfg.debug = debug
  140. return cfg
  141. }
  142. func (cfg AliyunClientConfig) Copy() AliyunClientConfig {
  143. return cfg
  144. }
  145. type SAliyunClient struct {
  146. *AliyunClientConfig
  147. clients map[string]*sdk.Client
  148. clientLock sync.Mutex
  149. ownerId string
  150. arn string
  151. nasEndpoints map[string]string
  152. vpcEndpoints map[string]string
  153. hbaseEndpoint map[string]string
  154. iregions []cloudprovider.ICloudRegion
  155. iBuckets []cloudprovider.ICloudBucket
  156. }
  157. func NewAliyunClient(cfg *AliyunClientConfig) (*SAliyunClient, error) {
  158. client := SAliyunClient{
  159. AliyunClientConfig: cfg,
  160. nasEndpoints: map[string]string{},
  161. vpcEndpoints: map[string]string{},
  162. }
  163. return &client, client.fetchRegions()
  164. }
  165. func jsonRequest(client *sdk.Client, domain, apiVersion, apiName string, params map[string]string, debug bool) (jsonutils.JSONObject, error) {
  166. return doRequest(client, domain, apiVersion, apiName, params, nil, debug)
  167. }
  168. func doRequest(client *sdk.Client, domain, apiVersion, apiName string, params map[string]string, body interface{}, debug bool) (jsonutils.JSONObject, error) {
  169. if debug {
  170. if !gotypes.IsNil(body) {
  171. log.Debugf("request %s %s %s %s", domain, apiVersion, apiName, jsonutils.Marshal(body))
  172. } else {
  173. log.Debugf("request %s %s %s %s", domain, apiVersion, apiName, params)
  174. }
  175. }
  176. var resp jsonutils.JSONObject
  177. var err error
  178. for i := 1; i < 4; i++ {
  179. resp, err = _jsonRequest(client, domain, apiVersion, apiName, params, body)
  180. retry := false
  181. if err != nil {
  182. for _, code := range []string{
  183. "ErrorClusterNotFound",
  184. "ErrorNodePoolNotFound",
  185. } {
  186. if strings.Contains(err.Error(), code) {
  187. return nil, errors.Wrap(cloudprovider.ErrNotFound, err.Error())
  188. }
  189. }
  190. if e, ok := errors.Cause(err).(*alierr.ServerError); ok {
  191. code := e.ErrorCode()
  192. switch code {
  193. case "InternalError":
  194. if apiName != "QueryAccountBalance" {
  195. return nil, err
  196. }
  197. if i != 1 {
  198. return nil, err
  199. }
  200. // 国际版阿里云需要请求新加坡
  201. domain = "business.ap-southeast-1.aliyuncs.com"
  202. retry = true
  203. case "InvalidAccessKeyId.NotFound",
  204. "InvalidAccessKeyId",
  205. "NoEnabledAccessKey",
  206. "InvalidAccessKeyId.Inactive",
  207. "Forbidden.AccessKeyDisabled",
  208. "Forbidden.AccessKey":
  209. return nil, errors.Wrapf(cloudprovider.ErrInvalidAccessKey, "%s", err.Error())
  210. case "Forbidden.RAM":
  211. return nil, errors.Wrapf(cloudprovider.ErrForbidden, "%s", err.Error())
  212. case "404 Not Found", "InstanceNotFound":
  213. return nil, errors.Wrap(cloudprovider.ErrNotFound, err.Error())
  214. case "OperationDenied.NoStock":
  215. return nil, errors.Wrapf(err, "所请求的套餐在指定的区域内已售罄;尝试其他套餐或选择其他区域和可用区。")
  216. case "InvalidInstance.NotSupported",
  217. "SignatureNonceUsed", // SignatureNonce 重复。每次请求的 SignatureNonce 在 15 分钟内不能重复。
  218. "BackendServer.configuring", // 负载均衡的前一个配置项正在配置中,请稍后再试。
  219. "Operation.Conflict", // 您当前的操作可能与其他人的操作产生了冲突,请稍后重试。
  220. "OperationDenied.ResourceControl", // 指定的区域处于资源控制中,请稍后再试。
  221. "ServiceIsStopping", // 监听正在停止,请稍后重试。
  222. "ProcessingSameRequest", // 正在处理相同的请求。请稍后再试。
  223. "ResourceInOperating", // 当前资源正在操作中,请求稍后重试。
  224. "InvalidFileSystemStatus.Ordering", // Message: The filesystem is ordering now, please check it later.
  225. "OperationUnsupported.EipNatBWPCheck": // create nat snat
  226. retry = true
  227. default:
  228. if strings.HasPrefix(code, "EntityNotExist.") || strings.HasSuffix(code, ".NotFound") || strings.HasSuffix(code, "NotExist") {
  229. if strings.HasPrefix(apiName, "Delete") {
  230. return jsonutils.NewDict(), nil
  231. }
  232. return nil, errors.Wrap(cloudprovider.ErrNotFound, err.Error())
  233. }
  234. return nil, err
  235. }
  236. } else {
  237. for _, code := range []string{
  238. "EOF",
  239. "i/o timeout",
  240. "TLS handshake timeout",
  241. "Client.Timeout exceeded while awaiting headers",
  242. "connection reset by peer",
  243. "context deadline exceeded",
  244. "server misbehaving",
  245. "try later",
  246. "Another operation is being performed", // Another operation is being performed on the DB instance or the DB instance is faulty(赋予RDS账号权限)
  247. } {
  248. if strings.Contains(err.Error(), code) {
  249. retry = true
  250. break
  251. }
  252. }
  253. }
  254. }
  255. if retry {
  256. if debug {
  257. log.Debugf("Retry %d...", i)
  258. }
  259. if apiName != "QueryAccountBalance" {
  260. time.Sleep(time.Second * time.Duration(i*10))
  261. }
  262. continue
  263. }
  264. if debug {
  265. log.Debugf("Response: %s", resp)
  266. }
  267. return resp, err
  268. }
  269. return resp, err
  270. }
  271. func _jsonRequest(client *sdk.Client, domain string, version string, apiName string, params map[string]string, body interface{}) (jsonutils.JSONObject, error) {
  272. req := requests.NewCommonRequest()
  273. req.Domain = domain
  274. req.Version = version
  275. req.ApiName = apiName
  276. if params != nil {
  277. for k, v := range params {
  278. req.QueryParams[k] = v
  279. }
  280. }
  281. if body != nil {
  282. req.Content = []byte(jsonutils.Marshal(body).String())
  283. req.GetHeaders()["Content-Type"] = "application/json"
  284. }
  285. req.Scheme = "https"
  286. req.GetHeaders()["User-Agent"] = "vendor/yunion-OneCloud@" + v.Get().GitVersion
  287. method := requests.POST
  288. for prefix, _method := range map[string]string{
  289. "Get": requests.GET,
  290. "Describe": requests.GET,
  291. "List": requests.GET,
  292. "Delete": requests.DELETE,
  293. } {
  294. if strings.HasPrefix(apiName, prefix) && !strings.HasPrefix(domain, "mongodb") {
  295. method = _method
  296. break
  297. }
  298. }
  299. if strings.HasPrefix(domain, "elasticsearch") {
  300. if strings.HasPrefix(apiName, "UntagResources") {
  301. method = requests.DELETE
  302. }
  303. req.Product = "elasticsearch"
  304. req.ServiceCode = "elasticsearch"
  305. pathPattern, ok := params["PathPattern"]
  306. if !ok {
  307. return nil, errors.Errorf("Roa request missing pathPattern")
  308. }
  309. delete(params, "PathPattern")
  310. req.PathPattern = pathPattern
  311. req.Method = method
  312. } else if strings.HasPrefix(domain, "alikafka") { //alikafka DeleteInstance必须显式指定Method
  313. req.Method = requests.POST
  314. } else if strings.HasPrefix(domain, "cs") { //容器
  315. pathPattern, ok := params["PathPattern"]
  316. if !ok {
  317. return nil, errors.Errorf("Roa request missing pathPattern")
  318. }
  319. delete(params, "PathPattern")
  320. req.PathPattern = pathPattern
  321. req.Method = method
  322. req.GetHeaders()["Content-Type"] = "application/json"
  323. } else if strings.HasPrefix(domain, "rocketmq") {
  324. pathPattern, ok := params["PathPattern"]
  325. if !ok {
  326. return nil, errors.Errorf("Roa request missing pathPattern")
  327. }
  328. delete(params, "PathPattern")
  329. req.PathPattern = pathPattern
  330. req.Method = method
  331. req.GetHeaders()["Content-Type"] = "application/json"
  332. } else if strings.HasPrefix(domain, "fc") {
  333. pathPattern, ok := params["PathPattern"]
  334. if !ok {
  335. return nil, errors.Errorf("Roa request missing pathPattern")
  336. }
  337. delete(params, "PathPattern")
  338. req.PathPattern = fmt.Sprintf("/%s/%s", req.Version, strings.TrimPrefix(pathPattern, "/"))
  339. req.Method = method
  340. req.GetHeaders()["Content-Type"] = "application/json"
  341. } else if strings.HasPrefix(domain, "mongodb") {
  342. req.Method = requests.POST
  343. req.GetHeaders()["Content-Type"] = "application/json"
  344. }
  345. resp, err := processCommonRequest(client, req)
  346. if err != nil {
  347. return nil, errors.Wrapf(err, "processCommonRequest with params %s", params)
  348. }
  349. respBody, err := jsonutils.Parse(resp.GetHttpContentBytes())
  350. if err != nil {
  351. return nil, errors.Wrapf(err, "jsonutils.Parse")
  352. }
  353. //{"Code":"InvalidInstanceType.ValueNotSupported","HostId":"ecs.aliyuncs.com","Message":"The specified instanceType beyond the permitted range.","RequestId":"0042EE30-0EDF-48A7-A414-56229D4AD532"}
  354. //{"Code":"200","Message":"successful","PageNumber":1,"PageSize":50,"RequestId":"BB4C970C-0E23-48DC-A3B0-EB21FFC70A29","RouterTableList":{"RouterTableListType":[{"CreationTime":"2017-03-19T13:37:40Z","Description":"","ResourceGroupId":"rg-acfmwie3cqoobmi","RouteTableId":"vtb-j6c60lectdi80rk5xz43g","RouteTableName":"","RouteTableType":"System","RouterId":"vrt-j6c00qrol733dg36iq4qj","RouterType":"VRouter","VSwitchIds":{"VSwitchId":["vsw-j6c3gig5ub4fmi2veyrus"]},"VpcId":"vpc-j6c86z3sh8ufhgsxwme0q"}]},"Success":true,"TotalCount":1}
  355. //{"Code":"Success","Data":{"CashCoupon":[]},"Message":"Successful!","RequestId":"87AD7E9A-3F8F-460F-9934-FFFE502325EE","Success":true}
  356. if respBody.Contains("Code") {
  357. code, _ := respBody.GetString("Code")
  358. if len(code) > 0 && !utils.IsInStringArray(code, []string{"200", "Success"}) {
  359. return nil, fmt.Errorf("%s", respBody.String())
  360. }
  361. }
  362. return respBody, nil
  363. }
  364. func (self *SAliyunClient) getNasEndpoint(regionId string) string {
  365. err := self.fetchNasEndpoints()
  366. if err != nil {
  367. return "nas.aliyuncs.com"
  368. }
  369. ep, ok := self.nasEndpoints[regionId]
  370. if ok && len(ep) > 0 {
  371. return ep
  372. }
  373. return "nas.aliyuncs.com"
  374. }
  375. func (self *SAliyunClient) fetchNasEndpoints() error {
  376. if len(self.nasEndpoints) > 0 {
  377. return nil
  378. }
  379. client, err := self.getDefaultClient()
  380. if err != nil {
  381. return errors.Wrapf(err, "getDefaultClient")
  382. }
  383. resp, err := jsonRequest(client, "nas.aliyuncs.com", ALIYUN_NAS_API_VERSION, "DescribeRegions", nil, self.debug)
  384. if err != nil {
  385. return errors.Wrapf(err, "DescribeRegions")
  386. }
  387. regions := []SRegion{}
  388. err = resp.Unmarshal(&regions, "Regions", "Region")
  389. if err != nil {
  390. return errors.Wrapf(err, "resp.Unmarshal")
  391. }
  392. for _, region := range regions {
  393. self.nasEndpoints[region.RegionId] = region.RegionEndpoint
  394. }
  395. return nil
  396. }
  397. func (self *SAliyunClient) getDefaultClient() (*sdk.Client, error) {
  398. client, err := self.getSdkClient(ALIYUN_DEFAULT_REGION)
  399. return client, err
  400. }
  401. func (self *SAliyunClient) getVpcEndpoint(regionId string) string {
  402. err := self.fetchVpcEndpoints()
  403. if err != nil {
  404. return "vpc.aliyuncs.com"
  405. }
  406. ep, ok := self.vpcEndpoints[regionId]
  407. if ok && len(ep) > 0 {
  408. return ep
  409. }
  410. return "vpc.aliyuncs.com"
  411. }
  412. func (self *SAliyunClient) fetchVpcEndpoints() error {
  413. if len(self.vpcEndpoints) > 0 {
  414. return nil
  415. }
  416. client, err := self.getDefaultClient()
  417. if err != nil {
  418. return errors.Wrapf(err, "getDefaultClient")
  419. }
  420. resp, err := jsonRequest(client, "vpc.aliyuncs.com", ALIYUN_API_VERSION_VPC, "DescribeRegions", nil, self.debug)
  421. if err != nil {
  422. return errors.Wrapf(err, "DescribeRegions")
  423. }
  424. regions := []SRegion{}
  425. err = resp.Unmarshal(&regions, "Regions", "Region")
  426. if err != nil {
  427. return errors.Wrapf(err, "resp.Unmarshal")
  428. }
  429. for _, region := range regions {
  430. self.vpcEndpoints[region.RegionId] = region.RegionEndpoint
  431. }
  432. return nil
  433. }
  434. func (self *SAliyunClient) _getSdkClient(regionId string) (*sdk.Client, error) {
  435. transport := httputils.GetAdaptiveTransport(true)
  436. transport.Proxy = self.cpcfg.ProxyFunc
  437. ts := cloudprovider.GetCheckTransport(transport, func(req *http.Request) (func(resp *http.Response) error, error) {
  438. params, err := url.ParseQuery(req.URL.RawQuery)
  439. if err != nil {
  440. return nil, errors.Wrapf(err, "ParseQuery(%s)", req.URL.RawQuery)
  441. }
  442. service := strings.Split(req.URL.Host, ".")[0]
  443. action := params.Get("Action")
  444. respCheck := func(resp *http.Response) error {
  445. if self.cpcfg.UpdatePermission != nil && resp.StatusCode >= 400 && resp.ContentLength > 0 {
  446. body, err := io.ReadAll(resp.Body)
  447. if err != nil {
  448. return nil
  449. }
  450. resp.Body = io.NopCloser(bytes.NewBuffer(body))
  451. obj, err := jsonutils.Parse(body)
  452. if err != nil {
  453. return nil
  454. }
  455. ret := struct{ Code string }{}
  456. obj.Unmarshal(&ret)
  457. if utils.IsInStringArray(ret.Code, []string{
  458. "NoPermission",
  459. "SubAccountNoPermission",
  460. }) || utils.HasPrefix(ret.Code, "Forbidden") ||
  461. action == "QueryAccountBalance" && ret.Code == "InternalError" {
  462. self.cpcfg.UpdatePermission(service, action)
  463. }
  464. }
  465. return nil
  466. }
  467. for _, prefix := range []string{"Get", "List", "Describe", "Query"} {
  468. if strings.HasPrefix(action, prefix) {
  469. return respCheck, nil
  470. }
  471. }
  472. if self.cpcfg.ReadOnly {
  473. return respCheck, errors.Wrapf(cloudprovider.ErrAccountReadOnly, "%s", action)
  474. }
  475. return respCheck, nil
  476. })
  477. client, err := sdk.NewClientWithOptions(
  478. regionId,
  479. &sdk.Config{
  480. HttpTransport: transport,
  481. Transport: ts,
  482. },
  483. credentials.NewBaseCredential(self.accessKey, self.accessSecret),
  484. )
  485. if len(self.accountId) > 0 {
  486. arn := fmt.Sprintf("acs:ram::%s:role/%s", self.accountId, DefaultAssumeRoleName)
  487. client, err = sdk.NewClientWithOptions(
  488. regionId,
  489. &sdk.Config{
  490. HttpTransport: transport,
  491. Transport: ts,
  492. },
  493. credentials.NewRamRoleArnCredential(self.accessKey, self.accessSecret, arn, self.accountId, 0),
  494. )
  495. }
  496. if err != nil {
  497. return nil, errors.Wrapf(err, "NewClient")
  498. }
  499. return client, nil
  500. }
  501. func (self *SAliyunClient) getSdkClient(regionId string) (*sdk.Client, error) {
  502. self.clientLock.Lock()
  503. defer self.clientLock.Unlock()
  504. if gotypes.IsNil(self.clients) {
  505. self.clients = map[string]*sdk.Client{}
  506. }
  507. client, ok := self.clients[regionId]
  508. if ok {
  509. return client, nil
  510. }
  511. client, err := self._getSdkClient(regionId)
  512. if err != nil {
  513. return nil, errors.Wrapf(err, "NewClient")
  514. }
  515. self.clients[regionId] = client
  516. return client, nil
  517. }
  518. func (self *SAliyunClient) imsRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) {
  519. cli, err := self.getDefaultClient()
  520. if err != nil {
  521. return nil, err
  522. }
  523. params = self.SetResourceGropuId(params)
  524. return jsonRequest(cli, "ims.aliyuncs.com", ALIYUN_IMS_API_VERSION, apiName, params, self.debug)
  525. }
  526. func (self *SAliyunClient) rmRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) {
  527. cli, err := self._getSdkClient(ALIYUN_DEFAULT_REGION)
  528. if err != nil {
  529. return nil, err
  530. }
  531. return jsonRequest(cli, "resourcemanager.aliyuncs.com", ALIYUN_RM_API_VERSION, apiName, params, self.debug)
  532. }
  533. func (self *SAliyunClient) ecsRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) {
  534. cli, err := self.getDefaultClient()
  535. if err != nil {
  536. return nil, err
  537. }
  538. params = self.SetResourceGropuId(params)
  539. return jsonRequest(cli, "ecs.aliyuncs.com", ALIYUN_API_VERSION, apiName, params, self.debug)
  540. }
  541. func (self *SAliyunClient) pvtzRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) {
  542. cli, err := self.getDefaultClient()
  543. if err != nil {
  544. return nil, err
  545. }
  546. params = self.SetResourceGropuId(params)
  547. return jsonRequest(cli, "pvtz.aliyuncs.com", ALIYUN_PVTZ_API_VERSION, apiName, params, self.debug)
  548. }
  549. func (self *SAliyunClient) alidnsRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) {
  550. cli, err := self.getDefaultClient()
  551. if err != nil {
  552. return nil, err
  553. }
  554. params = self.SetResourceGropuId(params)
  555. return jsonRequest(cli, "alidns.aliyuncs.com", ALIYUN_ALIDNS_API_VERSION, apiName, params, self.debug)
  556. }
  557. func (self *SAliyunClient) cbnRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) {
  558. cli, err := self.getDefaultClient()
  559. if err != nil {
  560. return nil, err
  561. }
  562. params = self.SetResourceGropuId(params)
  563. return jsonRequest(cli, "cbn.aliyuncs.com", ALIYUN_CBN_API_VERSION, apiName, params, self.debug)
  564. }
  565. func (self *SAliyunClient) cdnRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) {
  566. cli, err := self.getDefaultClient()
  567. if err != nil {
  568. return nil, err
  569. }
  570. params = self.SetResourceGropuId(params)
  571. return jsonRequest(cli, "cdn.aliyuncs.com", ALIYUN_CDN_API_VERSION, apiName, params, self.debug)
  572. }
  573. func (self *SAliyunClient) fetchRegions() error {
  574. if len(self.iregions) > 0 {
  575. return nil
  576. }
  577. body, err := self.ecsRequest("DescribeRegions", map[string]string{"AcceptLanguage": "zh-CN"})
  578. if err != nil {
  579. return errors.Wrapf(err, "DescribeRegions")
  580. }
  581. regions := make([]SRegion, 0)
  582. err = body.Unmarshal(&regions, "Regions", "Region")
  583. if err != nil {
  584. return errors.Wrapf(err, "resp.Unmarshal")
  585. }
  586. self.iregions = make([]cloudprovider.ICloudRegion, len(regions))
  587. for i := 0; i < len(regions); i += 1 {
  588. regions[i].client = self
  589. self.iregions[i] = &regions[i]
  590. }
  591. return nil
  592. }
  593. // oss endpoint
  594. // https://help.aliyun.com/document_detail/31837.html?spm=a2c4g.11186623.2.6.6E8ZkO
  595. func getOSSExternalDomain(regionId string) string {
  596. return fmt.Sprintf("oss-%s.aliyuncs.com", regionId)
  597. }
  598. func getOSSInternalDomain(regionId string) string {
  599. return fmt.Sprintf("oss-%s-internal.aliyuncs.com", regionId)
  600. }
  601. func (self *sCred) GetAccessKeyID() string {
  602. return self.AccessKeyId
  603. }
  604. func (self *sCred) GetAccessKeySecret() string {
  605. return self.AccessKeySecret
  606. }
  607. func (self *sCred) GetSecurityToken() string {
  608. return self.StsToken
  609. }
  610. type sCred struct {
  611. signers.SessionCredential
  612. }
  613. func (self *SAliyunClient) GetCredentials() oss.Credentials {
  614. ret := &sCred{}
  615. if len(self.accountId) == 0 {
  616. ret.AccessKeyId = self.accessKey
  617. ret.AccessKeySecret = self.accessSecret
  618. return ret
  619. }
  620. client, err := self.getDefaultClient()
  621. if err != nil {
  622. return ret
  623. }
  624. signer := client.GetSigner()
  625. arnSigner, ok := signer.(*signers.RamRoleArnSigner)
  626. if ok {
  627. ret.SessionCredential = *arnSigner.GetSessionCredential()
  628. }
  629. return ret
  630. }
  631. // https://help.aliyun.com/document_detail/31837.html?spm=a2c4g.11186623.2.6.XqEgD1
  632. func (client *SAliyunClient) getOssClientByEndpoint(endpoint string) (*oss.Client, error) {
  633. // NOTE
  634. //
  635. // oss package as of version 20181116160301-c6838fdc33ed does not
  636. // respect http.ProxyFromEnvironment.
  637. //
  638. // The ClientOption Proxy, AuthProxy lacks the feature NO_PROXY has
  639. // which can be used to whitelist ips, domains from http_proxy,
  640. // https_proxy setting
  641. // oss use no timeout client so as to send/download large files
  642. httpClient := client.cpcfg.AdaptiveTimeoutHttpClient()
  643. transport, _ := httpClient.Transport.(*http.Transport)
  644. httpClient.Transport = cloudprovider.GetCheckTransport(transport, func(req *http.Request) (func(resp *http.Response) error, error) {
  645. path, method := req.URL.Path, req.Method
  646. respCheck := func(resp *http.Response) error {
  647. if client.cpcfg.UpdatePermission != nil && resp.StatusCode == 403 {
  648. client.cpcfg.UpdatePermission("oss", fmt.Sprintf("%s %s", method, path))
  649. }
  650. return nil
  651. }
  652. if client.cpcfg.ReadOnly {
  653. if req.Method == "GET" || req.Method == "HEAD" {
  654. return respCheck, nil
  655. }
  656. return nil, errors.Wrapf(cloudprovider.ErrAccountReadOnly, "%s %s", req.Method, req.URL.RawPath)
  657. }
  658. return respCheck, nil
  659. })
  660. cliOpts := []oss.ClientOption{
  661. oss.HTTPClient(httpClient),
  662. oss.SetCredentialsProvider(client),
  663. }
  664. if !strings.HasPrefix(endpoint, "http") {
  665. endpoint = "https://" + endpoint
  666. }
  667. cli, err := oss.New(endpoint, client.accessKey, client.accessSecret, cliOpts...)
  668. if err != nil {
  669. return nil, errors.Wrap(err, "oss.New")
  670. }
  671. return cli, nil
  672. }
  673. func (client *SAliyunClient) getOssClient(regionId string) (*oss.Client, error) {
  674. ep := getOSSExternalDomain(regionId)
  675. return client.getOssClientByEndpoint(ep)
  676. }
  677. func (self *SAliyunClient) getRegionByRegionId(id string) (cloudprovider.ICloudRegion, error) {
  678. _id, ok := OSS_FINANCE_REGION_MAP[id]
  679. if ok {
  680. id = _id
  681. }
  682. for i := 0; i < len(self.iregions); i += 1 {
  683. if self.iregions[i].GetId() == id {
  684. return self.iregions[i], nil
  685. }
  686. }
  687. return nil, cloudprovider.ErrNotFound
  688. }
  689. func (self *SAliyunClient) invalidateIBuckets() {
  690. self.iBuckets = nil
  691. }
  692. func (self *SAliyunClient) getIBuckets() ([]cloudprovider.ICloudBucket, error) {
  693. if self.iBuckets == nil {
  694. err := self.fetchBuckets()
  695. if err != nil {
  696. return nil, errors.Wrap(err, "fetchBuckets")
  697. }
  698. }
  699. return self.iBuckets, nil
  700. }
  701. func (self *SAliyunClient) fetchBuckets() error {
  702. osscli, err := self.getOssClient(ALIYUN_DEFAULT_REGION)
  703. if err != nil {
  704. return errors.Wrap(err, "self.getOssClient")
  705. }
  706. ret := make([]cloudprovider.ICloudBucket, 0)
  707. marker := ""
  708. for {
  709. opts := []oss.Option{oss.MaxKeys(100)}
  710. if len(marker) > 0 {
  711. opts = append(opts, oss.Marker(marker))
  712. }
  713. result, err := osscli.ListBuckets(opts...)
  714. if err != nil {
  715. return errors.Wrap(err, "oss.ListBuckets")
  716. }
  717. if len(self.ownerId) == 0 {
  718. self.ownerId = result.Owner.ID
  719. }
  720. for _, bInfo := range result.Buckets {
  721. regionId := bInfo.Location[4:]
  722. region, err := self.getRegionByRegionId(regionId)
  723. if err != nil {
  724. log.Errorf("cannot find bucket's region %s", regionId)
  725. continue
  726. }
  727. b := SBucket{
  728. region: region.(*SRegion),
  729. Name: bInfo.Name,
  730. Location: bInfo.Location,
  731. CreationDate: bInfo.CreationDate,
  732. StorageClass: bInfo.StorageClass,
  733. }
  734. ret = append(ret, &b)
  735. }
  736. if !result.IsTruncated {
  737. break
  738. }
  739. marker = result.NextMarker
  740. }
  741. self.iBuckets = ret
  742. return nil
  743. }
  744. func (self *SAliyunClient) GetRegions() []SRegion {
  745. regions := make([]SRegion, len(self.iregions))
  746. for i := 0; i < len(regions); i += 1 {
  747. region := self.iregions[i].(*SRegion)
  748. regions[i] = *region
  749. }
  750. return regions
  751. }
  752. func (self *SAliyunClient) getSubAccount() ([]cloudprovider.SSubAccount, error) {
  753. subAccount := cloudprovider.SSubAccount{}
  754. subAccount.Id = self.GetAccountId()
  755. subAccount.Name = self.cpcfg.Name
  756. subAccount.Account = self.accessKey
  757. subAccount.HealthStatus = api.CLOUD_PROVIDER_HEALTH_NORMAL
  758. return []cloudprovider.SSubAccount{subAccount}, nil
  759. }
  760. func (self *SAliyunClient) GetSubAccounts() ([]cloudprovider.SSubAccount, error) {
  761. err := self.fetchRegions()
  762. if err != nil {
  763. return nil, err
  764. }
  765. ret, err := self.getSubAccount()
  766. if err != nil {
  767. return nil, errors.Wrapf(err, "GetSubAccount")
  768. }
  769. accountId := self.GetAccountId()
  770. if strings.HasSuffix(self.arn, ":root") {
  771. return ret, nil
  772. }
  773. accounts, err := self.ListAccounts()
  774. if err != nil {
  775. if e, ok := errors.Cause(err).(*alierr.ServerError); ok && (e.ErrorCode() == "EntityNotExists.ResourceDirectory" || e.ErrorCode() == "NoPermission") {
  776. return ret, nil
  777. }
  778. return nil, errors.Wrapf(err, "ListAccounts")
  779. }
  780. for i := range accounts {
  781. account := cloudprovider.SSubAccount{}
  782. account.Name = fmt.Sprintf("%s/%s", accounts[i].DisplayName, self.cpcfg.Name)
  783. account.Account = self.accessKey
  784. account.Id = accountId
  785. account.HealthStatus = api.CLOUD_PROVIDER_HEALTH_SUSPENDED
  786. if strings.HasSuffix(accounts[i].Status, "Success") {
  787. account.HealthStatus = api.CLOUD_PROVIDER_HEALTH_NORMAL
  788. }
  789. if accounts[i].AccountId != accountId {
  790. account.Name = fmt.Sprintf("%s/%s", accounts[i].DisplayName, accounts[i].AccountId)
  791. account.Account = fmt.Sprintf("%s/%s", self.accessKey, accounts[i].AccountId)
  792. account.Id = accounts[i].AccountId
  793. }
  794. ret = append(ret, account)
  795. }
  796. return ret, nil
  797. }
  798. func (self *SAliyunClient) GetAccountId() string {
  799. if len(self.ownerId) > 0 {
  800. return self.ownerId
  801. }
  802. caller, err := self.GetCallerIdentity()
  803. if err != nil {
  804. log.Errorf("GetCallerIdentity fail %s", err)
  805. return ""
  806. }
  807. self.ownerId = caller.AccountId
  808. self.arn = caller.Arn
  809. return self.ownerId
  810. }
  811. func (self *SAliyunClient) GetIRegions() ([]cloudprovider.ICloudRegion, error) {
  812. return self.iregions, nil
  813. }
  814. func (self *SAliyunClient) GetIRegionById(id string) (cloudprovider.ICloudRegion, error) {
  815. for i := 0; i < len(self.iregions); i += 1 {
  816. if self.iregions[i].GetGlobalId() == id {
  817. return self.iregions[i], nil
  818. }
  819. }
  820. return nil, cloudprovider.ErrNotFound
  821. }
  822. func (self *SAliyunClient) GetRegion(regionId string) *SRegion {
  823. if len(regionId) == 0 {
  824. regionId = ALIYUN_DEFAULT_REGION
  825. }
  826. for i := 0; i < len(self.iregions); i += 1 {
  827. if self.iregions[i].GetId() == regionId {
  828. return self.iregions[i].(*SRegion)
  829. }
  830. }
  831. return nil
  832. }
  833. func (self *SAliyunClient) GetIHostById(id string) (cloudprovider.ICloudHost, error) {
  834. for i := 0; i < len(self.iregions); i += 1 {
  835. ihost, err := self.iregions[i].GetIHostById(id)
  836. if err == nil {
  837. return ihost, nil
  838. } else if errors.Cause(err) != cloudprovider.ErrNotFound {
  839. return nil, err
  840. }
  841. }
  842. return nil, cloudprovider.ErrNotFound
  843. }
  844. func (self *SAliyunClient) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) {
  845. for i := 0; i < len(self.iregions); i += 1 {
  846. ihost, err := self.iregions[i].GetIVpcById(id)
  847. if err == nil {
  848. return ihost, nil
  849. } else if errors.Cause(err) != cloudprovider.ErrNotFound {
  850. return nil, err
  851. }
  852. }
  853. return nil, cloudprovider.ErrNotFound
  854. }
  855. func (self *SAliyunClient) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) {
  856. for i := 0; i < len(self.iregions); i += 1 {
  857. ihost, err := self.iregions[i].GetIStorageById(id)
  858. if err == nil {
  859. return ihost, nil
  860. } else if errors.Cause(err) != cloudprovider.ErrNotFound {
  861. return nil, err
  862. }
  863. }
  864. return nil, cloudprovider.ErrNotFound
  865. }
  866. func (self *SAliyunClient) GetProjects() ([]SResourceGroup, error) {
  867. pageSize, pageNumber := 50, 1
  868. resourceGroups := []SResourceGroup{}
  869. for {
  870. parts, total, err := self.GetResourceGroups(pageNumber, pageSize)
  871. if err != nil {
  872. return nil, errors.Wrap(err, "GetResourceGroups")
  873. }
  874. resourceGroups = append(resourceGroups, parts...)
  875. if len(resourceGroups) >= total {
  876. break
  877. }
  878. pageNumber += 1
  879. }
  880. return resourceGroups, nil
  881. }
  882. func (self *SAliyunClient) SetResourceGropuId(params map[string]string) map[string]string {
  883. if params == nil {
  884. params = map[string]string{}
  885. }
  886. for _, groupId := range self.cpcfg.AliyunResourceGroupIds {
  887. if utils.IsInStringArray(groupId, self.GetResourceGroupIds()) {
  888. params["ResourceGroupId"] = groupId
  889. }
  890. }
  891. return params
  892. }
  893. func (self *SAliyunClient) GetResourceGroupIds() []string {
  894. ret := []string{}
  895. resourceGroups, err := self.GetProjects()
  896. if err != nil {
  897. return ret
  898. }
  899. for i := range resourceGroups {
  900. ret = append(ret, resourceGroups[i].Id)
  901. }
  902. return ret
  903. }
  904. func (self *SAliyunClient) GetIProjects() ([]cloudprovider.ICloudProject, error) {
  905. ret := []cloudprovider.ICloudProject{}
  906. resourceGroups, err := self.GetProjects()
  907. if err != nil {
  908. return nil, err
  909. }
  910. for i := range resourceGroups {
  911. resourceGroups[i].client = self
  912. ret = append(ret, &resourceGroups[i])
  913. }
  914. return ret, nil
  915. }
  916. func (self *SAliyunClient) scRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) {
  917. client, err := self.getSdkClient(ALIYUN_DEFAULT_REGION)
  918. if err != nil {
  919. return nil, err
  920. }
  921. domain := "cas.aliyuncs.com"
  922. return jsonRequest(client, domain, ALIYUN_CAS_API_VERSION, apiName, params, self.debug)
  923. }
  924. func (self *SAliyunClient) GetISSLCertificates() ([]cloudprovider.ICloudSSLCertificate, error) {
  925. ret := make([]SSSLCertificate, 0)
  926. for {
  927. part, total, err := self.GetSSLCertificates(100, len(ret)/100+1)
  928. if err != nil {
  929. return nil, errors.Wrapf(err, "GetSSLCertificates")
  930. }
  931. ret = append(ret, part...)
  932. if len(ret) >= total {
  933. break
  934. }
  935. }
  936. result := make([]cloudprovider.ICloudSSLCertificate, 0)
  937. for i := range ret {
  938. if !ret[i].BuyInAliyun {
  939. continue
  940. }
  941. ret[i].client = self
  942. result = append(result, &ret[i])
  943. }
  944. return result, nil
  945. }
  946. func (self *SAliyunClient) GetISSLCertificate(certId string) (cloudprovider.ICloudSSLCertificate, error) {
  947. var res cloudprovider.ICloudSSLCertificate
  948. res, err := self.GetSSLCertificate(certId)
  949. if err != nil {
  950. return nil, errors.Wrapf(err, "GetSSLCertificate")
  951. }
  952. return res, nil
  953. }
  954. func (region *SAliyunClient) GetCapabilities() []string {
  955. caps := []string{
  956. cloudprovider.CLOUD_CAPABILITY_PROJECT,
  957. cloudprovider.CLOUD_CAPABILITY_COMPUTE,
  958. cloudprovider.CLOUD_CAPABILITY_NETWORK,
  959. cloudprovider.CLOUD_CAPABILITY_SECURITY_GROUP,
  960. cloudprovider.CLOUD_CAPABILITY_EIP,
  961. cloudprovider.CLOUD_CAPABILITY_LOADBALANCER,
  962. cloudprovider.CLOUD_CAPABILITY_OBJECTSTORE,
  963. cloudprovider.CLOUD_CAPABILITY_RDS,
  964. cloudprovider.CLOUD_CAPABILITY_CACHE,
  965. cloudprovider.CLOUD_CAPABILITY_EVENT,
  966. cloudprovider.CLOUD_CAPABILITY_CLOUDID,
  967. cloudprovider.CLOUD_CAPABILITY_DNSZONE,
  968. cloudprovider.CLOUD_CAPABILITY_INTERVPCNETWORK,
  969. cloudprovider.CLOUD_CAPABILITY_SAML_AUTH,
  970. cloudprovider.CLOUD_CAPABILITY_NAT,
  971. cloudprovider.CLOUD_CAPABILITY_NAS,
  972. cloudprovider.CLOUD_CAPABILITY_WAF,
  973. cloudprovider.CLOUD_CAPABILITY_QUOTA + cloudprovider.READ_ONLY_SUFFIX,
  974. cloudprovider.CLOUD_CAPABILITY_MONGO_DB + cloudprovider.READ_ONLY_SUFFIX,
  975. cloudprovider.CLOUD_CAPABILITY_ES + cloudprovider.READ_ONLY_SUFFIX,
  976. cloudprovider.CLOUD_CAPABILITY_KAFKA + cloudprovider.READ_ONLY_SUFFIX,
  977. cloudprovider.CLOUD_CAPABILITY_CDN + cloudprovider.READ_ONLY_SUFFIX,
  978. cloudprovider.CLOUD_CAPABILITY_CONTAINER + cloudprovider.READ_ONLY_SUFFIX,
  979. cloudprovider.CLOUD_CAPABILITY_TABLESTORE + cloudprovider.READ_ONLY_SUFFIX,
  980. cloudprovider.CLOUD_CAPABILITY_CERT,
  981. cloudprovider.CLOUD_CAPABILITY_SNAPSHOT_POLICY,
  982. }
  983. return caps
  984. }
  985. func (self *SAliyunClient) GetAccessEnv() string {
  986. switch self.cloudEnv {
  987. case ALIYUN_INTERNATIONAL_CLOUDENV:
  988. return api.CLOUD_ACCESS_ENV_ALIYUN_GLOBAL
  989. case ALIYUN_FINANCE_CLOUDENV:
  990. return api.CLOUD_ACCESS_ENV_ALIYUN_FINANCE
  991. default:
  992. return api.CLOUD_ACCESS_ENV_ALIYUN_GLOBAL
  993. }
  994. }