Bump proxmox-api-go

This commit is contained in:
Calle Pettersson 2020-01-17 20:26:44 +01:00
parent fce24ca71d
commit d70d1e8bf7
5 changed files with 272 additions and 12 deletions

2
go.mod
View File

@ -14,7 +14,7 @@ require (
github.com/NaverCloudPlatform/ncloud-sdk-go v0.0.0-20180110055012-c2e73f942591
github.com/PuerkitoBio/goquery v1.5.0 // indirect
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect
github.com/Telmate/proxmox-api-go v0.0.0-20191015171801-b0c2796b9fcf
github.com/Telmate/proxmox-api-go v0.0.0-20200116224409-320525bf3340
github.com/abdullin/seq v0.0.0-20160510034733-d5467c17e7af // indirect
github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190418113227-25233c783f4e
github.com/aliyun/aliyun-oss-go-sdk v0.0.0-20170113022742-e6dbea820a9f

3
go.sum
View File

@ -43,6 +43,8 @@ github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d h1:G0m3OIz70MZUW
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
github.com/Telmate/proxmox-api-go v0.0.0-20191015171801-b0c2796b9fcf h1:rVT2xsBm03Jp0r0yfGm5AMlqp0mZmxTTiNnSrc9S+Hs=
github.com/Telmate/proxmox-api-go v0.0.0-20191015171801-b0c2796b9fcf/go.mod h1:OGWyIMJ87/k/GCz8CGiWB2HOXsOVDM6Lpe/nFPkC4IQ=
github.com/Telmate/proxmox-api-go v0.0.0-20200116224409-320525bf3340 h1:bOjy6c07dpipWm11dL92FbtmXGnDywOm2uKzG4CePuY=
github.com/Telmate/proxmox-api-go v0.0.0-20200116224409-320525bf3340/go.mod h1:OGWyIMJ87/k/GCz8CGiWB2HOXsOVDM6Lpe/nFPkC4IQ=
github.com/abdullin/seq v0.0.0-20160510034733-d5467c17e7af h1:DBNMBMuMiWYu0b+8KMJuWmfCkcxl09JwdlqwDZZ6U14=
github.com/abdullin/seq v0.0.0-20160510034733-d5467c17e7af/go.mod h1:5Jv4cbFiHJMsVxt52+i0Ha45fjshj6wxYr1r19tB9bw=
github.com/agext/levenshtein v1.2.1 h1:QmvMAjj2aEICytGiWzmxoE0x2KZvE0fvmqMOfy2tjT8=
@ -693,4 +695,5 @@ honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
howett.net/plist v0.0.0-20181124034731-591f970eefbb/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=

View File

@ -39,10 +39,11 @@ type Client struct {
// VmRef - virtual machine ref parts
// map[type:qemu node:proxmox1-xx id:qemu/132 diskread:5.57424738e+08 disk:0 netin:5.9297450593e+10 mem:3.3235968e+09 uptime:1.4567097e+07 vmid:132 template:0 maxcpu:2 netout:6.053310416e+09 maxdisk:3.4359738368e+10 maxmem:8.592031744e+09 diskwrite:1.49663619584e+12 status:running cpu:0.00386980694947209 name:appt-app1-dev.xxx.xx]
type VmRef struct {
vmId int
node string
pool string
vmType string
vmId int
node string
pool string
vmType string
haState string
}
func (vmr *VmRef) SetNode(node string) {
@ -75,6 +76,10 @@ func (vmr *VmRef) Pool() string {
return vmr.pool
}
func (vmr *VmRef) HaState() string {
return vmr.haState
}
func NewVmRef(vmId int) (vmr *VmRef) {
vmr = &VmRef{vmId: vmId, node: "", vmType: ""}
return
@ -141,6 +146,9 @@ func (c *Client) GetVmInfo(vmr *VmRef) (vmInfo map[string]interface{}, err error
if vmInfo["pool"] != nil {
vmr.pool = vmInfo["pool"].(string)
}
if vmInfo["hastate"] != nil {
vmr.haState = vmInfo["hastate"].(string)
}
return
}
}
@ -160,6 +168,9 @@ func (c *Client) GetVmRefByName(vmName string) (vmr *VmRef, err error) {
if vm["pool"] != nil {
vmr.pool = vm["pool"].(string)
}
if vm["hastate"] != nil {
vmr.haState = vm["hastate"].(string)
}
return
}
}
@ -413,6 +424,23 @@ func (c *Client) DeleteVm(vmr *VmRef) (exitStatus string, err error) {
if err != nil {
return "", err
}
//Remove HA if required
if vmr.haState != "" {
url := fmt.Sprintf("/cluster/ha/resources/%d", vmr.vmId)
resp, err := c.session.Delete(url, nil, nil)
if err == nil {
taskResponse, err := ResponseJSON(resp)
if err != nil {
return "", err
}
exitStatus, err = c.WaitForCompletion(taskResponse)
if err != nil {
return "", err
}
}
}
url := fmt.Sprintf("/nodes/%s/%s/%d", vmr.node, vmr.vmType, vmr.vmId)
var taskResponse map[string]interface{}
_, err = c.session.RequestJSON("DELETE", url, nil, nil, nil, &taskResponse)
@ -536,6 +564,22 @@ func (c *Client) SetLxcConfig(vmr *VmRef, vmParams map[string]interface{}) (exit
return
}
// MigrateNode - Migrate a VM
func (c *Client) MigrateNode(vmr *VmRef, newTargetNode string, online bool) (exitStatus interface{}, err error) {
reqbody := ParamsToBody(map[string]interface{}{"target": newTargetNode, "online": online})
url := fmt.Sprintf("/nodes/%s/%s/%d/migrate", vmr.node, vmr.vmType, vmr.vmId)
resp, err := c.session.Post(url, nil, nil, &reqbody)
if err == nil {
taskResponse, err := ResponseJSON(resp)
if err != nil {
return nil, err
}
exitStatus, err = c.WaitForCompletion(taskResponse)
return exitStatus, err
}
return nil, err
}
func (c *Client) ResizeQemuDisk(vmr *VmRef, disk string, moreSizeGB int) (exitStatus interface{}, err error) {
// PUT
//disk:virtio0
@ -691,8 +735,23 @@ func (c *Client) Upload(node string, storage string, contentType string, filenam
req.Header.Add("Content-Type", mimetype)
req.Header.Add("Accept", "application/json")
_, err = c.session.Do(req)
return err
resp, err := c.session.Do(req)
if err != nil {
return err
}
taskResponse, err := ResponseJSON(resp)
if err != nil {
return err
}
exitStatus, err := c.WaitForCompletion(taskResponse)
if err != nil {
return err
}
if exitStatus != exitStatusSuccess {
return fmt.Errorf("Moving file to destination failed: %v", exitStatus)
}
return nil
}
func createUploadBody(contentType string, filename string, r io.Reader) (io.Reader, string, error) {
@ -787,3 +846,61 @@ func (c *Client) UpdateVMPool(vmr *VmRef, pool string) (exitStatus interface{},
}
return
}
func (c *Client) UpdateVMHA(vmr *VmRef, haState string) (exitStatus interface{}, err error) {
// Same hastate
if vmr.haState == haState {
return
}
//Remove HA
if haState == "" {
url := fmt.Sprintf("/cluster/ha/resources/%d", vmr.vmId)
resp, err := c.session.Delete(url, nil, nil)
if err == nil {
taskResponse, err := ResponseJSON(resp)
if err != nil {
return nil, err
}
exitStatus, err = c.WaitForCompletion(taskResponse)
}
return nil, err
}
//Activate HA
if vmr.haState == "" {
paramMap := map[string]interface{}{
"sid": vmr.vmId,
}
reqbody := ParamsToBody(paramMap)
resp, err := c.session.Post("/cluster/ha/resources", nil, nil, &reqbody)
if err == nil {
taskResponse, err := ResponseJSON(resp)
if err != nil {
return nil, err
}
exitStatus, err = c.WaitForCompletion(taskResponse)
if err != nil {
return nil, err
}
}
}
//Set wanted state
paramMap := map[string]interface{}{
"state": haState,
}
reqbody := ParamsToBody(paramMap)
url := fmt.Sprintf("/cluster/ha/resources/%d", vmr.vmId)
resp, err := c.session.Put(url, nil, nil, &reqbody)
if err == nil {
taskResponse, err := ResponseJSON(resp)
if err != nil {
return nil, err
}
exitStatus, err = c.WaitForCompletion(taskResponse)
}
return
}

View File

@ -23,15 +23,19 @@ type (
// ConfigQemu - Proxmox API QEMU options
type ConfigQemu struct {
VmID int `json:"vmid"`
Name string `json:"name"`
Description string `json:"desc"`
Pool string `json:"pool,omitempty"`
Bios string `json:"bios"`
Onboot bool `json:"onboot"`
Agent int `json:"agent"`
Memory int `json:"memory"`
Balloon int `json:"balloon"`
QemuOs string `json:"os"`
QemuCores int `json:"cores"`
QemuSockets int `json:"sockets"`
QemuVcpus int `json:"vcpus"`
QemuCpu string `json:"cpu"`
QemuNuma bool `json:"numa"`
Hotplug string `json:"hotplug"`
@ -41,8 +45,10 @@ type ConfigQemu struct {
BootDisk string `json:"bootdisk,omitempty"`
Scsihw string `json:"scsihw,omitempty"`
QemuDisks QemuDevices `json:"disk"`
QemuVga QemuDevice `json:"vga,omitempty"`
QemuNetworks QemuDevices `json:"network"`
QemuSerials QemuDevices `json:"serial,omitempty"`
HaState string `json:"hastate,omitempty"`
// Deprecated single disk.
DiskSize float64 `json:"diskGB"`
@ -93,6 +99,19 @@ func (config ConfigQemu) CreateVm(vmr *VmRef, client *Client) (err error) {
"boot": config.Boot,
"description": config.Description,
}
if config.Bios != "" {
params["bios"] = config.Bios
}
if config.Balloon >= 1 {
params["balloon"] = config.Balloon
}
if config.QemuVcpus >= 1 {
params["vcpus"] = config.QemuVcpus
}
if vmr.pool != "" {
params["pool"] = vmr.pool
}
@ -108,6 +127,13 @@ func (config ConfigQemu) CreateVm(vmr *VmRef, client *Client) (err error) {
// Create disks config.
config.CreateQemuDisksParams(vmr.vmId, params, false)
// Create vga config.
vgaParam := QemuDeviceParam{}
vgaParam = vgaParam.createDeviceParam(config.QemuVga, nil)
if len(vgaParam) > 0 {
params["vga"] = strings.Join(vgaParam, ",")
}
// Create networks config.
config.CreateQemuNetworksParams(vmr.vmId, params)
@ -118,6 +144,9 @@ func (config ConfigQemu) CreateVm(vmr *VmRef, client *Client) (err error) {
if err != nil {
return fmt.Errorf("Error creating VM: %v, error status: %s (params: %v)", err, exitStatus, params)
}
client.UpdateVMHA(vmr, config.HaState)
return
}
@ -175,6 +204,7 @@ func (config ConfigQemu) CloneVm(sourceVmr *VmRef, vmr *VmRef, client *Client) (
if err != nil {
return
}
return config.UpdateConfig(vmr, client)
}
@ -193,6 +223,25 @@ func (config ConfigQemu) UpdateConfig(vmr *VmRef, client *Client) (err error) {
"boot": config.Boot,
}
//Array to list deleted parameters
deleteParams := []string{}
if config.Bios != "" {
configParams["bios"] = config.Bios
}
if config.Balloon >= 1 {
configParams["balloon"] = config.Balloon
} else {
deleteParams = append(deleteParams, "balloon")
}
if config.QemuVcpus >= 1 {
configParams["vcpus"] = config.QemuVcpus
} else {
deleteParams = append(deleteParams, "vcpus")
}
if config.BootDisk != "" {
configParams["bootdisk"] = config.BootDisk
}
@ -202,11 +251,31 @@ func (config ConfigQemu) UpdateConfig(vmr *VmRef, client *Client) (err error) {
}
// Create disks config.
config.CreateQemuDisksParams(vmr.vmId, configParams, true)
configParamsDisk := map[string]interface{} {
"vmid": vmr.vmId,
}
config.CreateQemuDisksParams(vmr.vmId, configParamsDisk, false)
client.createVMDisks(vmr.node, configParamsDisk)
//Copy the disks to the global configParams
for key, value := range configParamsDisk {
//vmid is only required in createVMDisks
if key != "vmid" {
configParams[key] = value
}
}
// Create networks config.
config.CreateQemuNetworksParams(vmr.vmId, configParams)
// Create vga config.
vgaParam := QemuDeviceParam{}
vgaParam = vgaParam.createDeviceParam(config.QemuVga, nil)
if len(vgaParam) > 0 {
configParams["vga"] = strings.Join(vgaParam, ",")
} else {
deleteParams = append(deleteParams, "vga")
}
// Create serial interfaces
config.CreateQemuSerialsParams(vmr.vmId, configParams)
@ -242,12 +311,19 @@ func (config ConfigQemu) UpdateConfig(vmr *VmRef, client *Client) (err error) {
if config.Ipconfig2 != "" {
configParams["ipconfig2"] = config.Ipconfig2
}
if len(deleteParams) > 0 {
configParams["delete"] = strings.Join(deleteParams, ", ")
}
_, err = client.SetVmConfig(vmr, configParams)
if err != nil {
log.Fatal(err)
log.Print(err)
return err
}
client.UpdateVMHA(vmr, config.HaState)
_, err = client.UpdateVMPool(vmr, config.Pool)
return err
@ -312,6 +388,10 @@ func NewConfigQemuFromApi(vmr *VmRef, client *Client) (config *ConfigQemu, err e
if _, isSet := vmConfig["description"]; isSet {
description = vmConfig["description"].(string)
}
bios := "seabios"
if _, isSet := vmConfig["bios"]; isSet {
bios = vmConfig["bios"].(string)
}
onboot := true
if _, isSet := vmConfig["onboot"]; isSet {
onboot = Itob(int(vmConfig["onboot"].(float64)))
@ -335,10 +415,18 @@ func NewConfigQemuFromApi(vmr *VmRef, client *Client) (config *ConfigQemu, err e
if _, isSet := vmConfig["memory"]; isSet {
memory = vmConfig["memory"].(float64)
}
balloon := 0.0
if _, isSet := vmConfig["balloon"]; isSet {
balloon = vmConfig["balloon"].(float64)
}
cores := 1.0
if _, isSet := vmConfig["cores"]; isSet {
cores = vmConfig["cores"].(float64)
}
vcpus := 0.0
if _, isSet := vmConfig["vcpus"]; isSet {
vcpus = vmConfig["vcpus"].(float64)
}
sockets := 1.0
if _, isSet := vmConfig["sockets"]; isSet {
sockets = vmConfig["sockets"].(float64)
@ -369,9 +457,15 @@ func NewConfigQemuFromApi(vmr *VmRef, client *Client) (config *ConfigQemu, err e
if _, isSet := vmConfig["scsihw"]; isSet {
scsihw = vmConfig["scsihw"].(string)
}
hastate := ""
if _, isSet := vmConfig["hastate"]; isSet {
hastate = vmConfig["hastate"].(string)
}
config = &ConfigQemu{
Name: name,
Description: strings.TrimSpace(description),
Bios: bios,
Onboot: onboot,
Agent: agent,
QemuOs: ostype,
@ -385,10 +479,19 @@ func NewConfigQemuFromApi(vmr *VmRef, client *Client) (config *ConfigQemu, err e
Boot: boot,
BootDisk: bootdisk,
Scsihw: scsihw,
HaState: hastate,
QemuDisks: QemuDevices{},
QemuVga: QemuDevice{},
QemuNetworks: QemuDevices{},
QemuSerials: QemuDevices{},
}
if balloon >= 1 {
config.Balloon = int(balloon);
}
if vcpus >= 1 {
config.QemuVcpus = int(vcpus);
}
if vmConfig["ide2"] != nil {
isoMatch := rxIso.FindStringSubmatch(vmConfig["ide2"].(string))
@ -459,6 +562,16 @@ func NewConfigQemuFromApi(vmr *VmRef, client *Client) (config *ConfigQemu, err e
}
}
//Display
if vga, isSet := vmConfig["vga"]; isSet {
vgaList := strings.Split(vga.(string), ",")
vgaMap := QemuDevice{}
vgaMap.readDeviceConfig(vgaList)
if len(vgaMap) > 0 {
config.QemuVga = vgaMap
}
}
// Add networks.
nicNames := []string{}
@ -776,9 +889,9 @@ func (c ConfigQemu) CreateQemuDisksParams(
// Disk name.
var diskFile string
// Currently ZFS local, LVM, Ceph RBD, and Directory are considered.
// Currently ZFS local, LVM, Ceph RBD, CephFS and Directory are considered.
// Other formats are not verified, but could be added if they're needed.
rxStorageTypes := `(zfspool|lvm|rbd)`
rxStorageTypes := `(zfspool|lvm|rbd|cephfs)`
storageType := diskConfMap["storage_type"].(string)
if matched, _ := regexp.MatchString(rxStorageTypes, storageType); matched {
diskFile = fmt.Sprintf("file=%v:vm-%v-disk-%v", diskConfMap["storage"], vmID, diskID)
@ -865,3 +978,30 @@ func (c ConfigQemu) CreateQemuSerialsParams(
return nil
}
// NextId - Get next free VMID
func (c *Client) NextId() (id int, err error) {
var data map[string]interface{}
_, err = c.session.GetJSON("/cluster/nextid", nil, nil, &data)
if err != nil {
return -1, err
}
if data["data"] == nil || data["errors"] != nil {
return -1, fmt.Errorf(data["errors"].(string))
}
i, err := strconv.Atoi(data["data"].(string))
if err != nil {
return -1, err
}
return i, nil
}
// VMIdExists - If you pass an VMID that exists it will raise an error otherwise it will return the vmID
func (c *Client) VMIdExists(vmID int) (id int, err error) {
_, err = c.session.Get(fmt.Sprintf("/cluster/nextid?vmid=%d", vmID), nil, nil)
if err != nil {
return -1, err
}
return vmID, nil
}

2
vendor/modules.txt vendored
View File

@ -63,7 +63,7 @@ github.com/NaverCloudPlatform/ncloud-sdk-go/sdk
github.com/PuerkitoBio/goquery
# github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d
github.com/StackExchange/wmi
# github.com/Telmate/proxmox-api-go v0.0.0-20191015171801-b0c2796b9fcf
# github.com/Telmate/proxmox-api-go v0.0.0-20200116224409-320525bf3340
github.com/Telmate/proxmox-api-go/proxmox
# github.com/agext/levenshtein v1.2.1
github.com/agext/levenshtein