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:
parent
03c9b36b86
commit
26970541c4
@ -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
|
||||||
|
@ -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" {
|
||||||
|
@ -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":
|
||||||
|
@ -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),
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user