region.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644
  1. // Copyright 2023 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 volcengine
  15. import (
  16. "context"
  17. "fmt"
  18. "strings"
  19. "time"
  20. tos "github.com/volcengine/ve-tos-golang-sdk/v2/tos"
  21. "github.com/volcengine/ve-tos-golang-sdk/v2/tos/enum"
  22. sdk "github.com/volcengine/volc-sdk-golang/base"
  23. api "yunion.io/x/cloudmux/pkg/apis/compute"
  24. "yunion.io/x/cloudmux/pkg/cloudprovider"
  25. "yunion.io/x/cloudmux/pkg/multicloud"
  26. "yunion.io/x/jsonutils"
  27. "yunion.io/x/pkg/errors"
  28. "yunion.io/x/pkg/utils"
  29. )
  30. var RegionLocations = map[string]string{
  31. "cn-beijing": "华北2(北京)",
  32. "cn-shanghai": "华东2(上海)",
  33. "cn-guangzhou": "华南1(广州)",
  34. "ap-southeast-1": "亚太东南(柔佛)",
  35. "ap-southeast-3": "亚太东南(雅加达)",
  36. "cn-hongkong": "中国香港",
  37. }
  38. var RegionEndpoint = map[string]string{
  39. "cn-beijing": "cn-beijing.volces.com",
  40. "cn-shanghai": "cn-shanghai.volces.com",
  41. "cn-guangzhou": "cn-beijing.volces.com",
  42. "ap-southeast-1": "ap-southeast-1.volces.com",
  43. "cn-hongkong": "cn-hongkong.volces.com",
  44. "ap-southeast-3": "ap-southeast-3.volces.com",
  45. }
  46. type sStorageType struct {
  47. Id string
  48. Zones []string
  49. }
  50. type SRegion struct {
  51. multicloud.SRegion
  52. multicloud.SNoLbRegion
  53. client *SVolcEngineClient
  54. tosClient *tos.ClientV2
  55. RegionId string
  56. ivpcs []cloudprovider.ICloudVpc
  57. storageTypes []sStorageType
  58. storageCache *SStoragecache
  59. }
  60. func (region *SRegion) GetClient() *SVolcEngineClient {
  61. return region.client
  62. }
  63. func (region *SRegion) Refresh() error {
  64. return nil
  65. }
  66. func (region *SRegion) GetProvider() string {
  67. return CLOUD_PROVIDER_VOLCENGINE
  68. }
  69. func (region *SRegion) GetCloudEnv() string {
  70. return region.client.cloudEnv
  71. }
  72. func (region *SRegion) GetId() string {
  73. return region.RegionId
  74. }
  75. func (region *SRegion) GetName() string {
  76. if localName, ok := RegionLocations[region.RegionId]; ok {
  77. return localName
  78. }
  79. return region.RegionId
  80. }
  81. func (region *SRegion) GetGlobalId() string {
  82. return fmt.Sprintf("%s/%s", region.client.GetAccessEnv(), region.RegionId)
  83. }
  84. func (region *SRegion) GetI18n() cloudprovider.SModelI18nTable {
  85. return cloudprovider.SModelI18nTable{}
  86. }
  87. func (region *SRegion) GetStatus() string {
  88. return api.CLOUD_REGION_STATUS_INSERVER
  89. }
  90. func (region *SRegion) GetGeographicInfo() cloudprovider.SGeographicInfo {
  91. if info, ok := LatitudeAndLongitude[region.RegionId]; ok {
  92. return info
  93. }
  94. return cloudprovider.SGeographicInfo{}
  95. }
  96. func (region *SRegion) getStoragecache() *SStoragecache {
  97. if region.storageCache == nil {
  98. region.storageCache = &SStoragecache{region: region}
  99. }
  100. return region.storageCache
  101. }
  102. func (region *SRegion) GetZones(id string) ([]SZone, error) {
  103. params := map[string]string{}
  104. params["DestinationResource"] = "InstanceType"
  105. // DedicatedHost is not supported
  106. if len(id) > 0 {
  107. params["ZoneId"] = id
  108. }
  109. body, err := region.ecsRequest("DescribeAvailableResource", params)
  110. if err != nil {
  111. return nil, err
  112. }
  113. ret := []SZone{}
  114. err = body.Unmarshal(&ret, "AvailableZones")
  115. if err != nil {
  116. return nil, err
  117. }
  118. return ret, nil
  119. }
  120. func (region *SRegion) GetIZones() ([]cloudprovider.ICloudZone, error) {
  121. zones, err := region.GetZones("")
  122. if err != nil {
  123. return nil, errors.Wrapf(err, "GetZones")
  124. }
  125. ret := []cloudprovider.ICloudZone{}
  126. for i := range zones {
  127. zones[i].region = region
  128. ret = append(ret, &zones[i])
  129. }
  130. return ret, nil
  131. }
  132. func (region *SRegion) GetIZoneById(id string) (cloudprovider.ICloudZone, error) {
  133. zones, err := region.GetZones("")
  134. if err != nil {
  135. return nil, errors.Wrap(err, "GetZones")
  136. }
  137. for i := range zones {
  138. zones[i].region = region
  139. if zones[i].GetId() == id || zones[i].GetGlobalId() == id {
  140. return &zones[i], nil
  141. }
  142. }
  143. return nil, errors.Wrapf(cloudprovider.ErrNotFound, "%s", id)
  144. }
  145. // vpc
  146. func (region *SRegion) CreateIVpc(opts *cloudprovider.VpcCreateOptions) (cloudprovider.ICloudVpc, error) {
  147. vpc, err := region.CreateVpc(opts)
  148. if err != nil {
  149. return nil, err
  150. }
  151. return vpc, nil
  152. }
  153. func (region *SRegion) CreateVpc(opts *cloudprovider.VpcCreateOptions) (*SVpc, error) {
  154. params := make(map[string]string)
  155. if len(opts.CIDR) > 0 {
  156. params["CidrBlock"] = opts.CIDR
  157. }
  158. if len(opts.NAME) > 0 {
  159. params["VpcName"] = opts.NAME
  160. }
  161. if len(opts.Desc) > 0 {
  162. params["Description"] = opts.Desc
  163. }
  164. params["ClientToken"] = utils.GenRequestId(20)
  165. body, err := region.vpcRequest("CreateVpc", params)
  166. if err != nil {
  167. return nil, err
  168. }
  169. vpcId, err := body.GetString("VpcId")
  170. if err != nil {
  171. return nil, err
  172. }
  173. err = cloudprovider.Wait(5*time.Second, time.Minute, func() (bool, error) {
  174. _, err = region.getVpc(vpcId)
  175. if errors.Cause(err) == cloudprovider.ErrNotFound {
  176. return false, nil
  177. } else {
  178. return true, err
  179. }
  180. })
  181. if err != nil {
  182. return nil, errors.Wrapf(err, "cannot find networks after create")
  183. }
  184. return region.getVpc(vpcId)
  185. }
  186. func (region *SRegion) DeleteVpc(vpcId string) error {
  187. params := make(map[string]string)
  188. params["VpcId"] = vpcId
  189. _, err := region.vpcRequest("DeleteVpc", params)
  190. return err
  191. }
  192. func (region *SRegion) getVpc(vpcId string) (*SVpc, error) {
  193. vpcs, _, err := region.GetVpcs([]string{vpcId}, 1, 50)
  194. if err != nil {
  195. return nil, err
  196. }
  197. for _, vpc := range vpcs {
  198. if vpc.VpcId == vpcId {
  199. vpc.region = region
  200. return &vpc, nil
  201. }
  202. }
  203. return nil, errors.Wrapf(cloudprovider.ErrNotFound, "%s not found", vpcId)
  204. }
  205. func (region *SRegion) GetVpcs(vpcIds []string, pageNumber int, pageSize int) ([]SVpc, int, error) {
  206. params := make(map[string]string)
  207. params["PageSize"] = fmt.Sprintf("%d", pageSize)
  208. params["PageNumber"] = fmt.Sprintf("%d", pageNumber)
  209. if len(vpcIds) > 0 {
  210. for index, id := range vpcIds {
  211. key := fmt.Sprintf("VpcIds.%d", index+1)
  212. params[key] = id
  213. }
  214. }
  215. body, err := region.vpcRequest("DescribeVpcs", params)
  216. if err != nil {
  217. return nil, 0, errors.Wrapf(err, "GetVpcs fail")
  218. }
  219. vpcs := make([]SVpc, 0)
  220. err = body.Unmarshal(&vpcs, "Vpcs")
  221. if err != nil {
  222. return nil, 0, errors.Wrapf(err, "Unmarshal vpcs fail")
  223. }
  224. total, _ := body.Int("TotalCount")
  225. return vpcs, int(total), nil
  226. }
  227. func (region *SRegion) GetIVpcs() ([]cloudprovider.ICloudVpc, error) {
  228. if region.ivpcs == nil {
  229. vpcs, err := region.GetAllVpcs()
  230. if err != nil {
  231. return nil, err
  232. }
  233. region.ivpcs = make([]cloudprovider.ICloudVpc, len(vpcs))
  234. for i := 0; i < len(vpcs); i += 1 {
  235. vpcs[i].region = region
  236. region.ivpcs[i] = &vpcs[i]
  237. }
  238. }
  239. return region.ivpcs, nil
  240. }
  241. func (region *SRegion) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) {
  242. ivpcs, err := region.GetIVpcs()
  243. if err != nil {
  244. return nil, err
  245. }
  246. for i := 0; i < len(ivpcs); i += 1 {
  247. if ivpcs[i].GetGlobalId() == id {
  248. return ivpcs[i], nil
  249. }
  250. }
  251. return nil, cloudprovider.ErrNotFound
  252. }
  253. func (region *SRegion) GetAllVpcs() ([]SVpc, error) {
  254. vpcs := make([]SVpc, 0)
  255. pageNumber := 1
  256. for {
  257. part, total, err := region.GetVpcs(nil, pageNumber, 50)
  258. if err != nil {
  259. return nil, err
  260. }
  261. vpcs = append(vpcs, part...)
  262. if len(vpcs) >= total {
  263. break
  264. }
  265. pageNumber += 1
  266. }
  267. return vpcs, nil
  268. }
  269. // EIP
  270. func (region *SRegion) GetIEipById(eipId string) (cloudprovider.ICloudEIP, error) {
  271. eip, err := region.GetEip(eipId)
  272. if err != nil {
  273. return nil, err
  274. }
  275. return eip, nil
  276. }
  277. func (region *SRegion) GetIEips() ([]cloudprovider.ICloudEIP, error) {
  278. pageNumber := 1
  279. eips, total, err := region.GetEips(make([]string, 0), "", make([]string, 0), pageNumber, 100)
  280. if err != nil {
  281. return nil, err
  282. }
  283. for len(eips) < total {
  284. var parts []SEipAddress
  285. pageNumber++
  286. parts, total, err = region.GetEips(make([]string, 0), "", make([]string, 0), pageNumber, 100)
  287. if err != nil {
  288. return nil, err
  289. }
  290. eips = append(eips, parts...)
  291. }
  292. ret := make([]cloudprovider.ICloudEIP, len(eips))
  293. for i := 0; i < len(eips); i += 1 {
  294. ret[i] = &eips[i]
  295. }
  296. return ret, nil
  297. }
  298. // IBucket
  299. func (region *SRegion) IBucketExist(name string) (bool, error) {
  300. toscli, err := region.GetTosClient()
  301. if err != nil {
  302. return false, errors.Wrap(err, "region.GetTosClient")
  303. }
  304. _, err = toscli.HeadBucket(context.Background(), &tos.HeadBucketInput{Bucket: name})
  305. if err != nil || tos.StatusCode(err) != 404 {
  306. return false, errors.Wrap(err, "IsBucketExist")
  307. }
  308. return true, nil
  309. }
  310. func (region *SRegion) CreateIBucket(name string, storageClassStr string, aclStr string) error {
  311. toscli, err := region.GetTosClient()
  312. if err != nil {
  313. return errors.Wrap(err, "region.GetTosClient")
  314. }
  315. _, err = toscli.CreateBucketV2(context.Background(), &tos.CreateBucketV2Input{Bucket: name, ACL: enum.ACLType(aclStr), StorageClass: enum.StorageClassType(storageClassStr)})
  316. if err != nil {
  317. return errors.Wrap(err, "tos.CreateBucketV2")
  318. }
  319. region.client.invalidateIBuckets()
  320. return nil
  321. }
  322. func (region *SRegion) DeleteIBucket(name string) error {
  323. toscli, err := region.GetTosClient()
  324. if err != nil {
  325. return errors.Wrapf(err, "region.GetOssClient")
  326. }
  327. _, err = toscli.DeleteBucket(context.Background(), &tos.DeleteBucketInput{Bucket: name})
  328. if err != nil {
  329. if tos.StatusCode(err) == 404 {
  330. return nil
  331. }
  332. return errors.Wrap(err, "DeleteBucket")
  333. }
  334. region.client.invalidateIBuckets()
  335. return nil
  336. }
  337. func (region *SRegion) GetIBucketById(name string) (cloudprovider.ICloudBucket, error) {
  338. toscli, err := region.GetTosClient()
  339. if err != nil {
  340. return nil, errors.Wrapf(err, "region.GetOssClient")
  341. }
  342. out, err := toscli.ListBuckets(context.Background(), &tos.ListBucketsInput{})
  343. if err != nil {
  344. return nil, errors.Wrap(err, "ListBucket")
  345. }
  346. for _, bucket := range out.Buckets {
  347. if bucket.Name == name {
  348. t, err := time.Parse(time.RFC3339, bucket.CreationDate)
  349. if err != nil {
  350. return nil, errors.Wrapf(err, "Prase CreationDate error")
  351. }
  352. b := SBucket{
  353. region: region,
  354. Name: name,
  355. Location: bucket.Location,
  356. CreationDate: t,
  357. }
  358. return &b, nil
  359. }
  360. }
  361. return nil, errors.Wrapf(cloudprovider.ErrNotFound, "Bucket Not Found")
  362. }
  363. func (region *SRegion) GetIBucketByName(name string) (cloudprovider.ICloudBucket, error) {
  364. return region.GetIBucketById(name)
  365. }
  366. func (region *SRegion) GetIBuckets() ([]cloudprovider.ICloudBucket, error) {
  367. iBuckets, err := region.client.getIBuckets()
  368. if err != nil {
  369. return nil, errors.Wrap(err, "getIBuckets")
  370. }
  371. ret := make([]cloudprovider.ICloudBucket, 0)
  372. for i := range iBuckets {
  373. if iBuckets[i].GetIRegion().GetId() != region.GetId() {
  374. continue
  375. }
  376. ret = append(ret, iBuckets[i])
  377. }
  378. return ret, nil
  379. }
  380. func (region *SRegion) GetCapabilities() []string {
  381. return region.client.GetCapabilities()
  382. }
  383. // Security Group
  384. func (region *SRegion) CreateISecurityGroup(opts *cloudprovider.SecurityGroupCreateInput) (cloudprovider.ICloudSecurityGroup, error) {
  385. externalId, err := region.CreateSecurityGroup(opts)
  386. if err != nil {
  387. return nil, err
  388. }
  389. err = cloudprovider.Wait(5*time.Second, time.Minute, func() (bool, error) {
  390. _, err := region.GetISecurityGroupById(externalId)
  391. if errors.Cause(err) == cloudprovider.ErrNotFound {
  392. return false, nil
  393. } else {
  394. return true, err
  395. }
  396. })
  397. if err != nil {
  398. return nil, errors.Wrapf(err, "cannot find security group after create")
  399. }
  400. return region.GetISecurityGroupById(externalId)
  401. }
  402. func (region *SRegion) GetISecurityGroupById(secgroupId string) (cloudprovider.ICloudSecurityGroup, error) {
  403. return region.GetSecurityGroup(secgroupId)
  404. }
  405. func (region *SRegion) getSdkCredential(service string, token string) sdk.Credentials {
  406. return region.client.getSdkCredential(region.RegionId, service, token)
  407. }
  408. func (region *SRegion) ecsRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) {
  409. cred := region.getSdkCredential(VOLCENGINE_SERVICE_ECS, "")
  410. return region.client.jsonRequest(cred, VOLCENGINE_API, VOLCENGINE_API_VERSION, apiName, params)
  411. }
  412. func (region *SRegion) vpcRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) {
  413. cred := region.getSdkCredential(VOLCENGINE_SERVICE_VPC, "")
  414. return region.client.jsonRequest(cred, VOLCENGINE_API, VOLCENGINE_API_VERSION, apiName, params)
  415. }
  416. func (region *SRegion) natRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) {
  417. cred := region.getSdkCredential(VOLCENGINE_SERVICE_NAT, "")
  418. return region.client.jsonRequest(cred, VOLCENGINE_API, VOLCENGINE_API_VERSION, apiName, params)
  419. }
  420. func (region *SRegion) storageRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) {
  421. cred := region.getSdkCredential(VOLCENGINE_SERVICE_STORAGE, "")
  422. return region.client.jsonRequest(cred, VOLCENGINE_API, VOLCENGINE_API_VERSION, apiName, params)
  423. }
  424. func (region *SRegion) GetTosClient() (*tos.ClientV2, error) {
  425. if region.tosClient == nil {
  426. cli, err := region.client.getTosClient(region.RegionId)
  427. if err != nil {
  428. return nil, errors.Wrap(err, "region.client.getOssClient")
  429. }
  430. region.tosClient = cli
  431. }
  432. return region.tosClient, nil
  433. }
  434. func (region *SRegion) UpdateInstancePassword(instanceId string, passwd string) error {
  435. params := make(map[string]string)
  436. params["Password"] = passwd
  437. return region.modifyInstanceAttribute(instanceId, params)
  438. }
  439. func (region *SRegion) GetInstanceStatus(instanceId string) (string, error) {
  440. instance, err := region.GetInstance(instanceId)
  441. if err != nil {
  442. return "", err
  443. }
  444. return instance.Status, nil
  445. }
  446. func (region *SRegion) instanceOperation(instanceId string, apiName string, extra map[string]string) error {
  447. params := make(map[string]string)
  448. params["RegionId"] = region.RegionId
  449. params["InstanceId"] = instanceId
  450. if len(extra) > 0 {
  451. for k, v := range extra {
  452. params[k] = v
  453. }
  454. }
  455. _, err := region.ecsRequest(apiName, params)
  456. return err
  457. }
  458. func (region *SRegion) getBaseEndpoint() string {
  459. endpoint, ok := RegionEndpoint[region.RegionId]
  460. if ok {
  461. return endpoint
  462. }
  463. return fmt.Sprintf("%s.volces.com", region.RegionId)
  464. }
  465. func (region *SRegion) getS3Endpoint() string {
  466. base := region.getBaseEndpoint()
  467. if len(base) > 0 {
  468. return "tos-s3-" + base
  469. }
  470. return ""
  471. }
  472. func (region *SRegion) getTOSExternalDomain() string {
  473. return getTOSExternalDomain(region.RegionId)
  474. }
  475. func (region *SRegion) getTOSInternalDomain() string {
  476. return getTOSInternalDomain(region.RegionId)
  477. }
  478. func (region *SRegion) GetRouteTables(ids []string, pageNumber int, pageSize int) ([]SRouteTable, int, error) {
  479. if pageSize > 100 || pageSize <= 0 {
  480. pageSize = 100
  481. }
  482. params := make(map[string]string)
  483. params["PageSize"] = fmt.Sprintf("%d", pageSize)
  484. params["PageNumber"] = fmt.Sprintf("%d", pageNumber)
  485. if len(ids) > 0 {
  486. params["RouteTableId"] = strings.Join(ids, ",")
  487. }
  488. body, err := region.vpcRequest("DescribeRouteTableList", params)
  489. if err != nil {
  490. return nil, 0, errors.Wrapf(err, "GetRoutseTables fail")
  491. }
  492. routetables := make([]SRouteTable, 0)
  493. err = body.Unmarshal(&routetables, "RouteTables", "RouteTable")
  494. if err != nil {
  495. return nil, 0, errors.Wrapf(err, "Unmarshal routetables fail")
  496. }
  497. total, _ := body.Int("TotalCount")
  498. return routetables, int(total), nil
  499. }
  500. func (region *SRegion) GetIHostById(id string) (cloudprovider.ICloudHost, error) {
  501. izones, err := region.GetIZones()
  502. if err != nil {
  503. return nil, err
  504. }
  505. for i := 0; i < len(izones); i += 1 {
  506. ihost, err := izones[i].GetIHostById(id)
  507. if err == nil {
  508. return ihost, nil
  509. } else if errors.Cause(err) != cloudprovider.ErrNotFound {
  510. return nil, err
  511. }
  512. }
  513. return nil, cloudprovider.ErrNotFound
  514. }
  515. func (regioin *SRegion) GetIHosts() ([]cloudprovider.ICloudHost, error) {
  516. iHosts := make([]cloudprovider.ICloudHost, 0)
  517. izones, err := regioin.GetIZones()
  518. if err != nil {
  519. return nil, err
  520. }
  521. for i := 0; i < len(izones); i += 1 {
  522. iZoneHost, err := izones[i].GetIHosts()
  523. if err != nil {
  524. return nil, err
  525. }
  526. iHosts = append(iHosts, iZoneHost...)
  527. }
  528. return iHosts, nil
  529. }
  530. func (region *SRegion) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) {
  531. return region.GetDisk(id)
  532. }
  533. func (region *SRegion) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) {
  534. izones, err := region.GetIZones()
  535. if err != nil {
  536. return nil, err
  537. }
  538. for i := 0; i < len(izones); i += 1 {
  539. istore, err := izones[i].GetIStorageById(id)
  540. if err == nil {
  541. return istore, nil
  542. } else if errors.Cause(err) != cloudprovider.ErrNotFound {
  543. return nil, err
  544. }
  545. }
  546. return nil, cloudprovider.ErrNotFound
  547. }
  548. func (region *SRegion) GetIStorages() ([]cloudprovider.ICloudStorage, error) {
  549. iStores := make([]cloudprovider.ICloudStorage, 0)
  550. izones, err := region.GetIZones()
  551. if err != nil {
  552. return nil, err
  553. }
  554. for i := 0; i < len(izones); i += 1 {
  555. iZoneStores, err := izones[i].GetIStorages()
  556. if err != nil {
  557. return nil, err
  558. }
  559. iStores = append(iStores, iZoneStores...)
  560. }
  561. return iStores, nil
  562. }
  563. func (region *SRegion) GetIVMById(id string) (cloudprovider.ICloudVM, error) {
  564. return region.GetInstance(id)
  565. }
  566. func (region *SRegion) GetIVMs() ([]cloudprovider.ICloudVM, error) {
  567. vms, err := region.GetInstances("", nil)
  568. if err != nil {
  569. return nil, err
  570. }
  571. ret := []cloudprovider.ICloudVM{}
  572. for i := range vms {
  573. ret = append(ret, &vms[i])
  574. }
  575. return ret, nil
  576. }