mirror of
https://github.com/bpg/terraform-provider-proxmox.git
synced 2025-07-10 07:45:02 +00:00
Initial support for remote-exec provisioners
This commit is contained in:
parent
5d5f1c1835
commit
1dfe979e9e
@ -426,7 +426,9 @@ This resource doesn't expose any additional attributes.
|
||||
* `vm_id` - (Optional) The ID
|
||||
|
||||
###### Attributes
|
||||
This resource doesn't expose any additional attributes.
|
||||
* `ipv4_addresses` - The IPv4 addresses per network interface published by the QEMU agent (empty list when `agent.enabled` is `false`)
|
||||
* `ipv6_addresses` - The IPv6 addresses per network interface published by the QEMU agent (empty list when `agent.enabled` is `false`)
|
||||
* `network_interface_names` - The network interface names published by the QEMU agent (empty list when `agent.enabled` is `false`)
|
||||
|
||||
## Developing the Provider
|
||||
If you wish to work on the provider, you'll first need [Go](http://www.golang.org) installed on your machine (version 1.13+ is *required*). You'll also need to correctly setup a [GOPATH](http://golang.org/doc/code.html#GOPATH), as well as adding `$GOPATH/bin` to your `$PATH`.
|
||||
|
@ -8,7 +8,7 @@ resource "proxmox_virtual_environment_file" "ubuntu_cloud_image" {
|
||||
}
|
||||
}
|
||||
|
||||
resource "proxmox_virtual_environment_file" "cloud_init_config" {
|
||||
resource "proxmox_virtual_environment_file" "cloud_config" {
|
||||
content_type = "snippets"
|
||||
datastore_id = "${element(data.proxmox_virtual_environment_datastores.example.datastore_ids, index(data.proxmox_virtual_environment_datastores.example.datastore_ids, "local"))}"
|
||||
node_name = "${data.proxmox_virtual_environment_datastores.example.node_name}"
|
||||
@ -19,7 +19,7 @@ resource "proxmox_virtual_environment_file" "cloud_init_config" {
|
||||
chpasswd:
|
||||
list: |
|
||||
ubuntu:example
|
||||
expire: False
|
||||
expire: false
|
||||
hostname: terraform-provider-proxmox-example
|
||||
packages:
|
||||
- qemu-guest-agent
|
||||
@ -33,7 +33,7 @@ users:
|
||||
sudo: ALL=(ALL) NOPASSWD:ALL
|
||||
EOF
|
||||
|
||||
file_name = "terraform-provider-proxmox-example-cloud-init.yaml"
|
||||
file_name = "terraform-provider-proxmox-example-cloud-config.yaml"
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -16,11 +16,11 @@ resource "proxmox_virtual_environment_vm" "example" {
|
||||
|
||||
user_account {
|
||||
keys = ["${trimspace(tls_private_key.example.public_key_openssh)}"]
|
||||
password = "proxmoxtf"
|
||||
password = "example"
|
||||
username = "ubuntu"
|
||||
}
|
||||
|
||||
user_data_file_id = "${proxmox_virtual_environment_file.cloud_init_config.id}"
|
||||
user_data_file_id = "${proxmox_virtual_environment_file.cloud_config.id}"
|
||||
}
|
||||
|
||||
disk {
|
||||
@ -34,6 +34,20 @@ resource "proxmox_virtual_environment_vm" "example" {
|
||||
os_type = "l26"
|
||||
pool_id = "${proxmox_virtual_environment_pool.example.id}"
|
||||
vm_id = 2038
|
||||
|
||||
connection {
|
||||
type = "ssh"
|
||||
agent = false
|
||||
host = "${element(element(self.ipv4_addresses, index(self.network_interface_names, "eth0")), 0)}"
|
||||
private_key = "${tls_private_key.example.private_key_pem}"
|
||||
user = "ubuntu"
|
||||
}
|
||||
|
||||
provisioner "remote-exec" {
|
||||
inline = [
|
||||
"echo Welcome to $(hostname)!",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
resource "local_file" "example_ssh_private_key" {
|
||||
@ -54,3 +68,15 @@ resource "tls_private_key" "example" {
|
||||
output "resource_proxmox_virtual_environment_vm_example_id" {
|
||||
value = "${proxmox_virtual_environment_vm.example.id}"
|
||||
}
|
||||
|
||||
output "resource_proxmox_virtual_environment_vm_example_ipv4_addresses" {
|
||||
value = "${proxmox_virtual_environment_vm.example.ipv4_addresses}"
|
||||
}
|
||||
|
||||
output "resource_proxmox_virtual_environment_vm_example_ipv6_addresses" {
|
||||
value = "${proxmox_virtual_environment_vm.example.ipv6_addresses}"
|
||||
}
|
||||
|
||||
output "resource_proxmox_virtual_environment_vm_example_network_interface_names" {
|
||||
value = "${proxmox_virtual_environment_vm.example.network_interface_names}"
|
||||
}
|
||||
|
@ -66,6 +66,22 @@ VMID:
|
||||
return nil, errors.New("Unable to retrieve the next available VM identifier")
|
||||
}
|
||||
|
||||
// GetVMNetworkInterfacesFromAgent retrieves the network interfaces reported by the QEMU agent.
|
||||
func (c *VirtualEnvironmentClient) GetVMNetworkInterfacesFromAgent(nodeName string, vmID int) (*VirtualEnvironmentVMGetQEMUNetworkInterfacesResponseData, error) {
|
||||
resBody := &VirtualEnvironmentVMGetQEMUNetworkInterfacesResponseBody{}
|
||||
err := c.DoRequest(hmGET, fmt.Sprintf("nodes/%s/qemu/%d/agent/network-get-interfaces", url.PathEscape(nodeName), vmID), nil, resBody)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if resBody.Data == nil {
|
||||
return nil, errors.New("The server did not include a data object in the response")
|
||||
}
|
||||
|
||||
return resBody.Data, nil
|
||||
}
|
||||
|
||||
// GetVMStatus retrieves the status for a virtual machine.
|
||||
func (c *VirtualEnvironmentClient) GetVMStatus(nodeName string, vmID int) (*VirtualEnvironmentVMGetStatusResponseData, error) {
|
||||
resBody := &VirtualEnvironmentVMGetStatusResponseBody{}
|
||||
@ -112,6 +128,32 @@ func (c *VirtualEnvironmentClient) UpdateVMAsync(nodeName string, vmID int, d *V
|
||||
return c.DoRequest(hmPOST, fmt.Sprintf("nodes/%s/qemu/%d/config", url.PathEscape(nodeName), vmID), d, nil)
|
||||
}
|
||||
|
||||
// WaitForNetworkInterfacesFromAgent waits for a virtual machine's QEMU agent to publish the network interfaces.
|
||||
func (c *VirtualEnvironmentClient) WaitForNetworkInterfacesFromAgent(nodeName string, vmID int, timeout int, delay int) (*VirtualEnvironmentVMGetQEMUNetworkInterfacesResponseData, error) {
|
||||
timeDelay := int64(delay)
|
||||
timeMax := float64(timeout)
|
||||
timeStart := time.Now()
|
||||
timeElapsed := timeStart.Sub(timeStart)
|
||||
|
||||
for timeElapsed.Seconds() < timeMax {
|
||||
if int64(timeElapsed.Seconds())%timeDelay == 0 {
|
||||
data, err := c.GetVMNetworkInterfacesFromAgent(nodeName, vmID)
|
||||
|
||||
if err == nil && data != nil {
|
||||
return data, err
|
||||
}
|
||||
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
|
||||
timeElapsed = time.Now().Sub(timeStart)
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("Timeout while waiting for the QEMU agent on VM \"%d\" to publish the network interfaces", vmID)
|
||||
}
|
||||
|
||||
// WaitForState waits for a virtual machine to reach a specific state.
|
||||
func (c *VirtualEnvironmentClient) WaitForState(nodeName string, vmID int, state string, timeout int, delay int) error {
|
||||
state = strings.ToLower(state)
|
||||
@ -141,5 +183,5 @@ func (c *VirtualEnvironmentClient) WaitForState(nodeName string, vmID int, state
|
||||
timeElapsed = time.Now().Sub(timeStart)
|
||||
}
|
||||
|
||||
return fmt.Errorf("Failed to wait for VM \"%d\" to enter the state \"%s\"", vmID, state)
|
||||
return fmt.Errorf("Timeout while waiting for VM \"%d\" to enter the state \"%s\"", vmID, state)
|
||||
}
|
||||
|
@ -258,6 +258,43 @@ type VirtualEnvironmentVMCreateRequestBody struct {
|
||||
WatchdogDevice *CustomWatchdogDevice `json:"watchdog,omitempty" url:"watchdog,omitempty"`
|
||||
}
|
||||
|
||||
// VirtualEnvironmentVMGetQEMUNetworkInterfacesResponseBody contains the body from a QEMU get network interfaces response.
|
||||
type VirtualEnvironmentVMGetQEMUNetworkInterfacesResponseBody struct {
|
||||
Data *VirtualEnvironmentVMGetQEMUNetworkInterfacesResponseData `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
// VirtualEnvironmentVMGetQEMUNetworkInterfacesResponseData contains the data from a QEMU get network interfaces response.
|
||||
type VirtualEnvironmentVMGetQEMUNetworkInterfacesResponseData struct {
|
||||
Result *[]VirtualEnvironmentVMGetQEMUNetworkInterfacesResponseResult `json:"result,omitempty"`
|
||||
}
|
||||
|
||||
// VirtualEnvironmentVMGetQEMUNetworkInterfacesResponseResult contains the result from a QEMU get network interfaces response.
|
||||
type VirtualEnvironmentVMGetQEMUNetworkInterfacesResponseResult struct {
|
||||
MACAddress string `json:"hardware-address"`
|
||||
Name string `json:"name"`
|
||||
Statistics VirtualEnvironmentVMGetQEMUNetworkInterfacesResponseResultStatistics `json:"statistics"`
|
||||
IPAddresses *[]VirtualEnvironmentVMGetQEMUNetworkInterfacesResponseResultIPAddress `json:"ip-addresses,omitempty"`
|
||||
}
|
||||
|
||||
// VirtualEnvironmentVMGetQEMUNetworkInterfacesResponseResultIPAddress contains the IP address from a QEMU get network interfaces response.
|
||||
type VirtualEnvironmentVMGetQEMUNetworkInterfacesResponseResultIPAddress struct {
|
||||
Address string `json:"ip-address"`
|
||||
Prefix int `json:"prefix"`
|
||||
Type string `json:"ip-address-type"`
|
||||
}
|
||||
|
||||
// VirtualEnvironmentVMGetQEMUNetworkInterfacesResponseResultStatistics contains the statistics from a QEMU get network interfaces response.
|
||||
type VirtualEnvironmentVMGetQEMUNetworkInterfacesResponseResultStatistics struct {
|
||||
RXBytes int `json:"rx-bytes"`
|
||||
RXDropped int `json:"rx-dropped"`
|
||||
RXErrors int `json:"rx-errs"`
|
||||
RXPackets int `json:"rx-packets"`
|
||||
TXBytes int `json:"tx-bytes"`
|
||||
TXDropped int `json:"tx-dropped"`
|
||||
TXErrors int `json:"tx-errs"`
|
||||
TXPackets int `json:"tx-packets"`
|
||||
}
|
||||
|
||||
// VirtualEnvironmentVMGetResponseBody contains the body from an virtual machine get response.
|
||||
type VirtualEnvironmentVMGetResponseBody struct {
|
||||
Data *VirtualEnvironmentVMGetResponseData `json:"data,omitempty"`
|
||||
|
@ -89,6 +89,8 @@ const (
|
||||
mkResourceVirtualEnvironmentVMDiskSpeedReadBurstable = "read_burstable"
|
||||
mkResourceVirtualEnvironmentVMDiskSpeedWrite = "write"
|
||||
mkResourceVirtualEnvironmentVMDiskSpeedWriteBurstable = "write_burstable"
|
||||
mkResourceVirtualEnvironmentVMIPv4Addresses = "ipv4_addresses"
|
||||
mkResourceVirtualEnvironmentVMIPv6Addresses = "ipv6_addresses"
|
||||
mkResourceVirtualEnvironmentVMKeyboardLayout = "keyboard_layout"
|
||||
mkResourceVirtualEnvironmentVMMemory = "memory"
|
||||
mkResourceVirtualEnvironmentVMMemoryDedicated = "dedicated"
|
||||
@ -101,6 +103,7 @@ const (
|
||||
mkResourceVirtualEnvironmentVMNetworkDeviceMACAddress = "mac_address"
|
||||
mkResourceVirtualEnvironmentVMNetworkDeviceModel = "model"
|
||||
mkResourceVirtualEnvironmentVMNetworkDeviceVLANIDs = "vlan_ids"
|
||||
mkResourceVirtualEnvironmentVMNetworkInterfaceNames = "network_interface_names"
|
||||
mkResourceVirtualEnvironmentVMNodeName = "node_name"
|
||||
mkResourceVirtualEnvironmentVMOSType = "os_type"
|
||||
mkResourceVirtualEnvironmentVMPoolID = "pool_id"
|
||||
@ -193,7 +196,7 @@ func resourceVirtualEnvironmentVM() *schema.Resource {
|
||||
Description: "The cloud-init configuration",
|
||||
Optional: true,
|
||||
DefaultFunc: func() (interface{}, error) {
|
||||
return make([]interface{}, 0), nil
|
||||
return []interface{}{}, nil
|
||||
},
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
@ -202,7 +205,7 @@ func resourceVirtualEnvironmentVM() *schema.Resource {
|
||||
Description: "The DNS configuration",
|
||||
Optional: true,
|
||||
DefaultFunc: func() (interface{}, error) {
|
||||
return make([]interface{}, 0), nil
|
||||
return []interface{}{}, nil
|
||||
},
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
@ -228,7 +231,7 @@ func resourceVirtualEnvironmentVM() *schema.Resource {
|
||||
Description: "The IP configuration",
|
||||
Optional: true,
|
||||
DefaultFunc: func() (interface{}, error) {
|
||||
return make([]interface{}, 0), nil
|
||||
return []interface{}{}, nil
|
||||
},
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
@ -237,7 +240,7 @@ func resourceVirtualEnvironmentVM() *schema.Resource {
|
||||
Description: "The IPv4 configuration",
|
||||
Optional: true,
|
||||
DefaultFunc: func() (interface{}, error) {
|
||||
return make([]interface{}, 0), nil
|
||||
return []interface{}{}, nil
|
||||
},
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
@ -263,7 +266,7 @@ func resourceVirtualEnvironmentVM() *schema.Resource {
|
||||
Description: "The IPv6 configuration",
|
||||
Optional: true,
|
||||
DefaultFunc: func() (interface{}, error) {
|
||||
return make([]interface{}, 0), nil
|
||||
return []interface{}{}, nil
|
||||
},
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
@ -294,7 +297,7 @@ func resourceVirtualEnvironmentVM() *schema.Resource {
|
||||
Description: "The user account configuration",
|
||||
Required: true,
|
||||
DefaultFunc: func() (interface{}, error) {
|
||||
return make([]interface{}, 0), nil
|
||||
return []interface{}{}, nil
|
||||
},
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
@ -487,6 +490,24 @@ func resourceVirtualEnvironmentVM() *schema.Resource {
|
||||
MaxItems: 14,
|
||||
MinItems: 0,
|
||||
},
|
||||
mkResourceVirtualEnvironmentVMIPv4Addresses: {
|
||||
Type: schema.TypeList,
|
||||
Computed: true,
|
||||
Description: "The IPv4 addresses published by the QEMU agent",
|
||||
Elem: &schema.Schema{
|
||||
Type: schema.TypeList,
|
||||
Elem: &schema.Schema{Type: schema.TypeString},
|
||||
},
|
||||
},
|
||||
mkResourceVirtualEnvironmentVMIPv6Addresses: {
|
||||
Type: schema.TypeList,
|
||||
Computed: true,
|
||||
Description: "The IPv6 addresses published by the QEMU agent",
|
||||
Elem: &schema.Schema{
|
||||
Type: schema.TypeList,
|
||||
Elem: &schema.Schema{Type: schema.TypeString},
|
||||
},
|
||||
},
|
||||
mkResourceVirtualEnvironmentVMKeyboardLayout: {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
@ -591,7 +612,7 @@ func resourceVirtualEnvironmentVM() *schema.Resource {
|
||||
Optional: true,
|
||||
Description: "The VLAN identifiers",
|
||||
DefaultFunc: func() (interface{}, error) {
|
||||
return make([]interface{}, 0), nil
|
||||
return []interface{}{}, nil
|
||||
},
|
||||
Elem: &schema.Schema{Type: schema.TypeInt},
|
||||
},
|
||||
@ -600,6 +621,12 @@ func resourceVirtualEnvironmentVM() *schema.Resource {
|
||||
MaxItems: 8,
|
||||
MinItems: 0,
|
||||
},
|
||||
mkResourceVirtualEnvironmentVMNetworkInterfaceNames: {
|
||||
Type: schema.TypeList,
|
||||
Computed: true,
|
||||
Description: "The network interface names published by the QEMU agent",
|
||||
Elem: &schema.Schema{Type: schema.TypeString},
|
||||
},
|
||||
mkResourceVirtualEnvironmentVMNodeName: &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Description: "The node name",
|
||||
@ -649,37 +676,24 @@ func resourceVirtualEnvironmentVMCreate(d *schema.ResourceData, m interface{}) e
|
||||
return err
|
||||
}
|
||||
|
||||
resourceSchema := resourceVirtualEnvironmentVM().Schema
|
||||
agent := d.Get(mkResourceVirtualEnvironmentVMAgent).([]interface{})
|
||||
resource := resourceVirtualEnvironmentVM()
|
||||
|
||||
if len(agent) == 0 {
|
||||
agentDefault, err := resourceSchema[mkResourceVirtualEnvironmentVMAgent].DefaultValue()
|
||||
agentBlock, err := getSchemaBlock(resource, d, m, []string{mkResourceVirtualEnvironmentVMAgent}, 0, true)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
agent = agentDefault.([]interface{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
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{})
|
||||
cdromBlock, err := getSchemaBlock(resource, d, m, []string{mkResourceVirtualEnvironmentVMCDROM}, 0, true)
|
||||
|
||||
if len(cdrom) == 0 {
|
||||
cdromDefault, err := resourceSchema[mkResourceVirtualEnvironmentVMCDROM].DefaultValue()
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cdrom = cdromDefault.([]interface{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cdromBlock := cdrom[0].(map[string]interface{})
|
||||
cdromEnabled := cdromBlock[mkResourceVirtualEnvironmentVMCDROMEnabled].(bool)
|
||||
cdromFileID := cdromBlock[mkResourceVirtualEnvironmentVMCDROMFileID].(string)
|
||||
|
||||
@ -790,19 +804,12 @@ func resourceVirtualEnvironmentVMCreate(d *schema.ResourceData, m interface{}) e
|
||||
}
|
||||
}
|
||||
|
||||
cpu := d.Get(mkResourceVirtualEnvironmentVMCPU).([]interface{})
|
||||
cpuBlock, err := getSchemaBlock(resource, d, m, []string{mkResourceVirtualEnvironmentVMCPU}, 0, true)
|
||||
|
||||
if len(cpu) == 0 {
|
||||
cpuDefault, err := resourceSchema[mkResourceVirtualEnvironmentVMCPU].DefaultValue()
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cpu = cpuDefault.([]interface{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cpuBlock := cpu[0].(map[string]interface{})
|
||||
cpuCores := cpuBlock[mkResourceVirtualEnvironmentVMCPUCores].(int)
|
||||
cpuHotplugged := cpuBlock[mkResourceVirtualEnvironmentVMCPUHotplugged].(int)
|
||||
cpuSockets := cpuBlock[mkResourceVirtualEnvironmentVMCPUSockets].(int)
|
||||
@ -811,52 +818,20 @@ func resourceVirtualEnvironmentVMCreate(d *schema.ResourceData, m interface{}) e
|
||||
disk := d.Get(mkResourceVirtualEnvironmentVMDisk).([]interface{})
|
||||
scsiDevices := make(proxmox.CustomStorageDevices, len(disk))
|
||||
|
||||
diskSchemaElem := resourceSchema[mkResourceVirtualEnvironmentVMDisk].Elem
|
||||
diskSchemaResource := diskSchemaElem.(*schema.Resource)
|
||||
diskSpeedResource := diskSchemaResource.Schema[mkResourceVirtualEnvironmentVMDiskSpeed]
|
||||
|
||||
for i, d := range disk {
|
||||
block := d.(map[string]interface{})
|
||||
|
||||
datastoreID, _ := block[mkResourceVirtualEnvironmentVMDiskDatastoreID].(string)
|
||||
fileID, _ := block[mkResourceVirtualEnvironmentVMDiskFileID].(string)
|
||||
size, _ := block[mkResourceVirtualEnvironmentVMDiskSize].(int)
|
||||
speed := block[mkResourceVirtualEnvironmentVMDiskSpeed].([]interface{})
|
||||
|
||||
if len(speed) == 0 {
|
||||
diskSpeedDefault, err := diskSpeedResource.DefaultValue()
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
speed = diskSpeedDefault.([]interface{})
|
||||
}
|
||||
|
||||
speedBlock := speed[0].(map[string]interface{})
|
||||
speedLimitRead := speedBlock[mkResourceVirtualEnvironmentVMDiskSpeedRead].(int)
|
||||
speedLimitReadBurstable := speedBlock[mkResourceVirtualEnvironmentVMDiskSpeedReadBurstable].(int)
|
||||
speedLimitWrite := speedBlock[mkResourceVirtualEnvironmentVMDiskSpeedWrite].(int)
|
||||
speedLimitWriteBurstable := speedBlock[mkResourceVirtualEnvironmentVMDiskSpeedWriteBurstable].(int)
|
||||
|
||||
for i, diskEntry := range disk {
|
||||
diskDevice := proxmox.CustomStorageDevice{
|
||||
Enabled: true,
|
||||
}
|
||||
|
||||
if speedLimitRead > 0 {
|
||||
diskDevice.MaxReadSpeedMbps = &speedLimitRead
|
||||
}
|
||||
block := diskEntry.(map[string]interface{})
|
||||
datastoreID, _ := block[mkResourceVirtualEnvironmentVMDiskDatastoreID].(string)
|
||||
fileID, _ := block[mkResourceVirtualEnvironmentVMDiskFileID].(string)
|
||||
size, _ := block[mkResourceVirtualEnvironmentVMDiskSize].(int)
|
||||
|
||||
if speedLimitReadBurstable > 0 {
|
||||
diskDevice.BurstableReadSpeedMbps = &speedLimitReadBurstable
|
||||
}
|
||||
speedBlock, err := getSchemaBlock(resource, d, m, []string{mkResourceVirtualEnvironmentVMDisk, mkResourceVirtualEnvironmentVMDiskSpeed}, 0, false)
|
||||
|
||||
if speedLimitWrite > 0 {
|
||||
diskDevice.MaxWriteSpeedMbps = &speedLimitWrite
|
||||
}
|
||||
|
||||
if speedLimitWriteBurstable > 0 {
|
||||
diskDevice.BurstableWriteSpeedMbps = &speedLimitWriteBurstable
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if fileID != "" {
|
||||
@ -865,23 +840,39 @@ func resourceVirtualEnvironmentVMCreate(d *schema.ResourceData, m interface{}) e
|
||||
diskDevice.FileVolume = fmt.Sprintf("%s:%d", datastoreID, size)
|
||||
}
|
||||
|
||||
if len(speedBlock) > 0 {
|
||||
speedLimitRead := speedBlock[mkResourceVirtualEnvironmentVMDiskSpeedRead].(int)
|
||||
speedLimitReadBurstable := speedBlock[mkResourceVirtualEnvironmentVMDiskSpeedReadBurstable].(int)
|
||||
speedLimitWrite := speedBlock[mkResourceVirtualEnvironmentVMDiskSpeedWrite].(int)
|
||||
speedLimitWriteBurstable := speedBlock[mkResourceVirtualEnvironmentVMDiskSpeedWriteBurstable].(int)
|
||||
|
||||
if speedLimitRead > 0 {
|
||||
diskDevice.MaxReadSpeedMbps = &speedLimitRead
|
||||
}
|
||||
|
||||
if speedLimitReadBurstable > 0 {
|
||||
diskDevice.BurstableReadSpeedMbps = &speedLimitReadBurstable
|
||||
}
|
||||
|
||||
if speedLimitWrite > 0 {
|
||||
diskDevice.MaxWriteSpeedMbps = &speedLimitWrite
|
||||
}
|
||||
|
||||
if speedLimitWriteBurstable > 0 {
|
||||
diskDevice.BurstableWriteSpeedMbps = &speedLimitWriteBurstable
|
||||
}
|
||||
}
|
||||
|
||||
scsiDevices[i] = diskDevice
|
||||
}
|
||||
|
||||
keyboardLayout := d.Get(mkResourceVirtualEnvironmentVMKeyboardLayout).(string)
|
||||
memory := d.Get(mkResourceVirtualEnvironmentVMMemory).([]interface{})
|
||||
memoryBlock, err := getSchemaBlock(resource, d, m, []string{mkResourceVirtualEnvironmentVMMemory}, 0, true)
|
||||
|
||||
if len(memory) == 0 {
|
||||
memoryDefault, err := resourceSchema[mkResourceVirtualEnvironmentVMMemory].DefaultValue()
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
memory = memoryDefault.([]interface{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
memoryBlock := memory[0].(map[string]interface{})
|
||||
memoryDedicated := memoryBlock[mkResourceVirtualEnvironmentVMMemoryDedicated].(int)
|
||||
memoryFloating := memoryBlock[mkResourceVirtualEnvironmentVMMemoryFloating].(int)
|
||||
memoryShared := memoryBlock[mkResourceVirtualEnvironmentVMMemoryShared].(int)
|
||||
@ -891,8 +882,8 @@ func resourceVirtualEnvironmentVMCreate(d *schema.ResourceData, m interface{}) e
|
||||
networkDevice := d.Get(mkResourceVirtualEnvironmentVMNetworkDevice).([]interface{})
|
||||
networkDeviceObjects := make(proxmox.CustomNetworkDevices, len(networkDevice))
|
||||
|
||||
for i, d := range networkDevice {
|
||||
block := d.(map[string]interface{})
|
||||
for i, networkDeviceEntry := range networkDevice {
|
||||
block := networkDeviceEntry.(map[string]interface{})
|
||||
|
||||
bridge, _ := block[mkResourceVirtualEnvironmentVMNetworkDeviceBridge].(string)
|
||||
enabled, _ := block[mkResourceVirtualEnvironmentVMNetworkDeviceEnabled].(bool)
|
||||
@ -1540,6 +1531,43 @@ func resourceVirtualEnvironmentVMRead(d *schema.ResourceData, m interface{}) err
|
||||
|
||||
d.Set(mkResourceVirtualEnvironmentVMStarted, status.Status == "running")
|
||||
|
||||
// Populate the attributes that rely on the QEMU agent.
|
||||
ipv4Addresses := []interface{}{}
|
||||
ipv6Addresses := []interface{}{}
|
||||
networkInterfaceNames := []interface{}{}
|
||||
|
||||
if vmConfig.Agent != nil && vmConfig.Agent.Enabled != nil && *vmConfig.Agent.Enabled {
|
||||
networkInterfaces, err := veClient.WaitForNetworkInterfacesFromAgent(nodeName, vmID, 600, 5)
|
||||
|
||||
if err == nil && networkInterfaces.Result != nil {
|
||||
ipv4Addresses = make([]interface{}, len(*networkInterfaces.Result))
|
||||
ipv6Addresses = make([]interface{}, len(*networkInterfaces.Result))
|
||||
networkInterfaceNames = make([]interface{}, len(*networkInterfaces.Result))
|
||||
|
||||
for ri, rv := range *networkInterfaces.Result {
|
||||
rvIPv4Addresses := []interface{}{}
|
||||
rvIPv6Addresses := []interface{}{}
|
||||
|
||||
for _, ip := range *rv.IPAddresses {
|
||||
switch ip.Type {
|
||||
case "ipv4":
|
||||
rvIPv4Addresses = append(rvIPv4Addresses, ip.Address)
|
||||
case "ipv6":
|
||||
rvIPv6Addresses = append(rvIPv6Addresses, ip.Address)
|
||||
}
|
||||
}
|
||||
|
||||
ipv4Addresses[ri] = rvIPv4Addresses
|
||||
ipv6Addresses[ri] = rvIPv6Addresses
|
||||
networkInterfaceNames[ri] = rv.Name
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
d.Set(mkResourceVirtualEnvironmentVMIPv4Addresses, ipv4Addresses)
|
||||
d.Set(mkResourceVirtualEnvironmentVMIPv6Addresses, ipv6Addresses)
|
||||
d.Set(mkResourceVirtualEnvironmentVMNetworkInterfaceNames, networkInterfaceNames)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -43,16 +43,25 @@ func TestResourceVirtualEnvironmentVMSchema(t *testing.T) {
|
||||
mkResourceVirtualEnvironmentVMVMID,
|
||||
})
|
||||
|
||||
testComputedAttributes(t, s, []string{
|
||||
mkResourceVirtualEnvironmentVMIPv4Addresses,
|
||||
mkResourceVirtualEnvironmentVMIPv6Addresses,
|
||||
mkResourceVirtualEnvironmentVMNetworkInterfaceNames,
|
||||
})
|
||||
|
||||
testSchemaValueTypes(t, s, []string{
|
||||
mkResourceVirtualEnvironmentVMCDROM,
|
||||
mkResourceVirtualEnvironmentVMCloudInit,
|
||||
mkResourceVirtualEnvironmentVMCPU,
|
||||
mkResourceVirtualEnvironmentVMDescription,
|
||||
mkResourceVirtualEnvironmentVMDisk,
|
||||
mkResourceVirtualEnvironmentVMIPv4Addresses,
|
||||
mkResourceVirtualEnvironmentVMIPv6Addresses,
|
||||
mkResourceVirtualEnvironmentVMKeyboardLayout,
|
||||
mkResourceVirtualEnvironmentVMMemory,
|
||||
mkResourceVirtualEnvironmentVMName,
|
||||
mkResourceVirtualEnvironmentVMNetworkDevice,
|
||||
mkResourceVirtualEnvironmentVMNetworkInterfaceNames,
|
||||
mkResourceVirtualEnvironmentVMOSType,
|
||||
mkResourceVirtualEnvironmentVMPoolID,
|
||||
mkResourceVirtualEnvironmentVMStarted,
|
||||
@ -63,10 +72,13 @@ func TestResourceVirtualEnvironmentVMSchema(t *testing.T) {
|
||||
schema.TypeList,
|
||||
schema.TypeString,
|
||||
schema.TypeList,
|
||||
schema.TypeList,
|
||||
schema.TypeList,
|
||||
schema.TypeString,
|
||||
schema.TypeList,
|
||||
schema.TypeString,
|
||||
schema.TypeList,
|
||||
schema.TypeList,
|
||||
schema.TypeString,
|
||||
schema.TypeString,
|
||||
schema.TypeBool,
|
||||
|
@ -131,6 +131,50 @@ func getQEMUAgentTypeValidator() schema.SchemaValidateFunc {
|
||||
return validation.StringInSlice([]string{"isa", "virtio"}, false)
|
||||
}
|
||||
|
||||
func getSchemaBlock(r *schema.Resource, d *schema.ResourceData, m interface{}, k []string, i int, allowDefault bool) (map[string]interface{}, error) {
|
||||
var resourceBlock map[string]interface{}
|
||||
var resourceData interface{}
|
||||
var resourceSchema *schema.Schema
|
||||
|
||||
for ki, kv := range k {
|
||||
if ki == 0 {
|
||||
resourceData = d.Get(kv)
|
||||
resourceSchema = r.Schema[kv]
|
||||
} else {
|
||||
mapValues := resourceData.([]interface{})
|
||||
|
||||
if len(mapValues) <= i {
|
||||
return resourceBlock, fmt.Errorf("Index out of bounds %d", i)
|
||||
}
|
||||
|
||||
mapValue := mapValues[i].(map[string]interface{})
|
||||
|
||||
resourceData = mapValue[kv]
|
||||
resourceSchema = resourceSchema.Elem.(*schema.Resource).Schema[kv]
|
||||
}
|
||||
}
|
||||
|
||||
list := resourceData.([]interface{})
|
||||
|
||||
if len(list) == 0 {
|
||||
if allowDefault {
|
||||
listDefault, err := resourceSchema.DefaultValue()
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
list = listDefault.([]interface{})
|
||||
}
|
||||
}
|
||||
|
||||
if len(list) > i {
|
||||
resourceBlock = list[i].(map[string]interface{})
|
||||
}
|
||||
|
||||
return resourceBlock, nil
|
||||
}
|
||||
|
||||
func getVLANIDsValidator() schema.SchemaValidateFunc {
|
||||
return func(i interface{}, k string) (ws []string, es []error) {
|
||||
min := 1
|
||||
|
Loading…
Reference in New Issue
Block a user