0
0
mirror of https://github.com/bpg/terraform-provider-proxmox.git synced 2025-07-01 02:52:58 +00:00
terraform-provider-proxmox/proxmoxtf/resource_virtual_environment_vm.go
2019-12-27 19:13:40 +01:00

1074 lines
35 KiB
Go

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
package proxmoxtf
import (
"fmt"
"strconv"
"strings"
"github.com/danitso/terraform-provider-proxmox/proxmox"
"github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/terraform/helper/validation"
)
const (
dvResourceVirtualEnvironmentVMAgentEnabled = false
dvResourceVirtualEnvironmentVMAgentTrim = false
dvResourceVirtualEnvironmentVMAgentType = "virtio"
dvResourceVirtualEnvironmentVMCDROMEnabled = false
dvResourceVirtualEnvironmentVMCDROMFileID = ""
dvResourceVirtualEnvironmentVMCloudInitDNSDomain = ""
dvResourceVirtualEnvironmentVMCloudInitDNSServer = ""
dvResourceVirtualEnvironmentVMCPUCores = 1
dvResourceVirtualEnvironmentVMCPUHotplugged = 0
dvResourceVirtualEnvironmentVMCPUSockets = 1
dvResourceVirtualEnvironmentVMDescription = ""
dvResourceVirtualEnvironmentVMDiskDatastoreID = "local-lvm"
dvResourceVirtualEnvironmentVMDiskEnabled = true
dvResourceVirtualEnvironmentVMDiskFileFormat = "qcow2"
dvResourceVirtualEnvironmentVMDiskFileID = ""
dvResourceVirtualEnvironmentVMDiskSize = 8
dvResourceVirtualEnvironmentVMKeyboardLayout = "en-us"
dvResourceVirtualEnvironmentVMMemoryDedicated = 512
dvResourceVirtualEnvironmentVMMemoryFloating = 0
dvResourceVirtualEnvironmentVMMemoryShared = 0
dvResourceVirtualEnvironmentVMName = ""
dvResourceVirtualEnvironmentVMNetworkDeviceBridge = "vmbr0"
dvResourceVirtualEnvironmentVMNetworkDeviceEnabled = true
dvResourceVirtualEnvironmentVMNetworkDeviceMACAddress = ""
dvResourceVirtualEnvironmentVMNetworkDeviceModel = "virtio"
dvResourceVirtualEnvironmentVMNetworkDeviceVLANID = -1
dvResourceVirtualEnvironmentVMOSType = "other"
dvResourceVirtualEnvironmentVMPoolID = ""
dvResourceVirtualEnvironmentVMVMID = -1
mkResourceVirtualEnvironmentVMAgent = "agent"
mkResourceVirtualEnvironmentVMAgentEnabled = "enabled"
mkResourceVirtualEnvironmentVMAgentTrim = "trim"
mkResourceVirtualEnvironmentVMAgentType = "type"
mkResourceVirtualEnvironmentVMCDROM = "cdrom"
mkResourceVirtualEnvironmentVMCDROMEnabled = "enabled"
mkResourceVirtualEnvironmentVMCDROMFileID = "file_id"
mkResourceVirtualEnvironmentVMCloudInit = "cloud_init"
mkResourceVirtualEnvironmentVMCloudInitDNS = "dns"
mkResourceVirtualEnvironmentVMCloudInitDNSDomain = "domain"
mkResourceVirtualEnvironmentVMCloudInitDNSServer = "server"
mkResourceVirtualEnvironmentVMCloudInitIPConfig = "ip_config"
mkResourceVirtualEnvironmentVMCloudInitIPConfigIPv4 = "ipv4"
mkResourceVirtualEnvironmentVMCloudInitIPConfigIPv4Address = "address"
mkResourceVirtualEnvironmentVMCloudInitIPConfigIPv4Gateway = "gateway"
mkResourceVirtualEnvironmentVMCloudInitIPConfigIPv6 = "ipv6"
mkResourceVirtualEnvironmentVMCloudInitIPConfigIPv6Address = "address"
mkResourceVirtualEnvironmentVMCloudInitIPConfigIPv6Gateway = "gateway"
mkResourceVirtualEnvironmentVMCloudInitUserAccount = "user_account"
mkResourceVirtualEnvironmentVMCloudInitUserAccountKeys = "keys"
mkResourceVirtualEnvironmentVMCloudInitUserAccountUsername = "username"
mkResourceVirtualEnvironmentVMCPU = "cpu"
mkResourceVirtualEnvironmentVMCPUCores = "cores"
mkResourceVirtualEnvironmentVMCPUHotplugged = "hotplugged"
mkResourceVirtualEnvironmentVMCPUSockets = "sockets"
mkResourceVirtualEnvironmentVMDescription = "description"
mkResourceVirtualEnvironmentVMDisk = "disk"
mkResourceVirtualEnvironmentVMDiskDatastoreID = "datastore_id"
mkResourceVirtualEnvironmentVMDiskEnabled = "enabled"
mkResourceVirtualEnvironmentVMDiskFileFormat = "file_format"
mkResourceVirtualEnvironmentVMDiskFileID = "file_id"
mkResourceVirtualEnvironmentVMDiskSize = "size"
mkResourceVirtualEnvironmentVMKeyboardLayout = "keyboard_layout"
mkResourceVirtualEnvironmentVMMemory = "memory"
mkResourceVirtualEnvironmentVMMemoryDedicated = "dedicated"
mkResourceVirtualEnvironmentVMMemoryFloating = "floating"
mkResourceVirtualEnvironmentVMMemoryShared = "shared"
mkResourceVirtualEnvironmentVMName = "name"
mkResourceVirtualEnvironmentVMNetworkDevice = "network_device"
mkResourceVirtualEnvironmentVMNetworkDeviceBridge = "bridge"
mkResourceVirtualEnvironmentVMNetworkDeviceEnabled = "enabled"
mkResourceVirtualEnvironmentVMNetworkDeviceMACAddress = "mac_address"
mkResourceVirtualEnvironmentVMNetworkDeviceModel = "model"
mkResourceVirtualEnvironmentVMNetworkDeviceVLANID = "vlan_id"
mkResourceVirtualEnvironmentVMNodeName = "node_name"
mkResourceVirtualEnvironmentVMOSType = "os_type"
mkResourceVirtualEnvironmentVMPoolID = "pool_id"
mkResourceVirtualEnvironmentVMVMID = "vm_id"
)
func resourceVirtualEnvironmentVM() *schema.Resource {
return &schema.Resource{
Schema: map[string]*schema.Schema{
mkResourceVirtualEnvironmentVMAgent: &schema.Schema{
Type: schema.TypeList,
Description: "The QEMU agent configuration",
Optional: true,
DefaultFunc: func() (interface{}, error) {
defaultList := make([]interface{}, 1)
defaultMap := make(map[string]interface{})
defaultMap[mkResourceVirtualEnvironmentVMAgentEnabled] = dvResourceVirtualEnvironmentVMAgentEnabled
defaultMap[mkResourceVirtualEnvironmentVMAgentTrim] = dvResourceVirtualEnvironmentVMAgentTrim
defaultMap[mkResourceVirtualEnvironmentVMAgentType] = dvResourceVirtualEnvironmentVMAgentType
defaultList[0] = defaultMap
return defaultList, nil
},
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
mkResourceVirtualEnvironmentVMAgentEnabled: {
Type: schema.TypeBool,
Optional: true,
Description: "Whether to enable the QEMU agent",
Default: dvResourceVirtualEnvironmentVMAgentEnabled,
},
mkResourceVirtualEnvironmentVMAgentTrim: {
Type: schema.TypeBool,
Optional: true,
Description: "Whether to enable the FSTRIM feature in the QEMU agent",
Default: dvResourceVirtualEnvironmentVMAgentTrim,
},
mkResourceVirtualEnvironmentVMAgentType: {
Type: schema.TypeString,
Optional: true,
Description: "The QEMU agent interface type",
Default: dvResourceVirtualEnvironmentVMAgentType,
ValidateFunc: getQEMUAgentTypeValidator(),
},
},
},
MaxItems: 1,
MinItems: 0,
},
mkResourceVirtualEnvironmentVMCDROM: &schema.Schema{
Type: schema.TypeList,
Description: "The CDROM drive",
Optional: true,
DefaultFunc: func() (interface{}, error) {
defaultList := make([]interface{}, 1)
defaultMap := make(map[string]interface{})
defaultMap[mkResourceVirtualEnvironmentVMCDROMEnabled] = dvResourceVirtualEnvironmentVMCDROMEnabled
defaultMap[mkResourceVirtualEnvironmentVMCDROMFileID] = dvResourceVirtualEnvironmentVMCDROMFileID
defaultList[0] = defaultMap
return defaultList, nil
},
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
mkResourceVirtualEnvironmentVMCDROMEnabled: {
Type: schema.TypeBool,
Optional: true,
Description: "Whether to enable the CDROM drive",
Default: dvResourceVirtualEnvironmentVMCDROMEnabled,
},
mkResourceVirtualEnvironmentVMCDROMFileID: {
Type: schema.TypeString,
Optional: true,
Description: "The file id",
Default: dvResourceVirtualEnvironmentVMCDROMFileID,
ValidateFunc: getFileIDValidator(),
},
},
},
MaxItems: 1,
MinItems: 0,
},
mkResourceVirtualEnvironmentVMCloudInit: &schema.Schema{
Type: schema.TypeList,
Description: "The cloud-init configuration",
Optional: true,
DefaultFunc: func() (interface{}, error) {
return make([]interface{}, 0), nil
},
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
mkResourceVirtualEnvironmentVMCloudInitDNS: {
Type: schema.TypeList,
Description: "The DNS configuration",
Optional: true,
DefaultFunc: func() (interface{}, error) {
return make([]interface{}, 0), nil
},
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
mkResourceVirtualEnvironmentVMCloudInitDNSDomain: {
Type: schema.TypeString,
Optional: true,
Description: "The DNS search domain",
Default: dvResourceVirtualEnvironmentVMCloudInitDNSDomain,
},
mkResourceVirtualEnvironmentVMCloudInitDNSServer: {
Type: schema.TypeString,
Optional: true,
Description: "The DNS server",
Default: dvResourceVirtualEnvironmentVMCloudInitDNSServer,
},
},
},
MaxItems: 1,
MinItems: 0,
},
mkResourceVirtualEnvironmentVMCloudInitIPConfig: {
Type: schema.TypeList,
Description: "The IP configuration",
Optional: true,
DefaultFunc: func() (interface{}, error) {
return make([]interface{}, 0), nil
},
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
mkResourceVirtualEnvironmentVMCloudInitIPConfigIPv4: {
Type: schema.TypeList,
Description: "The IPv4 configuration",
Optional: true,
DefaultFunc: func() (interface{}, error) {
return make([]interface{}, 0), nil
},
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
mkResourceVirtualEnvironmentVMCloudInitIPConfigIPv4Address: {
Type: schema.TypeString,
Optional: true,
Description: "The IPv4 address",
Default: "",
},
mkResourceVirtualEnvironmentVMCloudInitIPConfigIPv4Gateway: {
Type: schema.TypeString,
Optional: true,
Description: "The IPv4 gateway",
Default: "",
},
},
},
MaxItems: 1,
MinItems: 0,
},
mkResourceVirtualEnvironmentVMCloudInitIPConfigIPv6: {
Type: schema.TypeList,
Description: "The IPv6 configuration",
Optional: true,
DefaultFunc: func() (interface{}, error) {
return make([]interface{}, 0), nil
},
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
mkResourceVirtualEnvironmentVMCloudInitIPConfigIPv6Address: {
Type: schema.TypeString,
Optional: true,
Description: "The IPv6 address",
Default: "",
},
mkResourceVirtualEnvironmentVMCloudInitIPConfigIPv6Gateway: {
Type: schema.TypeString,
Optional: true,
Description: "The IPv6 gateway",
Default: "",
},
},
},
MaxItems: 1,
MinItems: 0,
},
},
},
MaxItems: 8,
MinItems: 0,
},
mkResourceVirtualEnvironmentVMCloudInitUserAccount: {
Type: schema.TypeList,
Description: "The user account configuration",
Required: true,
DefaultFunc: func() (interface{}, error) {
return make([]interface{}, 0), nil
},
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
mkResourceVirtualEnvironmentVMCloudInitUserAccountKeys: {
Type: schema.TypeList,
Required: true,
Description: "The SSH keys",
Elem: &schema.Schema{Type: schema.TypeString},
},
mkResourceVirtualEnvironmentVMCloudInitUserAccountUsername: {
Type: schema.TypeString,
Required: true,
Description: "The SSH username",
},
},
},
MaxItems: 1,
MinItems: 0,
},
},
},
MaxItems: 1,
MinItems: 0,
},
mkResourceVirtualEnvironmentVMCPU: &schema.Schema{
Type: schema.TypeList,
Description: "The CPU allocation",
Optional: true,
DefaultFunc: func() (interface{}, error) {
defaultList := make([]interface{}, 1)
defaultMap := make(map[string]interface{})
defaultMap[mkResourceVirtualEnvironmentVMCPUCores] = dvResourceVirtualEnvironmentVMCPUCores
defaultMap[mkResourceVirtualEnvironmentVMCPUHotplugged] = dvResourceVirtualEnvironmentVMCPUHotplugged
defaultMap[mkResourceVirtualEnvironmentVMCPUSockets] = dvResourceVirtualEnvironmentVMCPUSockets
defaultList[0] = defaultMap
return defaultList, nil
},
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
mkResourceVirtualEnvironmentVMCPUCores: {
Type: schema.TypeInt,
Optional: true,
Description: "The number of CPU cores",
Default: dvResourceVirtualEnvironmentVMCPUCores,
ValidateFunc: validation.IntBetween(1, 2304),
},
mkResourceVirtualEnvironmentVMCPUHotplugged: {
Type: schema.TypeInt,
Optional: true,
Description: "The number of hotplugged vCPUs",
Default: dvResourceVirtualEnvironmentVMCPUHotplugged,
ValidateFunc: validation.IntBetween(0, 2304),
},
mkResourceVirtualEnvironmentVMCPUSockets: {
Type: schema.TypeInt,
Optional: true,
Description: "The number of CPU sockets",
Default: dvResourceVirtualEnvironmentVMCPUSockets,
ValidateFunc: validation.IntBetween(1, 16),
},
},
},
MaxItems: 1,
MinItems: 0,
},
mkResourceVirtualEnvironmentVMDescription: {
Type: schema.TypeString,
Optional: true,
Description: "The description",
Default: dvResourceVirtualEnvironmentVMDescription,
},
mkResourceVirtualEnvironmentVMDisk: &schema.Schema{
Type: schema.TypeList,
Description: "The disk devices",
Optional: true,
DefaultFunc: func() (interface{}, error) {
defaultList := make([]interface{}, 1)
defaultMap := make(map[string]interface{})
defaultMap[mkResourceVirtualEnvironmentVMDiskDatastoreID] = dvResourceVirtualEnvironmentVMDiskDatastoreID
defaultMap[mkResourceVirtualEnvironmentVMDiskFileFormat] = dvResourceVirtualEnvironmentVMDiskFileFormat
defaultMap[mkResourceVirtualEnvironmentVMDiskFileID] = dvResourceVirtualEnvironmentVMDiskFileID
defaultMap[mkResourceVirtualEnvironmentVMDiskSize] = dvResourceVirtualEnvironmentVMDiskSize
defaultList[0] = defaultMap
return defaultList, nil
},
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
mkResourceVirtualEnvironmentVMDiskDatastoreID: {
Type: schema.TypeString,
Optional: true,
Description: "The datastore id",
Default: dvResourceVirtualEnvironmentVMDiskDatastoreID,
},
mkResourceVirtualEnvironmentVMDiskEnabled: {
Type: schema.TypeBool,
Optional: true,
Description: "Whether to enable the disk",
Default: dvResourceVirtualEnvironmentVMDiskEnabled,
},
mkResourceVirtualEnvironmentVMDiskFileFormat: {
Type: schema.TypeString,
Optional: true,
Description: "The file format",
Default: dvResourceVirtualEnvironmentVMDiskFileFormat,
ValidateFunc: getFileFormatValidator(),
},
mkResourceVirtualEnvironmentVMDiskFileID: {
Type: schema.TypeString,
Optional: true,
Description: "The file id for a disk image",
Default: dvResourceVirtualEnvironmentVMDiskFileID,
ValidateFunc: getFileIDValidator(),
},
mkResourceVirtualEnvironmentVMDiskSize: {
Type: schema.TypeInt,
Optional: true,
Description: "The disk size in gigabytes",
Default: dvResourceVirtualEnvironmentVMDiskSize,
ValidateFunc: validation.IntBetween(1, 8192),
},
},
},
MaxItems: 14,
MinItems: 0,
},
mkResourceVirtualEnvironmentVMKeyboardLayout: {
Type: schema.TypeString,
Optional: true,
Description: "The keyboard layout",
Default: dvResourceVirtualEnvironmentVMKeyboardLayout,
ValidateFunc: getKeyboardLayoutValidator(),
},
mkResourceVirtualEnvironmentVMMemory: &schema.Schema{
Type: schema.TypeList,
Description: "The memory allocation",
Optional: true,
DefaultFunc: func() (interface{}, error) {
defaultList := make([]interface{}, 1)
defaultMap := make(map[string]interface{})
defaultMap[mkResourceVirtualEnvironmentVMMemoryDedicated] = dvResourceVirtualEnvironmentVMMemoryDedicated
defaultMap[mkResourceVirtualEnvironmentVMMemoryFloating] = dvResourceVirtualEnvironmentVMMemoryFloating
defaultMap[mkResourceVirtualEnvironmentVMMemoryShared] = dvResourceVirtualEnvironmentVMMemoryShared
defaultList[0] = defaultMap
return defaultList, nil
},
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
mkResourceVirtualEnvironmentVMMemoryDedicated: {
Type: schema.TypeInt,
Optional: true,
Description: "The dedicated memory in megabytes",
Default: dvResourceVirtualEnvironmentVMMemoryDedicated,
ValidateFunc: validation.IntBetween(64, 268435456),
},
mkResourceVirtualEnvironmentVMMemoryFloating: {
Type: schema.TypeInt,
Optional: true,
Description: "The floating memory in megabytes (balloon)",
Default: dvResourceVirtualEnvironmentVMMemoryFloating,
ValidateFunc: validation.IntBetween(0, 268435456),
},
mkResourceVirtualEnvironmentVMMemoryShared: {
Type: schema.TypeInt,
Optional: true,
Description: "The shared memory in megabytes",
Default: dvResourceVirtualEnvironmentVMMemoryShared,
ValidateFunc: validation.IntBetween(0, 268435456),
},
},
},
MaxItems: 1,
MinItems: 0,
},
mkResourceVirtualEnvironmentVMName: {
Type: schema.TypeString,
Optional: true,
Description: "The name",
Default: dvResourceVirtualEnvironmentVMName,
},
mkResourceVirtualEnvironmentVMNetworkDevice: &schema.Schema{
Type: schema.TypeList,
Description: "The network devices",
Optional: true,
DefaultFunc: func() (interface{}, error) {
return make([]interface{}, 1), nil
},
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
mkResourceVirtualEnvironmentVMNetworkDeviceBridge: {
Type: schema.TypeString,
Optional: true,
Description: "The bridge",
Default: dvResourceVirtualEnvironmentVMNetworkDeviceBridge,
},
mkResourceVirtualEnvironmentVMNetworkDeviceEnabled: {
Type: schema.TypeBool,
Optional: true,
Description: "Whether to enable the network device",
Default: dvResourceVirtualEnvironmentVMNetworkDeviceEnabled,
},
mkResourceVirtualEnvironmentVMNetworkDeviceMACAddress: {
Type: schema.TypeString,
Optional: true,
Description: "The MAC address",
Default: dvResourceVirtualEnvironmentVMNetworkDeviceMACAddress,
ValidateFunc: getMACAddressValidator(),
},
mkResourceVirtualEnvironmentVMNetworkDeviceModel: {
Type: schema.TypeString,
Optional: true,
Description: "The model",
Default: dvResourceVirtualEnvironmentVMNetworkDeviceModel,
ValidateFunc: getNetworkDeviceModelValidator(),
},
mkResourceVirtualEnvironmentVMNetworkDeviceVLANID: {
Type: schema.TypeInt,
Optional: true,
Description: "The VLAN identifier",
Default: dvResourceVirtualEnvironmentVMNetworkDeviceVLANID,
ValidateFunc: getVLANIDValidator(),
},
},
},
MaxItems: 8,
MinItems: 0,
},
mkResourceVirtualEnvironmentVMNodeName: &schema.Schema{
Type: schema.TypeString,
Description: "The node name",
Required: true,
},
mkResourceVirtualEnvironmentVMOSType: {
Type: schema.TypeString,
Optional: true,
Description: "The OS type",
Default: dvResourceVirtualEnvironmentVMOSType,
ValidateFunc: getOSTypeValidator(),
},
mkResourceVirtualEnvironmentVMPoolID: {
Type: schema.TypeString,
Optional: true,
Description: "The ID of the pool to assign the virtual machine to",
Default: dvResourceVirtualEnvironmentVMPoolID,
},
mkResourceVirtualEnvironmentVMVMID: {
Type: schema.TypeInt,
Optional: true,
ForceNew: true,
Description: "The VM identifier",
Default: dvResourceVirtualEnvironmentVMVMID,
ValidateFunc: getVMIDValidator(),
},
},
Create: resourceVirtualEnvironmentVMCreate,
Read: resourceVirtualEnvironmentVMRead,
Update: resourceVirtualEnvironmentVMUpdate,
Delete: resourceVirtualEnvironmentVMDelete,
}
}
func resourceVirtualEnvironmentVMCreate(d *schema.ResourceData, m interface{}) error {
config := m.(providerConfiguration)
veClient, err := config.GetVEClient()
if err != nil {
return err
}
schema := resourceVirtualEnvironmentVM().Schema
agent := d.Get(mkResourceVirtualEnvironmentVMAgent).([]interface{})
if len(agent) == 0 {
agentDefault, err := schema[mkResourceVirtualEnvironmentVMAgent].DefaultValue()
if err != nil {
return err
}
agent = agentDefault.([]interface{})
}
agentBlock := agent[0].(map[string]interface{})
agentEnabled := proxmox.CustomBool(agentBlock[mkResourceVirtualEnvironmentVMAgentEnabled].(bool))
agentTrim := proxmox.CustomBool(agentBlock[mkResourceVirtualEnvironmentVMAgentTrim].(bool))
agentType := agentBlock[mkResourceVirtualEnvironmentVMAgentType].(string)
cdrom := d.Get(mkResourceVirtualEnvironmentVMCDROM).([]interface{})
if len(cdrom) == 0 {
cdromDefault, err := schema[mkResourceVirtualEnvironmentVMCDROM].DefaultValue()
if err != nil {
return err
}
cdrom = cdromDefault.([]interface{})
}
cdromBlock := cdrom[0].(map[string]interface{})
cdromEnabled := cdromBlock[mkResourceVirtualEnvironmentVMCDROMEnabled].(bool)
cdromFileID := cdromBlock[mkResourceVirtualEnvironmentVMCDROMFileID].(string)
if cdromFileID == "" {
cdromFileID = "cdrom"
}
var cloudInitConfig *proxmox.CustomCloudInitConfig
cloudInit := d.Get(mkResourceVirtualEnvironmentVMCloudInit).([]interface{})
if len(cloudInit) > 0 {
cdromEnabled = true
cdromFileID = "local-lvm:cloudinit"
cloudInitBlock := cloudInit[0].(map[string]interface{})
cloudInitConfig = &proxmox.CustomCloudInitConfig{}
cloudInitDNS := cloudInitBlock[mkResourceVirtualEnvironmentVMCloudInitDNS].([]interface{})
if len(cloudInitDNS) > 0 {
cloudInitDNSBlock := cloudInitDNS[0].(map[string]interface{})
domain := cloudInitDNSBlock[mkResourceVirtualEnvironmentVMCloudInitDNSDomain].(string)
if domain != "" {
cloudInitConfig.SearchDomain = &domain
}
server := cloudInitDNSBlock[mkResourceVirtualEnvironmentVMCloudInitDNSServer].(string)
if server != "" {
cloudInitConfig.Nameserver = &server
}
}
cloudInitIPConfig := cloudInitBlock[mkResourceVirtualEnvironmentVMCloudInitIPConfig].([]interface{})
cloudInitConfig.IPConfig = make([]proxmox.CustomCloudInitIPConfig, len(cloudInitIPConfig))
for i, c := range cloudInitIPConfig {
configBlock := c.(map[string]interface{})
ipv4 := configBlock[mkResourceVirtualEnvironmentVMCloudInitIPConfigIPv4].([]interface{})
if len(ipv4) > 0 {
ipv4Block := ipv4[0].(map[string]interface{})
ipv4Address := ipv4Block[mkResourceVirtualEnvironmentVMCloudInitIPConfigIPv4Address].(string)
if ipv4Address != "" {
cloudInitConfig.IPConfig[i].IPv4 = &ipv4Address
}
ipv4Gateway := ipv4Block[mkResourceVirtualEnvironmentVMCloudInitIPConfigIPv4Gateway].(string)
if ipv4Gateway != "" {
cloudInitConfig.IPConfig[i].GatewayIPv4 = &ipv4Gateway
}
}
ipv6 := configBlock[mkResourceVirtualEnvironmentVMCloudInitIPConfigIPv6].([]interface{})
if len(ipv6) > 0 {
ipv6Block := ipv6[0].(map[string]interface{})
ipv6Address := ipv6Block[mkResourceVirtualEnvironmentVMCloudInitIPConfigIPv6Address].(string)
if ipv6Address != "" {
cloudInitConfig.IPConfig[i].IPv6 = &ipv6Address
}
ipv6Gateway := ipv6Block[mkResourceVirtualEnvironmentVMCloudInitIPConfigIPv6Gateway].(string)
if ipv6Gateway != "" {
cloudInitConfig.IPConfig[i].GatewayIPv6 = &ipv6Gateway
}
}
}
cloudInitUserAccount := cloudInitBlock[mkResourceVirtualEnvironmentVMCloudInitUserAccount].([]interface{})
if len(cloudInitUserAccount) > 0 {
cloudInitUserAccountBlock := cloudInitUserAccount[0].(map[string]interface{})
keys := cloudInitUserAccountBlock[mkResourceVirtualEnvironmentVMCloudInitUserAccountKeys].([]interface{})
if len(keys) > 0 {
sshKeys := make(proxmox.CustomCloudInitSSHKeys, len(keys))
for i, k := range keys {
sshKeys[i] = k.(string)
}
cloudInitConfig.SSHKeys = &sshKeys
}
username := cloudInitUserAccountBlock[mkResourceVirtualEnvironmentVMCloudInitUserAccountUsername].(string)
cloudInitConfig.Username = &username
}
}
cpu := d.Get(mkResourceVirtualEnvironmentVMCPU).([]interface{})
if len(cpu) == 0 {
cpuDefault, err := schema[mkResourceVirtualEnvironmentVMCPU].DefaultValue()
if err != nil {
return err
}
cpu = cpuDefault.([]interface{})
}
cpuBlock := cpu[0].(map[string]interface{})
cpuCores := cpuBlock[mkResourceVirtualEnvironmentVMCPUCores].(int)
cpuHotplugged := cpuBlock[mkResourceVirtualEnvironmentVMCPUHotplugged].(int)
cpuSockets := cpuBlock[mkResourceVirtualEnvironmentVMCPUSockets].(int)
description := d.Get(mkResourceVirtualEnvironmentVMDescription).(string)
disk := d.Get(mkResourceVirtualEnvironmentVMDisk).([]interface{})
scsiDevices := make(proxmox.CustomStorageDevices, len(disk))
for i, d := range disk {
block := d.(map[string]interface{})
datastoreID, _ := block[mkResourceVirtualEnvironmentVMDiskDatastoreID].(string)
enabled, _ := block[mkResourceVirtualEnvironmentVMDiskEnabled].(bool)
fileID, _ := block[mkResourceVirtualEnvironmentVMDiskFileID].(string)
size, _ := block[mkResourceVirtualEnvironmentVMDiskSize].(int)
diskDevice := proxmox.CustomStorageDevice{
Enabled: enabled,
}
if fileID != "" {
diskDevice.Enabled = false
} else {
diskDevice.FileVolume = fmt.Sprintf("%s:%d", datastoreID, size)
}
scsiDevices[i] = diskDevice
}
keyboardLayout := d.Get(mkResourceVirtualEnvironmentVMKeyboardLayout).(string)
memory := d.Get(mkResourceVirtualEnvironmentVMMemory).([]interface{})
if len(memory) == 0 {
memoryDefault, err := schema[mkResourceVirtualEnvironmentVMMemory].DefaultValue()
if err != nil {
return err
}
memory = memoryDefault.([]interface{})
}
memoryBlock := memory[0].(map[string]interface{})
memoryDedicated := memoryBlock[mkResourceVirtualEnvironmentVMMemoryDedicated].(int)
memoryFloating := memoryBlock[mkResourceVirtualEnvironmentVMMemoryFloating].(int)
memoryShared := memoryBlock[mkResourceVirtualEnvironmentVMMemoryShared].(int)
name := d.Get(mkResourceVirtualEnvironmentVMName).(string)
networkDevice := d.Get(mkResourceVirtualEnvironmentVMNetworkDevice).([]interface{})
networkDeviceObjects := make(proxmox.CustomNetworkDevices, len(networkDevice))
for i, d := range networkDevice {
block := d.(map[string]interface{})
bridge, _ := block[mkResourceVirtualEnvironmentVMNetworkDeviceBridge].(string)
enabled, _ := block[mkResourceVirtualEnvironmentVMNetworkDeviceEnabled].(bool)
macAddress, _ := block[mkResourceVirtualEnvironmentVMNetworkDeviceMACAddress].(string)
model, _ := block[mkResourceVirtualEnvironmentVMNetworkDeviceModel].(string)
vlanID, _ := block[mkResourceVirtualEnvironmentVMNetworkDeviceVLANID].(int)
device := proxmox.CustomNetworkDevice{
Enabled: enabled,
Model: model,
}
if bridge != "" {
device.Bridge = &bridge
}
if macAddress != "" {
device.MACAddress = &macAddress
}
if vlanID != -1 {
device.Trunks = []int{vlanID}
}
networkDeviceObjects[i] = device
}
nodeName := d.Get(mkResourceVirtualEnvironmentVMNodeName).(string)
osType := d.Get(mkResourceVirtualEnvironmentVMOSType).(string)
poolID := d.Get(mkResourceVirtualEnvironmentVMPoolID).(string)
vmID := d.Get(mkResourceVirtualEnvironmentVMVMID).(int)
if vmID == -1 {
vmIDNew, err := veClient.GetVMID()
if err != nil {
return err
}
vmID = *vmIDNew
}
var memorySharedObject *proxmox.CustomSharedMemory
bootDisk := "scsi0"
bootOrder := "c"
if cdromEnabled {
bootOrder = "cd"
}
ideDevice2Media := "cdrom"
ideDevices := proxmox.CustomStorageDevices{
proxmox.CustomStorageDevice{
Enabled: false,
},
proxmox.CustomStorageDevice{
Enabled: false,
},
proxmox.CustomStorageDevice{
Enabled: cdromEnabled,
FileVolume: cdromFileID,
Media: &ideDevice2Media,
},
}
if memoryShared > 0 {
memorySharedName := fmt.Sprintf("vm-%d-ivshmem", vmID)
memorySharedObject = &proxmox.CustomSharedMemory{
Name: &memorySharedName,
Size: memoryShared,
}
}
scsiHardware := "virtio-scsi-pci"
tabletDeviceEnabled := proxmox.CustomBool(true)
body := &proxmox.VirtualEnvironmentVMCreateRequestBody{
Agent: &proxmox.CustomAgent{
Enabled: &agentEnabled,
TrimClonedDisks: &agentTrim,
Type: &agentType,
},
BootDisk: &bootDisk,
BootOrder: &bootOrder,
CloudInitConfig: cloudInitConfig,
CPUCores: &cpuCores,
CPUSockets: &cpuSockets,
DedicatedMemory: &memoryDedicated,
FloatingMemory: &memoryFloating,
IDEDevices: ideDevices,
KeyboardLayout: &keyboardLayout,
NetworkDevices: networkDeviceObjects,
OSType: &osType,
SCSIDevices: scsiDevices,
SCSIHardware: &scsiHardware,
SerialDevices: []string{"socket"},
SharedMemory: memorySharedObject,
TabletDeviceEnabled: &tabletDeviceEnabled,
VMID: &vmID,
}
if cpuHotplugged > 0 {
body.VirtualCPUCount = &cpuHotplugged
}
if description != "" {
body.Description = &description
}
if name != "" {
body.Name = &name
}
if poolID != "" {
body.PoolID = &poolID
}
err = veClient.CreateVM(nodeName, body)
if err != nil {
return err
}
d.SetId(strconv.Itoa(vmID))
return resourceVirtualEnvironmentVMCreateImportedDisks(d, m)
}
func resourceVirtualEnvironmentVMCreateImportedDisks(d *schema.ResourceData, m interface{}) error {
config := m.(providerConfiguration)
veClient, err := config.GetVEClient()
if err != nil {
return err
}
nodeName := d.Get(mkResourceVirtualEnvironmentVMNodeName).(string)
vmID, err := strconv.Atoi(d.Id())
if err != nil {
return err
}
commands := []string{}
// Determine the ID of the next disk.
disk := d.Get(mkResourceVirtualEnvironmentVMDisk).([]interface{})
diskCount := 0
for _, d := range disk {
block := d.(map[string]interface{})
fileID, _ := block[mkResourceVirtualEnvironmentVMDiskFileID].(string)
if fileID == "" {
diskCount++
}
}
// Generate the commands required to import the specified disks.
importedDiskCount := 0
for i, d := range disk {
block := d.(map[string]interface{})
datastoreID, _ := block[mkResourceVirtualEnvironmentVMDiskDatastoreID].(string)
enabled, _ := block[mkResourceVirtualEnvironmentVMDiskEnabled].(bool)
fileFormat, _ := block[mkResourceVirtualEnvironmentVMDiskFileFormat].(string)
fileID, _ := block[mkResourceVirtualEnvironmentVMDiskFileID].(string)
size, _ := block[mkResourceVirtualEnvironmentVMDiskSize].(int)
if !enabled || fileID == "" {
continue
}
fileIDParts := strings.Split(fileID, ":")
filePath := fmt.Sprintf("/var/lib/vz/template/%s", fileIDParts[1])
filePathTmp := fmt.Sprintf("/tmp/vm-%d-disk-%d.%s", vmID, diskCount+importedDiskCount, fileFormat)
commands = append(
commands,
fmt.Sprintf("cp %s %s", filePath, filePathTmp),
fmt.Sprintf("qemu-img resize %s %dG", filePathTmp, size),
fmt.Sprintf("qm importdisk %d %s %s -format qcow2", vmID, filePathTmp, datastoreID),
fmt.Sprintf("qm set %d --scsi%d %s:vm-%d-disk-%d", vmID, i, datastoreID, vmID, diskCount+importedDiskCount),
fmt.Sprintf("rm -f %s", filePathTmp),
)
importedDiskCount++
}
// Execute the commands on the node and wait for the result.
// This is a highly experimental approach to disk imports and is not recommended by Proxmox.
if len(commands) > 0 {
err = veClient.ExecuteNodeCommands(nodeName, commands)
if err != nil {
return err
}
}
return resourceVirtualEnvironmentVMCreateStart(d, m)
}
func resourceVirtualEnvironmentVMCreateStart(d *schema.ResourceData, m interface{}) error {
config := m.(providerConfiguration)
veClient, err := config.GetVEClient()
if err != nil {
return err
}
nodeName := d.Get(mkResourceVirtualEnvironmentVMNodeName).(string)
vmID, err := strconv.Atoi(d.Id())
if err != nil {
return err
}
// Start the virtual machine and wait for it to reach a running state before continuing.
err = veClient.StartVM(nodeName, vmID)
if err != nil {
return err
}
err = veClient.WaitForState(nodeName, vmID, "running", 120, 5)
if err != nil {
return err
}
return resourceVirtualEnvironmentVMRead(d, m)
}
func resourceVirtualEnvironmentVMRead(d *schema.ResourceData, m interface{}) error {
/*
config := m.(providerConfiguration)
veClient, err := config.GetVEClient()
if err != nil {
return err
}
*/
return nil
}
func resourceVirtualEnvironmentVMUpdate(d *schema.ResourceData, m interface{}) error {
/*
config := m.(providerConfiguration)
veClient, err := config.GetVEClient()
if err != nil {
return err
}
*/
return resourceVirtualEnvironmentVMRead(d, m)
}
func resourceVirtualEnvironmentVMDelete(d *schema.ResourceData, m interface{}) error {
config := m.(providerConfiguration)
veClient, err := config.GetVEClient()
if err != nil {
return err
}
nodeName := d.Get(mkResourceVirtualEnvironmentVMNodeName).(string)
vmID, err := strconv.Atoi(d.Id())
if err != nil {
return err
}
// Shut down the virtual machine before deleting it.
forceStop := proxmox.CustomBool(true)
shutdownTimeout := 300
err = veClient.ShutdownVM(nodeName, vmID, &proxmox.VirtualEnvironmentVMShutdownRequestBody{
ForceStop: &forceStop,
Timeout: &shutdownTimeout,
})
if err != nil {
return err
}
err = veClient.WaitForState(nodeName, vmID, "stopped", 30, 5)
if err != nil {
return err
}
err = veClient.DeleteVM(nodeName, vmID)
if err != nil {
if strings.Contains(err.Error(), "HTTP 404") {
d.SetId("")
return nil
}
return err
}
// Wait for the state to become unavailable as that clearly indicates the destruction of the VM.
err = veClient.WaitForState(nodeName, vmID, "", 30, 2)
if err == nil {
return fmt.Errorf("Failed to delete VM \"%d\"", vmID)
}
d.SetId("")
return nil
}