region.go 27 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024
  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 qcloud
  15. import (
  16. "context"
  17. "fmt"
  18. "strconv"
  19. "strings"
  20. "time"
  21. "github.com/tencentyun/cos-go-sdk-v5"
  22. "yunion.io/x/jsonutils"
  23. "yunion.io/x/log"
  24. "yunion.io/x/pkg/errors"
  25. "yunion.io/x/pkg/utils"
  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. type SRegion struct {
  31. multicloud.SRegion
  32. client *SQcloudClient
  33. storageCache *SStoragecache
  34. instanceTypes []SInstanceType
  35. Region string
  36. RegionName string
  37. RegionState string
  38. Latitude float64
  39. Longitude float64
  40. fetchLocation bool
  41. }
  42. // 腾讯云不支持acl
  43. func (self *SRegion) GetILoadBalancerAcls() ([]cloudprovider.ICloudLoadbalancerAcl, error) {
  44. return []cloudprovider.ICloudLoadbalancerAcl{}, nil
  45. }
  46. func (self *SRegion) GetILoadBalancerAclById(aclId string) (cloudprovider.ICloudLoadbalancerAcl, error) {
  47. return nil, cloudprovider.ErrNotFound
  48. }
  49. func (self *SRegion) CreateILoadBalancerAcl(acl *cloudprovider.SLoadbalancerAccessControlList) (cloudprovider.ICloudLoadbalancerAcl, error) {
  50. return nil, cloudprovider.ErrNotSupported
  51. }
  52. func (self *SRegion) GetId() string {
  53. return self.Region
  54. }
  55. func (self *SRegion) GetName() string {
  56. return self.RegionName
  57. }
  58. func (self *SRegion) GetI18n() cloudprovider.SModelI18nTable {
  59. en := self.RegionName
  60. table := cloudprovider.SModelI18nTable{}
  61. table["name"] = cloudprovider.NewSModelI18nEntry(self.GetName()).CN(self.GetName()).EN(en)
  62. return table
  63. }
  64. func (self *SRegion) GetGlobalId() string {
  65. return fmt.Sprintf("%s/%s", CLOUD_PROVIDER_QCLOUD, self.Region)
  66. }
  67. func (self *SRegion) GetProvider() string {
  68. return CLOUD_PROVIDER_QCLOUD
  69. }
  70. func (self *SRegion) GetCloudEnv() string {
  71. return ""
  72. }
  73. func (self *SRegion) CreateIVpc(opts *cloudprovider.VpcCreateOptions) (cloudprovider.ICloudVpc, error) {
  74. params := make(map[string]string)
  75. if len(opts.CIDR) > 0 {
  76. params["CidrBlock"] = opts.CIDR
  77. }
  78. if len(opts.NAME) > 0 {
  79. params["VpcName"] = opts.NAME
  80. }
  81. body, err := self.vpcRequest("CreateVpc", params)
  82. if err != nil {
  83. return nil, err
  84. }
  85. vpcId, err := body.GetString("Vpc", "VpcId")
  86. if err != nil {
  87. return nil, err
  88. }
  89. vpc, err := self.GetVpc(vpcId)
  90. if err != nil {
  91. return nil, err
  92. }
  93. return vpc, nil
  94. }
  95. func (self *SRegion) GetCosClient(bucket *SBucket) (*cos.Client, error) {
  96. return self.client.getCosClient(bucket)
  97. }
  98. func (self *SRegion) GetClient() *SQcloudClient {
  99. return self.client
  100. }
  101. func (self *SRegion) GetIVMById(id string) (cloudprovider.ICloudVM, error) {
  102. return self.GetInstance(id)
  103. }
  104. func (self *SRegion) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) {
  105. return self.GetDisk(id)
  106. }
  107. func (self *SRegion) GetIEipById(eipId string) (cloudprovider.ICloudEIP, error) {
  108. if len(eipId) == 0 {
  109. return nil, cloudprovider.ErrNotFound
  110. }
  111. eips, total, err := self.GetEips(eipId, "", 0, 1)
  112. if err != nil {
  113. return nil, err
  114. }
  115. if total == 0 {
  116. return nil, cloudprovider.ErrNotFound
  117. }
  118. if total > 1 {
  119. return nil, cloudprovider.ErrDuplicateId
  120. }
  121. return &eips[0], nil
  122. }
  123. func (self *SRegion) GetIEips() ([]cloudprovider.ICloudEIP, error) {
  124. eips, total, err := self.GetEips("", "", 0, 50)
  125. if err != nil {
  126. return nil, err
  127. }
  128. for len(eips) < total {
  129. var parts []SEipAddress
  130. parts, total, err = self.GetEips("", "", len(eips), 50)
  131. if err != nil {
  132. return nil, err
  133. }
  134. eips = append(eips, parts...)
  135. }
  136. ret := make([]cloudprovider.ICloudEIP, len(eips))
  137. for i := 0; i < len(eips); i++ {
  138. ret[i] = &eips[i]
  139. }
  140. return ret, nil
  141. }
  142. func (self *SRegion) GetIHostById(id string) (cloudprovider.ICloudHost, error) {
  143. izones, err := self.GetIZones()
  144. if err != nil {
  145. return nil, err
  146. }
  147. for i := 0; i < len(izones); i += 1 {
  148. ihost, err := izones[i].GetIHostById(id)
  149. if err == nil {
  150. return ihost, nil
  151. } else if errors.Cause(err) != cloudprovider.ErrNotFound {
  152. return nil, err
  153. }
  154. }
  155. return nil, cloudprovider.ErrNotFound
  156. }
  157. func (self *SRegion) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) {
  158. izones, err := self.GetIZones()
  159. if err != nil {
  160. return nil, err
  161. }
  162. for i := 0; i < len(izones); i += 1 {
  163. istore, err := izones[i].GetIStorageById(id)
  164. if err == nil {
  165. return istore, nil
  166. } else if errors.Cause(err) != cloudprovider.ErrNotFound {
  167. return nil, err
  168. }
  169. }
  170. return nil, cloudprovider.ErrNotFound
  171. }
  172. func (self *SRegion) GetIHosts() ([]cloudprovider.ICloudHost, error) {
  173. iHosts := make([]cloudprovider.ICloudHost, 0)
  174. izones, err := self.GetIZones()
  175. if err != nil {
  176. return nil, err
  177. }
  178. for i := 0; i < len(izones); i += 1 {
  179. iZoneHost, err := izones[i].GetIHosts()
  180. if err != nil {
  181. return nil, err
  182. }
  183. iHosts = append(iHosts, iZoneHost...)
  184. }
  185. return iHosts, nil
  186. }
  187. func (self *SRegion) GetIStorages() ([]cloudprovider.ICloudStorage, error) {
  188. iStores := make([]cloudprovider.ICloudStorage, 0)
  189. izones, err := self.GetIZones()
  190. if err != nil {
  191. return nil, err
  192. }
  193. for i := 0; i < len(izones); i += 1 {
  194. iZoneStores, err := izones[i].GetIStorages()
  195. if err != nil {
  196. return nil, err
  197. }
  198. iStores = append(iStores, iZoneStores...)
  199. }
  200. return iStores, nil
  201. }
  202. func (self *SRegion) GetIStoragecacheById(id string) (cloudprovider.ICloudStoragecache, error) {
  203. storageCache := self.getStoragecache()
  204. if storageCache.GetGlobalId() == id {
  205. return self.storageCache, nil
  206. }
  207. return nil, cloudprovider.ErrNotFound
  208. }
  209. func (self *SRegion) GetIStoragecaches() ([]cloudprovider.ICloudStoragecache, error) {
  210. storageCache := self.getStoragecache()
  211. return []cloudprovider.ICloudStoragecache{storageCache}, nil
  212. }
  213. func (self *SRegion) updateInstance(instId string, name, desc, passwd, hostname string) error {
  214. params := make(map[string]string)
  215. params["InstanceId"] = instId
  216. if len(name) > 0 {
  217. params["InstanceName"] = name
  218. }
  219. if len(desc) > 0 {
  220. params["Description"] = desc
  221. }
  222. if len(passwd) > 0 {
  223. params["Password"] = passwd
  224. }
  225. if len(hostname) > 0 {
  226. params["HostName"] = hostname
  227. }
  228. _, err := self.cvmRequest("ModifyInstanceAttribute", params, true)
  229. return err
  230. }
  231. func (self *SRegion) UpdateInstancePassword(instId string, passwd string) error {
  232. return self.updateInstance(instId, "", "", passwd, "")
  233. }
  234. func (self *SRegion) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) {
  235. ivpcs, err := self.GetIVpcs()
  236. if err != nil {
  237. return nil, err
  238. }
  239. for i := 0; i < len(ivpcs); i++ {
  240. if ivpcs[i].GetGlobalId() == id {
  241. return ivpcs[i], nil
  242. }
  243. }
  244. return nil, cloudprovider.ErrNotFound
  245. }
  246. func (self *SRegion) getZoneById(id string) (*SZone, error) {
  247. zones, err := self.GetZones()
  248. if err != nil {
  249. return nil, err
  250. }
  251. for i := 0; i < len(zones); i += 1 {
  252. if zones[i].Zone == id {
  253. return &zones[i], nil
  254. }
  255. }
  256. return nil, errors.Wrapf(cloudprovider.ErrNotFound, "%s", id)
  257. }
  258. func (self *SRegion) GetIVpcs() ([]cloudprovider.ICloudVpc, error) {
  259. vpcs, err := self.GetVpcs(nil)
  260. if err != nil {
  261. return nil, errors.Wrapf(err, "GetVpcs")
  262. }
  263. ret := []cloudprovider.ICloudVpc{}
  264. for i := range vpcs {
  265. ret = append(ret, &vpcs[i])
  266. }
  267. return ret, nil
  268. }
  269. func (self *SRegion) GetIZoneById(id string) (cloudprovider.ICloudZone, error) {
  270. izones, err := self.GetIZones()
  271. if err != nil {
  272. return nil, err
  273. }
  274. for i := 0; i < len(izones); i += 1 {
  275. if izones[i].GetGlobalId() == id {
  276. return izones[i], nil
  277. }
  278. }
  279. return nil, cloudprovider.ErrNotFound
  280. }
  281. func (self *SRegion) GetIZones() ([]cloudprovider.ICloudZone, error) {
  282. zones, err := self.GetZones()
  283. if err != nil {
  284. return nil, err
  285. }
  286. ret := []cloudprovider.ICloudZone{}
  287. for i := range zones {
  288. ret = append(ret, &zones[i])
  289. }
  290. return ret, nil
  291. }
  292. func getReplaceKey(zoneId string) string {
  293. replceKey := map[string]string{"1": "一", "2": "二", "3": "三", "4": "四", "5": "五", "6": "六", "7": "七", "8": "八", "9": "九"}
  294. info := strings.Split(zoneId, "-")
  295. if len(info) >= 3 {
  296. return replceKey[info[len(info)-1]]
  297. }
  298. return ""
  299. }
  300. func (self *SRegion) GetZones() ([]SZone, error) {
  301. body, err := self.cvmRequest("DescribeZones", map[string]string{}, true)
  302. if err != nil {
  303. return nil, err
  304. }
  305. zones := make([]SZone, 0)
  306. err = body.Unmarshal(&zones, "ZoneSet")
  307. if err != nil {
  308. return nil, err
  309. }
  310. zoneName, zoneNameReplace := "", ""
  311. zoneMap := map[string]bool{}
  312. for i := 0; i < len(zones); i++ {
  313. if len(zoneName) == 0 {
  314. zoneName = zones[i].ZoneName
  315. zoneNameReplace = getReplaceKey(zones[i].Zone)
  316. }
  317. zones[i].region = self
  318. zoneMap[zones[i].Zone] = true
  319. }
  320. networks, err := self.GetNetworks(nil, "", "")
  321. if err != nil {
  322. return nil, errors.Wrapf(err, "GetNetworks")
  323. }
  324. for _, network := range networks {
  325. if _, ok := zoneMap[network.Zone]; !ok {
  326. zoneMap[network.Zone] = true
  327. zone := SZone{region: self, Zone: network.Zone, ZoneState: "Unknown"}
  328. newKey := getReplaceKey(network.Zone)
  329. if len(zoneNameReplace) > 0 && len(newKey) > 0 {
  330. zone.ZoneName = strings.Replace(zoneName, zoneNameReplace, newKey, 1)
  331. }
  332. zones = append(zones, zone)
  333. }
  334. }
  335. return zones, nil
  336. }
  337. func (self *SRegion) DeleteVpc(vpcId string) error {
  338. params := make(map[string]string)
  339. params["VpcId"] = vpcId
  340. _, err := self.vpcRequest("DeleteVpc", params)
  341. return err
  342. }
  343. func (self *SRegion) GetVpc(vpcId string) (*SVpc, error) {
  344. vpcs, err := self.GetVpcs([]string{vpcId})
  345. if err != nil {
  346. return nil, err
  347. }
  348. for i := range vpcs {
  349. if vpcs[i].VpcId == vpcId {
  350. vpcs[i].region = self
  351. return &vpcs[i], nil
  352. }
  353. }
  354. return nil, errors.Wrapf(cloudprovider.ErrNotFound, "GetVpc(%s)", vpcId)
  355. }
  356. func (self *SRegion) GetVpcs(vpcIds []string) ([]SVpc, error) {
  357. params := map[string]string{
  358. "Limit": "100",
  359. }
  360. for index, vpcId := range vpcIds {
  361. params[fmt.Sprintf("VpcIds.%d", index)] = vpcId
  362. }
  363. ret := []SVpc{}
  364. for {
  365. resp, err := self.vpcRequest("DescribeVpcs", params)
  366. if err != nil {
  367. return nil, err
  368. }
  369. part := struct {
  370. VpcSet []SVpc
  371. TotalCount float64
  372. }{}
  373. err = resp.Unmarshal(&part)
  374. if err != nil {
  375. return nil, errors.Wrapf(err, "Unmarshal")
  376. }
  377. for i := range part.VpcSet {
  378. part.VpcSet[i].region = self
  379. ret = append(ret, part.VpcSet[i])
  380. }
  381. if len(ret) >= int(part.TotalCount) || len(part.VpcSet) == 0 {
  382. break
  383. }
  384. params["Offset"] = fmt.Sprintf("%d", len(ret))
  385. }
  386. return ret, nil
  387. }
  388. func (self *SRegion) GetGeographicInfo() cloudprovider.SGeographicInfo {
  389. if info, ok := LatitudeAndLongitude[self.Region]; ok {
  390. return info
  391. }
  392. return cloudprovider.SGeographicInfo{}
  393. }
  394. func (self *SRegion) GetStatus() string {
  395. if self.RegionState == "AVAILABLE" {
  396. return api.CLOUD_REGION_STATUS_INSERVER
  397. }
  398. return api.CLOUD_REGION_STATUS_OUTOFSERVICE
  399. }
  400. func (self *SRegion) Refresh() error {
  401. // do nothing
  402. return nil
  403. }
  404. // 容器
  405. func (self *SRegion) tkeRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) {
  406. params["Region"] = self.Region
  407. return self.client.tkeRequest(apiName, params)
  408. }
  409. func (self *SRegion) vpcRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) {
  410. params["Region"] = self.Region
  411. return self.client.vpcRequest(apiName, params)
  412. }
  413. func (self *SRegion) auditRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) {
  414. params["Region"] = self.Region
  415. return self.client.auditRequest(apiName, params)
  416. }
  417. func (self *SRegion) cvmRequest(apiName string, params map[string]string, retry bool) (jsonutils.JSONObject, error) {
  418. params["Region"] = self.Region
  419. return self.client.jsonRequest(apiName, params, retry)
  420. }
  421. func (self *SRegion) cbsRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) {
  422. params["Region"] = self.Region
  423. return self.client.cbsRequest(apiName, params)
  424. }
  425. func (self *SRegion) clbRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) {
  426. params["Region"] = self.Region
  427. return self.client.clbRequest(apiName, params)
  428. }
  429. func (self *SRegion) cdbRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) {
  430. params["Region"] = self.Region
  431. return self.client.cdbRequest(apiName, params)
  432. }
  433. func (self *SRegion) mariadbRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) {
  434. params["Region"] = self.Region
  435. return self.client.mariadbRequest(apiName, params)
  436. }
  437. func (self *SRegion) postgresRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) {
  438. params["Region"] = self.Region
  439. return self.client.postgresRequest(apiName, params)
  440. }
  441. func (self *SRegion) sqlserverRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) {
  442. params["Region"] = self.Region
  443. return self.client.sqlserverRequest(apiName, params)
  444. }
  445. func (self *SRegion) kafkaRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) {
  446. params["Region"] = self.Region
  447. return self.client.kafkaRequest(apiName, params)
  448. }
  449. func (self *SRegion) redisRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) {
  450. params["Region"] = self.Region
  451. return self.client.redisRequest(apiName, params)
  452. }
  453. func (self *SRegion) dcdbRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) {
  454. params["Region"] = self.Region
  455. return self.client.dcdbRequest(apiName, params)
  456. }
  457. func (self *SRegion) mongodbRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) {
  458. params["Region"] = self.Region
  459. return self.client.mongodbRequest(apiName, params)
  460. }
  461. // Elasticsearch
  462. func (self *SRegion) esRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) {
  463. params["Region"] = self.Region
  464. return self.client.esRequest(apiName, params)
  465. }
  466. func (self *SRegion) wafRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) {
  467. params["Region"] = self.Region
  468. return self.client.wafRequest(apiName, params)
  469. }
  470. func (self *SRegion) memcachedRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) {
  471. params["Region"] = self.Region
  472. return self.client.memcachedRequest(apiName, params)
  473. }
  474. func (self *SRegion) GetNetworks(ids []string, vpcId, zone string) ([]SNetwork, error) {
  475. params := map[string]string{
  476. "Limit": "100",
  477. }
  478. for index, networkId := range ids {
  479. params[fmt.Sprintf("SubnetIds.%d", index)] = networkId
  480. }
  481. base := 0
  482. if len(vpcId) > 0 {
  483. params[fmt.Sprintf("Filters.%d.Name", base)] = "vpc-id"
  484. params[fmt.Sprintf("Filters.%d.Values.0", base)] = vpcId
  485. base++
  486. }
  487. if len(zone) > 0 {
  488. params[fmt.Sprintf("Filters.%d.Name", base)] = "zone"
  489. params[fmt.Sprintf("Filters.%d.Values.0", base)] = zone
  490. base++
  491. }
  492. ret := []SNetwork{}
  493. for {
  494. resp, err := self.vpcRequest("DescribeSubnets", params)
  495. if err != nil {
  496. return nil, err
  497. }
  498. part := struct {
  499. SubnetSet []SNetwork
  500. TotalCount float64
  501. }{}
  502. err = resp.Unmarshal(&part)
  503. if err != nil {
  504. return nil, err
  505. }
  506. ret = append(ret, part.SubnetSet...)
  507. if len(ret) >= int(part.TotalCount) || len(part.SubnetSet) == 0 {
  508. break
  509. }
  510. params["Offset"] = fmt.Sprintf("%d", len(ret))
  511. }
  512. return ret, nil
  513. }
  514. func (self *SRegion) GetNetwork(id string) (*SNetwork, error) {
  515. networks, err := self.GetNetworks([]string{id}, "", "")
  516. if err != nil {
  517. return nil, err
  518. }
  519. for i := range networks {
  520. if networks[i].SubnetId == id {
  521. return &networks[i], nil
  522. }
  523. }
  524. return nil, errors.Wrapf(cloudprovider.ErrNotFound, "%s", id)
  525. }
  526. func (self *SRegion) getStoragecache() *SStoragecache {
  527. if self.storageCache == nil {
  528. self.storageCache = &SStoragecache{region: self}
  529. }
  530. return self.storageCache
  531. }
  532. func (self *SRegion) CreateInstanceSimple(name string, imgId string, cpu int, memGB int, storageType string, dataDiskSizesGB []int, networkId string, passwd string, publicKey string, secgroup string, tags map[string]string) (*SInstance, error) {
  533. zones, err := self.GetZones()
  534. if err != nil {
  535. return nil, err
  536. }
  537. net, err := self.GetNetwork(networkId)
  538. if err != nil {
  539. return nil, err
  540. }
  541. for i := 0; i < len(zones); i += 1 {
  542. zone := zones[i]
  543. log.Debugf("Search in zone %s", zone.Zone)
  544. if zone.ZoneName != net.Zone {
  545. continue
  546. }
  547. desc := &cloudprovider.SManagedVMCreateConfig{
  548. Name: name,
  549. ExternalImageId: imgId,
  550. SysDisk: cloudprovider.SDiskInfo{SizeGB: 0, StorageType: storageType},
  551. Cpu: cpu,
  552. MemoryMB: memGB * 1024,
  553. ExternalNetworkId: networkId,
  554. Password: passwd,
  555. DataDisks: []cloudprovider.SDiskInfo{},
  556. PublicKey: publicKey,
  557. Tags: tags,
  558. ExternalSecgroupIds: []string{secgroup},
  559. }
  560. for _, sizeGB := range dataDiskSizesGB {
  561. desc.DataDisks = append(desc.DataDisks, cloudprovider.SDiskInfo{SizeGB: sizeGB, StorageType: storageType})
  562. }
  563. inst, err := zone.getHost().CreateVM(desc)
  564. if err != nil {
  565. return nil, err
  566. }
  567. return inst.(*SInstance), nil
  568. }
  569. return nil, fmt.Errorf("cannot find network %s", networkId)
  570. }
  571. func (self *SRegion) instanceOperation(instanceId string, opname string, extra map[string]string, retry bool) error {
  572. params := make(map[string]string)
  573. params["InstanceIds.0"] = instanceId
  574. if extra != nil && len(extra) > 0 {
  575. for k, v := range extra {
  576. params[k] = v
  577. }
  578. }
  579. _, err := self.cvmRequest(opname, params, retry)
  580. return err
  581. }
  582. func (self *SRegion) GetInstanceVNCUrl(instanceId string) (string, error) {
  583. params := make(map[string]string)
  584. params["InstanceId"] = instanceId
  585. body, err := self.cvmRequest("DescribeInstanceVncUrl", params, true)
  586. if err != nil {
  587. return "", err
  588. }
  589. return body.GetString("InstanceVncUrl")
  590. }
  591. func (self *SRegion) GetInstanceStatus(instanceId string) (string, error) {
  592. instance, err := self.GetInstance(instanceId)
  593. if err != nil {
  594. return "", err
  595. }
  596. return instance.InstanceState, nil
  597. }
  598. func (self *SRegion) QueryAccountBalance() (*SAccountBalance, error) {
  599. return self.client.QueryAccountBalance()
  600. }
  601. func (self *SRegion) getCosEndpoint() string {
  602. return fmt.Sprintf("cos.%s.myqcloud.com", self.GetId())
  603. }
  604. func (self *SRegion) getCosWebsiteEndpoint() string {
  605. return fmt.Sprintf("cos-website.%s.myqcloud.com", self.GetId())
  606. }
  607. func (region *SRegion) GetIBuckets() ([]cloudprovider.ICloudBucket, error) {
  608. iBuckets, err := region.client.getIBuckets()
  609. if err != nil {
  610. return nil, err
  611. }
  612. ret := make([]cloudprovider.ICloudBucket, 0)
  613. for i := range iBuckets {
  614. bucket := iBuckets[i].(*SBucket)
  615. if bucket.region.GetId() != region.GetId() {
  616. continue
  617. }
  618. ret = append(ret, iBuckets[i])
  619. }
  620. return ret, nil
  621. }
  622. func (region *SRegion) CreateIBucket(name string, storageClassStr string, aclStr string) error {
  623. bucket := &SBucket{
  624. region: region,
  625. Name: name,
  626. }
  627. coscli, err := region.GetCosClient(bucket)
  628. if err != nil {
  629. return errors.Wrap(err, "GetCosClient")
  630. }
  631. opts := &cos.BucketPutOptions{}
  632. if len(aclStr) > 0 {
  633. if utils.IsInStringArray(aclStr, []string{
  634. "private", "public-read", "public-read-write", "authenticated-read",
  635. }) {
  636. opts.XCosACL = aclStr
  637. } else {
  638. return errors.Error("invalid acl")
  639. }
  640. }
  641. _, err = coscli.Bucket.Put(context.Background(), opts)
  642. if err != nil {
  643. return errors.Wrap(err, "coscli.Bucket.Put")
  644. }
  645. region.client.invalidateIBuckets()
  646. return nil
  647. }
  648. func cosHttpCode(err error) int {
  649. if httpErr, ok := err.(*cos.ErrorResponse); ok {
  650. return httpErr.Response.StatusCode
  651. }
  652. return -1
  653. }
  654. func (region *SRegion) DeleteIBucket(name string) error {
  655. bucket := &SBucket{
  656. region: region,
  657. Name: name,
  658. }
  659. coscli, err := region.GetCosClient(bucket)
  660. if err != nil {
  661. return errors.Wrap(err, "GetCosClient")
  662. }
  663. _, err = coscli.Bucket.Delete(context.Background())
  664. if err != nil {
  665. if cosHttpCode(err) == 404 {
  666. return nil
  667. }
  668. return errors.Wrap(err, "DeleteBucket")
  669. }
  670. return nil
  671. }
  672. func (region *SRegion) IBucketExist(name string) (bool, error) {
  673. bucket := &SBucket{
  674. region: region,
  675. Name: name,
  676. }
  677. coscli, err := region.GetCosClient(bucket)
  678. if err != nil {
  679. return false, errors.Wrap(err, "GetCosClient")
  680. }
  681. _, err = coscli.Bucket.Head(context.Background())
  682. if err != nil {
  683. if cosHttpCode(err) == 404 {
  684. return false, nil
  685. }
  686. return false, errors.Wrap(err, "BucketExists")
  687. }
  688. return true, nil
  689. }
  690. func (region *SRegion) GetIBucketById(name string) (cloudprovider.ICloudBucket, error) {
  691. return cloudprovider.GetIBucketById(region, name)
  692. }
  693. func (region *SRegion) GetIBucketByName(name string) (cloudprovider.ICloudBucket, error) {
  694. return region.GetIBucketById(name)
  695. }
  696. func (self *SRegion) GetISecurityGroupById(id string) (cloudprovider.ICloudSecurityGroup, error) {
  697. secgroup, err := self.GetSecurityGroup(id)
  698. if err != nil {
  699. return nil, errors.Wrapf(err, "GetSecurityGroups(%s)", id)
  700. }
  701. return secgroup, nil
  702. }
  703. func (self *SRegion) GetISecurityGroups() ([]cloudprovider.ICloudSecurityGroup, error) {
  704. ret := []cloudprovider.ICloudSecurityGroup{}
  705. for {
  706. part, total, err := self.GetSecurityGroups(nil, "", len(ret), 100)
  707. if err != nil {
  708. return nil, err
  709. }
  710. for i := range part {
  711. part[i].region = self
  712. ret = append(ret, &part[i])
  713. }
  714. if len(part) == 0 || len(ret) >= total {
  715. break
  716. }
  717. }
  718. return ret, nil
  719. }
  720. func (self *SRegion) CreateISecurityGroup(opts *cloudprovider.SecurityGroupCreateInput) (cloudprovider.ICloudSecurityGroup, error) {
  721. group, err := self.CreateSecurityGroup(opts)
  722. if err != nil {
  723. return nil, err
  724. }
  725. return group, nil
  726. }
  727. func (region *SRegion) GetCapabilities() []string {
  728. return region.client.GetCapabilities()
  729. }
  730. func (region *SRegion) GetIElasticcaches() ([]cloudprovider.ICloudElasticcache, error) {
  731. caches, err := region.GetCloudElasticcaches("")
  732. if err != nil {
  733. return nil, errors.Wrap(err, "GetCloudElasticcaches")
  734. }
  735. ret := []cloudprovider.ICloudElasticcache{}
  736. for i := range caches {
  737. cache := caches[i]
  738. cache.region = region
  739. ret = append(ret, &cache)
  740. }
  741. mems := []SMemcached{}
  742. offset := 0
  743. for {
  744. part, total, err := region.GetMemcaches(nil, 100, offset)
  745. if err != nil {
  746. if errors.Cause(err) == cloudprovider.ErrNotSupported {
  747. return ret, nil
  748. }
  749. return nil, errors.Wrapf(err, "GetMemcaches")
  750. }
  751. mems = append(mems, part...)
  752. if len(mems) >= total {
  753. break
  754. }
  755. offset += len(part)
  756. }
  757. for i := range mems {
  758. mems[i].region = region
  759. ret = append(ret, &mems[i])
  760. }
  761. return ret, nil
  762. }
  763. func (region *SRegion) GetIElasticcacheById(id string) (cloudprovider.ICloudElasticcache, error) {
  764. if strings.HasPrefix(id, "cmem-") {
  765. memcacheds, _, err := region.GetMemcaches([]string{id}, 1, 0)
  766. if err != nil {
  767. return nil, errors.Wrapf(err, "GetMemcaches")
  768. }
  769. for i := range memcacheds {
  770. if memcacheds[i].GetGlobalId() == id {
  771. memcacheds[i].region = region
  772. return &memcacheds[i], nil
  773. }
  774. }
  775. return nil, errors.Wrapf(cloudprovider.ErrNotFound, "%s", id)
  776. }
  777. caches, err := region.GetCloudElasticcaches(id)
  778. if err != nil {
  779. return nil, errors.Wrap(err, "GetCloudElasticcaches")
  780. }
  781. for i := range caches {
  782. if caches[i].GetGlobalId() == id {
  783. caches[i].region = region
  784. return &caches[i], nil
  785. }
  786. }
  787. return nil, cloudprovider.ErrNotFound
  788. }
  789. // DescribeProductInfo 可以查询在售可用区信息
  790. // https://cloud.tencent.com/document/product/239/20026
  791. func (r *SRegion) CreateIElasticcaches(ec *cloudprovider.SCloudElasticCacheInput) (cloudprovider.ICloudElasticcache, error) {
  792. params := map[string]string{}
  793. if len(ec.ZoneIds) == 0 {
  794. return nil, fmt.Errorf("CreateIElasticcaches zone id should not be empty.")
  795. }
  796. zoneId, ok := zoneIdMaps[ec.ZoneIds[0]]
  797. if !ok {
  798. return nil, fmt.Errorf("can't convert zone %s to integer id", ec.ZoneIds[0])
  799. }
  800. if len(ec.ZoneIds) > 1 {
  801. for i := range ec.ZoneIds {
  802. if i == 0 {
  803. params[fmt.Sprintf("NodeSet.%d.NodeType", i)] = "0"
  804. params[fmt.Sprintf("NodeSet.%d.ZoneId", i)] = fmt.Sprintf("%d", zoneId)
  805. } else {
  806. _z, ok := zoneIdMaps[ec.ZoneIds[i]]
  807. if !ok {
  808. return nil, fmt.Errorf("can't convert zone %s to integer id", ec.ZoneIds[i])
  809. }
  810. params[fmt.Sprintf("NodeSet.%d.NodeType", i)] = "1"
  811. params[fmt.Sprintf("NodeSet.%d.ZoneId", i)] = fmt.Sprintf("%d", _z)
  812. }
  813. }
  814. }
  815. spec, err := parseLocalInstanceSpec(ec.InstanceType)
  816. if err != nil {
  817. return nil, errors.Wrap(err, "parseLocalInstanceSpec")
  818. }
  819. params["InstanceName"] = ec.InstanceName
  820. if len(ec.ProjectId) > 0 {
  821. params["ProjectId"] = ec.ProjectId
  822. }
  823. params["ZoneId"] = fmt.Sprintf("%d", zoneId)
  824. params["TypeId"] = spec.TypeId
  825. params["MemSize"] = strconv.Itoa(spec.MemSizeMB)
  826. params["RedisShardNum"] = spec.RedisShardNum
  827. params["RedisReplicasNum"] = spec.RedisReplicasNum
  828. params["GoodsNum"] = "1"
  829. if ec.NetworkType == api.LB_NETWORK_TYPE_VPC {
  830. params["VpcId"] = ec.VpcId
  831. params["SubnetId"] = ec.NetworkId
  832. for i := range ec.SecurityGroupIds {
  833. params[fmt.Sprintf("SecurityGroupIdList.%d", i)] = ec.SecurityGroupIds[i]
  834. }
  835. }
  836. params["Period"] = "1"
  837. params["BillingMode"] = "0"
  838. if ec.BillingCycle != nil && ec.BillingCycle.GetMonths() >= 1 {
  839. params["Period"] = strconv.Itoa(ec.BillingCycle.GetMonths())
  840. params["BillingMode"] = "1"
  841. // 自动续费
  842. if ec.BillingCycle.AutoRenew {
  843. params["AutoRenew"] = "1"
  844. }
  845. }
  846. if len(ec.Password) > 0 {
  847. params["NoAuth"] = "false"
  848. params["Password"] = ec.Password
  849. } else {
  850. params["NoAuth"] = "true"
  851. }
  852. resp, err := r.redisRequest("CreateInstances", params)
  853. if err != nil {
  854. return nil, errors.Wrap(err, "CreateInstances")
  855. }
  856. instanceId := ""
  857. if resp.Contains("InstanceIds") {
  858. ids := []string{}
  859. if err := resp.Unmarshal(&ids, "InstanceIds"); err != nil {
  860. log.Debugf("Unmarshal.InstanceIds %s", resp)
  861. } else {
  862. if len(ids) > 0 {
  863. instanceId = ids[0]
  864. }
  865. }
  866. }
  867. // try to fetch instance id from deal id
  868. if len(instanceId) == 0 {
  869. dealId, err := resp.GetString("DealId")
  870. if err != nil {
  871. return nil, errors.Wrap(err, "dealId")
  872. }
  873. // maybe is a dealId not a instance ID.
  874. if strings.HasPrefix(dealId, "crs-") {
  875. instanceId = dealId
  876. } else {
  877. err = cloudprovider.Wait(5*time.Second, 900*time.Second, func() (bool, error) {
  878. _realInstanceId, err := r.GetElasticcacheIdByDeal(dealId)
  879. if err != nil {
  880. return false, nil
  881. }
  882. instanceId = _realInstanceId
  883. return true, nil
  884. })
  885. if err != nil {
  886. return nil, errors.Wrap(err, "Wait.GetElasticcacheIdByDeal")
  887. }
  888. }
  889. }
  890. err = r.SetResourceTags("redis", "instance", []string{instanceId}, ec.Tags, false)
  891. if err != nil {
  892. log.Errorf("SetResourceTags(redis:%s,error:%s)", instanceId, err)
  893. }
  894. return r.GetIElasticcacheById(instanceId)
  895. }
  896. func (region *SRegion) GetIVMs() ([]cloudprovider.ICloudVM, error) {
  897. vms := make([]SInstance, 0)
  898. for {
  899. parts, total, err := region.GetInstances("", nil, len(vms), 50)
  900. if err != nil {
  901. return nil, err
  902. }
  903. vms = append(vms, parts...)
  904. if len(vms) >= total {
  905. break
  906. }
  907. }
  908. ivms := make([]cloudprovider.ICloudVM, len(vms))
  909. for i := 0; i < len(vms); i++ {
  910. ivms[i] = &vms[i]
  911. }
  912. return ivms, nil
  913. }