diff --git a/go.mod b/go.mod index 5ad27e675..a3aec0f38 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,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-20190815172943-ef9222844e60 + github.com/Telmate/proxmox-api-go v0.0.0-20191015171801-b0c2796b9fcf 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 diff --git a/go.sum b/go.sum index 7876cc4ab..009210c9a 100644 --- a/go.sum +++ b/go.sum @@ -29,6 +29,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-20190815172943-ef9222844e60 h1:iEmbIRk4brAP3wevhCr5MGAqxHUbbIDHvE+6D1/7pRA= github.com/Telmate/proxmox-api-go v0.0.0-20190815172943-ef9222844e60/go.mod h1:OGWyIMJ87/k/GCz8CGiWB2HOXsOVDM6Lpe/nFPkC4IQ= +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/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= diff --git a/vendor/github.com/Telmate/proxmox-api-go/proxmox/client.go b/vendor/github.com/Telmate/proxmox-api-go/proxmox/client.go index d8acfa33f..6afc03942 100644 --- a/vendor/github.com/Telmate/proxmox-api-go/proxmox/client.go +++ b/vendor/github.com/Telmate/proxmox-api-go/proxmox/client.go @@ -3,12 +3,14 @@ package proxmox // inspired by https://github.com/Telmate/vagrant-proxmox/blob/master/lib/vagrant-proxmox/proxmox/connection.rb import ( + "bytes" "crypto/tls" "encoding/json" "errors" "fmt" "io" "io/ioutil" + "mime/multipart" "net" "net/http" "regexp" @@ -57,7 +59,7 @@ func (vmr *VmRef) SetVmType(vmType string) { return } -func (vmr *VmRef) GetVmType() (string) { +func (vmr *VmRef) GetVmType() string { return vmr.vmType } @@ -90,7 +92,7 @@ func NewClient(apiUrl string, hclient *http.Client, tls *tls.Config) (client *Cl func (c *Client) Login(username string, password string, otp string) (err error) { c.Username = username c.Password = password - c.Otp = otp + c.Otp = otp return c.session.Login(username, password, otp) } @@ -135,6 +137,10 @@ func (c *Client) GetVmInfo(vmr *VmRef) (vmInfo map[string]interface{}, err error vmInfo = vm vmr.node = vmInfo["node"].(string) vmr.vmType = vmInfo["type"].(string) + vmr.pool = "" + if vmInfo["pool"] != nil { + vmr.pool = vmInfo["pool"].(string) + } return } } @@ -150,6 +156,10 @@ func (c *Client) GetVmRefByName(vmName string) (vmr *VmRef, err error) { vmr = NewVmRef(int(vm["vmid"].(float64))) vmr.node = vm["node"].(string) vmr.vmType = vm["type"].(string) + vmr.pool = "" + if vm["pool"] != nil { + vmr.pool = vm["pool"].(string) + } return } } @@ -667,6 +677,50 @@ func (c *Client) DeleteVMDisks( return nil } +func (c *Client) Upload(node string, storage string, contentType string, filename string, file io.Reader) error { + body, mimetype, err := createUploadBody(contentType, filename, file) + if err != nil { + return err + } + + url := fmt.Sprintf("%s/nodes/%s/storage/%s/upload", c.session.ApiUrl, node, storage) + req, err := c.session.NewRequest(http.MethodPost, url, nil, body) + if err != nil { + return err + } + req.Header.Add("Content-Type", mimetype) + req.Header.Add("Accept", "application/json") + + _, err = c.session.Do(req) + return err +} + +func createUploadBody(contentType string, filename string, r io.Reader) (io.Reader, string, error) { + var buf bytes.Buffer + w := multipart.NewWriter(&buf) + + err := w.WriteField("content", contentType) + if err != nil { + return nil, "", err + } + + fw, err := w.CreateFormFile("filename", filename) + if err != nil { + return nil, "", err + } + _, err = io.Copy(fw, r) + if err != nil { + return nil, "", err + } + + err = w.Close() + if err != nil { + return nil, "", err + } + + return &buf, w.FormDataContentType(), nil +} + // getStorageAndVolumeName - Extract disk storage and disk volume, since disk name is saved // in Proxmox with its storage. func getStorageAndVolumeName( @@ -685,3 +739,51 @@ func getStorageAndVolumeName( return storageName, volumeName } + +func (c *Client) UpdateVMPool(vmr *VmRef, pool string) (exitStatus interface{}, err error) { + // Same pool + if vmr.pool == pool { + return + } + + // Remove from old pool + if vmr.pool != "" { + paramMap := map[string]interface{}{ + "vms": vmr.vmId, + "delete": 1, + } + reqbody := ParamsToBody(paramMap) + url := fmt.Sprintf("/pools/%s", vmr.pool) + 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) + + if err != nil { + return nil, err + } + } + } + // Add to the new pool + if pool != "" { + paramMap := map[string]interface{}{ + "vms": vmr.vmId, + } + reqbody := ParamsToBody(paramMap) + url := fmt.Sprintf("/pools/%s", pool) + 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) + } else { + return nil, err + } + } + return +} diff --git a/vendor/github.com/Telmate/proxmox-api-go/proxmox/config_lxc.go b/vendor/github.com/Telmate/proxmox-api-go/proxmox/config_lxc.go index 58393f0e3..e0138690e 100644 --- a/vendor/github.com/Telmate/proxmox-api-go/proxmox/config_lxc.go +++ b/vendor/github.com/Telmate/proxmox-api-go/proxmox/config_lxc.go @@ -5,66 +5,66 @@ import ( "fmt" "io" "log" - "strings" "strconv" + "strings" ) // LXC options for the Proxmox API type configLxc struct { - Ostemplate string `json:"ostemplate"` - Arch string `json:"arch"` - BWLimit int `json:"bwlimit,omitempty"` - CMode string `json:"cmode"` - Console bool `json:"console"` - Cores int `json:"cores,omitempty"` - CPULimit int `json:"cpulimit"` - CPUUnits int `json:"cpuunits"` - Description string `json:"description,omitempty"` - Features QemuDevice `json:"features,omitempty"` - Force bool `json:"force,omitempty"` - Hookscript string `json:"hookscript,omitempty"` - Hostname string `json:"hostname,omitempty"` - IgnoreUnpackErrors bool `json:"ignore-unpack-errors,omitempty"` - Lock string `json:"lock,omitempty"` - Memory int `json:"memory"` - Mountpoints QemuDevices `json:"mountpoints,omitempty"` - Nameserver string `json:"nameserver,omitempty"` - Networks QemuDevices `json:"networks,omitempty"` - OnBoot bool `json:"onboot"` - OsType string `json:"ostype,omitempty"` - Password string `json:"password,omitempty"` - Pool string `json:"pool,omitempty"` - Protection bool `json:"protection"` - Restore bool `json:"restore,omitempty"` - RootFs string `json:"rootfs,omitempty"` - SearchDomain string `json:"searchdomain,omitempty"` - SSHPublicKeys string `json:"ssh-public-keys,omitempty"` - Start bool `json:"start"` - Startup string `json:"startup,omitempty"` - Storage string `json:"storage"` - Swap int `json:"swap"` - Template bool `json:"template,omitempty"` - Tty int `json:"tty"` - Unique bool `json:"unique,omitempty"` - Unprivileged bool `json:"unprivileged"` - Unused []string `json:"unused,omitempty"` + Ostemplate string `json:"ostemplate"` + Arch string `json:"arch"` + BWLimit int `json:"bwlimit,omitempty"` + CMode string `json:"cmode"` + Console bool `json:"console"` + Cores int `json:"cores,omitempty"` + CPULimit int `json:"cpulimit"` + CPUUnits int `json:"cpuunits"` + Description string `json:"description,omitempty"` + Features QemuDevice `json:"features,omitempty"` + Force bool `json:"force,omitempty"` + Hookscript string `json:"hookscript,omitempty"` + Hostname string `json:"hostname,omitempty"` + IgnoreUnpackErrors bool `json:"ignore-unpack-errors,omitempty"` + Lock string `json:"lock,omitempty"` + Memory int `json:"memory"` + Mountpoints QemuDevices `json:"mountpoints,omitempty"` + Nameserver string `json:"nameserver,omitempty"` + Networks QemuDevices `json:"networks,omitempty"` + OnBoot bool `json:"onboot"` + OsType string `json:"ostype,omitempty"` + Password string `json:"password,omitempty"` + Pool string `json:"pool,omitempty"` + Protection bool `json:"protection"` + Restore bool `json:"restore,omitempty"` + RootFs string `json:"rootfs,omitempty"` + SearchDomain string `json:"searchdomain,omitempty"` + SSHPublicKeys string `json:"ssh-public-keys,omitempty"` + Start bool `json:"start"` + Startup string `json:"startup,omitempty"` + Storage string `json:"storage"` + Swap int `json:"swap"` + Template bool `json:"template,omitempty"` + Tty int `json:"tty"` + Unique bool `json:"unique,omitempty"` + Unprivileged bool `json:"unprivileged"` + Unused []string `json:"unused,omitempty"` } -func NewConfigLxc() (configLxc) { +func NewConfigLxc() configLxc { return configLxc{ - Arch: "amd64", - CMode: "tty", - Console: true, - CPULimit: 0, - CPUUnits: 1024, - Memory: 512, - OnBoot: false, - Protection: false, - Start: false, - Storage: "local", - Swap: 512, - Template: false, - Tty: 2, + Arch: "amd64", + CMode: "tty", + Console: true, + CPULimit: 0, + CPUUnits: 1024, + Memory: 512, + OnBoot: false, + Protection: false, + Start: false, + Storage: "local", + Swap: 512, + Template: false, + Tty: 2, Unprivileged: false, } } @@ -162,7 +162,7 @@ func NewConfigLxcFromApi(vmr *VmRef, client *Client) (config *configLxc, err err mpNames := []string{} for k, _ := range lxcConfig { - if mpName:= rxMpName.FindStringSubmatch(k); len(mpName) > 0 { + if mpName := rxMpName.FindStringSubmatch(k); len(mpName) > 0 { mpNames = append(mpNames, mpName[0]) } } @@ -175,7 +175,7 @@ func NewConfigLxcFromApi(vmr *VmRef, client *Client) (config *configLxc, err err mpID, _ := strconv.Atoi(id[0]) // add mp id mpConfMap := QemuDevice{ - "id": mpID, + "id": mpID, } // add rest of device config mpConfMap.readDeviceConfig(mpConfList) @@ -211,7 +211,7 @@ func NewConfigLxcFromApi(vmr *VmRef, client *Client) (config *configLxc, err err nicID, _ := strconv.Atoi(id[0]) // add nic id nicConfMap := QemuDevice{ - "id": nicID, + "id": nicID, } // add rest of device config nicConfMap.readDeviceConfig(nicConfList) diff --git a/vendor/github.com/Telmate/proxmox-api-go/proxmox/config_qemu.go b/vendor/github.com/Telmate/proxmox-api-go/proxmox/config_qemu.go index eaffb1801..db7b40ccc 100644 --- a/vendor/github.com/Telmate/proxmox-api-go/proxmox/config_qemu.go +++ b/vendor/github.com/Telmate/proxmox-api-go/proxmox/config_qemu.go @@ -25,6 +25,7 @@ type ( type ConfigQemu struct { Name string `json:"name"` Description string `json:"desc"` + Pool string `json:"pool,omitempty"` Onboot bool `json:"onboot"` Agent int `json:"agent"` Memory int `json:"memory"` @@ -63,9 +64,10 @@ type ConfigQemu struct { Nameserver string `json:"nameserver"` Sshkeys string `json:"sshkeys"` - // arrays are hard, support 2 interfaces for now + // arrays are hard, support 3 interfaces for now Ipconfig0 string `json:"ipconfig0"` Ipconfig1 string `json:"ipconfig1"` + Ipconfig2 string `json:"ipconfig2"` } // CreateVm - Tell Proxmox API to make the VM @@ -156,16 +158,19 @@ func (config ConfigQemu) CloneVm(sourceVmr *VmRef, vmr *VmRef, client *Client) ( storage = disk0Storage } params := map[string]interface{}{ - "newid": vmr.vmId, - "target": vmr.node, - "name": config.Name, - "storage": storage, - "full": fullclone, + "newid": vmr.vmId, + "target": vmr.node, + "name": config.Name, + "full": fullclone, } if vmr.pool != "" { params["pool"] = vmr.pool } + if fullclone == "1" { + params["storage"] = storage + } + _, err = client.CloneQemuVm(sourceVmr, params) if err != nil { return @@ -234,7 +239,17 @@ func (config ConfigQemu) UpdateConfig(vmr *VmRef, client *Client) (err error) { if config.Ipconfig1 != "" { configParams["ipconfig1"] = config.Ipconfig1 } + if config.Ipconfig2 != "" { + configParams["ipconfig2"] = config.Ipconfig2 + } _, err = client.SetVmConfig(vmr, configParams) + if err != nil { + log.Fatal(err) + return err + } + + _, err = client.UpdateVMPool(vmr, config.Pool) + return err } @@ -404,6 +419,9 @@ func NewConfigQemuFromApi(vmr *VmRef, client *Client) (config *ConfigQemu, err e if _, isSet := vmConfig["ipconfig1"]; isSet { config.Ipconfig1 = vmConfig["ipconfig1"].(string) } + if _, isSet := vmConfig["ipconfig2"]; isSet { + config.Ipconfig2 = vmConfig["ipconfig2"].(string) + } // Add disks. diskNames := []string{} diff --git a/vendor/github.com/Telmate/proxmox-api-go/proxmox/session.go b/vendor/github.com/Telmate/proxmox-api-go/proxmox/session.go index 759d20e75..95da7d615 100644 --- a/vendor/github.com/Telmate/proxmox-api-go/proxmox/session.go +++ b/vendor/github.com/Telmate/proxmox-api-go/proxmox/session.go @@ -163,7 +163,7 @@ func (s *Session) Do(req *http.Request) (*http.Response, error) { if *Debug { d, _ := httputil.DumpRequestOut(req, true) - log.Printf(">>>>>>>>>> REQUEST:\n", string(d)) + log.Printf(">>>>>>>>>> REQUEST:\n%v", string(d)) } resp, err := s.httpClient.Do(req) @@ -174,7 +174,7 @@ func (s *Session) Do(req *http.Request) (*http.Response, error) { if *Debug { dr, _ := httputil.DumpResponse(resp, true) - log.Printf("<<<<<<<<<< RESULT:\n", string(dr)) + log.Printf("<<<<<<<<<< RESULT:\n%v", string(dr)) } if resp.StatusCode < 200 || resp.StatusCode > 299 { diff --git a/vendor/modules.txt b/vendor/modules.txt index 07ae109fe..ab0765451 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -59,7 +59,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-20190815172943-ef9222844e60 +# github.com/Telmate/proxmox-api-go v0.0.0-20191015171801-b0c2796b9fcf github.com/Telmate/proxmox-api-go/proxmox # github.com/agext/levenshtein v1.2.1 github.com/agext/levenshtein