instance.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719
  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 ctyun
  15. import (
  16. "context"
  17. "fmt"
  18. "strings"
  19. "time"
  20. "yunion.io/x/jsonutils"
  21. "yunion.io/x/pkg/errors"
  22. "yunion.io/x/pkg/util/billing"
  23. "yunion.io/x/pkg/utils"
  24. billing_api "yunion.io/x/cloudmux/pkg/apis/billing"
  25. api "yunion.io/x/cloudmux/pkg/apis/compute"
  26. "yunion.io/x/cloudmux/pkg/cloudprovider"
  27. "yunion.io/x/cloudmux/pkg/multicloud"
  28. )
  29. type SInstance struct {
  30. multicloud.SInstanceBase
  31. CtyunTags
  32. multicloud.SBillingBase
  33. host *SHost
  34. image *SImage
  35. AzName string
  36. ExpiredTime time.Time
  37. CreatedTime time.Time
  38. ProjectId string
  39. AttachedVolume []string
  40. InstanceId string
  41. DisplayName string
  42. InstanceName string
  43. OsType int
  44. InstanceStatus string
  45. OnDemand bool
  46. KeypairName string
  47. Addresses []struct {
  48. VpcName string
  49. AddressList []struct {
  50. Addr string
  51. Version int
  52. Type string
  53. }
  54. }
  55. SecGroupList []struct {
  56. SecurityGroupName string
  57. SecurityGroupId string
  58. }
  59. VipInfoList []interface{}
  60. AffinityGroup string
  61. Image struct {
  62. ImageId string
  63. ImageName string
  64. }
  65. Flavor struct {
  66. FlavorId string
  67. FlavorName string
  68. FlavorCPU int
  69. FlavorRAM int
  70. GpuType string
  71. GpuCount string
  72. GpuVendor string
  73. VideoMemSize string
  74. }
  75. ResourceId string
  76. UpdatedTime time.Time
  77. AvailableDay int
  78. ZabbixName string
  79. PrivateIP string
  80. PrivateIPv6 string
  81. VipCount int
  82. VpcId string
  83. VpcName string
  84. SubnetIDList []string
  85. FixedIPList []string
  86. FloatingIP string
  87. NetworkCardList []SInstanceNic
  88. }
  89. func (self *SInstance) GetBillingType() string {
  90. if !self.OnDemand {
  91. return billing_api.BILLING_TYPE_PREPAID
  92. }
  93. return billing_api.BILLING_TYPE_POSTPAID
  94. }
  95. func (self *SInstance) GetCreatedAt() time.Time {
  96. return self.CreatedTime
  97. }
  98. func (self *SInstance) GetExpiredAt() time.Time {
  99. return self.ExpiredTime
  100. }
  101. func (self *SInstance) GetId() string {
  102. return self.InstanceId
  103. }
  104. func (self *SInstance) GetName() string {
  105. return self.DisplayName
  106. }
  107. func (self *SInstance) GetHostname() string {
  108. return self.InstanceName
  109. }
  110. func (self *SInstance) GetGlobalId() string {
  111. return self.GetId()
  112. }
  113. func (self *SInstance) GetStatus() string {
  114. switch self.InstanceStatus {
  115. case "backingup":
  116. return api.VM_BACKUP_CREATING
  117. case "creating", "master_order_creating":
  118. return api.VM_DEPLOYING
  119. case "expired", "freezing", "stopped":
  120. return api.VM_READY
  121. case "stopping":
  122. return api.VM_STOPPING
  123. case "rebuild":
  124. return api.VM_REBUILD_ROOT
  125. case "restarting", "starting":
  126. return api.VM_STARTING
  127. case "running":
  128. return api.VM_RUNNING
  129. default:
  130. return api.VM_UNKNOWN
  131. }
  132. }
  133. func (self *SInstance) Refresh() error {
  134. vm, err := self.host.zone.region.GetInstance(self.GetId())
  135. if err != nil {
  136. return err
  137. }
  138. return jsonutils.Update(self, vm)
  139. }
  140. func (self *SInstance) GetProjectId() string {
  141. return self.ProjectId
  142. }
  143. func (self *SInstance) GetIHost() cloudprovider.ICloudHost {
  144. return self.host
  145. }
  146. func (self *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) {
  147. storages, err := self.host.zone.GetStorages()
  148. if err != nil {
  149. return nil, err
  150. }
  151. ret := []cloudprovider.ICloudDisk{}
  152. for _, diskId := range self.AttachedVolume {
  153. disk, err := self.host.zone.region.GetDisk(diskId)
  154. if err != nil {
  155. return nil, errors.Wrapf(err, "GetDisk %s", diskId)
  156. }
  157. find := false
  158. for i := range storages {
  159. if disk.DiskType == storages[i].storageType {
  160. disk.storage = &storages[i]
  161. find = true
  162. break
  163. }
  164. }
  165. if !find {
  166. return nil, fmt.Errorf("failed to found disk storage type %s", disk.DiskType)
  167. }
  168. ret = append(ret, disk)
  169. }
  170. return ret, nil
  171. }
  172. func (self *SInstance) GetINics() ([]cloudprovider.ICloudNic, error) {
  173. ret := []cloudprovider.ICloudNic{}
  174. for i := range self.NetworkCardList {
  175. self.NetworkCardList[i].instance = self
  176. ret = append(ret, &self.NetworkCardList[i])
  177. }
  178. return ret, nil
  179. }
  180. func (self *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) {
  181. if len(self.FloatingIP) == 0 {
  182. return nil, nil
  183. }
  184. eips, err := self.host.zone.region.GetEips("ACTIVE")
  185. if err != nil {
  186. return nil, err
  187. }
  188. for i := range eips {
  189. if eips[i].EipAddress == self.FloatingIP {
  190. eips[i].region = self.host.zone.region
  191. return &eips[i], nil
  192. }
  193. }
  194. return nil, errors.Wrapf(cloudprovider.ErrNotFound, "%s", self.FloatingIP)
  195. }
  196. func (self *SInstance) GetVcpuCount() int {
  197. return self.Flavor.FlavorCPU
  198. }
  199. func (self *SInstance) GetVmemSizeMB() int {
  200. return self.Flavor.FlavorRAM
  201. }
  202. func (self *SInstance) GetBootOrder() string {
  203. return "dcn"
  204. }
  205. func (self *SInstance) GetVga() string {
  206. return "std"
  207. }
  208. func (self *SInstance) GetVdi() string {
  209. return "vnc"
  210. }
  211. func (self *SInstance) GetImage() (*SImage, error) {
  212. if self.image != nil {
  213. return self.image, nil
  214. }
  215. var err error
  216. self.image, err = self.host.zone.region.GetImage(self.Image.ImageId)
  217. return self.image, err
  218. }
  219. func (self *SInstance) GetOsType() cloudprovider.TOsType {
  220. image, err := self.GetImage()
  221. if err != nil {
  222. return cloudprovider.OsTypeLinux
  223. }
  224. return image.GetOsType()
  225. }
  226. func (self *SInstance) GetFullOsName() string {
  227. image, err := self.GetImage()
  228. if err != nil {
  229. return self.image.ImageName
  230. }
  231. return image.GetFullOsName()
  232. }
  233. func (self *SInstance) GetBios() cloudprovider.TBiosType {
  234. image, err := self.GetImage()
  235. if err != nil {
  236. return cloudprovider.BIOS
  237. }
  238. return image.GetBios()
  239. }
  240. func (self *SInstance) GetOsArch() string {
  241. image, err := self.GetImage()
  242. if err != nil {
  243. return ""
  244. }
  245. return image.GetOsArch()
  246. }
  247. func (self *SInstance) GetOsDist() string {
  248. image, err := self.GetImage()
  249. if err != nil {
  250. return ""
  251. }
  252. return image.GetOsDist()
  253. }
  254. func (self *SInstance) GetOsVersion() string {
  255. image, err := self.GetImage()
  256. if err != nil {
  257. return ""
  258. }
  259. return image.GetOsVersion()
  260. }
  261. func (self *SInstance) GetOsLang() string {
  262. image, err := self.GetImage()
  263. if err != nil {
  264. return ""
  265. }
  266. return image.GetOsLang()
  267. }
  268. func (self *SInstance) GetMachine() string {
  269. return "pc"
  270. }
  271. func (self *SInstance) GetInstanceType() string {
  272. return self.Flavor.FlavorName
  273. }
  274. func (self *SInstance) GetSecurityGroupIds() ([]string, error) {
  275. ret := []string{}
  276. for _, sec := range self.SecGroupList {
  277. ret = append(ret, sec.SecurityGroupId)
  278. }
  279. return ret, nil
  280. }
  281. func (self *SInstance) SetSecurityGroups(secgroupIds []string) error {
  282. currentIds, err := self.GetSecurityGroupIds()
  283. if err != nil {
  284. return errors.Wrap(err, "GetSecurityGroupIds")
  285. }
  286. adds := []string{}
  287. for i := range secgroupIds {
  288. if !utils.IsInStringArray(secgroupIds[i], currentIds) {
  289. adds = append(adds, secgroupIds[i])
  290. }
  291. }
  292. for i := range adds {
  293. err := self.host.zone.region.AssignSecurityGroup(self.GetId(), adds[i])
  294. if err != nil {
  295. return errors.Wrap(err, "Instance.SetSecurityGroups")
  296. }
  297. }
  298. removes := []string{}
  299. for i := range currentIds {
  300. if !utils.IsInStringArray(currentIds[i], secgroupIds) {
  301. removes = append(removes, currentIds[i])
  302. }
  303. }
  304. for i := range removes {
  305. err := self.host.zone.region.UnsignSecurityGroup(self.GetId(), removes[i])
  306. if err != nil {
  307. return errors.Wrap(err, "Instance.SetSecurityGroups")
  308. }
  309. }
  310. return nil
  311. }
  312. func (self *SInstance) GetHypervisor() string {
  313. return api.HYPERVISOR_CTYUN
  314. }
  315. func (self *SInstance) StartVM(ctx context.Context) error {
  316. return self.host.zone.region.StartVM(self.GetId())
  317. }
  318. func (self *SInstance) StopVM(ctx context.Context, opts *cloudprovider.ServerStopOptions) error {
  319. return self.host.zone.region.StopVM(self.GetId())
  320. }
  321. func (self *SInstance) DeleteVM(ctx context.Context) error {
  322. return self.host.zone.region.DeleteVM(self.GetId())
  323. }
  324. func (self *SRegion) UpdateVM(vmId string, opts cloudprovider.SInstanceUpdateOptions) error {
  325. params := map[string]interface{}{
  326. "instanceID": vmId,
  327. "displayName": opts.NAME,
  328. }
  329. _, err := self.post(SERVICE_ECS, "/v4/ecs/update-instance", params)
  330. return err
  331. }
  332. func (self *SInstance) UpdateVM(ctx context.Context, input cloudprovider.SInstanceUpdateOptions) error {
  333. if self.DisplayName == input.NAME {
  334. return nil
  335. }
  336. return self.host.zone.region.UpdateVM(self.InstanceId, input)
  337. }
  338. func (self *SInstance) UpdateUserData(userData string) error {
  339. return cloudprovider.ErrNotSupported
  340. }
  341. func (self *SRegion) RebuildRoot(vmId string, opts *cloudprovider.SManagedVMRebuildRootConfig) error {
  342. params := map[string]interface{}{
  343. "instanceID": vmId,
  344. "password": opts.Password,
  345. "imageID": opts.ImageId,
  346. }
  347. _, err := self.post(SERVICE_ECS, "/v4/ecs/rebuild-instance", params)
  348. return err
  349. }
  350. func (self *SInstance) RebuildRoot(ctx context.Context, opts *cloudprovider.SManagedVMRebuildRootConfig) (string, error) {
  351. oldDiskId := self.AttachedVolume[0]
  352. err := self.host.zone.region.RebuildRoot(self.InstanceId, opts)
  353. if err != nil {
  354. return "", err
  355. }
  356. cloudprovider.Wait(time.Second*10, time.Minute*5, func() (bool, error) {
  357. self.Refresh()
  358. if oldDiskId != self.AttachedVolume[0] {
  359. return true, nil
  360. }
  361. return false, nil
  362. })
  363. return self.AttachedVolume[0], nil
  364. }
  365. func (self *SRegion) AttachKeypair(vmId, keyName string) error {
  366. params := map[string]interface{}{
  367. "instanceID": vmId,
  368. "keyPairName": keyName,
  369. }
  370. _, err := self.post(SERVICE_ECS, "/v4/ecs/keypair/attach-instance", params)
  371. return err
  372. }
  373. func (self *SRegion) DetachKeypair(vmId, keyName string) error {
  374. params := map[string]interface{}{
  375. "instanceID": vmId,
  376. "keyPairName": keyName,
  377. }
  378. _, err := self.post(SERVICE_ECS, "/v4/ecs/keypair/detach-instance", params)
  379. return err
  380. }
  381. func (self *SInstance) DeployVM(ctx context.Context, opts *cloudprovider.SInstanceDeployOptions) error {
  382. if len(opts.Password) > 0 {
  383. return self.host.zone.region.ResetVMPassword(self.GetId(), opts.Password)
  384. }
  385. if len(opts.PublicKey) > 0 {
  386. keypair, err := self.host.zone.region.syncKeypair(opts.Password)
  387. if err != nil {
  388. return errors.Wrapf(err, "syncKeypair")
  389. }
  390. return self.host.zone.region.AttachKeypair(self.InstanceId, keypair.KeyPairName)
  391. }
  392. if opts.DeleteKeypair && len(self.KeypairName) > 0 {
  393. return self.host.zone.region.DetachKeypair(self.InstanceId, self.KeypairName)
  394. }
  395. return nil
  396. }
  397. func (self *SRegion) ChangeVMConfig(id, instanceType string) error {
  398. skus, err := self.GetServerSkus("")
  399. if err != nil {
  400. return errors.Wrapf(err, "GetServerSkus")
  401. }
  402. for i := range skus {
  403. if skus[i].FlavorName == instanceType {
  404. instanceType = skus[i].FlavorId
  405. break
  406. }
  407. }
  408. params := map[string]interface{}{
  409. "instanceID": id,
  410. "clientToken": utils.GenRequestId(20),
  411. "flavorID": instanceType,
  412. }
  413. _, err = self.post(SERVICE_ECS, "/v4/ecs/update-flavor-spec", params)
  414. return err
  415. }
  416. func (self *SInstance) ChangeConfig(ctx context.Context, config *cloudprovider.SManagedVMChangeConfig) error {
  417. return self.host.zone.region.ChangeVMConfig(self.GetId(), config.InstanceType)
  418. }
  419. func (self *SRegion) GetInstanceVnc(vmId string) (string, error) {
  420. params := map[string]interface{}{
  421. "instanceID": vmId,
  422. }
  423. resp, err := self.list(SERVICE_ECS, "/v4/ecs/vnc/details", params)
  424. if err != nil {
  425. return "", err
  426. }
  427. return resp.GetString("returnObj", "token")
  428. }
  429. func (self *SInstance) GetVNCInfo(input *cloudprovider.ServerVncInput) (*cloudprovider.ServerVncOutput, error) {
  430. url, err := self.host.zone.region.GetInstanceVnc(self.InstanceId)
  431. if err != nil {
  432. return nil, err
  433. }
  434. protocol := "ctyun"
  435. if strings.HasPrefix(url, "wss") {
  436. protocol = "vnc"
  437. }
  438. ret := &cloudprovider.ServerVncOutput{
  439. Url: url,
  440. Protocol: protocol,
  441. InstanceId: self.GetId(),
  442. Hypervisor: api.HYPERVISOR_CTYUN,
  443. }
  444. return ret, nil
  445. }
  446. func (self *SRegion) AttachDisk(id, diskId string) error {
  447. params := map[string]interface{}{
  448. "diskID": diskId,
  449. "instanceID": id,
  450. }
  451. _, err := self.post(SERVICE_EBS, "/v4/ebs/attach-ebs", params)
  452. return err
  453. }
  454. func (self *SInstance) AttachDisk(ctx context.Context, diskId string) error {
  455. return self.host.zone.region.AttachDisk(self.InstanceId, diskId)
  456. }
  457. func (self *SRegion) DetachDisk(id, diskId string) error {
  458. params := map[string]interface{}{
  459. "diskID": diskId,
  460. "instanceID": id,
  461. }
  462. _, err := self.post(SERVICE_EBS, "/v4/ebs/detach-ebs", params)
  463. return err
  464. }
  465. func (self *SInstance) DetachDisk(ctx context.Context, diskId string) error {
  466. return self.host.zone.region.DetachDisk(self.InstanceId, diskId)
  467. }
  468. func (self *SInstance) Renew(bc billing.SBillingCycle) error {
  469. _, err := self.host.zone.region.RenewVM(self.GetId(), &bc)
  470. if err != nil {
  471. return errors.Wrap(err, "Instance.Renew.RenewVM")
  472. }
  473. return nil
  474. }
  475. func (self *SInstance) GetError() error {
  476. return nil
  477. }
  478. func (self *SRegion) CreateInstance(zoneId string, opts *cloudprovider.SManagedVMCreateConfig) (string, error) {
  479. image, err := self.GetImage(opts.ExternalImageId)
  480. if err != nil {
  481. return "", errors.Wrapf(err, "GetImage %s", opts.ExternalImageId)
  482. }
  483. if image.DiskSize > opts.SysDisk.SizeGB {
  484. opts.SysDisk.SizeGB = image.DiskSize
  485. }
  486. if opts.SysDisk.SizeGB < 40 {
  487. opts.SysDisk.SizeGB = 40
  488. }
  489. skus, err := self.GetServerSkus("")
  490. if err != nil {
  491. return "", errors.Wrapf(err, "GetServerSkus")
  492. }
  493. for i := range skus {
  494. if skus[i].FlavorName == opts.InstanceType {
  495. opts.InstanceType = skus[i].FlavorId
  496. break
  497. }
  498. }
  499. disks := []map[string]interface{}{}
  500. for _, disk := range opts.DataDisks {
  501. disks = append(disks, map[string]interface{}{
  502. "diskName": disk.Name,
  503. "diskSize": disk.SizeGB,
  504. "diskType": disk.StorageType,
  505. })
  506. }
  507. nets := map[string]interface{}{
  508. "subnetID": opts.ExternalNetworkId,
  509. "isMaster": true,
  510. }
  511. if len(opts.IpAddr) > 0 {
  512. nets["fixedIP"] = opts.IpAddr
  513. }
  514. imageType, _ := map[string]int{
  515. "private": 0,
  516. "public": 1,
  517. "shared": 2,
  518. "safe": 3,
  519. "community": 4,
  520. }[image.Visibility]
  521. params := map[string]interface{}{
  522. "clientToken": utils.GenRequestId(20),
  523. "userPassword": opts.Password,
  524. "imageID": opts.ExternalImageId,
  525. "imageType": imageType,
  526. "userData": opts.UserData,
  527. "instanceName": opts.Hostname,
  528. "displayName": opts.Name,
  529. "flavorID": opts.InstanceType,
  530. "onDemand": true,
  531. "extIP": "0",
  532. "vpcID": opts.ExternalVpcId,
  533. "bootDiskType": opts.SysDisk.StorageType,
  534. "bootDiskSize": opts.SysDisk.SizeGB,
  535. "secGroupList": opts.ExternalSecgroupIds,
  536. "azName": zoneId,
  537. "dataDiskList": disks,
  538. "networkCardList": []map[string]interface{}{nets},
  539. }
  540. if len(opts.PublicKey) > 0 {
  541. keypair, err := self.syncKeypair(opts.PublicKey)
  542. if err != nil {
  543. return "", errors.Wrapf(err, "syncKeypair")
  544. }
  545. params["keyPairID"] = keypair.KeyPairId
  546. }
  547. if opts.BillingCycle != nil {
  548. params["onDemand"] = false
  549. if opts.BillingCycle.AutoRenew {
  550. params["autoRenewStatus"] = "true"
  551. }
  552. if opts.BillingCycle.GetYears() > 0 {
  553. params["cycleType"] = "YEAR"
  554. params["cycleCount"] = opts.BillingCycle.GetYears()
  555. } else if opts.BillingCycle.GetMonths() > 0 {
  556. params["cycleType"] = "MONTH"
  557. params["cycleCount"] = opts.BillingCycle.GetMonths()
  558. }
  559. }
  560. resp, err := self.post(SERVICE_ECS, "/v4/ecs/create-instance", params)
  561. if err != nil {
  562. return "", err
  563. }
  564. orderId, err := resp.GetString("returnObj", "masterOrderID")
  565. if err != nil {
  566. return "", err
  567. }
  568. return self.GetResourceId(orderId)
  569. }
  570. func (self *SRegion) GetResourceId(orderId string) (string, error) {
  571. params := map[string]interface{}{
  572. "masterOrderId": orderId,
  573. }
  574. for i := 0; i < 10; i++ {
  575. resp, err := self.list(SERVICE_ECS, "/v4/order/query-uuid", params)
  576. if err != nil {
  577. return "", err
  578. }
  579. ids := []string{}
  580. resp.Unmarshal(&ids, "returnObj", "resourceUUID")
  581. for i := range ids {
  582. return ids[i], nil
  583. }
  584. time.Sleep(time.Second * 10)
  585. }
  586. return "", errors.Wrapf(cloudprovider.ErrNotFound, "failed get uuid by order id: %s", orderId)
  587. }
  588. func (self *SRegion) AssignSecurityGroup(vmId, groupId string) error {
  589. params := map[string]interface{}{
  590. "securityGroupID": groupId,
  591. "instanceID": vmId,
  592. "action": "joinSecurityGroup",
  593. }
  594. _, err := self.post(SERVICE_ECS, "/v4/ecs/vpc/join-security-group", params)
  595. return err
  596. }
  597. func (self *SRegion) UnsignSecurityGroup(vmId, groupId string) error {
  598. params := map[string]interface{}{
  599. "securityGroupID": groupId,
  600. "instanceID": vmId,
  601. "action": "joinSecurityGroup",
  602. }
  603. _, err := self.post(SERVICE_ECS, "/v4/ecs/vpc/leave-security-group", params)
  604. return err
  605. }
  606. func (self *SRegion) StartVM(id string) error {
  607. params := map[string]interface{}{
  608. "instanceID": id,
  609. }
  610. _, err := self.post(SERVICE_ECS, "/v4/ecs/start-instance", params)
  611. return err
  612. }
  613. func (self *SRegion) StopVM(id string) error {
  614. params := map[string]interface{}{
  615. "instanceID": id,
  616. }
  617. _, err := self.post(SERVICE_ECS, "/v4/ecs/stop-instance", params)
  618. return err
  619. }
  620. func (self *SRegion) DeleteVM(id string) error {
  621. params := map[string]interface{}{
  622. "instanceID": id,
  623. "clientToken": utils.GenRequestId(20),
  624. }
  625. _, err := self.post(SERVICE_ECS, "/v4/ecs/unsubscribe-instance", params)
  626. return err
  627. }
  628. func (self *SRegion) RenewVM(vmId string, bc *billing.SBillingCycle) ([]string, error) {
  629. return nil, cloudprovider.ErrNotImplemented
  630. }
  631. func (self *SRegion) ResetVMPassword(id, password string) error {
  632. params := map[string]interface{}{
  633. "instanceID": id,
  634. "newPassword": password,
  635. }
  636. _, err := self.post(SERVICE_ECS, "/v4/ecs/reset-password", params)
  637. return err
  638. }