host.go 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  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 proxmox
  15. import (
  16. "fmt"
  17. "net/url"
  18. "strconv"
  19. "strings"
  20. "time"
  21. "yunion.io/x/jsonutils"
  22. "yunion.io/x/pkg/errors"
  23. "yunion.io/x/cloudmux/pkg/apis"
  24. api "yunion.io/x/cloudmux/pkg/apis/compute"
  25. "yunion.io/x/cloudmux/pkg/cloudprovider"
  26. "yunion.io/x/cloudmux/pkg/multicloud"
  27. )
  28. type SHost struct {
  29. multicloud.SHostBase
  30. ProxmoxTags
  31. zone *SZone
  32. Id string
  33. Node string
  34. Uptime int `json:"uptime"`
  35. Wait int `json:"wait"`
  36. Idle int `json:"idle"`
  37. Kversion string `json:"kversion"`
  38. Pveversion string `json:"pveversion"`
  39. CPU int `json:"cpu"`
  40. Loadavg []string `json:"loadavg"`
  41. Rootfs Rootfs `json:"rootfs"`
  42. Swap Swap `json:"swap"`
  43. Memory Memory `json:"memory"`
  44. Cpuinfo Cpuinfo `json:"cpuinfo"`
  45. Ksm Ksm `json:"ksm"`
  46. }
  47. type Rootfs struct {
  48. Used int64 `json:"used"`
  49. Total int64 `json:"total"`
  50. Avail int64 `json:"avail"`
  51. Free int64 `json:"free"`
  52. }
  53. type Swap struct {
  54. Free int64 `json:"free"`
  55. Used int64 `json:"used"`
  56. Total int64 `json:"total"`
  57. }
  58. type Memory struct {
  59. Free int64 `json:"free"`
  60. Used int64 `json:"used"`
  61. Total int64 `json:"total"`
  62. }
  63. type Cpuinfo struct {
  64. Flags string `json:"flags"`
  65. Hvm string `json:"hvm"`
  66. Cores int `json:"cores"`
  67. Model string `json:"model"`
  68. Mhz float64 `json:"mhz"`
  69. Cpus int `json:"cpus"`
  70. UserHz int `json:"user_hz"`
  71. Sockets int `json:"sockets"`
  72. }
  73. type Ksm struct {
  74. Shared int `json:"shared"`
  75. }
  76. func (self *SHost) GetId() string {
  77. return self.Id
  78. }
  79. func (self *SHost) GetGlobalId() string {
  80. return self.Id
  81. }
  82. func (self *SHost) GetName() string {
  83. return self.Node
  84. }
  85. func (self *SHost) GetEnabled() bool {
  86. return true
  87. }
  88. func (self *SHost) GetHostStatus() string {
  89. return api.HOST_ONLINE
  90. }
  91. func (self *SHost) GetStatus() string {
  92. return api.HOST_STATUS_RUNNING
  93. }
  94. func (self *SHost) GetCpuArchitecture() string {
  95. if strings.Contains(self.Kversion, "arm") {
  96. return apis.OS_ARCH_AARCH64
  97. }
  98. return apis.OS_ARCH_X86_64
  99. }
  100. func (self *SHost) GetAccessIp() string {
  101. network := fmt.Sprintf("nodes/%s/network", self.Node)
  102. ret := []struct {
  103. Address string
  104. }{}
  105. err := self.zone.region.get(network, url.Values{}, &ret)
  106. if err != nil {
  107. return ""
  108. }
  109. for i := range ret {
  110. if len(ret[i].Address) > 0 {
  111. return ret[i].Address
  112. }
  113. }
  114. return ""
  115. }
  116. func (self *SHost) GetAccessMac() string {
  117. return ""
  118. }
  119. func (self *SHost) GetSysInfo() jsonutils.JSONObject {
  120. return jsonutils.NewDict()
  121. }
  122. func (self *SHost) GetSN() string {
  123. return ""
  124. }
  125. func (self *SHost) GetCpuCount() int {
  126. return int(self.Cpuinfo.Cores)
  127. }
  128. func (self *SHost) GetNodeCount() int8 {
  129. return int8(self.Cpuinfo.Sockets)
  130. }
  131. func (self *SHost) GetCpuDesc() string {
  132. return self.Cpuinfo.Model
  133. }
  134. func (self *SHost) GetCpuMhz() int {
  135. return int(self.Cpuinfo.Mhz)
  136. }
  137. func (self *SHost) GetCpuCmtbound() float32 {
  138. return 1
  139. }
  140. func (self *SHost) GetMemSizeMB() int {
  141. return int(self.Memory.Total / 1024 / 1024)
  142. }
  143. func (self *SHost) GetMemCmtbound() float32 {
  144. return 1
  145. }
  146. func (self *SHost) GetReservedMemoryMb() int {
  147. return 0
  148. }
  149. func (self *SHost) GetStorageSizeMB() int64 {
  150. return self.Rootfs.Total / 1024 / 1024
  151. }
  152. func (self *SHost) GetStorageType() string {
  153. return api.STORAGE_LOCAL
  154. }
  155. func (self *SHost) GetHostType() string {
  156. return api.HOST_TYPE_PROXMOX
  157. }
  158. func (self *SHost) GetIsMaintenance() bool {
  159. return false
  160. }
  161. func (self *SHost) GetVersion() string {
  162. return self.Pveversion
  163. }
  164. func (self *SHost) CreateVM(opts *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) {
  165. vmId := self.zone.region.GetClusterVmMaxId()
  166. if vmId == -1 {
  167. return nil, errors.Errorf("failed to get vm number by %d", vmId)
  168. }
  169. vmId++
  170. storage, err := self.zone.region.GetStorage(opts.SysDisk.StorageExternalId)
  171. if err != nil {
  172. return nil, errors.Wrapf(err, "GetStorage")
  173. }
  174. body := map[string]interface{}{
  175. "vmid": vmId,
  176. "name": opts.Name,
  177. "ide2": fmt.Sprintf("%s,media=cdrom", opts.ExternalImageId),
  178. "ostype": "other",
  179. "sockets": 1,
  180. "cores": opts.Cpu,
  181. "cpu": "host",
  182. "kvm": 1,
  183. "hotplug": "network,disk,usb",
  184. "memory": opts.MemoryMB,
  185. "description": opts.OsDistribution,
  186. "scsihw": "virtio-scsi-pci",
  187. "net0": "virtio,bridge=vmbr0,firewall=1",
  188. "scsi0": fmt.Sprintf("%s:%d", storage.Storage, opts.SysDisk.SizeGB),
  189. }
  190. for i, disk := range opts.DataDisks {
  191. storage, err := self.zone.region.GetStorage(disk.StorageExternalId)
  192. if err != nil {
  193. return nil, err
  194. }
  195. body[fmt.Sprintf("scsi%d", i+1)] = fmt.Sprintf("%s:%d", storage.Storage, opts.SysDisk.SizeGB)
  196. }
  197. res := fmt.Sprintf("/nodes/%s/qemu", self.Node)
  198. _, err = self.zone.region.post(res, jsonutils.Marshal(body))
  199. if err != nil {
  200. return nil, err
  201. }
  202. vmIdRet := strconv.Itoa(vmId)
  203. cloudprovider.Wait(time.Second*5, time.Minute, func() (bool, error) {
  204. _, err := self.zone.region.GetInstance(vmIdRet)
  205. if err != nil {
  206. if errors.Cause(err) == cloudprovider.ErrNotFound {
  207. return false, nil
  208. }
  209. return false, errors.Wrapf(err, "after created")
  210. }
  211. return true, nil
  212. })
  213. vm, err := self.zone.region.GetInstance(vmIdRet)
  214. if err != nil {
  215. return nil, err
  216. }
  217. vm.host = self
  218. return vm, nil
  219. }
  220. func (host *SHost) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error) {
  221. wires, err := host.getIWires()
  222. if err != nil {
  223. return nil, errors.Wrap(err, "getIWires")
  224. }
  225. return cloudprovider.GetHostNetifs(host, wires), nil
  226. }
  227. func (self *SHost) GetIVMs() ([]cloudprovider.ICloudVM, error) {
  228. vms, err := self.zone.region.GetInstances(self.Id)
  229. if err != nil {
  230. return nil, errors.Wrapf(err, "GetInstances")
  231. }
  232. ret := []cloudprovider.ICloudVM{}
  233. for i := range vms {
  234. vms[i].host = self
  235. ret = append(ret, &vms[i])
  236. }
  237. return ret, nil
  238. }
  239. func (self *SHost) GetIVMById(id string) (cloudprovider.ICloudVM, error) {
  240. vm, err := self.zone.region.GetInstance(id)
  241. if err != nil {
  242. return nil, err
  243. }
  244. hostId := fmt.Sprintf("node/%s", vm.Node)
  245. if hostId != self.Id {
  246. return nil, cloudprovider.ErrNotFound
  247. }
  248. vm.host = self
  249. return vm, nil
  250. }
  251. func (self *SHost) getIWires() ([]cloudprovider.ICloudWire, error) {
  252. wires, err := self.zone.region.GetWires()
  253. if err != nil {
  254. return nil, err
  255. }
  256. ret := []cloudprovider.ICloudWire{}
  257. for i := range wires {
  258. wires[i].region = self.zone.region
  259. ret = append(ret, &wires[i])
  260. }
  261. return ret, nil
  262. }
  263. func (self *SHost) GetIStorages() ([]cloudprovider.ICloudStorage, error) {
  264. storages, err := self.zone.region.GetStoragesByHost(self.Node)
  265. if err != nil {
  266. return nil, err
  267. }
  268. ret := []cloudprovider.ICloudStorage{}
  269. for i := range storages {
  270. storages[i].zone = self.zone
  271. ret = append(ret, &storages[i])
  272. }
  273. return ret, nil
  274. }
  275. func (self *SHost) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) {
  276. storage, err := self.zone.region.GetStorage(id)
  277. if err != nil {
  278. return nil, err
  279. }
  280. storage.zone = self.zone
  281. return storage, nil
  282. }
  283. func (self *SRegion) GetHosts() ([]SHost, error) {
  284. hosts := []SHost{}
  285. resources, err := self.GetClusterNodeResources()
  286. if err != nil {
  287. return nil, err
  288. }
  289. for _, res := range resources {
  290. host := &SHost{}
  291. status := fmt.Sprintf("nodes/%s/status", res.Node)
  292. err := self.get(status, url.Values{}, host)
  293. if err != nil {
  294. return nil, err
  295. }
  296. host.Id = res.Id
  297. host.Node = res.Node
  298. hosts = append(hosts, *host)
  299. }
  300. return hosts, nil
  301. }
  302. func (self *SRegion) GetHost(id string) (*SHost, error) {
  303. ret := &SHost{}
  304. nodeName := ""
  305. //"id": "node/nodeNAME",
  306. splited := strings.Split(id, "/")
  307. if len(splited) == 2 {
  308. nodeName = splited[1]
  309. }
  310. res := fmt.Sprintf("nodes/%s/status", nodeName)
  311. err := self.get(res, url.Values{}, ret)
  312. if err != nil {
  313. return nil, err
  314. }
  315. ret.Id = id
  316. ret.Node = nodeName
  317. return ret, nil
  318. }