instance.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532
  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 bingocloud
  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/cloudmux/pkg/apis"
  23. api "yunion.io/x/cloudmux/pkg/apis/compute"
  24. "yunion.io/x/cloudmux/pkg/cloudprovider"
  25. "yunion.io/x/cloudmux/pkg/multicloud"
  26. )
  27. type SInstance struct {
  28. BingoTags
  29. multicloud.SInstanceBase
  30. node *SNode
  31. ReservationId string `json:"reservationId"`
  32. OwnerId string
  33. GroupSet []struct {
  34. GroupId string
  35. GroupName string
  36. }
  37. InstancesSet struct {
  38. InstanceId string `json:"instanceId"`
  39. InstanceName string `json:"instanceName"`
  40. HostName string `json:"hostName"`
  41. ImageId string `json:"imageId"`
  42. InstanceState struct {
  43. Code int `json:"code"`
  44. Name string `json:"name"`
  45. PendingProgress string `json:"pendingProgress"`
  46. } `json:"instanceState"`
  47. PrivateDNSName string `json:"privateDnsName"`
  48. DNSName string `json:"dnsName"`
  49. PrivateIPAddress string `json:"privateIpAddress"`
  50. PrivateIPAddresses string `json:"privateIpAddresses"`
  51. IPAddress string `json:"ipAddress"`
  52. NifInfo string `json:"nifInfo"`
  53. KeyName string `json:"keyName"`
  54. AmiLaunchIndex int `json:"amiLaunchIndex"`
  55. ProductCodesSet []struct {
  56. ProductCode string `json:"productCode"`
  57. } `json:"productCodesSet"`
  58. InstanceType string `json:"instanceType"`
  59. VmtypeCPU int `json:"vmtype_cpu"`
  60. VmtypeMem int `json:"vmtype_mem"`
  61. VmtypeDisk int `json:"vmtype_disk"`
  62. VmtypeGpu int `json:"vmtype_gpu"`
  63. VmtypeSsd int `json:"vmtype_ssd"`
  64. VmtypeHdd int `json:"vmtype_hdd"`
  65. VmtypeHba int `json:"vmtype_hba"`
  66. VmtypeSriov int `json:"vmtype_sriov"`
  67. LaunchTime time.Time `json:"launchTime"`
  68. RootDeviceType string `json:"rootDeviceType"`
  69. HostAddress string `json:"hostAddress"`
  70. Platform string `json:"platform"`
  71. UseCompactMode bool `json:"useCompactMode"`
  72. ExtendDisk bool `json:"extendDisk"`
  73. Placement struct {
  74. AvailabilityZone string `json:"availabilityZone"`
  75. } `json:"placement"`
  76. Namespace string `json:"namespace"`
  77. KernelId string `json:"kernelId"`
  78. RamdiskId string `json:"ramdiskId"`
  79. OperName string `json:"operName"`
  80. OperProgress int `json:"operProgress"`
  81. Features string `json:"features"`
  82. Monitoring struct {
  83. State string `json:"state"`
  84. } `json:"monitoring"`
  85. SubnetId string `json:"subnetId"`
  86. VpcId string `json:"vpcId"`
  87. StorageId string `json:"storageId"`
  88. DisableAPITermination bool `json:"disableApiTermination"`
  89. Vncdisabled bool `json:"vncdisabled"`
  90. StartTime time.Time `json:"startTime"`
  91. CustomStatus string `json:"customStatus"`
  92. SystemStatus int `json:"systemStatus"`
  93. NetworkStatus int `json:"networkStatus"`
  94. ScheduleTags string `json:"scheduleTags"`
  95. StorageScheduleTags string `json:"storageScheduleTags"`
  96. IsEncrypt bool `json:"isEncrypt"`
  97. IsImported bool `json:"isImported"`
  98. Ec2Version string `json:"ec2Version"`
  99. Passphrase string `json:"passphrase"`
  100. DrsEnabled bool `json:"drs_enabled"`
  101. LaunchPriority int `json:"launchPriority"`
  102. CPUPriority int `json:"cpuPriority"`
  103. MemPriority int `json:"memPriority"`
  104. CPUQuota int `json:"cpuQuota"`
  105. AutoMigrate bool `json:"autoMigrate"`
  106. DrMirrorId string `json:"drMirrorId"`
  107. BlockDeviceMapping []struct {
  108. DeviceName string `json:"deviceName"`
  109. Ebs struct {
  110. AttachTime time.Time `json:"attachTime"`
  111. DeleteOnTermination bool `json:"deleteOnTermination"`
  112. Status string `json:"status"`
  113. VolumeId string `json:"volumeId"`
  114. Size int `json:"size"`
  115. } `json:"ebs"`
  116. } `json:"blockDeviceMapping"`
  117. EnableLiveScaleup bool `json:"enableLiveScaleup"`
  118. ImageBytes int64 `json:"imageBytes"`
  119. StatusReason string `json:"statusReason"`
  120. Hypervisor string `json:"hypervisor"`
  121. Bootloader string `json:"bootloader"`
  122. BmMachineId string `json:"bmMachineId"`
  123. }
  124. }
  125. func (self *SInstance) GetId() string {
  126. return self.InstancesSet.InstanceId
  127. }
  128. func (self *SInstance) GetGlobalId() string {
  129. return self.GetId()
  130. }
  131. func (self *SInstance) GetName() string {
  132. if len(self.InstancesSet.InstanceName) > 0 {
  133. return self.InstancesSet.InstanceName
  134. }
  135. return self.GetId()
  136. }
  137. func (self *SInstance) GetSecurityGroupIds() ([]string, error) {
  138. var ret []string
  139. for _, sec := range self.GroupSet {
  140. ret = append(ret, sec.GroupId)
  141. }
  142. return ret, nil
  143. }
  144. func (self *SInstance) SetSecurityGroups(secgroupIds []string) error {
  145. return self.node.cluster.region.modifyInstanceAttribute(self.InstancesSet.InstanceId, map[string]string{"GroupId": secgroupIds[0]})
  146. }
  147. func (self *SInstance) AttachDisk(ctx context.Context, diskId string) error {
  148. return nil
  149. }
  150. func (self *SInstance) DetachDisk(ctx context.Context, diskId string) error {
  151. return nil
  152. }
  153. func (self *SInstance) ChangeConfig(ctx context.Context, config *cloudprovider.SManagedVMChangeConfig) error {
  154. return cloudprovider.ErrNotImplemented
  155. }
  156. func (self *SInstance) DeployVM(ctx context.Context, opts *cloudprovider.SInstanceDeployOptions) error {
  157. attrs := make(map[string]string)
  158. if opts.Password != "" {
  159. attrs["InstanceAction"] = "ResetPassword"
  160. }
  161. return self.node.cluster.region.modifyInstanceAttribute(self.InstancesSet.InstanceId, attrs)
  162. }
  163. func (self *SInstance) DeleteVM(ctx context.Context) error {
  164. params := map[string]string{}
  165. params["InstanceId.1"] = self.InstancesSet.InstanceId
  166. _, err := self.node.cluster.region.invoke("TerminateInstances", params)
  167. return err
  168. }
  169. func (self *SInstance) GetVcpuCount() int {
  170. return self.InstancesSet.VmtypeCPU
  171. }
  172. func (self *SInstance) GetVmemSizeMB() int {
  173. return self.InstancesSet.VmtypeMem
  174. }
  175. func (self *SInstance) GetBootOrder() string {
  176. return "cdn"
  177. }
  178. func (self *SInstance) GetVga() string {
  179. return ""
  180. }
  181. func (self *SInstance) GetVdi() string {
  182. return ""
  183. }
  184. func (self *SInstance) GetOsArch() string {
  185. return apis.OS_ARCH_X86_64
  186. }
  187. func (self *SInstance) GetOsType() cloudprovider.TOsType {
  188. if self.InstancesSet.Platform == "linux" {
  189. return cloudprovider.OsTypeLinux
  190. }
  191. return cloudprovider.OsTypeWindows
  192. }
  193. func (self *SInstance) GetFullOsName() string {
  194. return ""
  195. }
  196. func (self *SInstance) GetBios() cloudprovider.TBiosType {
  197. return cloudprovider.ToBiosType(self.InstancesSet.Bootloader)
  198. }
  199. func (i *SInstance) GetOsDist() string {
  200. return ""
  201. }
  202. func (i *SInstance) GetOsVersion() string {
  203. return ""
  204. }
  205. func (i *SInstance) GetOsLang() string {
  206. return ""
  207. }
  208. func (self *SInstance) GetMachine() string {
  209. return ""
  210. }
  211. func (self *SInstance) GetInstanceType() string {
  212. return self.InstancesSet.InstanceType
  213. }
  214. func (self *SInstance) GetError() error {
  215. return nil
  216. }
  217. func (self *SInstance) GetHostname() string {
  218. return self.InstancesSet.HostName
  219. }
  220. func (self *SInstance) GetIHost() cloudprovider.ICloudHost {
  221. return self.node
  222. }
  223. func (self *SInstance) GetIHostId() string {
  224. info := strings.Split(self.InstancesSet.HostAddress, "@")
  225. if len(info) == 2 {
  226. return info[1]
  227. }
  228. return ""
  229. }
  230. func (self *SInstance) GetHypervisor() string {
  231. return api.HYPERVISOR_BINGO_CLOUD
  232. }
  233. func (self *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) {
  234. storages, err := self.node.cluster.region.getStorages()
  235. if err != nil {
  236. return nil, err
  237. }
  238. storageMaps := map[string]SStorage{}
  239. for i := range storages {
  240. storageMaps[storages[i].StorageId] = storages[i]
  241. }
  242. var ret []cloudprovider.ICloudDisk
  243. for _, _disk := range self.InstancesSet.BlockDeviceMapping {
  244. disk, err := self.node.cluster.region.GetDisk(_disk.Ebs.VolumeId)
  245. if err != nil {
  246. return nil, err
  247. }
  248. storage, ok := storageMaps[disk.StorageId]
  249. if ok {
  250. storage.cluster = self.node.cluster
  251. disk.storage = &storage
  252. ret = append(ret, disk)
  253. }
  254. }
  255. return ret, nil
  256. }
  257. func (self *SInstance) GetINics() ([]cloudprovider.ICloudNic, error) {
  258. nics, err := self.node.cluster.region.GetInstanceNics(self.InstancesSet.InstanceId)
  259. if err != nil {
  260. return nil, err
  261. }
  262. var ret []cloudprovider.ICloudNic
  263. for i := range nics {
  264. ret = append(ret, &nics[i])
  265. }
  266. return ret, nil
  267. }
  268. func (self *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) {
  269. eips, _, err := self.node.cluster.region.GetEips("", self.InstancesSet.InstanceId, "")
  270. if err != nil {
  271. return nil, err
  272. }
  273. for i := range eips {
  274. eips[i].region = self.node.cluster.region
  275. return &eips[i], nil
  276. }
  277. return nil, nil
  278. }
  279. func (self *SInstance) GetProjectId() string {
  280. return ""
  281. }
  282. func (self *SInstance) Refresh() error {
  283. newInstances, _, err := self.node.cluster.region.GetInstances(self.InstancesSet.InstanceId, self.node.NodeId, MAX_RESULT, "")
  284. if err != nil {
  285. return err
  286. }
  287. if len(newInstances) == 1 {
  288. return jsonutils.Update(self, &newInstances[0])
  289. }
  290. return cloudprovider.ErrNotFound
  291. }
  292. func (self *SInstance) GetStatus() string {
  293. switch self.InstancesSet.InstanceState.Name {
  294. case "stopped":
  295. return api.VM_READY
  296. default:
  297. return self.InstancesSet.InstanceState.Name
  298. }
  299. }
  300. func (self *SInstance) GetVNCInfo(input *cloudprovider.ServerVncInput) (*cloudprovider.ServerVncOutput, error) {
  301. params := map[string]string{}
  302. params["InstanceId"] = self.InstancesSet.InstanceId
  303. resp, err := self.node.cluster.region.invoke("GetVncInfo", params)
  304. if err != nil {
  305. return nil, err
  306. }
  307. result := struct {
  308. GetVncInfoResult *cloudprovider.ServerVncOutput `json:"getVncInfoResult"`
  309. }{}
  310. _ = resp.Unmarshal(&result)
  311. result.GetVncInfoResult.InstanceId = self.InstancesSet.InstanceId
  312. result.GetVncInfoResult.Hypervisor = self.GetHypervisor()
  313. return result.GetVncInfoResult, nil
  314. }
  315. func (self *SInstance) RebuildRoot(ctx context.Context, config *cloudprovider.SManagedVMRebuildRootConfig) (string, error) {
  316. params := map[string]string{}
  317. params["InstanceId"] = self.InstancesSet.InstanceId
  318. params["ImageId"] = config.ImageId
  319. params["InstanceType"] = self.InstancesSet.InstanceType
  320. if config.PublicKey != "" {
  321. params["KeyName"] = config.PublicKey
  322. }
  323. isOk := "false"
  324. result, err := self.node.cluster.region.invoke("ReinstallInstance", params)
  325. if err != nil {
  326. return "", err
  327. }
  328. _ = result.Unmarshal(&isOk, "return")
  329. if isOk != "true" {
  330. return "", errors.Wrap(cloudprovider.ErrUnknown, "RebuildRoot")
  331. }
  332. iDisks, err := self.GetIDisks()
  333. if err != nil {
  334. return "", err
  335. }
  336. if len(iDisks) > 0 {
  337. return iDisks[0].GetGlobalId(), nil
  338. }
  339. return "", errors.Wrap(cloudprovider.ErrUnknown, "RebuildRoot")
  340. }
  341. func (self *SInstance) StartVM(ctx context.Context) error {
  342. params := map[string]string{}
  343. params["InstanceId.1"] = self.InstancesSet.InstanceId
  344. _, err := self.node.cluster.region.invoke("StartInstances", params)
  345. return err
  346. }
  347. func (self *SInstance) SuspendVM(ctx context.Context) error {
  348. params := map[string]string{}
  349. params["InstanceId.1"] = self.InstancesSet.InstanceId
  350. _, err := self.node.cluster.region.invoke("SuspendInstances", params)
  351. return err
  352. }
  353. func (self *SInstance) ResumeVM(ctx context.Context) error {
  354. params := map[string]string{}
  355. params["InstanceId.1"] = self.InstancesSet.InstanceId
  356. _, err := self.node.cluster.region.invoke("ResumeInstances", params)
  357. return err
  358. }
  359. func (self *SInstance) StopVM(ctx context.Context, opts *cloudprovider.ServerStopOptions) error {
  360. params := map[string]string{}
  361. params["InstanceId.1"] = self.InstancesSet.InstanceId
  362. _, err := self.node.cluster.region.invoke("StopInstances", params)
  363. return err
  364. }
  365. func (self *SInstance) UpdateUserData(userData string) error {
  366. return self.node.cluster.region.modifyInstanceAttribute(self.InstancesSet.InstanceId, map[string]string{"UserData": userData})
  367. }
  368. func (self *SInstance) UpdateInstanceType(instanceType string) error {
  369. return self.node.cluster.region.modifyInstanceAttribute(self.InstancesSet.InstanceId, map[string]string{"InstanceType": instanceType})
  370. }
  371. func (self *SInstance) UpdateVM(ctx context.Context, input cloudprovider.SInstanceUpdateOptions) error {
  372. return self.node.cluster.region.modifyInstanceAttribute(self.InstancesSet.InstanceId, map[string]string{"InstanceName": input.NAME})
  373. }
  374. func (self *SInstance) CreateInstanceSnapshot(ctx context.Context, name string, desc string) (cloudprovider.ICloudInstanceSnapshot, error) {
  375. newId, err := self.node.cluster.region.createInstanceSnapshot(self.InstancesSet.InstanceId, name, desc)
  376. if err != nil {
  377. return nil, err
  378. }
  379. return self.GetInstanceSnapshot(newId)
  380. }
  381. func (self *SInstance) GetInstanceSnapshot(id string) (cloudprovider.ICloudInstanceSnapshot, error) {
  382. snapshots, err := self.node.cluster.region.getInstanceSnapshots(self.InstancesSet.InstanceId, id)
  383. if err != nil {
  384. return nil, err
  385. }
  386. for i := range snapshots {
  387. if snapshots[i].GetGlobalId() == id {
  388. snapshots[i].region = self.node.cluster.region
  389. return &snapshots[i], nil
  390. }
  391. }
  392. return nil, cloudprovider.ErrNotFound
  393. }
  394. func (self *SInstance) GetInstanceSnapshots() ([]cloudprovider.ICloudInstanceSnapshot, error) {
  395. snapshots, err := self.node.cluster.region.getInstanceSnapshots(self.InstancesSet.InstanceId, "")
  396. if err != nil {
  397. return nil, err
  398. }
  399. var ret []cloudprovider.ICloudInstanceSnapshot
  400. for i := range snapshots {
  401. snapshots[i].region = self.node.cluster.region
  402. ret = append(ret, &snapshots[i])
  403. }
  404. return ret, nil
  405. }
  406. func (self *SInstance) ResetToInstanceSnapshot(ctx context.Context, idStr string) error {
  407. return self.node.cluster.region.revertInstanceSnapshot(idStr)
  408. }
  409. func (self *SRegion) GetIVMById(id string) (cloudprovider.ICloudVM, error) {
  410. vms, _, err := self.GetInstances(id, "", 1, "")
  411. if err != nil {
  412. return nil, err
  413. }
  414. for i := range vms {
  415. if vms[i].GetGlobalId() == id {
  416. return &vms[i], nil
  417. }
  418. }
  419. return nil, cloudprovider.ErrNotFound
  420. }
  421. func (self *SRegion) GetInstances(id, nodeId string, maxResult int, nextToken string) ([]SInstance, string, error) {
  422. params := map[string]string{}
  423. if maxResult > 0 {
  424. params["MaxRecords"] = fmt.Sprintf("%d", maxResult)
  425. }
  426. if len(nextToken) > 0 {
  427. params["NextToken"] = nextToken
  428. }
  429. idx := 1
  430. if len(nodeId) > 0 {
  431. params[fmt.Sprintf("Filter.%d.Name", idx)] = "node-id"
  432. params[fmt.Sprintf("Filter.%d.Value.1", idx)] = nodeId
  433. idx++
  434. }
  435. if len(id) > 0 {
  436. params[fmt.Sprintf("Filter.%d.Name", idx)] = "instance-id"
  437. params[fmt.Sprintf("Filter.%d.Value.1", idx)] = id
  438. idx++
  439. }
  440. resp, err := self.invoke("DescribeInstances", params)
  441. if err != nil {
  442. return nil, "", err
  443. }
  444. result := struct {
  445. NextToken string
  446. ReservationSet []SInstance
  447. }{}
  448. _ = resp.Unmarshal(&result)
  449. return result.ReservationSet, result.NextToken, nil
  450. }
  451. func (self *SRegion) modifyInstanceAttribute(instanceId string, attrs map[string]string) error {
  452. params := map[string]string{}
  453. params["InstanceId"] = instanceId
  454. for key, value := range attrs {
  455. params["Attribute"] = key
  456. params["Value"] = value
  457. _, err := self.client.invoke("ModifyInstanceAttribute", params)
  458. if err != nil {
  459. return err
  460. }
  461. }
  462. return nil
  463. }