0
0
mirror of https://github.com/bpg/terraform-provider-proxmox.git synced 2025-07-03 03:52:58 +00:00

feat(vm): support PCI device resource mapping (#500)

* feat(vm): support PCI device resource mapping

* fix: linter error

* fix: minor cleanup

---------

Co-authored-by: Pavel Boldyrev <627562+bpg@users.noreply.github.com>
This commit is contained in:
Risto Oikarinen 2023-08-21 01:00:11 +03:00 committed by GitHub
parent 03c9b36b86
commit 26970541c4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 81 additions and 17 deletions

View File

@ -31,7 +31,7 @@ resource "proxmox_virtual_environment_vm" "ubuntu_vm" {
up_delay = "60" up_delay = "60"
down_delay = "60" down_delay = "60"
} }
disk { disk {
datastore_id = "local-lvm" datastore_id = "local-lvm"
file_id = proxmox_virtual_environment_file.ubuntu_cloud_image.id 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). - `hostpci` - (Optional) A host PCI device mapping (multiple blocks supported).
- `device` - (Required) The PCI device name for Proxmox, in form - `device` - (Required) The PCI device name for Proxmox, in form
of `hostpciX` where `X` is a sequential number from 0 to 3. 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. - `mdev` - (Optional) The mediated device ID to use.
- `pcie` - (Optional) Tells Proxmox to use a PCIe or PCI port. Some - `pcie` - (Optional) Tells Proxmox to use a PCIe or PCI port. Some
guests/device combination require PCIe rather than PCI. PCIe is only guests/device combination require PCIe rather than PCI. PCIe is only

View File

@ -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" { output "resource_proxmox_virtual_environment_vm_example_id" {

View File

@ -118,7 +118,8 @@ type CustomNUMADevices []CustomNUMADevice
// CustomPCIDevice handles QEMU host PCI device mapping parameters. // CustomPCIDevice handles QEMU host PCI device mapping parameters.
type CustomPCIDevice struct { 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"` MDev *string `json:"mdev,omitempty" url:"mdev,omitempty"`
PCIExpress *types.CustomBool `json:"pcie,omitempty" url:"pcie,omitempty,int"` PCIExpress *types.CustomBool `json:"pcie,omitempty" url:"pcie,omitempty,int"`
ROMBAR *types.CustomBool `json:"rombar,omitempty" url:"rombar,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. // EncodeValues converts a CustomPCIDevice struct to a URL vlaue.
func (r CustomPCIDevice) EncodeValues(key string, v *url.Values) error { func (r CustomPCIDevice) EncodeValues(key string, v *url.Values) error {
values := []string{ values := []string{}
fmt.Sprintf("host=%s", strings.Join(r.DeviceIDs, ";")),
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 { if r.MDev != nil {
@ -1606,11 +1617,15 @@ func (r *CustomPCIDevice) UnmarshalJSON(b []byte) error {
for _, p := range pairs { for _, p := range pairs {
v := strings.Split(strings.TrimSpace(p), "=") v := strings.Split(strings.TrimSpace(p), "=")
if len(v) == 1 { if len(v) == 1 {
r.DeviceIDs = strings.Split(v[0], ";") dIds := strings.Split(v[0], ";")
r.DeviceIDs = &dIds
} else if len(v) == 2 { } else if len(v) == 2 {
switch v[0] { switch v[0] {
case "host": case "host":
r.DeviceIDs = strings.Split(v[1], ";") dIds := strings.Split(v[0], ";")
r.DeviceIDs = &dIds
case "mapping":
r.Mapping = &v[1]
case "mdev": case "mdev":
r.MDev = &v[1] r.MDev = &v[1]
case "pcie": case "pcie":

View File

@ -78,7 +78,7 @@ func TestCustomPCIDevice_UnmarshalJSON(t *testing.T) {
name: "id only pci device", name: "id only pci device",
line: `"0000:81:00.2"`, line: `"0000:81:00.2"`,
want: &CustomPCIDevice{ want: &CustomPCIDevice{
DeviceIDs: []string{"0000:81:00.2"}, DeviceIDs: &[]string{"0000:81:00.2"},
MDev: nil, MDev: nil,
PCIExpress: types.BoolPtr(false), PCIExpress: types.BoolPtr(false),
ROMBAR: types.BoolPtr(true), ROMBAR: types.BoolPtr(true),
@ -90,7 +90,20 @@ func TestCustomPCIDevice_UnmarshalJSON(t *testing.T) {
name: "pci device with more details", name: "pci device with more details",
line: `"host=81:00.4,pcie=0,rombar=1,x-vga=0"`, line: `"host=81:00.4,pcie=0,rombar=1,x-vga=0"`,
want: &CustomPCIDevice{ 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, MDev: nil,
PCIExpress: types.BoolPtr(false), PCIExpress: types.BoolPtr(false),
ROMBAR: types.BoolPtr(true), ROMBAR: types.BoolPtr(true),

View File

@ -195,6 +195,7 @@ const (
mkResourceVirtualEnvironmentVMHostPCI = "hostpci" mkResourceVirtualEnvironmentVMHostPCI = "hostpci"
mkResourceVirtualEnvironmentVMHostPCIDevice = "device" mkResourceVirtualEnvironmentVMHostPCIDevice = "device"
mkResourceVirtualEnvironmentVMHostPCIDeviceID = "id" mkResourceVirtualEnvironmentVMHostPCIDeviceID = "id"
mkResourceVirtualEnvironmentVMHostPCIDeviceMapping = "mapping"
mkResourceVirtualEnvironmentVMHostPCIDeviceMDev = "mdev" mkResourceVirtualEnvironmentVMHostPCIDeviceMDev = "mdev"
mkResourceVirtualEnvironmentVMHostPCIDevicePCIE = "pcie" mkResourceVirtualEnvironmentVMHostPCIDevicePCIE = "pcie"
mkResourceVirtualEnvironmentVMHostPCIDeviceROMBAR = "rombar" mkResourceVirtualEnvironmentVMHostPCIDeviceROMBAR = "rombar"
@ -1009,9 +1010,15 @@ func VM() *schema.Resource {
Required: true, Required: true,
}, },
mkResourceVirtualEnvironmentVMHostPCIDeviceID: { 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, 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)", Description: "The resource mapping name of the device, for example gpu. Use either this or id.",
Required: true, Optional: true,
}, },
mkResourceVirtualEnvironmentVMHostPCIDeviceMDev: { mkResourceVirtualEnvironmentVMHostPCIDeviceMDev: {
Type: schema.TypeString, Type: schema.TypeString,
@ -1019,9 +1026,10 @@ func VM() *schema.Resource {
Optional: true, Optional: true,
}, },
mkResourceVirtualEnvironmentVMHostPCIDevicePCIE: { mkResourceVirtualEnvironmentVMHostPCIDevicePCIE: {
Type: schema.TypeBool, 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.", Description: "Tells Proxmox VE to use a PCIe or PCI port. Some guests/device combination require PCIe rather " +
Optional: true, "than PCI. PCIe is only available for q35 machine types.",
Optional: true,
}, },
mkResourceVirtualEnvironmentVMHostPCIDeviceROMBAR: { mkResourceVirtualEnvironmentVMHostPCIDeviceROMBAR: {
Type: schema.TypeBool, Type: schema.TypeBool,
@ -3137,15 +3145,16 @@ func vmGetHostPCIDeviceObjects(d *schema.ResourceData) vms.CustomPCIDevices {
) )
romfile, _ := block[mkResourceVirtualEnvironmentVMHostPCIDeviceROMFile].(string) romfile, _ := block[mkResourceVirtualEnvironmentVMHostPCIDeviceROMFile].(string)
xvga := types.CustomBool(block[mkResourceVirtualEnvironmentVMHostPCIDeviceXVGA].(bool)) xvga := types.CustomBool(block[mkResourceVirtualEnvironmentVMHostPCIDeviceXVGA].(bool))
mapping, _ := block[mkResourceVirtualEnvironmentVMHostPCIDeviceMapping].(string)
device := vms.CustomPCIDevice{ device := vms.CustomPCIDevice{
DeviceIDs: strings.Split(ids, ";"),
PCIExpress: &pcie, PCIExpress: &pcie,
ROMBAR: &rombar, ROMBAR: &rombar,
XVGA: &xvga, XVGA: &xvga,
} }
if ids != "" { if ids != "" {
device.DeviceIDs = strings.Split(ids, ";") dIds := strings.Split(ids, ";")
device.DeviceIDs = &dIds
} }
if mdev != "" { if mdev != "" {
@ -3156,6 +3165,10 @@ func vmGetHostPCIDeviceObjects(d *schema.ResourceData) vms.CustomPCIDevices {
device.ROMFile = &romfile device.ROMFile = &romfile
} }
if mapping != "" {
device.Mapping = &mapping
}
pciDeviceObjects[i] = device pciDeviceObjects[i] = device
} }
@ -3923,7 +3936,11 @@ func vmReadCustom(
pci := map[string]interface{}{} pci := map[string]interface{}{}
pci[mkResourceVirtualEnvironmentVMHostPCIDevice] = pi 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 { if pp.MDev != nil {
pci[mkResourceVirtualEnvironmentVMHostPCIDeviceMDev] = *pp.MDev pci[mkResourceVirtualEnvironmentVMHostPCIDeviceMDev] = *pp.MDev
@ -3955,6 +3972,12 @@ func vmReadCustom(
pci[mkResourceVirtualEnvironmentVMHostPCIDeviceXVGA] = false pci[mkResourceVirtualEnvironmentVMHostPCIDeviceXVGA] = false
} }
if pp.Mapping != nil {
pci[mkResourceVirtualEnvironmentVMHostPCIDeviceMapping] = *pp.Mapping
} else {
pci[mkResourceVirtualEnvironmentVMHostPCIDeviceMapping] = ""
}
pciMap[pi] = pci pciMap[pi] = pci
} }