diff --git a/docs/resources/virtual_environment_vm.md b/docs/resources/virtual_environment_vm.md index 354a4f9eb..43ac9c6ca 100644 --- a/docs/resources/virtual_environment_vm.md +++ b/docs/resources/virtual_environment_vm.md @@ -31,7 +31,7 @@ resource "proxmox_virtual_environment_vm" "ubuntu_vm" { up_delay = "60" down_delay = "60" } - + disk { datastore_id = "local-lvm" file_id = proxmox_virtual_environment_file.ubuntu_cloud_image.id @@ -283,7 +283,9 @@ output "ubuntu_vm_public_key" { - `hostpci` - (Optional) A host PCI device mapping (multiple blocks supported). - `device` - (Required) The PCI device name for Proxmox, in form of `hostpciX` where `X` is a sequential number from 0 to 3. - - `id` - (Required) The PCI device ID. + - `id` - (Optional) The PCI device ID. Use either this or `mapping`. + - `mapping` - (Optional) The resource mapping name of the device, for + example gpu. Use either this or `id`. - `mdev` - (Optional) The mediated device ID to use. - `pcie` - (Optional) Tells Proxmox to use a PCIe or PCI port. Some guests/device combination require PCIe rather than PCI. PCIe is only diff --git a/example/resource_virtual_environment_vm.tf b/example/resource_virtual_environment_vm.tf index df3cbde80..1a172a698 100644 --- a/example/resource_virtual_environment_vm.tf +++ b/example/resource_virtual_environment_vm.tf @@ -147,6 +147,17 @@ resource "proxmox_virtual_environment_vm" "example" { } } + #hostpci { + # device = "hostpci0" + # id = "0000:00:1f.0" + # pcie = true + #} + + #hostpci { + # device = "hostpci1" + # mapping = "gpu" + # pcie = true + #} } output "resource_proxmox_virtual_environment_vm_example_id" { diff --git a/proxmox/nodes/vms/vms_types.go b/proxmox/nodes/vms/vms_types.go index 34dc74eb4..0eccbab5c 100644 --- a/proxmox/nodes/vms/vms_types.go +++ b/proxmox/nodes/vms/vms_types.go @@ -118,7 +118,8 @@ type CustomNUMADevices []CustomNUMADevice // CustomPCIDevice handles QEMU host PCI device mapping parameters. type CustomPCIDevice struct { - DeviceIDs []string `json:"host" url:"host,semicolon"` + DeviceIDs *[]string `json:"host,omitempty" url:"host,omitempty,semicolon"` + Mapping *string `json:"mapping,omitempty" url:"mapping,omitempty"` MDev *string `json:"mdev,omitempty" url:"mdev,omitempty"` PCIExpress *types.CustomBool `json:"pcie,omitempty" url:"pcie,omitempty,int"` ROMBAR *types.CustomBool `json:"rombar,omitempty" url:"rombar,omitempty,int"` @@ -912,8 +913,18 @@ func (r CustomNUMADevices) EncodeValues(key string, v *url.Values) error { // EncodeValues converts a CustomPCIDevice struct to a URL vlaue. func (r CustomPCIDevice) EncodeValues(key string, v *url.Values) error { - values := []string{ - fmt.Sprintf("host=%s", strings.Join(r.DeviceIDs, ";")), + values := []string{} + + if r.DeviceIDs == nil && r.Mapping == nil { + return fmt.Errorf("either device ID or resource mapping must be set") + } + + if r.DeviceIDs != nil { + values = append(values, fmt.Sprintf("host=%s", strings.Join(*r.DeviceIDs, ";"))) + } + + if r.Mapping != nil { + values = append(values, fmt.Sprintf("mapping=%s", *r.Mapping)) } if r.MDev != nil { @@ -1606,11 +1617,15 @@ func (r *CustomPCIDevice) UnmarshalJSON(b []byte) error { for _, p := range pairs { v := strings.Split(strings.TrimSpace(p), "=") if len(v) == 1 { - r.DeviceIDs = strings.Split(v[0], ";") + dIds := strings.Split(v[0], ";") + r.DeviceIDs = &dIds } else if len(v) == 2 { switch v[0] { case "host": - r.DeviceIDs = strings.Split(v[1], ";") + dIds := strings.Split(v[0], ";") + r.DeviceIDs = &dIds + case "mapping": + r.Mapping = &v[1] case "mdev": r.MDev = &v[1] case "pcie": diff --git a/proxmox/nodes/vms/vms_types_test.go b/proxmox/nodes/vms/vms_types_test.go index 7807d4e75..ef4e48e7c 100644 --- a/proxmox/nodes/vms/vms_types_test.go +++ b/proxmox/nodes/vms/vms_types_test.go @@ -78,7 +78,7 @@ func TestCustomPCIDevice_UnmarshalJSON(t *testing.T) { name: "id only pci device", line: `"0000:81:00.2"`, want: &CustomPCIDevice{ - DeviceIDs: []string{"0000:81:00.2"}, + DeviceIDs: &[]string{"0000:81:00.2"}, MDev: nil, PCIExpress: types.BoolPtr(false), ROMBAR: types.BoolPtr(true), @@ -90,7 +90,20 @@ func TestCustomPCIDevice_UnmarshalJSON(t *testing.T) { name: "pci device with more details", line: `"host=81:00.4,pcie=0,rombar=1,x-vga=0"`, want: &CustomPCIDevice{ - DeviceIDs: []string{"81:00.4"}, + DeviceIDs: &[]string{"81:00.4"}, + MDev: nil, + PCIExpress: types.BoolPtr(false), + ROMBAR: types.BoolPtr(true), + ROMFile: nil, + XVGA: types.BoolPtr(false), + }, + }, + { + name: "pci device with mapping", + line: `"mapping=mappeddevice,pcie=0,rombar=1,x-vga=0"`, + want: &CustomPCIDevice{ + DeviceIDs: nil, + Mapping: types.StrPtr("mappeddevice"), MDev: nil, PCIExpress: types.BoolPtr(false), ROMBAR: types.BoolPtr(true), diff --git a/proxmoxtf/resource/vm.go b/proxmoxtf/resource/vm.go index 2ee3956d4..35510cf9d 100644 --- a/proxmoxtf/resource/vm.go +++ b/proxmoxtf/resource/vm.go @@ -195,6 +195,7 @@ const ( mkResourceVirtualEnvironmentVMHostPCI = "hostpci" mkResourceVirtualEnvironmentVMHostPCIDevice = "device" mkResourceVirtualEnvironmentVMHostPCIDeviceID = "id" + mkResourceVirtualEnvironmentVMHostPCIDeviceMapping = "mapping" mkResourceVirtualEnvironmentVMHostPCIDeviceMDev = "mdev" mkResourceVirtualEnvironmentVMHostPCIDevicePCIE = "pcie" mkResourceVirtualEnvironmentVMHostPCIDeviceROMBAR = "rombar" @@ -1009,9 +1010,15 @@ func VM() *schema.Resource { Required: true, }, mkResourceVirtualEnvironmentVMHostPCIDeviceID: { + Type: schema.TypeString, + Description: "The PCI ID of the device, for example 0000:00:1f.0 (or 0000:00:1f.0;0000:00:1f.1 for multiple " + + "device functions, or 0000:00:1f for all functions). Use either this or mapping.", + Optional: true, + }, + mkResourceVirtualEnvironmentVMHostPCIDeviceMapping: { Type: schema.TypeString, - Description: "The PCI ID of the device, for example 0000:00:1f.0 (or 0000:00:1f.0;0000:00:1f.1 for multiple device functions, or 0000:00:1f for all functions)", - Required: true, + Description: "The resource mapping name of the device, for example gpu. Use either this or id.", + Optional: true, }, mkResourceVirtualEnvironmentVMHostPCIDeviceMDev: { Type: schema.TypeString, @@ -1019,9 +1026,10 @@ func VM() *schema.Resource { Optional: true, }, mkResourceVirtualEnvironmentVMHostPCIDevicePCIE: { - Type: schema.TypeBool, - Description: "Tells Proxmox VE to use a PCIe or PCI port. Some guests/device combination require PCIe rather than PCI. PCIe is only available for q35 machine types.", - Optional: true, + Type: schema.TypeBool, + Description: "Tells Proxmox VE to use a PCIe or PCI port. Some guests/device combination require PCIe rather " + + "than PCI. PCIe is only available for q35 machine types.", + Optional: true, }, mkResourceVirtualEnvironmentVMHostPCIDeviceROMBAR: { Type: schema.TypeBool, @@ -3137,15 +3145,16 @@ func vmGetHostPCIDeviceObjects(d *schema.ResourceData) vms.CustomPCIDevices { ) romfile, _ := block[mkResourceVirtualEnvironmentVMHostPCIDeviceROMFile].(string) xvga := types.CustomBool(block[mkResourceVirtualEnvironmentVMHostPCIDeviceXVGA].(bool)) + mapping, _ := block[mkResourceVirtualEnvironmentVMHostPCIDeviceMapping].(string) device := vms.CustomPCIDevice{ - DeviceIDs: strings.Split(ids, ";"), PCIExpress: &pcie, ROMBAR: &rombar, XVGA: &xvga, } if ids != "" { - device.DeviceIDs = strings.Split(ids, ";") + dIds := strings.Split(ids, ";") + device.DeviceIDs = &dIds } if mdev != "" { @@ -3156,6 +3165,10 @@ func vmGetHostPCIDeviceObjects(d *schema.ResourceData) vms.CustomPCIDevices { device.ROMFile = &romfile } + if mapping != "" { + device.Mapping = &mapping + } + pciDeviceObjects[i] = device } @@ -3923,7 +3936,11 @@ func vmReadCustom( pci := map[string]interface{}{} pci[mkResourceVirtualEnvironmentVMHostPCIDevice] = pi - pci[mkResourceVirtualEnvironmentVMHostPCIDeviceID] = strings.Join(pp.DeviceIDs, ";") + if pp.DeviceIDs != nil { + pci[mkResourceVirtualEnvironmentVMHostPCIDeviceID] = strings.Join(*pp.DeviceIDs, ";") + } else { + pci[mkResourceVirtualEnvironmentVMHostPCIDeviceID] = "" + } if pp.MDev != nil { pci[mkResourceVirtualEnvironmentVMHostPCIDeviceMDev] = *pp.MDev @@ -3955,6 +3972,12 @@ func vmReadCustom( pci[mkResourceVirtualEnvironmentVMHostPCIDeviceXVGA] = false } + if pp.Mapping != nil { + pci[mkResourceVirtualEnvironmentVMHostPCIDeviceMapping] = *pp.Mapping + } else { + pci[mkResourceVirtualEnvironmentVMHostPCIDeviceMapping] = "" + } + pciMap[pi] = pci }