instances.go 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713
  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 ksyun
  15. import (
  16. "context"
  17. "fmt"
  18. "strings"
  19. "time"
  20. billing_api "yunion.io/x/cloudmux/pkg/apis/billing"
  21. api "yunion.io/x/cloudmux/pkg/apis/compute"
  22. "yunion.io/x/cloudmux/pkg/cloudprovider"
  23. "yunion.io/x/cloudmux/pkg/multicloud"
  24. "yunion.io/x/jsonutils"
  25. "yunion.io/x/log"
  26. "yunion.io/x/pkg/errors"
  27. "yunion.io/x/pkg/util/imagetools"
  28. "yunion.io/x/pkg/utils"
  29. )
  30. type InstanceConfigure struct {
  31. Vcpu int `json:"VCPU"`
  32. Gpu int `json:"GPU"`
  33. MemoryGb int `json:"MemoryGb"`
  34. DataDiskGb int `json:"DataDiskGb"`
  35. RootDiskGb int `json:"RootDiskGb"`
  36. DataDiskType string `json:"DataDiskType"`
  37. Vgpu string `json:"VGPU"`
  38. }
  39. type InstanceState struct {
  40. Name string `json:"Name"`
  41. OnMigrate bool `json:"OnMigrate"`
  42. CostTime string `json:"CostTime"`
  43. TimeStamp string `json:"TimeStamp"`
  44. }
  45. type Monitoring struct {
  46. State string `json:"State"`
  47. }
  48. type GroupSet struct {
  49. GroupID string `json:"GroupId"`
  50. }
  51. type InstanceSecurityGroupSet struct {
  52. SecurityGroupId string `json:"SecurityGroupId"`
  53. }
  54. type NetworkInterfaceSet struct {
  55. AllocationId string `json:"AllocationId"`
  56. NetworkInterfaceId string `json:"NetworkInterfaceId"`
  57. NetworkInterfaceType string `json:"NetworkInterfaceType"`
  58. VpcId string `json:"VpcId"`
  59. SubnetId string `json:"SubnetId"`
  60. MacAddress string `json:"MacAddress"`
  61. PrivateIPAddress string `json:"PrivateIpAddress"`
  62. GroupSet []GroupSet `json:"GroupSet"`
  63. SecurityGroupSet []InstanceSecurityGroupSet `json:"SecurityGroupSet"`
  64. NetworkInterfaceName string `json:"NetworkInterfaceName"`
  65. }
  66. type SystemDisk struct {
  67. DiskId string `json:"DiskId"`
  68. DiskType string `json:"DiskType"`
  69. DiskSize int `json:"DiskSize"`
  70. }
  71. type DataDisks struct {
  72. DiskId string `json:"DiskId"`
  73. DiskType string `json:"DiskType"`
  74. DiskSize int `json:"DiskSize"`
  75. DeleteWithInstance bool `json:"DeleteWithInstance"`
  76. Encrypted bool `json:"Encrypted"`
  77. }
  78. type SInstance struct {
  79. multicloud.SInstanceBase
  80. SKsyunTags
  81. host *SHost
  82. region *SRegion
  83. InstanceId string `json:"InstanceId"`
  84. ProjectId string `json:"ProjectId"`
  85. ShutdownNoCharge bool `json:"ShutdownNoCharge"`
  86. IsDistributeIpv6 bool `json:"IsDistributeIpv6"`
  87. InstanceName string `json:"InstanceName"`
  88. InstanceType string `json:"InstanceType"`
  89. InstanceConfigure InstanceConfigure `json:"InstanceConfigure"`
  90. ImageID string `json:"ImageId"`
  91. SubnetId string `json:"SubnetId"`
  92. PrivateIPAddress string `json:"PrivateIpAddress"`
  93. InstanceState InstanceState `json:"InstanceState"`
  94. Monitoring Monitoring `json:"Monitoring"`
  95. NetworkInterfaceSet []NetworkInterfaceSet `json:"NetworkInterfaceSet"`
  96. SriovNetSupport string `json:"SriovNetSupport"`
  97. IsShowSriovNetSupport bool `json:"IsShowSriovNetSupport"`
  98. CreationDate time.Time `json:"CreationDate"`
  99. AvailabilityZone string `json:"AvailabilityZone"`
  100. AvailabilityZoneName string `json:"AvailabilityZoneName"`
  101. DedicatedUuid string `json:"DedicatedUuid"`
  102. ProductType int `json:"ProductType"`
  103. ProductWhat int `json:"ProductWhat"`
  104. LiveUpgradeSupport bool `json:"LiveUpgradeSupport"`
  105. ChargeType string `json:"ChargeType"`
  106. SystemDisk SystemDisk `json:"SystemDisk"`
  107. HostName string `json:"HostName"`
  108. UserData string `json:"UserData"`
  109. Migration int `json:"Migration"`
  110. DataDisks []DataDisks `json:"DataDisks"`
  111. VncSupport bool `json:"VncSupport"`
  112. Platform string `json:"Platform"`
  113. ServiceEndTime time.Time `json:"ServiceEndTime"`
  114. BootMode string `json:"BootMode"`
  115. }
  116. func (region *SRegion) GetInstances(zoneName string, instanceIds []string) ([]SInstance, error) {
  117. projectIds, err := region.client.GetSplitProjectIds()
  118. if err != nil {
  119. return nil, err
  120. }
  121. ret := []SInstance{}
  122. for _, projects := range projectIds {
  123. part, err := region.getInstances(zoneName, instanceIds, projects)
  124. if err != nil {
  125. return nil, err
  126. }
  127. ret = append(ret, part...)
  128. }
  129. return ret, nil
  130. }
  131. func (region *SRegion) getInstances(zoneName string, instanceIds []string, projectIds []string) ([]SInstance, error) {
  132. instances := []SInstance{}
  133. params := map[string]interface{}{
  134. "MaxResults": "1000",
  135. "Marker": "0",
  136. }
  137. if len(zoneName) > 0 {
  138. params["Filter.1.Name"] = "availability-zone-name"
  139. params["Filter.1.Value.1"] = zoneName
  140. }
  141. for i, v := range instanceIds {
  142. params[fmt.Sprintf("InstanceId.%d", i+1)] = v
  143. }
  144. for i, v := range projectIds {
  145. params[fmt.Sprintf("ProjectId.%d", i+1)] = v
  146. }
  147. for {
  148. resp, err := region.ecsRequest("DescribeInstances", params)
  149. if err != nil {
  150. return nil, errors.Wrap(err, "list instance")
  151. }
  152. part := struct {
  153. InstancesSet []SInstance `json:"InstancesSet"`
  154. Marker int `json:"Marker"`
  155. InstanceCount int `json:"InstanceCount"`
  156. }{}
  157. err = resp.Unmarshal(&part)
  158. if err != nil {
  159. return nil, errors.Wrap(err, "unmarshal instances")
  160. }
  161. instances = append(instances, part.InstancesSet...)
  162. if len(instances) >= part.InstanceCount {
  163. break
  164. }
  165. params["Marker"] = fmt.Sprintf("%d", part.Marker)
  166. }
  167. return instances, nil
  168. }
  169. func (region *SRegion) GetInstance(instanceId string) (*SInstance, error) {
  170. instances, err := region.GetInstances("", []string{instanceId})
  171. if err != nil {
  172. return nil, errors.Wrap(err, "GetInstances")
  173. }
  174. for i := range instances {
  175. if instances[i].GetGlobalId() == instanceId {
  176. return &instances[i], nil
  177. }
  178. }
  179. return nil, errors.Wrapf(cloudprovider.ErrNotFound, "%s", instanceId)
  180. }
  181. func (ins *SInstance) Refresh() error {
  182. extIns, err := ins.getRegion().GetInstance(ins.GetGlobalId())
  183. if err != nil {
  184. return errors.Wrap(err, "GetInstance")
  185. }
  186. return jsonutils.Update(ins, extIns)
  187. }
  188. func (ins *SInstance) GetTags() (map[string]string, error) {
  189. tags, err := ins.getRegion().ListTags("kec-instance", ins.InstanceId)
  190. if err != nil {
  191. return nil, err
  192. }
  193. return tags.GetTags(), nil
  194. }
  195. func (ins *SInstance) SetTags(tags map[string]string, replace bool) error {
  196. return ins.getRegion().SetResourceTags("kec-instance", ins.InstanceId, tags, replace)
  197. }
  198. func (ins *SInstance) getRegion() *SRegion {
  199. if ins.region != nil {
  200. return ins.region
  201. }
  202. return ins.host.zone.region
  203. }
  204. func (ins *SInstance) AssignSecurityGroup(secgroupId string) error {
  205. groupIds, err := ins.GetSecurityGroupIds()
  206. if err != nil {
  207. return err
  208. }
  209. groupIds = append(groupIds, secgroupId)
  210. return ins.SetSecurityGroups(groupIds)
  211. }
  212. func (ins *SInstance) AttachDisk(ctx context.Context, diskId string) error {
  213. return ins.getRegion().AttachDisk(ins.InstanceId, diskId)
  214. }
  215. func (region *SRegion) AttachDisk(instanceId, diskId string) error {
  216. params := map[string]interface{}{
  217. "VolumeId": diskId,
  218. "InstanceId": instanceId,
  219. "DeleteWithInstance": "true",
  220. }
  221. _, err := region.ebsRequest("AttachVolume", params)
  222. return err
  223. }
  224. func (ins *SInstance) ChangeConfig(ctx context.Context, opts *cloudprovider.SManagedVMChangeConfig) error {
  225. return ins.getRegion().ChangeConfig(ins.InstanceId, opts)
  226. }
  227. func (region *SRegion) ChangeConfig(instanceId string, opts *cloudprovider.SManagedVMChangeConfig) error {
  228. params := map[string]interface{}{
  229. "InstanceId": instanceId,
  230. "InstanceType": opts.InstanceType,
  231. }
  232. _, err := region.ecsRequest("ModifyInstanceType", params)
  233. return err
  234. }
  235. func (ins *SInstance) DeleteVM(ctx context.Context) error {
  236. return ins.getRegion().DeleteVM(ins.InstanceId)
  237. }
  238. func (region *SRegion) DeleteVM(instanceId string) error {
  239. params := map[string]interface{}{
  240. "InstanceId.1": instanceId,
  241. "ForceDelete": "true",
  242. }
  243. _, err := region.ecsRequest("TerminateInstances", params)
  244. return err
  245. }
  246. func (ins *SInstance) DetachDisk(ctx context.Context, diskId string) error {
  247. return ins.getRegion().DetachDisk(ins.InstanceId, diskId)
  248. }
  249. func (region *SRegion) DetachDisk(instanceId, diskId string) error {
  250. params := map[string]interface{}{
  251. "VolumeId": diskId,
  252. }
  253. if len(instanceId) > 0 {
  254. params["InstanceId"] = instanceId
  255. }
  256. _, err := region.ecsRequest("DetachVolume", params)
  257. return err
  258. }
  259. func (ins *SInstance) GetBios() cloudprovider.TBiosType {
  260. if strings.Contains(ins.BootMode, "BIOS") {
  261. return cloudprovider.BIOS
  262. }
  263. return cloudprovider.UEFI
  264. }
  265. func (ins *SInstance) GetBootOrder() string {
  266. return ""
  267. }
  268. func (ins *SInstance) GetError() error {
  269. return nil
  270. }
  271. func (ins *SInstance) GetFullOsName() string {
  272. return ins.Platform
  273. }
  274. func (ins *SInstance) GetGlobalId() string {
  275. return ins.InstanceId
  276. }
  277. func (ins *SInstance) GetId() string {
  278. return ins.InstanceId
  279. }
  280. func (ins *SInstance) GetInstanceType() string {
  281. return ins.InstanceType
  282. }
  283. func (ins *SInstance) GetMachine() string {
  284. return "pc"
  285. }
  286. func (ins *SInstance) GetHostname() string {
  287. return ins.HostName
  288. }
  289. func (ins *SInstance) GetName() string {
  290. return ins.InstanceName
  291. }
  292. func (ins *SInstance) GetOsArch() string {
  293. return imagetools.NormalizeImageInfo(ins.Platform, "", "", "", "").OsArch
  294. }
  295. func (ins *SInstance) GetOsDist() string {
  296. return imagetools.NormalizeImageInfo(ins.Platform, "", "", "", "").OsArch
  297. }
  298. func (ins *SInstance) GetOsLang() string {
  299. return ""
  300. }
  301. func (ins *SInstance) GetOsType() cloudprovider.TOsType {
  302. imageInfo := imagetools.NormalizeImageInfo("", "", "", ins.Platform, "")
  303. return cloudprovider.TOsType(imageInfo.OsType)
  304. }
  305. func (ins *SInstance) GetOsVersion() string {
  306. return imagetools.NormalizeImageInfo(ins.Platform, "", "", "", "").OsVersion
  307. }
  308. func (ins *SInstance) GetProjectId() string {
  309. return ins.ProjectId
  310. }
  311. func (ins *SInstance) GetSecurityGroupIds() ([]string, error) {
  312. ids := []string{}
  313. for _, netSet := range ins.NetworkInterfaceSet {
  314. for _, secgroupSet := range netSet.SecurityGroupSet {
  315. ids = append(ids, secgroupSet.SecurityGroupId)
  316. }
  317. }
  318. return ids, nil
  319. }
  320. func (ins *SInstance) GetStatus() string {
  321. switch ins.InstanceState.Name {
  322. case "block_device_mapping", "scheduling", "updating_password", "rebuilding", "updating_hostname":
  323. return api.VM_DEPLOYING
  324. case "active":
  325. return api.VM_RUNNING
  326. case "stopping":
  327. return api.VM_STOPPING
  328. case "stopped":
  329. return api.VM_READY
  330. }
  331. return ins.InstanceState.Name
  332. }
  333. func (ins *SInstance) GetHypervisor() string {
  334. return api.HYPERVISOR_KSYUN
  335. }
  336. func (ins *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) {
  337. disks, err := ins.getRegion().GetDiskByInstanceId(ins.GetId())
  338. if err != nil {
  339. return nil, errors.Wrap(err, "getDisks")
  340. }
  341. res := []cloudprovider.ICloudDisk{}
  342. storages, err := ins.host.zone.GetStorages()
  343. if err != nil {
  344. return nil, errors.Wrap(err, "GetStorages")
  345. }
  346. for i := 0; i < len(disks); i++ {
  347. for j := range storages {
  348. if disks[i].VolumeType == storages[j].StorageType {
  349. disks[i].storage = &storages[j]
  350. break
  351. }
  352. }
  353. if disks[i].storage == nil {
  354. return nil, fmt.Errorf("failed to found disk storage type %s", disks[i].VolumeType)
  355. }
  356. res = append(res, &disks[i])
  357. }
  358. if ins.SystemDisk.DiskType == api.STORAGE_KSYUN_LOCAL_SSD {
  359. disk := &SDisk{
  360. VolumeId: ins.SystemDisk.DiskId,
  361. VolumeType: ins.SystemDisk.DiskType,
  362. VolumeName: ins.SystemDisk.DiskId,
  363. Size: ins.SystemDisk.DiskSize,
  364. VolumeCategory: "system",
  365. }
  366. storage := &SStorage{
  367. zone: ins.host.zone,
  368. StorageType: api.STORAGE_KSYUN_LOCAL_SSD,
  369. }
  370. disk.storage = storage
  371. res = append(res, disk)
  372. }
  373. for i := range ins.DataDisks {
  374. if ins.DataDisks[i].DiskType == api.STORAGE_KSYUN_LOCAL_SSD {
  375. disk := &SDisk{
  376. VolumeId: ins.DataDisks[i].DiskId,
  377. VolumeType: ins.DataDisks[i].DiskType,
  378. VolumeName: ins.DataDisks[i].DiskId,
  379. Size: ins.DataDisks[i].DiskSize,
  380. VolumeCategory: "data",
  381. }
  382. storage := &SStorage{
  383. zone: ins.host.zone,
  384. StorageType: api.STORAGE_KSYUN_LOCAL_SSD,
  385. }
  386. disk.storage = storage
  387. res = append(res, disk)
  388. }
  389. }
  390. return res, nil
  391. }
  392. func (ins *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) {
  393. eipIds := []string{}
  394. for _, set := range ins.NetworkInterfaceSet {
  395. if len(set.AllocationId) > 0 {
  396. eipIds = append(eipIds, set.AllocationId)
  397. }
  398. }
  399. if len(eipIds) == 0 {
  400. return nil, cloudprovider.ErrNotFound
  401. }
  402. eips, err := ins.getRegion().GetEips(eipIds)
  403. if err != nil {
  404. return nil, errors.Wrap(err, "get eips")
  405. }
  406. if len(eips) == 0 {
  407. return nil, errors.ErrNotFound
  408. }
  409. for _, eip := range eips {
  410. if utils.IsInStringArray(eip.GetId(), eipIds) {
  411. eip.region = ins.getRegion()
  412. return &eip, nil
  413. }
  414. }
  415. return nil, errors.Wrapf(err, "instanceId id:%s", ins.GetGlobalId())
  416. }
  417. func (ins *SInstance) GetINics() ([]cloudprovider.ICloudNic, error) {
  418. nics := []cloudprovider.ICloudNic{}
  419. for i := 0; i < len(ins.NetworkInterfaceSet); i++ {
  420. nic := SInstanceNic{
  421. Instance: ins,
  422. Id: ins.NetworkInterfaceSet[i].SubnetId,
  423. IpAddr: ins.NetworkInterfaceSet[i].PrivateIPAddress,
  424. MacAddr: ins.NetworkInterfaceSet[i].MacAddress,
  425. }
  426. nics = append(nics, &nic)
  427. }
  428. return nics, nil
  429. }
  430. func (ins *SInstance) GetVNCInfo(input *cloudprovider.ServerVncInput) (*cloudprovider.ServerVncOutput, error) {
  431. vnc, err := ins.getRegion().GetVNCInfo(ins.InstanceId)
  432. if err != nil {
  433. return nil, errors.Wrap(err, "GetVNCInfo")
  434. }
  435. ret := &cloudprovider.ServerVncOutput{
  436. Url: fmt.Sprintf("http://kec.console.ksyun.com/kec/connect/vnc?VncUrl=%s", vnc),
  437. Protocol: "ksyun",
  438. InstanceId: ins.InstanceId,
  439. Hypervisor: api.HYPERVISOR_KSYUN,
  440. }
  441. return ret, nil
  442. }
  443. /*
  444. {
  445. "RequestId":
  446. "91f6c5ea-f0b0-4d1a-9f87-6154f1823442003",
  447. "VncUrl":
  448. "ws://tjwqone.vnc.ksyun.com:80/websockify?token=u4-394839af-a920-4394-bfe3-f99b88c87fa1"
  449. }
  450. */
  451. func (region *SRegion) GetVNCInfo(instanceId string) (string, error) {
  452. resp, err := region.ecsRequest("DescribeInstanceVncUrl", map[string]interface{}{"InstanceId": instanceId})
  453. if err != nil {
  454. return "", errors.Wrap(err, "GetVNCAddress")
  455. }
  456. return resp.GetString("VncUrl")
  457. }
  458. func (ins *SInstance) GetVcpuCount() int {
  459. return ins.InstanceConfigure.Vcpu
  460. }
  461. func (ins *SInstance) GetVmemSizeMB() int {
  462. return ins.InstanceConfigure.MemoryGb * 1024
  463. }
  464. func (ins *SInstance) GetVdi() string {
  465. return ""
  466. }
  467. func (ins *SInstance) GetVga() string {
  468. return ""
  469. }
  470. func (region *SRegion) BindKeypair(instanceId, keyName, publicKey string) error {
  471. keyId, err := region.syncKeypair(keyName, publicKey)
  472. if err != nil {
  473. return errors.Wrapf(err, "syncKeypair %s", keyName)
  474. }
  475. return region.AttachKey(instanceId, keyId)
  476. }
  477. func (region *SRegion) AttachKey(instanceId, keyId string) error {
  478. params := map[string]interface{}{
  479. "InstanceId.1": instanceId,
  480. "KeyId.1": keyId,
  481. }
  482. _, err := region.ecsRequest("AttachKey", params)
  483. return err
  484. }
  485. func (ins *SInstance) RebuildRoot(ctx context.Context, opts *cloudprovider.SManagedVMRebuildRootConfig) (string, error) {
  486. err := ins.getRegion().RebuildRoot(ins.InstanceId, opts)
  487. if err != nil {
  488. return "", err
  489. }
  490. if len(opts.PublicKey) > 0 {
  491. keyName := opts.KeypairName
  492. if len(keyName) == 0 {
  493. keyName = ins.InstanceName
  494. }
  495. err = ins.getRegion().BindKeypair(ins.InstanceId, keyName, opts.PublicKey)
  496. if err != nil {
  497. log.Errorf("BindKeypair %s error: %v", keyName, err)
  498. }
  499. }
  500. disks, err := ins.GetIDisks()
  501. if err != nil {
  502. return "", err
  503. }
  504. if len(disks) == 0 {
  505. return "", fmt.Errorf("server %s has no volume attached.", ins.GetId())
  506. }
  507. return disks[0].GetGlobalId(), nil
  508. }
  509. func (region *SRegion) RebuildRoot(instanceId string, opts *cloudprovider.SManagedVMRebuildRootConfig) error {
  510. params := map[string]interface{}{
  511. "InstanceId": instanceId,
  512. "ImageId": opts.ImageId,
  513. }
  514. if len(opts.Password) > 0 {
  515. params["InstancePassword"] = opts.Password
  516. }
  517. if len(opts.UserData) > 0 {
  518. params["UserData"] = opts.UserData
  519. }
  520. _, err := region.ecsRequest("ModifyInstanceImage", params)
  521. return err
  522. }
  523. func (ins *SInstance) SetSecurityGroups(secgroupIds []string) error {
  524. nicId := ""
  525. for _, netSet := range ins.NetworkInterfaceSet {
  526. if netSet.NetworkInterfaceType == "primary" {
  527. nicId = netSet.NetworkInterfaceId
  528. break
  529. }
  530. }
  531. return ins.getRegion().SetSecurityGroups(secgroupIds, ins.InstanceId, nicId, ins.SubnetId)
  532. }
  533. func (ins *SInstance) StartVM(ctx context.Context) error {
  534. return ins.getRegion().StartVM(ins.InstanceId)
  535. }
  536. func (ins *SInstance) StopVM(ctx context.Context, opts *cloudprovider.ServerStopOptions) error {
  537. return ins.getRegion().StopVM(ins.InstanceId, opts.IsForce, opts.StopCharging)
  538. }
  539. func (region *SRegion) StartVM(instanceId string) error {
  540. params := map[string]interface{}{
  541. "InstanceId.1": instanceId,
  542. }
  543. _, err := region.ecsRequest("StartInstances", params)
  544. if err != nil {
  545. return errors.Wrap(err, "StartInstances")
  546. }
  547. return nil
  548. }
  549. func (region *SRegion) StopVM(instanceId string, force, stopCharging bool) error {
  550. params := map[string]interface{}{
  551. "InstanceId.1": instanceId,
  552. "StoppedMode": "KeepCharging",
  553. }
  554. if stopCharging {
  555. params["StoppedMode"] = "StopCharging"
  556. }
  557. if force {
  558. params["ForceStop"] = "true"
  559. }
  560. _, err := region.ecsRequest("StopInstances", params)
  561. if err != nil {
  562. return errors.Wrap(err, "StopInstances")
  563. }
  564. return nil
  565. }
  566. func (ins *SInstance) UpdateUserData(userData string) error {
  567. return cloudprovider.ErrNotSupported
  568. }
  569. func (ins *SInstance) UpdateVM(ctx context.Context, opts cloudprovider.SInstanceUpdateOptions) error {
  570. return ins.getRegion().UpdateVM(ins.InstanceId, opts)
  571. }
  572. func (region *SRegion) UpdateVM(instanceId string, opts cloudprovider.SInstanceUpdateOptions) error {
  573. params := map[string]interface{}{
  574. "InstanceId": instanceId,
  575. }
  576. if len(opts.NAME) > 0 {
  577. params["InstanceName"] = opts.NAME
  578. }
  579. if len(opts.HostName) > 0 {
  580. params["HostName"] = opts.HostName
  581. }
  582. _, err := region.ecsRequest("ModifyInstanceAttribute", params)
  583. return err
  584. }
  585. func (ins *SInstance) GetIHost() cloudprovider.ICloudHost {
  586. return ins.host
  587. }
  588. func (ins *SInstance) DeployVM(ctx context.Context, opts *cloudprovider.SInstanceDeployOptions) error {
  589. if len(opts.PublicKey) > 0 {
  590. return ins.getRegion().BindKeypair(ins.InstanceId, opts.KeypairName, opts.PublicKey)
  591. }
  592. return ins.getRegion().DeployVM(ins.InstanceId, opts)
  593. }
  594. func (region *SRegion) DeployVM(instanceId string, opts *cloudprovider.SInstanceDeployOptions) error {
  595. params := map[string]interface{}{
  596. "InstanceId": instanceId,
  597. "InstancePassword": opts.Password,
  598. "RestartMode": "Restart",
  599. }
  600. _, err := region.ecsRequest("ModifyInstanceAttribute", params)
  601. return err
  602. }
  603. func (ins *SInstance) GetBillingType() string {
  604. if ins.ChargeType == "Monthly" {
  605. return billing_api.BILLING_TYPE_PREPAID
  606. }
  607. return billing_api.BILLING_TYPE_POSTPAID
  608. }
  609. func (ins *SInstance) GetCreatedAt() time.Time {
  610. return ins.CreationDate
  611. }
  612. func (ins *SInstance) GetExpiredAt() time.Time {
  613. return ins.ServiceEndTime
  614. }
  615. func (ins *SInstance) SaveImage(opts *cloudprovider.SaveImageOptions) (cloudprovider.ICloudImage, error) {
  616. return ins.host.zone.region.SaveImage(ins.InstanceId, opts)
  617. }
  618. func (region *SRegion) SaveImage(instanceId string, opts *cloudprovider.SaveImageOptions) (cloudprovider.ICloudImage, error) {
  619. params := map[string]interface{}{
  620. "InstanceId": instanceId,
  621. "Name": opts.Name,
  622. }
  623. resp, err := region.ecsRequest("CreateImage", params)
  624. if err != nil {
  625. return nil, errors.Wrapf(err, "CreateImage")
  626. }
  627. imageId, err := resp.GetString("ImageId")
  628. if err != nil {
  629. return nil, errors.Wrapf(err, "get imageId")
  630. }
  631. return region.GetImage(imageId)
  632. }