2017-02-09 04:53:24 +00:00
|
|
|
package proxmox
|
|
|
|
|
|
|
|
import (
|
2017-02-10 19:43:21 +00:00
|
|
|
"fmt"
|
2017-02-13 21:09:55 +00:00
|
|
|
"log"
|
2018-07-16 18:57:46 +00:00
|
|
|
"math"
|
2017-02-28 17:30:44 +00:00
|
|
|
"path"
|
2018-07-13 17:25:37 +00:00
|
|
|
"regexp"
|
2017-02-10 19:43:21 +00:00
|
|
|
"strconv"
|
2017-03-06 23:44:46 +00:00
|
|
|
"strings"
|
2017-02-13 19:11:33 +00:00
|
|
|
"time"
|
2018-07-10 17:25:46 +00:00
|
|
|
|
|
|
|
pxapi "github.com/Telmate/proxmox-api-go/proxmox"
|
|
|
|
"github.com/hashicorp/terraform/helper/schema"
|
2017-02-09 04:53:24 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func resourceVmQemu() *schema.Resource {
|
2017-02-09 21:36:31 +00:00
|
|
|
*pxapi.Debug = true
|
2017-02-09 04:53:24 +00:00
|
|
|
return &schema.Resource{
|
|
|
|
Create: resourceVmQemuCreate,
|
|
|
|
Read: resourceVmQemuRead,
|
2017-02-10 19:43:21 +00:00
|
|
|
Update: resourceVmQemuUpdate,
|
2017-02-09 04:53:24 +00:00
|
|
|
Delete: resourceVmQemuDelete,
|
2017-05-24 17:18:06 +00:00
|
|
|
Importer: &schema.ResourceImporter{
|
|
|
|
State: resourceVmQemuImport,
|
|
|
|
},
|
2017-02-09 04:53:24 +00:00
|
|
|
|
|
|
|
Schema: map[string]*schema.Schema{
|
|
|
|
"name": {
|
|
|
|
Type: schema.TypeString,
|
|
|
|
Required: true,
|
|
|
|
},
|
|
|
|
"desc": {
|
|
|
|
Type: schema.TypeString,
|
2017-02-09 21:36:31 +00:00
|
|
|
Optional: true,
|
2017-05-01 21:13:58 +00:00
|
|
|
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
|
|
|
|
return strings.TrimSpace(old) == strings.TrimSpace(new)
|
|
|
|
},
|
2017-02-09 21:36:31 +00:00
|
|
|
},
|
|
|
|
"target_node": {
|
|
|
|
Type: schema.TypeString,
|
|
|
|
Required: true,
|
2018-07-13 17:25:37 +00:00
|
|
|
ForceNew: true,
|
2017-02-09 21:36:31 +00:00
|
|
|
},
|
|
|
|
"ssh_forward_ip": {
|
|
|
|
Type: schema.TypeString,
|
2018-07-16 16:10:23 +00:00
|
|
|
Optional: true,
|
2017-02-09 21:36:31 +00:00
|
|
|
},
|
|
|
|
"iso": {
|
|
|
|
Type: schema.TypeString,
|
|
|
|
Optional: true,
|
2018-07-13 17:25:37 +00:00
|
|
|
ForceNew: true,
|
2017-02-09 21:36:31 +00:00
|
|
|
},
|
|
|
|
"clone": {
|
|
|
|
Type: schema.TypeString,
|
|
|
|
Optional: true,
|
2018-07-13 17:25:37 +00:00
|
|
|
ForceNew: true,
|
2017-02-09 21:36:31 +00:00
|
|
|
},
|
|
|
|
"storage": {
|
|
|
|
Type: schema.TypeString,
|
|
|
|
Required: true,
|
2017-02-10 19:43:21 +00:00
|
|
|
},
|
2018-07-13 17:25:37 +00:00
|
|
|
"storage_type": {
|
|
|
|
Type: schema.TypeString,
|
|
|
|
Optional: true,
|
2018-07-16 18:57:46 +00:00
|
|
|
ForceNew: false,
|
|
|
|
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
|
|
|
|
if new == "" {
|
|
|
|
return true // empty template ok
|
|
|
|
}
|
|
|
|
return strings.TrimSpace(old) == strings.TrimSpace(new)
|
|
|
|
},
|
2018-07-13 17:25:37 +00:00
|
|
|
},
|
2017-02-10 19:43:21 +00:00
|
|
|
"qemu_os": {
|
|
|
|
Type: schema.TypeString,
|
|
|
|
Optional: true,
|
|
|
|
Default: "l26",
|
2018-07-16 18:57:46 +00:00
|
|
|
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
|
|
|
|
if old == "" {
|
|
|
|
return true // reading empty ok
|
|
|
|
}
|
|
|
|
return strings.TrimSpace(old) == strings.TrimSpace(new)
|
|
|
|
},
|
2017-02-09 21:36:31 +00:00
|
|
|
},
|
|
|
|
"memory": {
|
|
|
|
Type: schema.TypeInt,
|
|
|
|
Required: true,
|
|
|
|
},
|
|
|
|
"cores": {
|
|
|
|
Type: schema.TypeInt,
|
|
|
|
Required: true,
|
|
|
|
},
|
|
|
|
"sockets": {
|
|
|
|
Type: schema.TypeInt,
|
|
|
|
Required: true,
|
2017-02-10 19:43:21 +00:00
|
|
|
},
|
|
|
|
"disk_gb": {
|
|
|
|
Type: schema.TypeFloat,
|
|
|
|
Required: true,
|
2018-07-16 18:57:46 +00:00
|
|
|
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
|
|
|
|
// bigger ok
|
|
|
|
oldf, _ := strconv.ParseFloat(old, 64)
|
|
|
|
newf, _ := strconv.ParseFloat(new, 64)
|
|
|
|
return oldf >= newf
|
|
|
|
},
|
2017-02-10 19:43:21 +00:00
|
|
|
},
|
|
|
|
"nic": {
|
|
|
|
Type: schema.TypeString,
|
|
|
|
Required: true,
|
|
|
|
},
|
|
|
|
"bridge": {
|
|
|
|
Type: schema.TypeString,
|
|
|
|
Required: true,
|
|
|
|
},
|
|
|
|
"vlan": {
|
|
|
|
Type: schema.TypeInt,
|
|
|
|
Optional: true,
|
|
|
|
Default: -1,
|
|
|
|
},
|
|
|
|
"os_type": {
|
|
|
|
Type: schema.TypeString,
|
|
|
|
Optional: true,
|
|
|
|
},
|
|
|
|
"os_network_config": {
|
|
|
|
Type: schema.TypeString,
|
|
|
|
Optional: true,
|
2017-02-09 21:36:31 +00:00
|
|
|
ForceNew: true,
|
2017-05-01 21:13:58 +00:00
|
|
|
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
|
|
|
|
return strings.TrimSpace(old) == strings.TrimSpace(new)
|
|
|
|
},
|
2017-02-09 04:53:24 +00:00
|
|
|
},
|
2017-02-11 00:06:14 +00:00
|
|
|
"ssh_user": {
|
|
|
|
Type: schema.TypeString,
|
|
|
|
Optional: true,
|
|
|
|
ForceNew: true,
|
|
|
|
},
|
|
|
|
"ssh_private_key": {
|
2017-02-15 23:32:37 +00:00
|
|
|
Type: schema.TypeString,
|
|
|
|
Optional: true,
|
|
|
|
Sensitive: true,
|
2017-03-06 23:44:46 +00:00
|
|
|
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
|
|
|
|
return strings.TrimSpace(old) == strings.TrimSpace(new)
|
|
|
|
},
|
2017-02-11 00:06:14 +00:00
|
|
|
},
|
2017-02-28 17:30:44 +00:00
|
|
|
"force_create": {
|
|
|
|
Type: schema.TypeBool,
|
|
|
|
Optional: true,
|
|
|
|
Default: false,
|
|
|
|
},
|
2018-07-13 17:25:37 +00:00
|
|
|
"mac": {
|
|
|
|
Type: schema.TypeString,
|
|
|
|
Optional: true,
|
|
|
|
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
|
2018-07-16 18:57:46 +00:00
|
|
|
if new == "" {
|
|
|
|
return true // macaddr auto-generates and its ok
|
2018-07-13 17:25:37 +00:00
|
|
|
}
|
|
|
|
return strings.TrimSpace(old) == strings.TrimSpace(new)
|
|
|
|
},
|
|
|
|
},
|
|
|
|
"ci_wait": { // how long to wait before provision
|
|
|
|
Type: schema.TypeInt,
|
|
|
|
Optional: true,
|
|
|
|
Default: 30,
|
2018-07-19 16:53:00 +00:00
|
|
|
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
|
|
|
|
if old == "" {
|
|
|
|
return true // old empty ok
|
|
|
|
}
|
|
|
|
return strings.TrimSpace(old) == strings.TrimSpace(new)
|
|
|
|
},
|
2018-07-13 17:25:37 +00:00
|
|
|
},
|
|
|
|
"ciuser": {
|
|
|
|
Type: schema.TypeString,
|
|
|
|
Optional: true,
|
|
|
|
},
|
|
|
|
"cipassword": {
|
|
|
|
Type: schema.TypeString,
|
|
|
|
Optional: true,
|
|
|
|
},
|
|
|
|
"searchdomain": {
|
|
|
|
Type: schema.TypeString,
|
|
|
|
Optional: true,
|
|
|
|
},
|
|
|
|
"nameserver": {
|
|
|
|
Type: schema.TypeString,
|
|
|
|
Optional: true,
|
|
|
|
},
|
|
|
|
"sshkeys": {
|
|
|
|
Type: schema.TypeString,
|
|
|
|
Optional: true,
|
2018-07-16 18:57:46 +00:00
|
|
|
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
|
|
|
|
return strings.TrimSpace(old) == strings.TrimSpace(new)
|
|
|
|
},
|
2018-07-13 17:25:37 +00:00
|
|
|
},
|
|
|
|
"ipconfig0": {
|
|
|
|
Type: schema.TypeString,
|
|
|
|
Optional: true,
|
|
|
|
},
|
|
|
|
"ipconfig1": {
|
|
|
|
Type: schema.TypeString,
|
|
|
|
Optional: true,
|
|
|
|
},
|
2017-02-09 21:36:31 +00:00
|
|
|
},
|
|
|
|
}
|
2017-02-09 04:53:24 +00:00
|
|
|
}
|
|
|
|
|
2018-07-13 17:25:37 +00:00
|
|
|
var rxIPconfig = regexp.MustCompile("ip6?=([0-9a-fA-F:\\.]+)")
|
|
|
|
|
2017-02-09 04:53:24 +00:00
|
|
|
func resourceVmQemuCreate(d *schema.ResourceData, meta interface{}) error {
|
2017-07-21 01:35:01 +00:00
|
|
|
pconf := meta.(*providerConfiguration)
|
|
|
|
pmParallelBegin(pconf)
|
|
|
|
client := pconf.Client
|
2017-02-10 19:43:21 +00:00
|
|
|
vmName := d.Get("name").(string)
|
2018-07-13 17:25:37 +00:00
|
|
|
diskGB := d.Get("disk_gb").(float64)
|
2017-02-09 04:53:24 +00:00
|
|
|
config := pxapi.ConfigQemu{
|
2017-02-10 19:43:21 +00:00
|
|
|
Name: vmName,
|
|
|
|
Description: d.Get("desc").(string),
|
|
|
|
Storage: d.Get("storage").(string),
|
|
|
|
Memory: d.Get("memory").(int),
|
|
|
|
QemuCores: d.Get("cores").(int),
|
|
|
|
QemuSockets: d.Get("sockets").(int),
|
2018-07-13 17:25:37 +00:00
|
|
|
DiskSize: diskGB,
|
2017-02-10 19:43:21 +00:00
|
|
|
QemuOs: d.Get("qemu_os").(string),
|
|
|
|
QemuNicModel: d.Get("nic").(string),
|
|
|
|
QemuBrige: d.Get("bridge").(string),
|
|
|
|
QemuVlanTag: d.Get("vlan").(int),
|
2018-07-13 17:25:37 +00:00
|
|
|
QemuMacAddr: d.Get("mac").(string),
|
|
|
|
CIuser: d.Get("ciuser").(string),
|
|
|
|
CIpassword: d.Get("cipassword").(string),
|
|
|
|
Searchdomain: d.Get("searchdomain").(string),
|
|
|
|
Nameserver: d.Get("nameserver").(string),
|
|
|
|
Sshkeys: d.Get("sshkeys").(string),
|
|
|
|
Ipconfig0: d.Get("ipconfig0").(string),
|
|
|
|
Ipconfig1: d.Get("ipconfig1").(string),
|
2017-02-09 21:36:31 +00:00
|
|
|
}
|
2017-02-13 21:09:55 +00:00
|
|
|
log.Print("[DEBUG] checking for duplicate name")
|
2017-02-10 19:43:21 +00:00
|
|
|
dupVmr, _ := client.GetVmRefByName(vmName)
|
|
|
|
|
2017-02-28 17:30:44 +00:00
|
|
|
forceCreate := d.Get("force_create").(bool)
|
|
|
|
targetNode := d.Get("target_node").(string)
|
|
|
|
|
|
|
|
if dupVmr != nil && forceCreate {
|
2017-07-21 01:35:01 +00:00
|
|
|
pmParallelEnd(pconf)
|
2017-02-28 17:30:44 +00:00
|
|
|
return fmt.Errorf("Duplicate VM name (%s) with vmId: %d. Set force_create=false to recycle", vmName, dupVmr.VmId())
|
|
|
|
} else if dupVmr != nil && dupVmr.Node() != targetNode {
|
2017-07-21 01:35:01 +00:00
|
|
|
pmParallelEnd(pconf)
|
2017-02-28 17:30:44 +00:00
|
|
|
return fmt.Errorf("Duplicate VM name (%s) with vmId: %d on different target_node=%s", vmName, dupVmr.VmId(), dupVmr.Node())
|
2017-02-10 19:43:21 +00:00
|
|
|
}
|
2017-02-09 21:36:31 +00:00
|
|
|
|
2017-02-28 17:30:44 +00:00
|
|
|
vmr := dupVmr
|
|
|
|
|
|
|
|
if vmr == nil {
|
|
|
|
// get unique id
|
2017-07-21 01:35:01 +00:00
|
|
|
nextid, err := nextVmId(pconf)
|
2017-02-09 21:36:31 +00:00
|
|
|
if err != nil {
|
2017-07-21 01:35:01 +00:00
|
|
|
pmParallelEnd(pconf)
|
2017-02-09 21:36:31 +00:00
|
|
|
return err
|
|
|
|
}
|
2017-02-28 17:30:44 +00:00
|
|
|
vmr = pxapi.NewVmRef(nextid)
|
2017-02-13 21:09:55 +00:00
|
|
|
|
2017-02-28 17:30:44 +00:00
|
|
|
vmr.SetNode(targetNode)
|
|
|
|
// check if ISO or clone
|
|
|
|
if d.Get("clone").(string) != "" {
|
|
|
|
sourceVmr, err := client.GetVmRefByName(d.Get("clone").(string))
|
|
|
|
if err != nil {
|
2017-07-21 01:35:01 +00:00
|
|
|
pmParallelEnd(pconf)
|
2017-02-28 17:30:44 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
log.Print("[DEBUG] cloning VM")
|
|
|
|
err = config.CloneVm(sourceVmr, vmr, client)
|
|
|
|
if err != nil {
|
2017-07-21 01:35:01 +00:00
|
|
|
pmParallelEnd(pconf)
|
2017-02-28 17:30:44 +00:00
|
|
|
return err
|
|
|
|
}
|
2017-02-13 21:09:55 +00:00
|
|
|
|
2017-07-21 01:35:01 +00:00
|
|
|
// give sometime to proxmox to catchup
|
|
|
|
time.Sleep(5 * time.Second)
|
|
|
|
|
2018-07-13 17:25:37 +00:00
|
|
|
err = prepareDiskSize(client, vmr, diskGB)
|
2017-02-28 17:30:44 +00:00
|
|
|
if err != nil {
|
2017-07-21 01:35:01 +00:00
|
|
|
pmParallelEnd(pconf)
|
2017-02-28 17:30:44 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
} else if d.Get("iso").(string) != "" {
|
|
|
|
config.QemuIso = d.Get("iso").(string)
|
|
|
|
err := config.CreateVm(vmr, client)
|
2017-02-13 21:09:55 +00:00
|
|
|
if err != nil {
|
2017-07-21 01:35:01 +00:00
|
|
|
pmParallelEnd(pconf)
|
2017-02-13 21:09:55 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
2017-02-28 17:30:44 +00:00
|
|
|
} else {
|
|
|
|
log.Printf("[DEBUG] recycling VM vmId: %d", vmr.VmId())
|
2017-03-23 21:24:25 +00:00
|
|
|
|
|
|
|
client.StopVm(vmr)
|
|
|
|
|
|
|
|
err := config.UpdateConfig(vmr, client)
|
|
|
|
if err != nil {
|
2017-07-21 01:35:01 +00:00
|
|
|
pmParallelEnd(pconf)
|
2017-03-23 21:24:25 +00:00
|
|
|
return err
|
|
|
|
}
|
2017-07-21 01:35:01 +00:00
|
|
|
|
|
|
|
// give sometime to proxmox to catchup
|
|
|
|
time.Sleep(5 * time.Second)
|
|
|
|
|
2018-07-13 17:25:37 +00:00
|
|
|
err = prepareDiskSize(client, vmr, diskGB)
|
2017-02-09 21:36:31 +00:00
|
|
|
if err != nil {
|
2017-07-21 01:35:01 +00:00
|
|
|
pmParallelEnd(pconf)
|
2017-02-09 21:36:31 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
2017-05-24 17:18:06 +00:00
|
|
|
d.SetId(resourceId(targetNode, "qemu", vmr.VmId()))
|
2017-02-10 19:43:21 +00:00
|
|
|
|
2017-07-21 01:35:01 +00:00
|
|
|
// give sometime to proxmox to catchup
|
|
|
|
time.Sleep(5 * time.Second)
|
|
|
|
|
2017-02-13 21:09:55 +00:00
|
|
|
log.Print("[DEBUG] starting VM")
|
2017-02-28 17:30:44 +00:00
|
|
|
_, err := client.StartVm(vmr)
|
2017-02-09 21:36:31 +00:00
|
|
|
if err != nil {
|
2017-07-21 01:35:01 +00:00
|
|
|
pmParallelEnd(pconf)
|
2017-02-09 21:36:31 +00:00
|
|
|
return err
|
|
|
|
}
|
2018-07-13 17:25:37 +00:00
|
|
|
|
|
|
|
sshPort := "22"
|
|
|
|
sshHost := ""
|
|
|
|
if config.HasCloudInit() {
|
|
|
|
if d.Get("ssh_forward_ip") != nil {
|
|
|
|
sshHost = d.Get("ssh_forward_ip").(string)
|
2018-07-16 18:57:46 +00:00
|
|
|
}
|
|
|
|
if sshHost == "" {
|
2018-07-13 17:25:37 +00:00
|
|
|
// parse IP address out of ipconfig0
|
|
|
|
ipMatch := rxIPconfig.FindStringSubmatch(d.Get("ipconfig0").(string))
|
|
|
|
sshHost = ipMatch[1]
|
2018-10-02 19:13:09 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
// Check if we got a speficied port
|
|
|
|
if strings.Contains(sshHost, ":") {
|
|
|
|
sshParts := strings.Split(sshHost, ":")
|
|
|
|
sshHost = sshParts[0]
|
|
|
|
sshPort = sshParts[1]
|
2018-07-13 17:25:37 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
log.Print("[DEBUG] setting up SSH forward")
|
|
|
|
sshPort, err = pxapi.SshForwardUsernet(vmr, client)
|
|
|
|
if err != nil {
|
|
|
|
pmParallelEnd(pconf)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
sshHost = d.Get("ssh_forward_ip").(string)
|
2017-02-09 21:36:31 +00:00
|
|
|
}
|
|
|
|
|
2017-07-21 01:35:01 +00:00
|
|
|
// Done with proxmox API, end parallel and do the SSH things
|
|
|
|
pmParallelEnd(pconf)
|
|
|
|
|
2017-02-09 21:36:31 +00:00
|
|
|
d.SetConnInfo(map[string]string{
|
2018-07-10 21:50:35 +00:00
|
|
|
"type": "ssh",
|
2018-07-13 17:25:37 +00:00
|
|
|
"host": sshHost,
|
2018-07-10 21:50:35 +00:00
|
|
|
"port": sshPort,
|
|
|
|
"user": d.Get("ssh_user").(string),
|
|
|
|
"private_key": d.Get("ssh_private_key").(string),
|
|
|
|
"pm_api_url": client.ApiUrl,
|
|
|
|
"pm_user": client.Username,
|
|
|
|
"pm_password": client.Password,
|
|
|
|
"pm_tls_insecure": "true", // TODO - pass pm_tls_insecure state around, but if we made it this far, default insecure
|
2017-02-09 21:36:31 +00:00
|
|
|
})
|
|
|
|
|
2017-02-11 00:06:14 +00:00
|
|
|
switch d.Get("os_type").(string) {
|
|
|
|
|
|
|
|
case "ubuntu":
|
2017-02-13 19:11:33 +00:00
|
|
|
// give sometime to bootup
|
2017-07-21 01:35:01 +00:00
|
|
|
time.Sleep(9 * time.Second)
|
2017-02-11 00:06:14 +00:00
|
|
|
err = preProvisionUbuntu(d)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2017-02-09 04:53:24 +00:00
|
|
|
|
2017-03-30 22:40:34 +00:00
|
|
|
case "centos":
|
|
|
|
// give sometime to bootup
|
2017-07-21 01:35:01 +00:00
|
|
|
time.Sleep(9 * time.Second)
|
2017-03-30 22:40:34 +00:00
|
|
|
err = preProvisionCentos(d)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2018-07-13 17:25:37 +00:00
|
|
|
case "cloud-init":
|
|
|
|
// wait for OS too boot awhile...
|
2018-07-16 16:10:23 +00:00
|
|
|
log.Print("[DEBUG] sleeping for OS bootup...")
|
2018-07-13 17:25:37 +00:00
|
|
|
time.Sleep(time.Duration(d.Get("ci_wait").(int)) * time.Second)
|
|
|
|
|
2017-02-11 00:06:14 +00:00
|
|
|
default:
|
|
|
|
return fmt.Errorf("Unknown os_type: %s", d.Get("os_type").(string))
|
|
|
|
}
|
2017-07-21 01:35:01 +00:00
|
|
|
|
2017-02-09 04:53:24 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2017-02-10 19:43:21 +00:00
|
|
|
func resourceVmQemuUpdate(d *schema.ResourceData, meta interface{}) error {
|
2017-07-21 01:35:01 +00:00
|
|
|
pconf := meta.(*providerConfiguration)
|
|
|
|
pmParallelBegin(pconf)
|
|
|
|
client := pconf.Client
|
2017-02-13 21:09:55 +00:00
|
|
|
vmr, err := client.GetVmRefByName(d.Get("name").(string))
|
|
|
|
if err != nil {
|
2017-07-21 01:35:01 +00:00
|
|
|
pmParallelEnd(pconf)
|
2017-02-13 21:09:55 +00:00
|
|
|
return err
|
|
|
|
}
|
2017-02-14 00:08:21 +00:00
|
|
|
vmName := d.Get("name").(string)
|
2018-07-13 17:25:37 +00:00
|
|
|
diskGB := d.Get("disk_gb").(float64)
|
2017-02-14 00:08:21 +00:00
|
|
|
config := pxapi.ConfigQemu{
|
|
|
|
Name: vmName,
|
|
|
|
Description: d.Get("desc").(string),
|
|
|
|
Storage: d.Get("storage").(string),
|
|
|
|
Memory: d.Get("memory").(int),
|
|
|
|
QemuCores: d.Get("cores").(int),
|
|
|
|
QemuSockets: d.Get("sockets").(int),
|
2018-07-13 17:25:37 +00:00
|
|
|
DiskSize: diskGB,
|
2017-02-14 00:08:21 +00:00
|
|
|
QemuOs: d.Get("qemu_os").(string),
|
|
|
|
QemuNicModel: d.Get("nic").(string),
|
|
|
|
QemuBrige: d.Get("bridge").(string),
|
|
|
|
QemuVlanTag: d.Get("vlan").(int),
|
2018-07-13 17:25:37 +00:00
|
|
|
QemuMacAddr: d.Get("mac").(string),
|
|
|
|
CIuser: d.Get("ciuser").(string),
|
|
|
|
CIpassword: d.Get("cipassword").(string),
|
|
|
|
Searchdomain: d.Get("searchdomain").(string),
|
|
|
|
Nameserver: d.Get("nameserver").(string),
|
|
|
|
Sshkeys: d.Get("sshkeys").(string),
|
|
|
|
Ipconfig0: d.Get("ipconfig0").(string),
|
|
|
|
Ipconfig1: d.Get("ipconfig1").(string),
|
2017-02-14 00:08:21 +00:00
|
|
|
}
|
|
|
|
|
2017-07-21 15:34:57 +00:00
|
|
|
err = config.UpdateConfig(vmr, client)
|
|
|
|
if err != nil {
|
|
|
|
pmParallelEnd(pconf)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// give sometime to proxmox to catchup
|
|
|
|
time.Sleep(5 * time.Second)
|
2017-02-14 00:08:21 +00:00
|
|
|
|
2018-07-13 17:25:37 +00:00
|
|
|
prepareDiskSize(client, vmr, diskGB)
|
2017-02-14 00:08:21 +00:00
|
|
|
|
2017-07-21 15:34:57 +00:00
|
|
|
// give sometime to proxmox to catchup
|
|
|
|
time.Sleep(5 * time.Second)
|
|
|
|
|
|
|
|
log.Print("[DEBUG] starting VM")
|
|
|
|
_, err = client.StartVm(vmr)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
pmParallelEnd(pconf)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2017-02-13 21:09:55 +00:00
|
|
|
sshPort, err := pxapi.SshForwardUsernet(vmr, client)
|
|
|
|
if err != nil {
|
2017-07-21 01:35:01 +00:00
|
|
|
pmParallelEnd(pconf)
|
2017-02-13 21:09:55 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
d.SetConnInfo(map[string]string{
|
|
|
|
"type": "ssh",
|
|
|
|
"host": d.Get("ssh_forward_ip").(string),
|
|
|
|
"port": sshPort,
|
|
|
|
"user": d.Get("ssh_user").(string),
|
|
|
|
"private_key": d.Get("ssh_private_key").(string),
|
|
|
|
})
|
2017-07-21 01:35:01 +00:00
|
|
|
pmParallelEnd(pconf)
|
2017-07-21 15:34:57 +00:00
|
|
|
|
|
|
|
// give sometime to bootup
|
|
|
|
time.Sleep(9 * time.Second)
|
2017-02-10 19:43:21 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2017-02-09 21:36:31 +00:00
|
|
|
func resourceVmQemuRead(d *schema.ResourceData, meta interface{}) error {
|
2017-07-21 01:35:01 +00:00
|
|
|
pconf := meta.(*providerConfiguration)
|
|
|
|
pmParallelBegin(pconf)
|
|
|
|
client := pconf.Client
|
2017-02-10 19:43:21 +00:00
|
|
|
vmr, err := client.GetVmRefByName(d.Get("name").(string))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
config, err := pxapi.NewConfigQemuFromApi(vmr, client)
|
|
|
|
if err != nil {
|
2017-07-21 01:35:01 +00:00
|
|
|
pmParallelEnd(pconf)
|
2017-02-10 19:43:21 +00:00
|
|
|
return err
|
|
|
|
}
|
2017-05-24 17:18:06 +00:00
|
|
|
d.SetId(resourceId(vmr.Node(), "qemu", vmr.VmId()))
|
2017-02-10 19:58:10 +00:00
|
|
|
d.Set("target_node", vmr.Node())
|
2017-02-10 19:43:21 +00:00
|
|
|
d.Set("name", config.Name)
|
|
|
|
d.Set("desc", config.Description)
|
|
|
|
d.Set("storage", config.Storage)
|
2018-07-13 17:25:37 +00:00
|
|
|
d.Set("storage_type", config.StorageType)
|
2017-02-10 19:43:21 +00:00
|
|
|
d.Set("memory", config.Memory)
|
|
|
|
d.Set("cores", config.QemuCores)
|
|
|
|
d.Set("sockets", config.QemuSockets)
|
|
|
|
d.Set("disk_gb", config.DiskSize)
|
|
|
|
d.Set("qemu_os", config.QemuOs)
|
|
|
|
d.Set("nic", config.QemuNicModel)
|
|
|
|
d.Set("bridge", config.QemuBrige)
|
|
|
|
d.Set("vlan", config.QemuVlanTag)
|
2018-07-13 17:25:37 +00:00
|
|
|
d.Set("mac", config.QemuMacAddr)
|
|
|
|
|
|
|
|
d.Set("ciuser", config.CIuser)
|
|
|
|
d.Set("cipassword", config.CIpassword)
|
|
|
|
d.Set("searchdomain", config.Searchdomain)
|
|
|
|
d.Set("nameserver", config.Nameserver)
|
|
|
|
d.Set("sshkeys", config.Sshkeys)
|
|
|
|
d.Set("ipconfig0", config.Ipconfig0)
|
|
|
|
d.Set("ipconfig1", config.Ipconfig1)
|
|
|
|
|
2017-07-21 01:35:01 +00:00
|
|
|
pmParallelEnd(pconf)
|
2017-02-10 19:43:21 +00:00
|
|
|
return nil
|
2017-02-09 04:53:24 +00:00
|
|
|
}
|
|
|
|
|
2017-05-24 17:18:06 +00:00
|
|
|
func resourceVmQemuImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
|
2017-07-21 01:35:01 +00:00
|
|
|
// TODO: research proper import
|
2017-05-24 17:18:06 +00:00
|
|
|
err := resourceVmQemuRead(d, meta)
|
|
|
|
return []*schema.ResourceData{d}, err
|
|
|
|
}
|
|
|
|
|
2017-02-09 04:53:24 +00:00
|
|
|
func resourceVmQemuDelete(d *schema.ResourceData, meta interface{}) error {
|
2017-07-21 01:35:01 +00:00
|
|
|
pconf := meta.(*providerConfiguration)
|
|
|
|
pmParallelBegin(pconf)
|
|
|
|
client := pconf.Client
|
2017-02-28 17:30:44 +00:00
|
|
|
vmId, _ := strconv.Atoi(path.Base(d.Id()))
|
2017-02-15 00:00:54 +00:00
|
|
|
vmr := pxapi.NewVmRef(vmId)
|
|
|
|
_, err := client.StopVm(vmr)
|
|
|
|
if err != nil {
|
2017-07-21 01:35:01 +00:00
|
|
|
pmParallelEnd(pconf)
|
2017-02-15 00:00:54 +00:00
|
|
|
return err
|
|
|
|
}
|
2017-07-21 01:35:01 +00:00
|
|
|
// give sometime to proxmox to catchup
|
|
|
|
time.Sleep(2 * time.Second)
|
2017-02-15 00:00:54 +00:00
|
|
|
_, err = client.DeleteVm(vmr)
|
2017-07-21 01:35:01 +00:00
|
|
|
pmParallelEnd(pconf)
|
2017-02-09 04:53:24 +00:00
|
|
|
return err
|
|
|
|
}
|
2017-02-28 17:30:44 +00:00
|
|
|
|
2018-07-13 17:25:37 +00:00
|
|
|
func prepareDiskSize(client *pxapi.Client, vmr *pxapi.VmRef, diskGB float64) error {
|
2017-02-28 17:30:44 +00:00
|
|
|
clonedConfig, err := pxapi.NewConfigQemuFromApi(vmr, client)
|
2017-07-21 15:34:57 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2018-07-13 17:25:37 +00:00
|
|
|
if diskGB > clonedConfig.DiskSize {
|
|
|
|
log.Print("[DEBUG] resizing disk " + clonedConfig.StorageType)
|
2018-07-16 18:57:46 +00:00
|
|
|
diffSize := int(math.Ceil(diskGB - clonedConfig.DiskSize))
|
|
|
|
_, err = client.ResizeQemuDisk(vmr, clonedConfig.StorageType+"0", diffSize)
|
2017-02-28 17:30:44 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|