0
0
mirror of https://github.com/bpg/terraform-provider-proxmox.git synced 2025-08-22 19:38:35 +00:00

feat(vm): add support for SMBIOS settings (#454)

* feat(vm): add support for SMBIOS settings

* fix linter errors

* fix smbios error at clone
This commit is contained in:
Pavel Boldyrev 2023-08-05 20:31:17 -04:00 committed by GitHub
parent 824e51c650
commit 85ff60d4bd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 247 additions and 6 deletions

View File

@ -414,6 +414,14 @@ output "ubuntu_vm_public_key" {
- `virtio-scsi-single` - VirtIO SCSI (single queue). - `virtio-scsi-single` - VirtIO SCSI (single queue).
- `megasas` - LSI Logic MegaRAID SAS. - `megasas` - LSI Logic MegaRAID SAS.
- `pvscsi` - VMware Paravirtual SCSI. - `pvscsi` - VMware Paravirtual SCSI.
- `smbios` - (Optional) The SMBIOS (type1) settings for the VM.
- `family`- (Optional) The family string.
- `manufacturer` - (Optional) The manufacturer.
- `product` - (Optional) The product ID.
- `serial` - (Optional) The serial number.
- `sku` - (Optional) The SKU number.
- `uuid` - (Optional) The UUID (defaults to randomly generated UUID).
- `version` - (Optional) The version.
- `started` - (Optional) Whether to start the virtual machine (defaults - `started` - (Optional) Whether to start the virtual machine (defaults
to `true`). to `true`).
- `startup` - (Optional) Defines startup and shutdown behavior of the VM. - `startup` - (Optional) Defines startup and shutdown behavior of the VM.

View File

@ -13,6 +13,12 @@ resource "proxmox_virtual_environment_vm" "example_template" {
numa = true numa = true
} }
smbios {
manufacturer = "Terraform"
product = "Terraform Provider Proxmox"
version = "0.0.1"
}
startup { startup {
order = "3" order = "3"
up_delay = "60" up_delay = "60"

View File

@ -140,7 +140,7 @@ type CustomSharedMemory struct {
// CustomSMBIOS handles QEMU SMBIOS parameters. // CustomSMBIOS handles QEMU SMBIOS parameters.
type CustomSMBIOS struct { type CustomSMBIOS struct {
Base64 *types.CustomBool `json:"base64,omitempty" url:"base64,omitempty"` Base64 *types.CustomBool `json:"base64,omitempty" url:"base64,omitempty,int"`
Family *string `json:"family,omitempty" url:"family,omitempty"` Family *string `json:"family,omitempty" url:"family,omitempty"`
Manufacturer *string `json:"manufacturer,omitempty" url:"manufacturer,omitempty"` Manufacturer *string `json:"manufacturer,omitempty" url:"manufacturer,omitempty"`
Product *string `json:"product,omitempty" url:"product,omitempty"` Product *string `json:"product,omitempty" url:"product,omitempty"`
@ -1673,7 +1673,7 @@ func (r *CustomSMBIOS) UnmarshalJSON(b []byte) error {
pairs := strings.Split(s, ",") pairs := strings.Split(s, ",")
for _, p := range pairs { for _, p := range pairs {
v := strings.Split(strings.TrimSpace(p), "=") v := strings.SplitN(strings.TrimSpace(p), "=", 2)
if len(v) == 2 { if len(v) == 2 {
switch v[0] { switch v[0] {

View File

@ -8,6 +8,7 @@ package resource
import ( import (
"context" "context"
"encoding/base64"
"errors" "errors"
"fmt" "fmt"
"sort" "sort"
@ -16,6 +17,7 @@ import (
"time" "time"
"unicode" "unicode"
"github.com/google/uuid"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
@ -103,6 +105,12 @@ const (
dvResourceVirtualEnvironmentVMOperatingSystemType = "other" dvResourceVirtualEnvironmentVMOperatingSystemType = "other"
dvResourceVirtualEnvironmentVMPoolID = "" dvResourceVirtualEnvironmentVMPoolID = ""
dvResourceVirtualEnvironmentVMSerialDeviceDevice = "socket" dvResourceVirtualEnvironmentVMSerialDeviceDevice = "socket"
dvResourceVirtualEnvironmentVMSMBIOSFamily = ""
dvResourceVirtualEnvironmentVMSMBIOSManufacturer = ""
dvResourceVirtualEnvironmentVMSMBIOSProduct = ""
dvResourceVirtualEnvironmentVMSMBIOSSKU = ""
dvResourceVirtualEnvironmentVMSMBIOSSerial = ""
dvResourceVirtualEnvironmentVMSMBIOSVersion = ""
dvResourceVirtualEnvironmentVMStarted = true dvResourceVirtualEnvironmentVMStarted = true
dvResourceVirtualEnvironmentVMStartupOrder = -1 dvResourceVirtualEnvironmentVMStartupOrder = -1
dvResourceVirtualEnvironmentVMStartupUpDelay = -1 dvResourceVirtualEnvironmentVMStartupUpDelay = -1
@ -234,6 +242,14 @@ const (
mkResourceVirtualEnvironmentVMPoolID = "pool_id" mkResourceVirtualEnvironmentVMPoolID = "pool_id"
mkResourceVirtualEnvironmentVMSerialDevice = "serial_device" mkResourceVirtualEnvironmentVMSerialDevice = "serial_device"
mkResourceVirtualEnvironmentVMSerialDeviceDevice = "device" mkResourceVirtualEnvironmentVMSerialDeviceDevice = "device"
mkResourceVirtualEnvironmentVMSMBIOS = "smbios"
mkResourceVirtualEnvironmentVMSMBIOSFamily = "family"
mkResourceVirtualEnvironmentVMSMBIOSManufacturer = "manufacturer"
mkResourceVirtualEnvironmentVMSMBIOSProduct = "product"
mkResourceVirtualEnvironmentVMSMBIOSSKU = "sku"
mkResourceVirtualEnvironmentVMSMBIOSSerial = "serial"
mkResourceVirtualEnvironmentVMSMBIOSUUID = "uuid"
mkResourceVirtualEnvironmentVMSMBIOSVersion = "version"
mkResourceVirtualEnvironmentVMStarted = "started" mkResourceVirtualEnvironmentVMStarted = "started"
mkResourceVirtualEnvironmentVMStartup = "startup" mkResourceVirtualEnvironmentVMStartup = "startup"
mkResourceVirtualEnvironmentVMStartupOrder = "order" mkResourceVirtualEnvironmentVMStartupOrder = "order"
@ -1212,6 +1228,59 @@ func VM() *schema.Resource {
MaxItems: maxResourceVirtualEnvironmentVMSerialDevices, MaxItems: maxResourceVirtualEnvironmentVMSerialDevices,
MinItems: 0, MinItems: 0,
}, },
mkResourceVirtualEnvironmentVMSMBIOS: {
Type: schema.TypeList,
Description: "Specifies SMBIOS (type1) settings for the VM",
Optional: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
mkResourceVirtualEnvironmentVMSMBIOSFamily: {
Type: schema.TypeString,
Description: "Sets SMBIOS family string",
Optional: true,
Default: dvResourceVirtualEnvironmentVMSMBIOSFamily,
},
mkResourceVirtualEnvironmentVMSMBIOSManufacturer: {
Type: schema.TypeString,
Description: "Sets SMBIOS manufacturer",
Optional: true,
Default: dvResourceVirtualEnvironmentVMSMBIOSManufacturer,
},
mkResourceVirtualEnvironmentVMSMBIOSProduct: {
Type: schema.TypeString,
Description: "Sets SMBIOS product ID",
Optional: true,
Default: dvResourceVirtualEnvironmentVMSMBIOSProduct,
},
mkResourceVirtualEnvironmentVMSMBIOSSerial: {
Type: schema.TypeString,
Description: "Sets SMBIOS serial number",
Optional: true,
Default: dvResourceVirtualEnvironmentVMSMBIOSSerial,
},
mkResourceVirtualEnvironmentVMSMBIOSSKU: {
Type: schema.TypeString,
Description: "Sets SMBIOS SKU",
Optional: true,
Default: dvResourceVirtualEnvironmentVMSMBIOSSKU,
},
mkResourceVirtualEnvironmentVMSMBIOSUUID: {
Type: schema.TypeString,
Description: "Sets SMBIOS UUID",
Optional: true,
Computed: true,
},
mkResourceVirtualEnvironmentVMSMBIOSVersion: {
Type: schema.TypeString,
Description: "Sets SMBIOS version",
Optional: true,
Default: dvResourceVirtualEnvironmentVMSMBIOSVersion,
},
},
},
MaxItems: 1,
MinItems: 0,
},
mkResourceVirtualEnvironmentVMStarted: { mkResourceVirtualEnvironmentVMStarted: {
Type: schema.TypeBool, Type: schema.TypeBool,
Description: "Whether to start the virtual machine", Description: "Whether to start the virtual machine",
@ -1252,7 +1321,6 @@ func VM() *schema.Resource {
MaxItems: 1, MaxItems: 1,
MinItems: 0, MinItems: 0,
}, },
mkResourceVirtualEnvironmentVMTabletDevice: { mkResourceVirtualEnvironmentVMTabletDevice: {
Type: schema.TypeBool, Type: schema.TypeBool,
Description: "Whether to enable the USB tablet device", Description: "Whether to enable the USB tablet device",
@ -2189,6 +2257,8 @@ func vmCreateCustom(ctx context.Context, d *schema.ResourceData, m interface{})
serialDevices := vmGetSerialDeviceList(d) serialDevices := vmGetSerialDeviceList(d)
smbios := vmGetSMBIOS(d)
startupOrder := vmGetStartupOrder(d) startupOrder := vmGetStartupOrder(d)
onBoot := types.CustomBool(d.Get(mkResourceVirtualEnvironmentVMOnBoot).(bool)) onBoot := types.CustomBool(d.Get(mkResourceVirtualEnvironmentVMOnBoot).(bool))
@ -2311,6 +2381,7 @@ func vmCreateCustom(ctx context.Context, d *schema.ResourceData, m interface{})
SerialDevices: serialDevices, SerialDevices: serialDevices,
SharedMemory: memorySharedObject, SharedMemory: memorySharedObject,
StartOnBoot: &onBoot, StartOnBoot: &onBoot,
SMBIOS: smbios,
StartupOrder: startupOrder, StartupOrder: startupOrder,
TabletDeviceEnabled: &tabletDevice, TabletDeviceEnabled: &tabletDevice,
Template: &template, Template: &template,
@ -3053,6 +3124,68 @@ func vmGetSerialDeviceList(d *schema.ResourceData) vms.CustomSerialDevices {
return list return list
} }
func vmGetSMBIOS(d *schema.ResourceData) *vms.CustomSMBIOS {
smbiosSections := d.Get(mkResourceVirtualEnvironmentVMSMBIOS).([]interface{})
//nolint:nestif
if len(smbiosSections) > 0 {
smbiosBlock := smbiosSections[0].(map[string]interface{})
b64 := types.CustomBool(true)
family, _ := smbiosBlock[mkResourceVirtualEnvironmentVMSMBIOSFamily].(string)
manufacturer, _ := smbiosBlock[mkResourceVirtualEnvironmentVMSMBIOSManufacturer].(string)
product, _ := smbiosBlock[mkResourceVirtualEnvironmentVMSMBIOSProduct].(string)
serial, _ := smbiosBlock[mkResourceVirtualEnvironmentVMSMBIOSSerial].(string)
sku, _ := smbiosBlock[mkResourceVirtualEnvironmentVMSMBIOSSKU].(string)
version, _ := smbiosBlock[mkResourceVirtualEnvironmentVMSMBIOSVersion].(string)
uid, _ := smbiosBlock[mkResourceVirtualEnvironmentVMSMBIOSUUID].(string)
smbios := vms.CustomSMBIOS{
Base64: &b64,
}
if family != "" {
v := base64.StdEncoding.EncodeToString([]byte(family))
smbios.Family = &v
}
if manufacturer != "" {
v := base64.StdEncoding.EncodeToString([]byte(manufacturer))
smbios.Manufacturer = &v
}
if product != "" {
v := base64.StdEncoding.EncodeToString([]byte(product))
smbios.Product = &v
}
if serial != "" {
v := base64.StdEncoding.EncodeToString([]byte(serial))
smbios.Serial = &v
}
if sku != "" {
v := base64.StdEncoding.EncodeToString([]byte(sku))
smbios.SKU = &v
}
if version != "" {
v := base64.StdEncoding.EncodeToString([]byte(version))
smbios.Version = &v
}
if uid != "" {
smbios.UUID = &uid
}
if smbios.UUID == nil || *smbios.UUID == "" {
smbios.UUID = types.StrPtr(uuid.New().String())
}
return &smbios
}
return nil
}
func vmGetStartupOrder(d *schema.ResourceData) *vms.CustomStartupOrder { func vmGetStartupOrder(d *schema.ResourceData) *vms.CustomStartupOrder {
startup := d.Get(mkResourceVirtualEnvironmentVMStartup).([]interface{}) startup := d.Get(mkResourceVirtualEnvironmentVMStartup).([]interface{})
if len(startup) > 0 { if len(startup) > 0 {
@ -4137,6 +4270,90 @@ func vmReadCustom(
diags = append(diags, diag.FromErr(err)...) diags = append(diags, diag.FromErr(err)...)
} }
// Compare the SMBIOS to the one stored in the state.
var smbios map[string]interface{}
//nolint:nestif
if vmConfig.SMBIOS != nil {
smbios = map[string]interface{}{}
if vmConfig.SMBIOS.Family != nil {
b, err := base64.StdEncoding.DecodeString(*vmConfig.SMBIOS.Family)
diags = append(diags, diag.FromErr(err)...)
smbios[mkResourceVirtualEnvironmentVMSMBIOSFamily] = string(b)
} else {
smbios[mkResourceVirtualEnvironmentVMSMBIOSFamily] = dvResourceVirtualEnvironmentVMSMBIOSFamily
}
if vmConfig.SMBIOS.Manufacturer != nil {
b, err := base64.StdEncoding.DecodeString(*vmConfig.SMBIOS.Manufacturer)
diags = append(diags, diag.FromErr(err)...)
smbios[mkResourceVirtualEnvironmentVMSMBIOSManufacturer] = string(b)
} else {
smbios[mkResourceVirtualEnvironmentVMSMBIOSManufacturer] = dvResourceVirtualEnvironmentVMSMBIOSManufacturer
}
if vmConfig.SMBIOS.Product != nil {
b, err := base64.StdEncoding.DecodeString(*vmConfig.SMBIOS.Product)
diags = append(diags, diag.FromErr(err)...)
smbios[mkResourceVirtualEnvironmentVMSMBIOSProduct] = string(b)
} else {
smbios[mkResourceVirtualEnvironmentVMSMBIOSProduct] = dvResourceVirtualEnvironmentVMSMBIOSProduct
}
if vmConfig.SMBIOS.Serial != nil {
b, err := base64.StdEncoding.DecodeString(*vmConfig.SMBIOS.Serial)
diags = append(diags, diag.FromErr(err)...)
smbios[mkResourceVirtualEnvironmentVMSMBIOSSerial] = string(b)
} else {
smbios[mkResourceVirtualEnvironmentVMSMBIOSSerial] = dvResourceVirtualEnvironmentVMSMBIOSSerial
}
if vmConfig.SMBIOS.SKU != nil {
b, err := base64.StdEncoding.DecodeString(*vmConfig.SMBIOS.SKU)
diags = append(diags, diag.FromErr(err)...)
smbios[mkResourceVirtualEnvironmentVMSMBIOSSKU] = string(b)
} else {
smbios[mkResourceVirtualEnvironmentVMSMBIOSSKU] = dvResourceVirtualEnvironmentVMSMBIOSSKU
}
if vmConfig.SMBIOS.Version != nil {
b, err := base64.StdEncoding.DecodeString(*vmConfig.SMBIOS.Version)
diags = append(diags, diag.FromErr(err)...)
smbios[mkResourceVirtualEnvironmentVMSMBIOSVersion] = string(b)
} else {
smbios[mkResourceVirtualEnvironmentVMSMBIOSVersion] = dvResourceVirtualEnvironmentVMSMBIOSVersion
}
if vmConfig.SMBIOS.UUID != nil {
smbios[mkResourceVirtualEnvironmentVMSMBIOSUUID] = *vmConfig.SMBIOS.UUID
} else {
smbios[mkResourceVirtualEnvironmentVMSMBIOSUUID] = nil
}
}
currentSMBIOS := d.Get(mkResourceVirtualEnvironmentVMSMBIOS).([]interface{})
//nolint:gocritic
if len(clone) > 0 {
if len(currentSMBIOS) > 0 {
err := d.Set(mkResourceVirtualEnvironmentVMSMBIOS, currentSMBIOS)
diags = append(diags, diag.FromErr(err)...)
}
} else if len(smbios) == 0 {
err := d.Set(mkResourceVirtualEnvironmentVMSMBIOS, []interface{}{})
diags = append(diags, diag.FromErr(err)...)
} else if len(currentSMBIOS) > 0 ||
smbios[mkResourceVirtualEnvironmentVMSMBIOSFamily] != dvResourceVirtualEnvironmentVMSMBIOSFamily ||
smbios[mkResourceVirtualEnvironmentVMSMBIOSManufacturer] != dvResourceVirtualEnvironmentVMSMBIOSManufacturer ||
smbios[mkResourceVirtualEnvironmentVMSMBIOSProduct] != dvResourceVirtualEnvironmentVMSMBIOSProduct ||
smbios[mkResourceVirtualEnvironmentVMSMBIOSSerial] != dvResourceVirtualEnvironmentVMSMBIOSSerial ||
smbios[mkResourceVirtualEnvironmentVMSMBIOSSKU] != dvResourceVirtualEnvironmentVMSMBIOSSKU ||
smbios[mkResourceVirtualEnvironmentVMSMBIOSVersion] != dvResourceVirtualEnvironmentVMSMBIOSVersion {
err := d.Set(mkResourceVirtualEnvironmentVMSMBIOS, []interface{}{smbios})
diags = append(diags, diag.FromErr(err)...)
}
// Compare the startup order to the one stored in the state. // Compare the startup order to the one stored in the state.
var startup map[string]interface{} var startup map[string]interface{}
@ -4171,15 +4388,15 @@ func vmReadCustom(
err := d.Set(mkResourceVirtualEnvironmentVMStartup, []interface{}{startup}) err := d.Set(mkResourceVirtualEnvironmentVMStartup, []interface{}{startup})
diags = append(diags, diag.FromErr(err)...) diags = append(diags, diag.FromErr(err)...)
} }
} else if len(startup) == 0 {
err := d.Set(mkResourceVirtualEnvironmentVMStartup, []interface{}{})
diags = append(diags, diag.FromErr(err)...)
} else if len(currentStartup) > 0 || } else if len(currentStartup) > 0 ||
startup[mkResourceVirtualEnvironmentVMStartupOrder] != mkResourceVirtualEnvironmentVMStartupOrder || startup[mkResourceVirtualEnvironmentVMStartupOrder] != mkResourceVirtualEnvironmentVMStartupOrder ||
startup[mkResourceVirtualEnvironmentVMStartupUpDelay] != dvResourceVirtualEnvironmentVMStartupUpDelay || startup[mkResourceVirtualEnvironmentVMStartupUpDelay] != dvResourceVirtualEnvironmentVMStartupUpDelay ||
startup[mkResourceVirtualEnvironmentVMStartupDownDelay] != dvResourceVirtualEnvironmentVMStartupDownDelay { startup[mkResourceVirtualEnvironmentVMStartupDownDelay] != dvResourceVirtualEnvironmentVMStartupDownDelay {
err := d.Set(mkResourceVirtualEnvironmentVMStartup, []interface{}{startup}) err := d.Set(mkResourceVirtualEnvironmentVMStartup, []interface{}{startup})
diags = append(diags, diag.FromErr(err)...) diags = append(diags, diag.FromErr(err)...)
} else {
err := d.Set(mkResourceVirtualEnvironmentVMStartup, []interface{}{})
diags = append(diags, diag.FromErr(err)...)
} }
// Compare the VGA configuration to the one stored in the state. // Compare the VGA configuration to the one stored in the state.
@ -4955,8 +5172,18 @@ func vmUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.D
rebootRequired = true rebootRequired = true
} }
if d.HasChange(mkResourceVirtualEnvironmentVMSMBIOS) {
updateBody.SMBIOS = vmGetSMBIOS(d)
if updateBody.SMBIOS == nil {
del = append(del, "smbios1")
}
}
if d.HasChange(mkResourceVirtualEnvironmentVMStartup) { if d.HasChange(mkResourceVirtualEnvironmentVMStartup) {
updateBody.StartupOrder = vmGetStartupOrder(d) updateBody.StartupOrder = vmGetStartupOrder(d)
if updateBody.StartupOrder == nil {
del = append(del, "startup")
}
} }
// Prepare the new VGA configuration. // Prepare the new VGA configuration.