Bump proxmox-api-go dependency
This commit is contained in:
parent
058fa2116d
commit
8c2c1a82cb
|
@ -46,7 +46,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
|
|||
return nil, err
|
||||
}
|
||||
|
||||
err = b.proxmoxClient.Login(b.config.Username, b.config.Password)
|
||||
err = b.proxmoxClient.Login(b.config.Username, b.config.Password, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -30,6 +30,8 @@ func (s *stepStartVM) Run(ctx context.Context, state multistep.StateBag) multist
|
|||
config := proxmox.ConfigQemu{
|
||||
Name: c.VMName,
|
||||
Agent: agent,
|
||||
Boot: "cdn", // Boot priority, c:CDROM -> d:Disk -> n:Network
|
||||
QemuCpu: "host",
|
||||
Description: "Packer ephemeral build VM",
|
||||
Memory: c.Memory,
|
||||
QemuCores: c.Cores,
|
||||
|
@ -142,7 +144,7 @@ func (s *stepStartVM) Cleanup(state multistep.StateBag) {
|
|||
ui.Say("Stopping VM")
|
||||
_, err := client.StopVm(vmRef)
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Error stop VM. Please stop and delete it manually: %s", err))
|
||||
ui.Error(fmt.Sprintf("Error stopping VM. Please stop and delete it manually: %s", err))
|
||||
return
|
||||
}
|
||||
|
||||
|
|
2
go.mod
2
go.mod
|
@ -8,7 +8,7 @@ require (
|
|||
github.com/Azure/go-ntlmssp v0.0.0-20180810175552-4a21cbd618b4 // indirect
|
||||
github.com/ChrisTrenkamp/goxpath v0.0.0-20170625215350-4fe035839290
|
||||
github.com/NaverCloudPlatform/ncloud-sdk-go v0.0.0-20180110055012-c2e73f942591
|
||||
github.com/Telmate/proxmox-api-go v0.0.0-20190614181158-26cd147831a4
|
||||
github.com/Telmate/proxmox-api-go v0.0.0-20190815172943-ef9222844e60
|
||||
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
|
||||
|
|
2
go.sum
2
go.sum
|
@ -25,6 +25,8 @@ github.com/NaverCloudPlatform/ncloud-sdk-go v0.0.0-20180110055012-c2e73f942591 h
|
|||
github.com/NaverCloudPlatform/ncloud-sdk-go v0.0.0-20180110055012-c2e73f942591/go.mod h1:EHGzQGbwozJBj/4qj3WGrTJ0FqjgOTOxLQ0VNWvPn08=
|
||||
github.com/Telmate/proxmox-api-go v0.0.0-20190614181158-26cd147831a4 h1:o//09WenT9BNcQypCYfOBfRe5gtLUvUfTPq0xQqPMEI=
|
||||
github.com/Telmate/proxmox-api-go v0.0.0-20190614181158-26cd147831a4/go.mod h1:OGWyIMJ87/k/GCz8CGiWB2HOXsOVDM6Lpe/nFPkC4IQ=
|
||||
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/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/aliyun/alibaba-cloud-sdk-go v0.0.0-20190418113227-25233c783f4e h1:/8wOj52pewmIX/8d5eVO3t7Rr3astkBI/ruyg4WNqRo=
|
||||
|
|
|
@ -31,6 +31,7 @@ type Client struct {
|
|||
ApiUrl string
|
||||
Username string
|
||||
Password string
|
||||
Otp string
|
||||
}
|
||||
|
||||
// VmRef - virtual machine ref parts
|
||||
|
@ -38,6 +39,7 @@ type Client struct {
|
|||
type VmRef struct {
|
||||
vmId int
|
||||
node string
|
||||
pool string
|
||||
vmType string
|
||||
}
|
||||
|
||||
|
@ -46,11 +48,19 @@ func (vmr *VmRef) SetNode(node string) {
|
|||
return
|
||||
}
|
||||
|
||||
func (vmr *VmRef) SetPool(pool string) {
|
||||
vmr.pool = pool
|
||||
}
|
||||
|
||||
func (vmr *VmRef) SetVmType(vmType string) {
|
||||
vmr.vmType = vmType
|
||||
return
|
||||
}
|
||||
|
||||
func (vmr *VmRef) GetVmType() (string) {
|
||||
return vmr.vmType
|
||||
}
|
||||
|
||||
func (vmr *VmRef) VmId() int {
|
||||
return vmr.vmId
|
||||
}
|
||||
|
@ -59,6 +69,10 @@ func (vmr *VmRef) Node() string {
|
|||
return vmr.node
|
||||
}
|
||||
|
||||
func (vmr *VmRef) Pool() string {
|
||||
return vmr.pool
|
||||
}
|
||||
|
||||
func NewVmRef(vmId int) (vmr *VmRef) {
|
||||
vmr = &VmRef{vmId: vmId, node: "", vmType: ""}
|
||||
return
|
||||
|
@ -73,10 +87,11 @@ func NewClient(apiUrl string, hclient *http.Client, tls *tls.Config) (client *Cl
|
|||
return client, err
|
||||
}
|
||||
|
||||
func (c *Client) Login(username string, password string) (err error) {
|
||||
func (c *Client) Login(username string, password string, otp string) (err error) {
|
||||
c.Username = username
|
||||
c.Password = password
|
||||
return c.session.Login(username, password)
|
||||
c.Otp = otp
|
||||
return c.session.Login(username, password, otp)
|
||||
}
|
||||
|
||||
func (c *Client) GetJsonRetryable(url string, data *map[string]interface{}, tries int) error {
|
||||
|
@ -275,10 +290,26 @@ func (c *Client) MonitorCmd(vmr *VmRef, command string) (monitorRes map[string]i
|
|||
reqbody := ParamsToBody(map[string]interface{}{"command": command})
|
||||
url := fmt.Sprintf("/nodes/%s/%s/%d/monitor", vmr.node, vmr.vmType, vmr.vmId)
|
||||
resp, err := c.session.Post(url, nil, nil, &reqbody)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
monitorRes, err = ResponseJSON(resp)
|
||||
return
|
||||
}
|
||||
|
||||
func (c *Client) Sendkey(vmr *VmRef, qmKey string) error {
|
||||
err := c.CheckVmRef(vmr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
reqbody := ParamsToBody(map[string]interface{}{"key": qmKey})
|
||||
url := fmt.Sprintf("/nodes/%s/%s/%d/sendkey", vmr.node, vmr.vmType, vmr.vmId)
|
||||
// No return, even for errors: https://bugzilla.proxmox.com/show_bug.cgi?id=2275
|
||||
_, err = c.session.Put(url, nil, nil, &reqbody)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// WaitForCompletion - poll the API for task completion
|
||||
func (c *Client) WaitForCompletion(taskResponse map[string]interface{}) (waitExitStatus string, err error) {
|
||||
if taskResponse["errors"] != nil {
|
||||
|
@ -416,6 +447,29 @@ func (c *Client) CreateQemuVm(node string, vmParams map[string]interface{}) (exi
|
|||
return
|
||||
}
|
||||
|
||||
func (c *Client) CreateLxcContainer(node string, vmParams map[string]interface{}) (exitStatus string, err error) {
|
||||
reqbody := ParamsToBody(vmParams)
|
||||
url := fmt.Sprintf("/nodes/%s/lxc", node)
|
||||
var resp *http.Response
|
||||
resp, err = c.session.Post(url, nil, nil, &reqbody)
|
||||
defer resp.Body.Close()
|
||||
if err != nil {
|
||||
// This might not work if we never got a body. We'll ignore errors in trying to read,
|
||||
// but extract the body if possible to give any error information back in the exitStatus
|
||||
b, _ := ioutil.ReadAll(resp.Body)
|
||||
exitStatus = string(b)
|
||||
return exitStatus, err
|
||||
}
|
||||
|
||||
taskResponse, err := ResponseJSON(resp)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
exitStatus, err = c.WaitForCompletion(taskResponse)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (c *Client) CloneQemuVm(vmr *VmRef, vmParams map[string]interface{}) (exitStatus string, err error) {
|
||||
reqbody := ParamsToBody(vmParams)
|
||||
url := fmt.Sprintf("/nodes/%s/qemu/%d/clone", vmr.node, vmr.vmId)
|
||||
|
@ -457,6 +511,21 @@ func (c *Client) SetVmConfig(vmr *VmRef, vmParams map[string]interface{}) (exitS
|
|||
return
|
||||
}
|
||||
|
||||
// SetLxcConfig - send config options
|
||||
func (c *Client) SetLxcConfig(vmr *VmRef, vmParams map[string]interface{}) (exitStatus interface{}, err error) {
|
||||
reqbody := ParamsToBody(vmParams)
|
||||
url := fmt.Sprintf("/nodes/%s/%s/%d/config", vmr.node, vmr.vmType, 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
|
||||
}
|
||||
|
||||
func (c *Client) ResizeQemuDisk(vmr *VmRef, disk string, moreSizeGB int) (exitStatus interface{}, err error) {
|
||||
// PUT
|
||||
//disk:virtio0
|
||||
|
@ -478,6 +547,23 @@ func (c *Client) ResizeQemuDisk(vmr *VmRef, disk string, moreSizeGB int) (exitSt
|
|||
return
|
||||
}
|
||||
|
||||
func (c *Client) MoveQemuDisk(vmr *VmRef, disk string, storage string) (exitStatus interface{}, err error) {
|
||||
if disk == "" {
|
||||
disk = "virtio0"
|
||||
}
|
||||
reqbody := ParamsToBody(map[string]interface{}{"disk": disk, "storage": storage, "delete": true})
|
||||
url := fmt.Sprintf("/nodes/%s/%s/%d/move_disk", 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
|
||||
}
|
||||
|
||||
// GetNextID - Get next free VMID
|
||||
func (c *Client) GetNextID(currentID int) (nextID int, err error) {
|
||||
var data map[string]interface{}
|
||||
|
|
|
@ -0,0 +1,433 @@
|
|||
package proxmox
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"strings"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// 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"`
|
||||
}
|
||||
|
||||
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,
|
||||
Unprivileged: false,
|
||||
}
|
||||
}
|
||||
|
||||
func NewConfigLxcFromJson(io io.Reader) (config configLxc, err error) {
|
||||
config = NewConfigLxc()
|
||||
err = json.NewDecoder(io).Decode(config)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
return config, err
|
||||
}
|
||||
log.Println(config)
|
||||
return
|
||||
}
|
||||
|
||||
func NewConfigLxcFromApi(vmr *VmRef, client *Client) (config *configLxc, err error) {
|
||||
// prepare json map to receive the information from the api
|
||||
var lxcConfig map[string]interface{}
|
||||
lxcConfig, err = client.GetVmConfig(vmr)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// prepare a new lxc config to store and return\
|
||||
// the information from api
|
||||
newConfig := NewConfigLxc()
|
||||
config = &newConfig
|
||||
|
||||
arch := ""
|
||||
if _, isSet := lxcConfig["arch"]; isSet {
|
||||
arch = lxcConfig["arch"].(string)
|
||||
}
|
||||
cmode := ""
|
||||
if _, isSet := lxcConfig["cmode"]; isSet {
|
||||
cmode = lxcConfig["cmode"].(string)
|
||||
}
|
||||
console := true
|
||||
if _, isSet := lxcConfig["console"]; isSet {
|
||||
console = Itob(int(lxcConfig["console"].(float64)))
|
||||
}
|
||||
cores := 1
|
||||
if _, isSet := lxcConfig["cores"]; isSet {
|
||||
cores = int(lxcConfig["cores"].(float64))
|
||||
}
|
||||
cpulimit := 0
|
||||
if _, isSet := lxcConfig["cpulimit"]; isSet {
|
||||
cpulimit, _ = strconv.Atoi(lxcConfig["cpulimit"].(string))
|
||||
}
|
||||
cpuunits := 1024
|
||||
if _, isSet := lxcConfig["cpuunits"]; isSet {
|
||||
cpuunits = int(lxcConfig["cpuunits"].(float64))
|
||||
}
|
||||
description := ""
|
||||
if _, isSet := lxcConfig["description"]; isSet {
|
||||
description = lxcConfig["description"].(string)
|
||||
}
|
||||
|
||||
// add features, if any
|
||||
if features, isSet := lxcConfig["features"]; isSet {
|
||||
featureList := strings.Split(features.(string), ",")
|
||||
|
||||
// create new device map to store features
|
||||
featureMap := QemuDevice{}
|
||||
// add all features to device map
|
||||
featureMap.readDeviceConfig(featureList)
|
||||
// prepare empty feature map
|
||||
if config.Features == nil {
|
||||
config.Features = QemuDevice{}
|
||||
}
|
||||
// and device config to networks
|
||||
if len(featureMap) > 0 {
|
||||
config.Features = featureMap
|
||||
}
|
||||
}
|
||||
|
||||
hookscript := ""
|
||||
if _, isSet := lxcConfig["hookscript"]; isSet {
|
||||
hookscript = lxcConfig["hookscript"].(string)
|
||||
}
|
||||
hostname := ""
|
||||
if _, isSet := lxcConfig["hostname"]; isSet {
|
||||
hostname = lxcConfig["hostname"].(string)
|
||||
}
|
||||
lock := ""
|
||||
if _, isSet := lxcConfig["lock"]; isSet {
|
||||
lock = lxcConfig["lock"].(string)
|
||||
}
|
||||
memory := 512
|
||||
if _, isSet := lxcConfig["memory"]; isSet {
|
||||
memory = int(lxcConfig["memory"].(float64))
|
||||
}
|
||||
|
||||
// add mountpoints
|
||||
mpNames := []string{}
|
||||
|
||||
for k, _ := range lxcConfig {
|
||||
if mpName:= rxMpName.FindStringSubmatch(k); len(mpName) > 0 {
|
||||
mpNames = append(mpNames, mpName[0])
|
||||
}
|
||||
}
|
||||
|
||||
for _, mpName := range mpNames {
|
||||
mpConfStr := lxcConfig[mpName]
|
||||
mpConfList := strings.Split(mpConfStr.(string), ",")
|
||||
|
||||
id := rxDeviceID.FindStringSubmatch(mpName)
|
||||
mpID, _ := strconv.Atoi(id[0])
|
||||
// add mp id
|
||||
mpConfMap := QemuDevice{
|
||||
"id": mpID,
|
||||
}
|
||||
// add rest of device config
|
||||
mpConfMap.readDeviceConfig(mpConfList)
|
||||
// prepare empty mountpoint map
|
||||
if config.Mountpoints == nil {
|
||||
config.Mountpoints = QemuDevices{}
|
||||
}
|
||||
// and device config to mountpoints
|
||||
if len(mpConfMap) > 0 {
|
||||
config.Mountpoints[mpID] = mpConfMap
|
||||
}
|
||||
}
|
||||
|
||||
nameserver := ""
|
||||
if _, isSet := lxcConfig["nameserver"]; isSet {
|
||||
nameserver = lxcConfig["nameserver"].(string)
|
||||
}
|
||||
|
||||
// add networks
|
||||
nicNames := []string{}
|
||||
|
||||
for k, _ := range lxcConfig {
|
||||
if nicName := rxNicName.FindStringSubmatch(k); len(nicName) > 0 {
|
||||
nicNames = append(nicNames, nicName[0])
|
||||
}
|
||||
}
|
||||
|
||||
for _, nicName := range nicNames {
|
||||
nicConfStr := lxcConfig[nicName]
|
||||
nicConfList := strings.Split(nicConfStr.(string), ",")
|
||||
|
||||
id := rxDeviceID.FindStringSubmatch(nicName)
|
||||
nicID, _ := strconv.Atoi(id[0])
|
||||
// add nic id
|
||||
nicConfMap := QemuDevice{
|
||||
"id": nicID,
|
||||
}
|
||||
// add rest of device config
|
||||
nicConfMap.readDeviceConfig(nicConfList)
|
||||
// prepare empty network map
|
||||
if config.Networks == nil {
|
||||
config.Networks = QemuDevices{}
|
||||
}
|
||||
// and device config to networks
|
||||
if len(nicConfMap) > 0 {
|
||||
config.Networks[nicID] = nicConfMap
|
||||
}
|
||||
}
|
||||
|
||||
onboot := false
|
||||
if _, isSet := lxcConfig["onboot"]; isSet {
|
||||
onboot = Itob(int(lxcConfig["onboot"].(float64)))
|
||||
}
|
||||
ostype := ""
|
||||
if _, isSet := lxcConfig["ostype"]; isSet {
|
||||
ostype = lxcConfig["ostype"].(string)
|
||||
}
|
||||
protection := false
|
||||
if _, isSet := lxcConfig["protection"]; isSet {
|
||||
protection = Itob(int(lxcConfig["protection"].(float64)))
|
||||
}
|
||||
rootfs := ""
|
||||
if _, isSet := lxcConfig["rootfs"]; isSet {
|
||||
rootfs = lxcConfig["rootfs"].(string)
|
||||
}
|
||||
searchdomain := ""
|
||||
if _, isSet := lxcConfig["searchdomain"]; isSet {
|
||||
searchdomain = lxcConfig["searchdomain"].(string)
|
||||
}
|
||||
startup := ""
|
||||
if _, isSet := lxcConfig["startup"]; isSet {
|
||||
startup = lxcConfig["startup"].(string)
|
||||
}
|
||||
swap := 512
|
||||
if _, isSet := lxcConfig["swap"]; isSet {
|
||||
swap = int(lxcConfig["swap"].(float64))
|
||||
}
|
||||
template := false
|
||||
if _, isSet := lxcConfig["template"]; isSet {
|
||||
template = Itob(int(lxcConfig["template"].(float64)))
|
||||
}
|
||||
tty := 2
|
||||
if _, isSet := lxcConfig["tty"]; isSet {
|
||||
tty = int(lxcConfig["tty"].(float64))
|
||||
}
|
||||
unprivileged := false
|
||||
if _, isset := lxcConfig["unprivileged"]; isset {
|
||||
unprivileged = Itob(int(lxcConfig["unprivileged"].(float64)))
|
||||
}
|
||||
var unused []string
|
||||
if _, isset := lxcConfig["unused"]; isset {
|
||||
unused = lxcConfig["unused"].([]string)
|
||||
}
|
||||
|
||||
config.Arch = arch
|
||||
config.CMode = cmode
|
||||
config.Console = console
|
||||
config.Cores = cores
|
||||
config.CPULimit = cpulimit
|
||||
config.CPUUnits = cpuunits
|
||||
config.Description = description
|
||||
config.OnBoot = onboot
|
||||
config.Hookscript = hookscript
|
||||
config.Hostname = hostname
|
||||
config.Lock = lock
|
||||
config.Memory = memory
|
||||
config.Nameserver = nameserver
|
||||
config.OnBoot = onboot
|
||||
config.OsType = ostype
|
||||
config.Protection = protection
|
||||
config.RootFs = rootfs
|
||||
config.SearchDomain = searchdomain
|
||||
config.Startup = startup
|
||||
config.Swap = swap
|
||||
config.Template = template
|
||||
config.Tty = tty
|
||||
config.Unprivileged = unprivileged
|
||||
config.Unused = unused
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// create LXC container using the Proxmox API
|
||||
func (config configLxc) CreateLxc(vmr *VmRef, client *Client) (err error) {
|
||||
vmr.SetVmType("lxc")
|
||||
|
||||
// convert config to map
|
||||
params, _ := json.Marshal(&config)
|
||||
var paramMap map[string]interface{}
|
||||
json.Unmarshal(params, ¶mMap)
|
||||
|
||||
// build list of features
|
||||
// add features as parameter list to lxc parameters
|
||||
// this overwrites the orginal formatting with a
|
||||
// comma separated list of "key=value" pairs
|
||||
featuresParam := QemuDeviceParam{}
|
||||
featuresParam = featuresParam.createDeviceParam(config.Features, nil)
|
||||
paramMap["features"] = strings.Join(featuresParam, ",")
|
||||
|
||||
// build list of mountpoints
|
||||
// this does the same as for the feature list
|
||||
// except that there can be multiple of these mountpoint sets
|
||||
// and each mountpoint set comes with a new id
|
||||
for mpID, mpConfMap := range config.Mountpoints {
|
||||
mpConfParam := QemuDeviceParam{}
|
||||
mpConfParam = mpConfParam.createDeviceParam(mpConfMap, nil)
|
||||
|
||||
// add mp to lxc parameters
|
||||
mpName := fmt.Sprintf("mp%v", mpID)
|
||||
paramMap[mpName] = strings.Join(mpConfParam, ",")
|
||||
}
|
||||
|
||||
// build list of network parameters
|
||||
for nicID, nicConfMap := range config.Networks {
|
||||
nicConfParam := QemuDeviceParam{}
|
||||
nicConfParam = nicConfParam.createDeviceParam(nicConfMap, nil)
|
||||
|
||||
// add nic to lxc parameters
|
||||
nicName := fmt.Sprintf("net%v", nicID)
|
||||
paramMap[nicName] = strings.Join(nicConfParam, ",")
|
||||
}
|
||||
|
||||
// build list of unused volumes for sake of completenes,
|
||||
// even if it is not recommended to change these volumes manually
|
||||
for volID, vol := range config.Unused {
|
||||
// add volume to lxc parameters
|
||||
volName := fmt.Sprintf("unused%v", volID)
|
||||
paramMap[volName] = vol
|
||||
}
|
||||
|
||||
// now that we concatenated the key value parameter
|
||||
// list for the networks, mountpoints and unused volumes,
|
||||
// remove the original keys, since the Proxmox API does
|
||||
// not know how to handle this key
|
||||
delete(paramMap, "networks")
|
||||
delete(paramMap, "mountpoints")
|
||||
delete(paramMap, "unused")
|
||||
|
||||
// amend vmid
|
||||
paramMap["vmid"] = vmr.vmId
|
||||
|
||||
exitStatus, err := client.CreateLxcContainer(vmr.node, paramMap)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating LXC container: %v, error status: %s (params: %v)", err, exitStatus, params)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (config configLxc) UpdateConfig(vmr *VmRef, client *Client) (err error) {
|
||||
// convert config to map
|
||||
params, _ := json.Marshal(&config)
|
||||
var paramMap map[string]interface{}
|
||||
json.Unmarshal(params, ¶mMap)
|
||||
|
||||
// build list of features
|
||||
// add features as parameter list to lxc parameters
|
||||
// this overwrites the orginal formatting with a
|
||||
// comma separated list of "key=value" pairs
|
||||
featuresParam := QemuDeviceParam{}
|
||||
featuresParam = featuresParam.createDeviceParam(config.Features, nil)
|
||||
paramMap["features"] = strings.Join(featuresParam, ",")
|
||||
|
||||
// build list of mountpoints
|
||||
// this does the same as for the feature list
|
||||
// except that there can be multiple of these mountpoint sets
|
||||
// and each mountpoint set comes with a new id
|
||||
for mpID, mpConfMap := range config.Mountpoints {
|
||||
mpConfParam := QemuDeviceParam{}
|
||||
mpConfParam = mpConfParam.createDeviceParam(mpConfMap, nil)
|
||||
|
||||
// add mp to lxc parameters
|
||||
mpName := fmt.Sprintf("mp%v", mpID)
|
||||
paramMap[mpName] = strings.Join(mpConfParam, ",")
|
||||
}
|
||||
|
||||
// build list of network parameters
|
||||
for nicID, nicConfMap := range config.Networks {
|
||||
nicConfParam := QemuDeviceParam{}
|
||||
nicConfParam = nicConfParam.createDeviceParam(nicConfMap, nil)
|
||||
|
||||
// add nic to lxc parameters
|
||||
nicName := fmt.Sprintf("net%v", nicID)
|
||||
paramMap[nicName] = strings.Join(nicConfParam, ",")
|
||||
}
|
||||
|
||||
// build list of unused volumes for sake of completenes,
|
||||
// even if it is not recommended to change these volumes manually
|
||||
for volID, vol := range config.Unused {
|
||||
// add volume to lxc parameters
|
||||
volName := fmt.Sprintf("unused%v", volID)
|
||||
paramMap[volName] = vol
|
||||
}
|
||||
|
||||
// now that we concatenated the key value parameter
|
||||
// list for the networks, mountpoints and unused volumes,
|
||||
// remove the original keys, since the Proxmox API does
|
||||
// not know how to handle this key
|
||||
delete(paramMap, "networks")
|
||||
delete(paramMap, "mountpoints")
|
||||
delete(paramMap, "unused")
|
||||
|
||||
// delete parameters wich are not supported in updated operations
|
||||
delete(paramMap, "pool")
|
||||
delete(paramMap, "storage")
|
||||
delete(paramMap, "password")
|
||||
delete(paramMap, "ostemplate")
|
||||
delete(paramMap, "start")
|
||||
// even though it is listed as a PUT option in the API documentation
|
||||
// we remove it here because "it should not be modified manually";
|
||||
// also, error "500 unable to modify read-only option: 'unprivileged'"
|
||||
delete(paramMap, "unprivileged")
|
||||
|
||||
_, err = client.SetLxcConfig(vmr, paramMap)
|
||||
return err
|
||||
}
|
|
@ -31,10 +31,17 @@ type ConfigQemu struct {
|
|||
QemuOs string `json:"os"`
|
||||
QemuCores int `json:"cores"`
|
||||
QemuSockets int `json:"sockets"`
|
||||
QemuCpu string `json:"cpu"`
|
||||
QemuNuma bool `json:"numa"`
|
||||
Hotplug string `json:"hotplug"`
|
||||
QemuIso string `json:"iso"`
|
||||
FullClone *int `json:"fullclone"`
|
||||
Boot string `json:"boot"`
|
||||
BootDisk string `json:"bootdisk,omitempty"`
|
||||
Scsihw string `json:"scsihw,omitempty"`
|
||||
QemuDisks QemuDevices `json:"disk"`
|
||||
QemuNetworks QemuDevices `json:"network"`
|
||||
QemuSerials QemuDevices `json:"serial,omitempty"`
|
||||
|
||||
// Deprecated single disk.
|
||||
DiskSize float64 `json:"diskGB"`
|
||||
|
@ -50,6 +57,7 @@ type ConfigQemu struct {
|
|||
// cloud-init options
|
||||
CIuser string `json:"ciuser"`
|
||||
CIpassword string `json:"cipassword"`
|
||||
CIcustom string `json:"cicustom"`
|
||||
|
||||
Searchdomain string `json:"searchdomain"`
|
||||
Nameserver string `json:"nameserver"`
|
||||
|
@ -76,10 +84,24 @@ func (config ConfigQemu) CreateVm(vmr *VmRef, client *Client) (err error) {
|
|||
"ostype": config.QemuOs,
|
||||
"sockets": config.QemuSockets,
|
||||
"cores": config.QemuCores,
|
||||
"cpu": "host",
|
||||
"cpu": config.QemuCpu,
|
||||
"numa": config.QemuNuma,
|
||||
"hotplug": config.Hotplug,
|
||||
"memory": config.Memory,
|
||||
"boot": config.Boot,
|
||||
"description": config.Description,
|
||||
}
|
||||
if vmr.pool != "" {
|
||||
params["pool"] = vmr.pool
|
||||
}
|
||||
|
||||
if config.BootDisk != "" {
|
||||
params["bootdisk"] = config.BootDisk
|
||||
}
|
||||
|
||||
if config.Scsihw != "" {
|
||||
params["scsihw"] = config.Scsihw
|
||||
}
|
||||
|
||||
// Create disks config.
|
||||
config.CreateQemuDisksParams(vmr.vmId, params, false)
|
||||
|
@ -87,6 +109,9 @@ func (config ConfigQemu) CreateVm(vmr *VmRef, client *Client) (err error) {
|
|||
// Create networks config.
|
||||
config.CreateQemuNetworksParams(vmr.vmId, params)
|
||||
|
||||
// Create serial interfaces
|
||||
config.CreateQemuSerialsParams(vmr.vmId, params)
|
||||
|
||||
exitStatus, err := client.CreateQemuVm(vmr.node, params)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating VM: %v, error status: %s (params: %v)", err, exitStatus, params)
|
||||
|
@ -102,7 +127,8 @@ func (config ConfigQemu) HasCloudInit() bool {
|
|||
config.Nameserver != "" ||
|
||||
config.Sshkeys != "" ||
|
||||
config.Ipconfig0 != "" ||
|
||||
config.Ipconfig1 != ""
|
||||
config.Ipconfig1 != "" ||
|
||||
config.CIcustom != ""
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -136,6 +162,10 @@ func (config ConfigQemu) CloneVm(sourceVmr *VmRef, vmr *VmRef, client *Client) (
|
|||
"storage": storage,
|
||||
"full": fullclone,
|
||||
}
|
||||
if vmr.pool != "" {
|
||||
params["pool"] = vmr.pool
|
||||
}
|
||||
|
||||
_, err = client.CloneQemuVm(sourceVmr, params)
|
||||
if err != nil {
|
||||
return
|
||||
|
@ -151,7 +181,19 @@ func (config ConfigQemu) UpdateConfig(vmr *VmRef, client *Client) (err error) {
|
|||
"agent": config.Agent,
|
||||
"sockets": config.QemuSockets,
|
||||
"cores": config.QemuCores,
|
||||
"cpu": config.QemuCpu,
|
||||
"numa": config.QemuNuma,
|
||||
"hotplug": config.Hotplug,
|
||||
"memory": config.Memory,
|
||||
"boot": config.Boot,
|
||||
}
|
||||
|
||||
if config.BootDisk != "" {
|
||||
configParams["bootdisk"] = config.BootDisk
|
||||
}
|
||||
|
||||
if config.Scsihw != "" {
|
||||
configParams["scsihw"] = config.Scsihw
|
||||
}
|
||||
|
||||
// Create disks config.
|
||||
|
@ -160,6 +202,9 @@ func (config ConfigQemu) UpdateConfig(vmr *VmRef, client *Client) (err error) {
|
|||
// Create networks config.
|
||||
config.CreateQemuNetworksParams(vmr.vmId, configParams)
|
||||
|
||||
// Create serial interfaces
|
||||
config.CreateQemuSerialsParams(vmr.vmId, configParams)
|
||||
|
||||
// cloud-init options
|
||||
if config.CIuser != "" {
|
||||
configParams["ciuser"] = config.CIuser
|
||||
|
@ -167,6 +212,9 @@ func (config ConfigQemu) UpdateConfig(vmr *VmRef, client *Client) (err error) {
|
|||
if config.CIpassword != "" {
|
||||
configParams["cipassword"] = config.CIpassword
|
||||
}
|
||||
if config.CIcustom != "" {
|
||||
configParams["cicustom"] = config.CIcustom
|
||||
}
|
||||
if config.Searchdomain != "" {
|
||||
configParams["searchdomain"] = config.Searchdomain
|
||||
}
|
||||
|
@ -202,11 +250,13 @@ func NewConfigQemuFromJson(io io.Reader) (config *ConfigQemu, err error) {
|
|||
}
|
||||
|
||||
var (
|
||||
rxIso = regexp.MustCompile(`(.*?),media`)
|
||||
rxDeviceID = regexp.MustCompile(`\d+`)
|
||||
rxDiskName = regexp.MustCompile(`(virtio|scsi)\d+`)
|
||||
rxDiskType = regexp.MustCompile(`\D+`)
|
||||
rxNicName = regexp.MustCompile(`net\d+`)
|
||||
rxIso = regexp.MustCompile(`(.*?),media`)
|
||||
rxDeviceID = regexp.MustCompile(`\d+`)
|
||||
rxDiskName = regexp.MustCompile(`(virtio|scsi)\d+`)
|
||||
rxDiskType = regexp.MustCompile(`\D+`)
|
||||
rxNicName = regexp.MustCompile(`net\d+`)
|
||||
rxMpName = regexp.MustCompile(`mp\d+`)
|
||||
rxSerialName = regexp.MustCompile(`serial\d+`)
|
||||
)
|
||||
|
||||
func NewConfigQemuFromApi(vmr *VmRef, client *Client) (config *ConfigQemu, err error) {
|
||||
|
@ -278,6 +328,32 @@ func NewConfigQemuFromApi(vmr *VmRef, client *Client) (config *ConfigQemu, err e
|
|||
if _, isSet := vmConfig["sockets"]; isSet {
|
||||
sockets = vmConfig["sockets"].(float64)
|
||||
}
|
||||
cpu := "host"
|
||||
if _, isSet := vmConfig["cpu"]; isSet {
|
||||
cpu = vmConfig["cpu"].(string)
|
||||
}
|
||||
numa := false
|
||||
if _, isSet := vmConfig["numa"]; isSet {
|
||||
numa = Itob(int(vmConfig["numa"].(float64)))
|
||||
}
|
||||
//Can be network,disk,cpu,memory,usb
|
||||
hotplug := "network,disk,usb"
|
||||
if _, isSet := vmConfig["hotplug"]; isSet {
|
||||
hotplug = vmConfig["hotplug"].(string)
|
||||
}
|
||||
//boot by default from hard disk (c), CD-ROM (d), network (n).
|
||||
boot := "cdn"
|
||||
if _, isSet := vmConfig["boot"]; isSet {
|
||||
boot = vmConfig["boot"].(string)
|
||||
}
|
||||
bootdisk := ""
|
||||
if _, isSet := vmConfig["bootdisk"]; isSet {
|
||||
bootdisk = vmConfig["bootdisk"].(string)
|
||||
}
|
||||
scsihw := "lsi"
|
||||
if _, isSet := vmConfig["scsihw"]; isSet {
|
||||
scsihw = vmConfig["scsihw"].(string)
|
||||
}
|
||||
config = &ConfigQemu{
|
||||
Name: name,
|
||||
Description: strings.TrimSpace(description),
|
||||
|
@ -287,9 +363,16 @@ func NewConfigQemuFromApi(vmr *VmRef, client *Client) (config *ConfigQemu, err e
|
|||
Memory: int(memory),
|
||||
QemuCores: int(cores),
|
||||
QemuSockets: int(sockets),
|
||||
QemuCpu: cpu,
|
||||
QemuNuma: numa,
|
||||
Hotplug: hotplug,
|
||||
QemuVlanTag: -1,
|
||||
Boot: boot,
|
||||
BootDisk: bootdisk,
|
||||
Scsihw: scsihw,
|
||||
QemuDisks: QemuDevices{},
|
||||
QemuNetworks: QemuDevices{},
|
||||
QemuSerials: QemuDevices{},
|
||||
}
|
||||
|
||||
if vmConfig["ide2"] != nil {
|
||||
|
@ -303,6 +386,9 @@ func NewConfigQemuFromApi(vmr *VmRef, client *Client) (config *ConfigQemu, err e
|
|||
if _, isSet := vmConfig["cipassword"]; isSet {
|
||||
config.CIpassword = vmConfig["cipassword"].(string)
|
||||
}
|
||||
if _, isSet := vmConfig["cicustom"]; isSet {
|
||||
config.CIcustom = vmConfig["cicustom"].(string)
|
||||
}
|
||||
if _, isSet := vmConfig["searchdomain"]; isSet {
|
||||
config.Searchdomain = vmConfig["searchdomain"].(string)
|
||||
}
|
||||
|
@ -388,6 +474,30 @@ func NewConfigQemuFromApi(vmr *VmRef, client *Client) (config *ConfigQemu, err e
|
|||
}
|
||||
}
|
||||
|
||||
// Add serials
|
||||
serialNames := []string{}
|
||||
|
||||
for k, _ := range vmConfig {
|
||||
if serialName := rxSerialName.FindStringSubmatch(k); len(serialName) > 0 {
|
||||
serialNames = append(serialNames, serialName[0])
|
||||
}
|
||||
}
|
||||
|
||||
for _, serialName := range serialNames {
|
||||
id := rxDeviceID.FindStringSubmatch(serialName)
|
||||
serialID, _ := strconv.Atoi(id[0])
|
||||
|
||||
serialConfMap := QemuDevice{
|
||||
"id": serialID,
|
||||
"type": vmConfig[serialName],
|
||||
}
|
||||
|
||||
// And device config to serials map.
|
||||
if len(serialConfMap) > 0 {
|
||||
config.QemuSerials[serialID] = serialConfMap
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -620,7 +730,9 @@ func (c ConfigQemu) CreateQemuDisksParams(
|
|||
"storage_type": "lvm", // default old style
|
||||
"cache": "none", // default old value
|
||||
}
|
||||
|
||||
if c.QemuDisks == nil {
|
||||
c.QemuDisks = make(QemuDevices)
|
||||
}
|
||||
c.QemuDisks[0] = deprecatedStyleMap
|
||||
}
|
||||
|
||||
|
@ -646,9 +758,9 @@ func (c ConfigQemu) CreateQemuDisksParams(
|
|||
|
||||
// Disk name.
|
||||
var diskFile string
|
||||
// Currently ZFS local, LVM, and Directory are considered.
|
||||
// Currently ZFS local, LVM, Ceph RBD, and Directory are considered.
|
||||
// Other formats are not verified, but could be added if they're needed.
|
||||
rxStorageTypes := `(zfspool|lvm)`
|
||||
rxStorageTypes := `(zfspool|lvm|rbd)`
|
||||
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)
|
||||
|
@ -716,3 +828,22 @@ func (c ConfigQemu) String() string {
|
|||
jsConf, _ := json.Marshal(c)
|
||||
return string(jsConf)
|
||||
}
|
||||
|
||||
// Create parameters for serial interface
|
||||
func (c ConfigQemu) CreateQemuSerialsParams(
|
||||
vmID int,
|
||||
params map[string]interface{},
|
||||
) error {
|
||||
|
||||
// For new style with multi disk device.
|
||||
for serialID, serialConfMap := range c.QemuSerials {
|
||||
// Device name.
|
||||
deviceType := serialConfMap["type"].(string)
|
||||
qemuSerialName := "serial" + strconv.Itoa(serialID)
|
||||
|
||||
// Add back to Qemu prams.
|
||||
params[qemuSerialName] = deviceType
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -106,8 +106,12 @@ func TypedResponse(resp *http.Response, v interface{}) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *Session) Login(username string, password string) (err error) {
|
||||
reqbody := ParamsToBody(map[string]interface{}{"username": username, "password": password})
|
||||
func (s *Session) Login(username string, password string, otp string) (err error) {
|
||||
reqUser := map[string]interface{}{"username": username, "password": password}
|
||||
if otp != "" {
|
||||
reqUser["otp"] = otp
|
||||
}
|
||||
reqbody := ParamsToBody(reqUser)
|
||||
olddebug := *Debug
|
||||
*Debug = false // don't share passwords in debug log
|
||||
resp, err := s.Post("/access/ticket", nil, nil, &reqbody)
|
||||
|
@ -127,6 +131,10 @@ func (s *Session) Login(username string, password string) (err error) {
|
|||
return fmt.Errorf("Invalid login response:\n-----\n%s\n-----", dr)
|
||||
}
|
||||
dat := jbody["data"].(map[string]interface{})
|
||||
//Check if the 2FA was required
|
||||
if dat["NeedTFA"] == 1.0 {
|
||||
return errors.New("Missing TFA code")
|
||||
}
|
||||
s.AuthTicket = dat["ticket"].(string)
|
||||
s.CsrfToken = dat["CSRFPreventionToken"].(string)
|
||||
return nil
|
||||
|
|
|
@ -50,7 +50,7 @@ github.com/NaverCloudPlatform/ncloud-sdk-go/sdk
|
|||
github.com/NaverCloudPlatform/ncloud-sdk-go/common
|
||||
github.com/NaverCloudPlatform/ncloud-sdk-go/request
|
||||
github.com/NaverCloudPlatform/ncloud-sdk-go/oauth
|
||||
# github.com/Telmate/proxmox-api-go v0.0.0-20190614181158-26cd147831a4
|
||||
# github.com/Telmate/proxmox-api-go v0.0.0-20190815172943-ef9222844e60
|
||||
github.com/Telmate/proxmox-api-go/proxmox
|
||||
# github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190418113227-25233c783f4e
|
||||
github.com/aliyun/alibaba-cloud-sdk-go/sdk/errors
|
||||
|
|
Loading…
Reference in New Issue