instance.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550
  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 baidu
  15. import (
  16. "context"
  17. "fmt"
  18. "net/url"
  19. "strings"
  20. "time"
  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/pkg/errors"
  26. "yunion.io/x/pkg/utils"
  27. )
  28. type SInstance struct {
  29. multicloud.SInstanceBase
  30. SBaiduTag
  31. host *SHost
  32. Id string
  33. Name string
  34. RoleName string
  35. Hostname string
  36. InstanceType string
  37. Spec string
  38. Status string
  39. Desc string
  40. CreatedFrom string
  41. PaymentTiming string
  42. CreateTime time.Time
  43. InternalIP string
  44. PublicIP string
  45. CPUCount int
  46. IsomerismCard string
  47. CardCount string
  48. NpuVideoMemory string
  49. MemoryCapacityInGB int
  50. LocalDiskSizeInGB int
  51. ImageId string
  52. ImageName string
  53. ImageType string
  54. PlacementPolicy string
  55. SubnetId string
  56. VpcId string
  57. HostId string
  58. SwitchId string
  59. RackId string
  60. DeploysetId string
  61. ZoneName string
  62. DedicatedHostId string
  63. OsVersion string
  64. OsArch string
  65. OsName string
  66. HosteyeType string
  67. NicInfo NicInfo
  68. DeletionProtection int
  69. Ipv6 string
  70. Volumes []SDisk
  71. NetworkCapacityInMbps int
  72. }
  73. func (region *SRegion) GetInstances(zoneName string, instanceIds []string) ([]SInstance, error) {
  74. params := url.Values{}
  75. if len(zoneName) > 0 {
  76. params.Set("zoneName", zoneName)
  77. }
  78. if len(instanceIds) > 0 {
  79. params.Set("instanceIds", strings.Join(instanceIds, ","))
  80. }
  81. ret := []SInstance{}
  82. for {
  83. resp, err := region.bccList("v2/instance", params)
  84. if err != nil {
  85. return nil, errors.Wrap(err, "list instance")
  86. }
  87. part := struct {
  88. NextMarker string
  89. Instances []SInstance
  90. }{}
  91. err = resp.Unmarshal(&part)
  92. if err != nil {
  93. return nil, err
  94. }
  95. ret = append(ret, part.Instances...)
  96. if len(part.NextMarker) == 0 {
  97. break
  98. }
  99. params.Set("marker", part.NextMarker)
  100. }
  101. return ret, nil
  102. }
  103. func (region *SRegion) GetInstance(instanceId string) (*SInstance, error) {
  104. resp, err := region.bccList(fmt.Sprintf("v2/instance/%s", instanceId), nil)
  105. if err != nil {
  106. return nil, errors.Wrap(err, "show instance")
  107. }
  108. ret := &SInstance{}
  109. err = resp.Unmarshal(ret, "instance")
  110. if err != nil {
  111. return nil, errors.Wrap(err, "unmarshal instance")
  112. }
  113. return ret, nil
  114. }
  115. func (ins *SInstance) AssignSecurityGroup(secgroupId string) error {
  116. return ins.host.zone.region.AssignSecurityGroup(ins.Id, secgroupId)
  117. }
  118. func (region *SRegion) AssignSecurityGroup(vmId string, secgroupId string) error {
  119. params := url.Values{}
  120. params.Set("bind", "")
  121. body := map[string]interface{}{
  122. "securityGroupId": secgroupId,
  123. }
  124. _, err := region.bccUpdate(fmt.Sprintf("v2/instance/%s", vmId), params, body)
  125. return err
  126. }
  127. func (region *SRegion) RevokeSecurityGroup(vmId string, secgroupId string) error {
  128. params := url.Values{}
  129. params.Set("unbind", "")
  130. body := map[string]interface{}{
  131. "securityGroupId": secgroupId,
  132. }
  133. _, err := region.bccUpdate(fmt.Sprintf("v2/instance/%s", vmId), params, body)
  134. return err
  135. }
  136. func (ins *SInstance) AttachDisk(ctx context.Context, diskId string) error {
  137. return ins.host.zone.region.AttachDisk(ins.Id, diskId)
  138. }
  139. func (region *SRegion) AttachDisk(vmId string, diskId string) error {
  140. params := url.Values{}
  141. params.Set("attach", "")
  142. body := map[string]interface{}{
  143. "instanceId": vmId,
  144. }
  145. _, err := region.bccUpdate(fmt.Sprintf("v2/volume/%s", diskId), params, body)
  146. return err
  147. }
  148. func (ins *SInstance) ChangeConfig(ctx context.Context, opts *cloudprovider.SManagedVMChangeConfig) error {
  149. return ins.host.zone.region.ChangeVmConfig(ins.Id, opts.InstanceType)
  150. }
  151. func (region *SRegion) ChangeVmConfig(vmId string, instanceType string) error {
  152. params := url.Values{}
  153. params.Set("clientToken", utils.GenRequestId(20))
  154. params.Set("resize", "")
  155. body := map[string]interface{}{
  156. "spec": instanceType,
  157. }
  158. _, err := region.bccUpdate(fmt.Sprintf("v2/instance/%s", vmId), params, body)
  159. return err
  160. }
  161. func (ins *SInstance) DeleteVM(ctx context.Context) error {
  162. return ins.host.zone.region.DeleteVm(ins.Id)
  163. }
  164. func (ins *SInstance) Refresh() error {
  165. vm, err := ins.host.zone.region.GetInstance(ins.Id)
  166. if err != nil {
  167. return err
  168. }
  169. return jsonutils.Update(ins, vm)
  170. }
  171. func (region *SRegion) DeleteVm(id string) error {
  172. params := url.Values{}
  173. body := map[string]interface{}{
  174. "relatedReleaseFlag": true,
  175. "deleteCdsSnapshotFlag": true,
  176. "deleteRelatedEnisFlag": true,
  177. "bccRecycleFlag": false,
  178. }
  179. _, err := region.bccPost(fmt.Sprintf("v2/instance/%s", id), params, body)
  180. return err
  181. }
  182. func (ins *SInstance) DetachDisk(ctx context.Context, diskId string) error {
  183. return ins.host.zone.region.DetachDisk(ins.Id, diskId)
  184. }
  185. func (region *SRegion) DetachDisk(vmId string, diskId string) error {
  186. params := url.Values{}
  187. params.Set("detach", "")
  188. body := map[string]interface{}{
  189. "instanceId": vmId,
  190. }
  191. _, err := region.bccUpdate(fmt.Sprintf("v2/volume/%s", diskId), params, body)
  192. return err
  193. }
  194. func (ins *SInstance) GetBios() cloudprovider.TBiosType {
  195. return ""
  196. }
  197. func (ins *SInstance) GetBootOrder() string {
  198. return "bcd"
  199. }
  200. func (ins *SInstance) GetError() error {
  201. return nil
  202. }
  203. func (ins *SInstance) GetFullOsName() string {
  204. return ""
  205. }
  206. func (ins *SInstance) GetGlobalId() string {
  207. return ins.Id
  208. }
  209. func (ins *SInstance) GetId() string {
  210. return ins.Id
  211. }
  212. func (ins *SInstance) GetInstanceType() string {
  213. return ins.Spec
  214. }
  215. func (ins *SInstance) GetMachine() string {
  216. return "pc"
  217. }
  218. func (ins *SInstance) GetHostname() string {
  219. return ins.Hostname
  220. }
  221. func (ins *SInstance) GetName() string {
  222. return ins.Name
  223. }
  224. func (ins *SInstance) GetOsArch() string {
  225. return getOsArch(ins.OsArch)
  226. }
  227. func (ins *SInstance) GetOsDist() string {
  228. return ""
  229. }
  230. func (ins *SInstance) GetOsLang() string {
  231. return ins.OsName
  232. }
  233. func (ins *SInstance) GetOsType() cloudprovider.TOsType {
  234. if strings.Contains(strings.ToLower(ins.OsName), "windows") {
  235. return cloudprovider.OsTypeWindows
  236. }
  237. return cloudprovider.OsTypeLinux
  238. }
  239. func (ins *SInstance) GetOsVersion() string {
  240. return ins.OsVersion
  241. }
  242. func (ins *SInstance) GetProjectId() string {
  243. return ""
  244. }
  245. func (ins *SInstance) GetSecurityGroupIds() ([]string, error) {
  246. return ins.NicInfo.SecurityGroups, nil
  247. }
  248. func (ins *SInstance) GetStatus() string {
  249. switch ins.Status {
  250. case "Running":
  251. return api.VM_RUNNING
  252. case "Stopped":
  253. return api.VM_READY
  254. case "Stopping":
  255. return api.VM_STOPPING
  256. case "Starting":
  257. return api.VM_STARTING
  258. default:
  259. return strings.ToLower(ins.Status)
  260. }
  261. }
  262. func (ins *SInstance) GetHypervisor() string {
  263. return api.HYPERVISOR_BAIDU
  264. }
  265. func (ins *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) {
  266. disks, err := ins.host.zone.region.GetDisks("", "", ins.Id)
  267. if err != nil {
  268. return nil, err
  269. }
  270. storages, err := ins.host.zone.region.GetStorageTypes(ins.host.zone.ZoneName)
  271. if err != nil {
  272. return nil, err
  273. }
  274. ret := []cloudprovider.ICloudDisk{}
  275. for i := range disks {
  276. for j := range storages {
  277. if isMatchStorageType(disks[i].StorageType, storages[j].StorageType) {
  278. storages[i].zone = ins.host.zone
  279. disks[i].storage = &storages[i]
  280. ret = append(ret, &disks[i])
  281. break
  282. }
  283. }
  284. }
  285. return ret, nil
  286. }
  287. func (ins *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) {
  288. eips, err := ins.host.zone.region.GetEips(ins.Id)
  289. if err != nil {
  290. return nil, err
  291. }
  292. for i := range eips {
  293. eips[i].region = ins.host.zone.region
  294. return &eips[i], nil
  295. }
  296. return nil, cloudprovider.ErrNotFound
  297. }
  298. func (ins *SInstance) GetINics() ([]cloudprovider.ICloudNic, error) {
  299. return []cloudprovider.ICloudNic{&ins.NicInfo}, nil
  300. }
  301. func (ins *SInstance) GetVNCInfo(input *cloudprovider.ServerVncInput) (*cloudprovider.ServerVncOutput, error) {
  302. url, err := ins.host.zone.region.GetInstanceVnc(ins.Id)
  303. if err != nil {
  304. return nil, err
  305. }
  306. return &cloudprovider.ServerVncOutput{
  307. Url: url,
  308. Protocol: "baidu",
  309. InstanceId: ins.Id,
  310. Hypervisor: api.HYPERVISOR_BAIDU,
  311. OsName: string(ins.GetOsType()),
  312. }, nil
  313. }
  314. func (ins *SInstance) GetVcpuCount() int {
  315. return ins.CPUCount
  316. }
  317. func (ins *SInstance) GetVmemSizeMB() int {
  318. return ins.MemoryCapacityInGB * 1024
  319. }
  320. func (ins *SInstance) GetVdi() string {
  321. return ""
  322. }
  323. func (ins *SInstance) GetVga() string {
  324. return ""
  325. }
  326. func (ins *SInstance) RebuildRoot(ctx context.Context, opts *cloudprovider.SManagedVMRebuildRootConfig) (string, error) {
  327. disks, err := ins.host.zone.region.GetDisks("", "", ins.Id)
  328. if err != nil {
  329. return "", err
  330. }
  331. systemDiskId := ""
  332. for _, disk := range disks {
  333. if disk.IsSystemVolume {
  334. systemDiskId = disk.Id
  335. }
  336. }
  337. err = ins.host.zone.region.RebuildRoot(ins.Id, opts)
  338. if err != nil {
  339. return "", err
  340. }
  341. return systemDiskId, nil
  342. }
  343. func (region *SRegion) RebuildRoot(vmId string, opts *cloudprovider.SManagedVMRebuildRootConfig) error {
  344. params := url.Values{}
  345. params.Set("rebuild", "")
  346. body := map[string]interface{}{
  347. "imageId": opts.ImageId,
  348. "userData": opts.UserData,
  349. }
  350. var err error
  351. if len(opts.PublicKey) > 0 {
  352. keypair, err := region.SyncKeypair(fmt.Sprintf("auto-generate-%d", time.Now().Unix()), opts.PublicKey)
  353. if err != nil {
  354. return err
  355. }
  356. body["keypairId"] = keypair.KeypairId
  357. } else if len(opts.Password) > 0 {
  358. body["adminPass"], err = AesECBEncryptHex(region.client.accessKeySecret, opts.Password)
  359. if err != nil {
  360. return err
  361. }
  362. }
  363. _, err = region.bccUpdate(fmt.Sprintf("v2/instance/%s", vmId), params, body)
  364. return err
  365. }
  366. func (ins *SInstance) SetSecurityGroups(secgroupIds []string) error {
  367. current, err := ins.GetSecurityGroupIds()
  368. if err != nil {
  369. return errors.Wrapf(err, "GetSecurityGroupIds")
  370. }
  371. for _, secgroupId := range secgroupIds {
  372. if !utils.IsInStringArray(secgroupId, current) {
  373. err = ins.host.zone.region.AssignSecurityGroup(ins.Id, secgroupId)
  374. if err != nil {
  375. return errors.Wrapf(err, "AssignSecurityGroup %s", secgroupId)
  376. }
  377. }
  378. }
  379. for _, secgroupId := range current {
  380. if !utils.IsInStringArray(secgroupId, secgroupIds) {
  381. err = ins.host.zone.region.RevokeSecurityGroup(ins.Id, secgroupId)
  382. if err != nil {
  383. return errors.Wrapf(err, "RevokeSecurityGroup %s", secgroupId)
  384. }
  385. }
  386. }
  387. return nil
  388. }
  389. func (ins *SInstance) StartVM(ctx context.Context) error {
  390. return ins.host.zone.region.StartVM(ins.Id)
  391. }
  392. func (region *SRegion) StartVM(vmId string) error {
  393. params := url.Values{}
  394. params.Set("start", "")
  395. _, err := region.bccUpdate(fmt.Sprintf("v2/instance/%s", vmId), params, nil)
  396. return err
  397. }
  398. func (ins *SInstance) StopVM(ctx context.Context, opts *cloudprovider.ServerStopOptions) error {
  399. return ins.host.zone.region.StopVM(ins.Id, opts)
  400. }
  401. func (region *SRegion) StopVM(vmId string, opts *cloudprovider.ServerStopOptions) error {
  402. params := url.Values{}
  403. params.Set("stop", "")
  404. body := map[string]interface{}{
  405. "forceStop": opts.IsForce,
  406. "stopWithNoCharge": opts.StopCharging,
  407. }
  408. _, err := region.bccUpdate(fmt.Sprintf("v2/instance/%s", vmId), params, body)
  409. return err
  410. }
  411. func (ins *SInstance) UpdateUserData(userData string) error {
  412. return cloudprovider.ErrNotSupported
  413. }
  414. func (ins *SInstance) UpdateVM(ctx context.Context, input cloudprovider.SInstanceUpdateOptions) error {
  415. if len(input.HostName) > 0 {
  416. err := ins.host.zone.region.UpdateVmHostname(ins.Id, input.HostName)
  417. if err != nil {
  418. return err
  419. }
  420. }
  421. if len(input.Description) > 0 {
  422. err := ins.host.zone.region.UpdateVmDesc(ins.Id, input.Description)
  423. if err != nil {
  424. return err
  425. }
  426. }
  427. if len(input.NAME) > 0 {
  428. err := ins.host.zone.region.UpdateVmAttr(ins.Id, input.NAME)
  429. if err != nil {
  430. return err
  431. }
  432. }
  433. return nil
  434. }
  435. func (region *SRegion) UpdateVmAttr(vmId string, name string) error {
  436. params := url.Values{}
  437. params.Set("modifyAttribute", "")
  438. body := map[string]interface{}{
  439. "name": name,
  440. }
  441. _, err := region.bccUpdate(fmt.Sprintf("v2/instance/%s", vmId), params, body)
  442. return err
  443. }
  444. func (region *SRegion) UpdateVmDesc(vmId string, desc string) error {
  445. params := url.Values{}
  446. params.Set("modifyDesc", "")
  447. body := map[string]interface{}{
  448. "desc": desc,
  449. }
  450. _, err := region.bccUpdate(fmt.Sprintf("v2/instance/%s", vmId), params, body)
  451. return err
  452. }
  453. func (region *SRegion) UpdateVmHostname(vmId string, hostname string) error {
  454. params := url.Values{}
  455. params.Set("changeHostname", "")
  456. body := map[string]interface{}{
  457. "reboot": false,
  458. "hostname": hostname,
  459. }
  460. _, err := region.bccUpdate(fmt.Sprintf("v2/instance/%s", vmId), params, body)
  461. return err
  462. }
  463. func (ins *SInstance) GetIHost() cloudprovider.ICloudHost {
  464. return ins.host
  465. }
  466. func (region *SRegion) UpdateVmPassword(vmId string, passwd string) error {
  467. params := url.Values{}
  468. params.Set("changePass", "")
  469. body := map[string]interface{}{
  470. "adminPass": passwd,
  471. }
  472. _, err := region.bccUpdate(fmt.Sprintf("v2/instance/%s", vmId), params, body)
  473. return err
  474. }
  475. func (ins *SInstance) DeployVM(ctx context.Context, opts *cloudprovider.SInstanceDeployOptions) error {
  476. if len(opts.Password) > 0 {
  477. return ins.host.zone.region.UpdateVmPassword(ins.Id, opts.Password)
  478. }
  479. return nil
  480. }
  481. func (region *SRegion) GetInstanceVnc(vmId string) (string, error) {
  482. params := url.Values{}
  483. resp, err := region.bccList(fmt.Sprintf("v2/instance/%s/vnc", vmId), params)
  484. if err != nil {
  485. return "", err
  486. }
  487. return resp.GetString("vncUrl")
  488. }