yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/proxmox/host.go (about)

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