mirror of
https://github.com/bpg/terraform-provider-proxmox.git
synced 2025-06-30 02:31:10 +00:00
feat(vm): add support for AMD SEV (#1952)
Signed-off-by: Anton Iacobaeus <anton.iacobaeus@canarybit.eu>
This commit is contained in:
parent
68132bb1fb
commit
28ae95bd09
@ -134,6 +134,20 @@ output "ubuntu_vm_public_key" {
|
|||||||
- `type` - (Optional) The QEMU agent interface type (defaults to `virtio`).
|
- `type` - (Optional) The QEMU agent interface type (defaults to `virtio`).
|
||||||
- `isa` - ISA Serial Port.
|
- `isa` - ISA Serial Port.
|
||||||
- `virtio` - VirtIO (paravirtualized).
|
- `virtio` - VirtIO (paravirtualized).
|
||||||
|
- `amd_sev` - (Optional) Secure Encrypted Virtualization (SEV) features by AMD CPUs.
|
||||||
|
- `type` - (Optional) Enable standard SEV with `std` or enable experimental
|
||||||
|
SEV-ES with the `es` option or enable experimental SEV-SNP with the `snp` option
|
||||||
|
(defaults to `std`).
|
||||||
|
- `allow_smt` - (Optional) Sets policy bit to allow Simultaneous Multi Threading (SMT)
|
||||||
|
(Ignored unless for SEV-SNP) (defaults to `true`).
|
||||||
|
- `kernel_hashes` - (Optional) Add kernel hashes to guest firmware for measured
|
||||||
|
linux kernel launch (defaults to `false`).
|
||||||
|
- `no_debug` - (Optional) Sets policy bit to disallow debugging of guest (defaults
|
||||||
|
to `false`).
|
||||||
|
- `no_key_sharing` - (Optional) Sets policy bit to disallow key sharing with
|
||||||
|
other guests (Ignored for SEV-SNP) (defaults to `false`).
|
||||||
|
|
||||||
|
The `amd_sev` setting is only allowed for a `root@pam` authenticated user.
|
||||||
- `audio_device` - (Optional) An audio device.
|
- `audio_device` - (Optional) An audio device.
|
||||||
- `device` - (Optional) The device (defaults to `intel-hda`).
|
- `device` - (Optional) The device (defaults to `intel-hda`).
|
||||||
- `AC97` - Intel 82801AA AC97 Audio.
|
- `AC97` - Intel 82801AA AC97 Audio.
|
||||||
@ -642,6 +656,27 @@ and when refreshing resources. The provider has no way to distinguish between
|
|||||||
trusts the user to set `agent.enabled` correctly and waits for
|
trusts the user to set `agent.enabled` correctly and waits for
|
||||||
`qemu-guest-agent` to start.
|
`qemu-guest-agent` to start.
|
||||||
|
|
||||||
|
## AMD SEV
|
||||||
|
AMD SEV (-ES, -SNP) are security features for AMD processors. SEV-SNP support
|
||||||
|
is included in Proxmox version **8.4**, see [Proxmox Wiki](
|
||||||
|
https://pve.proxmox.com/wiki/Qemu/KVM_Virtual_Machines#qm_virtual_machines_settings)
|
||||||
|
and [Proxmox Documentation](https://pve.proxmox.com/pve-docs/pve-admin-guide.html#qm_memory_encryption)
|
||||||
|
for more information.
|
||||||
|
|
||||||
|
`amd-sev` requires root and therefore `root@pam` auth.
|
||||||
|
|
||||||
|
SEV-SNP requires `bios = OVMF` and a supported AMD CPU (`EPYC-v4` for instance),
|
||||||
|
`machine = q35` is also advised. No EFI disk is required since SEV-SNP uses
|
||||||
|
consolidated read-only firmware. A configured EFI will be ignored.
|
||||||
|
|
||||||
|
All changes made to `amd_sev` will trigger reboots. Removing or adding the
|
||||||
|
`amd_sev` block will force a replacement of the resource. Modifying the `amd_sev`
|
||||||
|
block will not trigger replacements.
|
||||||
|
|
||||||
|
`allow_smt` is by default set to `true` even if `snp` is not the selected type.
|
||||||
|
Proxmox will ignore this value when `snp` is not in use. Likewise `no_key_sharing`
|
||||||
|
is `false` by default but ignored by Proxmox when `snp` is in use.
|
||||||
|
|
||||||
## Important Notes
|
## Important Notes
|
||||||
|
|
||||||
### `local-lvm` Datastore
|
### `local-lvm` Datastore
|
||||||
|
110
proxmox/nodes/vms/custom_amdsev.go
Normal file
110
proxmox/nodes/vms/custom_amdsev.go
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
/*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package vms
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/bpg/terraform-provider-proxmox/proxmox/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CustomAMDSEV handles AMDSEV parameters.
|
||||||
|
type CustomAMDSEV struct {
|
||||||
|
Type string `json:"type" url:"type"`
|
||||||
|
AllowSMT *types.CustomBool `json:"allow-smt" url:"allow-smt,int"`
|
||||||
|
KernelHashes *types.CustomBool `json:"kernel-hashes" url:"kernel-hashes,int"`
|
||||||
|
NoDebug *types.CustomBool `json:"no-debug" url:"no-debug,int"`
|
||||||
|
NoKeySharing *types.CustomBool `json:"no-key-sharing" url:"no-key-sharing,int"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncodeValues converts a CustomAMDSEV struct to a URL value.
|
||||||
|
func (r *CustomAMDSEV) EncodeValues(key string, v *url.Values) error {
|
||||||
|
values := []string{
|
||||||
|
fmt.Sprintf("type=%s", r.Type),
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.AllowSMT != nil {
|
||||||
|
if *r.AllowSMT {
|
||||||
|
values = append(values, "allow-smt=1")
|
||||||
|
} else {
|
||||||
|
values = append(values, "allow-smt=0")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.KernelHashes != nil {
|
||||||
|
if *r.KernelHashes {
|
||||||
|
values = append(values, "kernel-hashes=1")
|
||||||
|
} else {
|
||||||
|
values = append(values, "kernel-hashes=0")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.NoDebug != nil {
|
||||||
|
if *r.NoDebug {
|
||||||
|
values = append(values, "no-debug=1")
|
||||||
|
} else {
|
||||||
|
values = append(values, "no-debug=0")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.NoKeySharing != nil {
|
||||||
|
if *r.NoKeySharing {
|
||||||
|
values = append(values, "no-key-sharing=1")
|
||||||
|
} else {
|
||||||
|
values = append(values, "no-key-sharing=0")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(values) > 0 {
|
||||||
|
v.Add(key, strings.Join(values, ","))
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON converts a CustomAMDSEV string to an object.
|
||||||
|
func (r *CustomAMDSEV) UnmarshalJSON(b []byte) error {
|
||||||
|
var s string
|
||||||
|
|
||||||
|
if err := json.Unmarshal(b, &s); err != nil {
|
||||||
|
return fmt.Errorf("error unmarshalling CustomAMDSEV: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
pairs := strings.Split(s, ",")
|
||||||
|
|
||||||
|
for i, p := range pairs {
|
||||||
|
v := strings.Split(strings.TrimSpace(p), "=")
|
||||||
|
|
||||||
|
if len(v) == 1 && i == 0 {
|
||||||
|
r.Type = v[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(v) == 2 {
|
||||||
|
switch v[0] {
|
||||||
|
case "type":
|
||||||
|
r.Type = v[1]
|
||||||
|
case "allow-smt":
|
||||||
|
allow_smt := types.CustomBool(v[1] == "1")
|
||||||
|
r.AllowSMT = &allow_smt
|
||||||
|
case "kernel-hashes":
|
||||||
|
kernel_hashes := types.CustomBool(v[1] == "1")
|
||||||
|
r.KernelHashes = &kernel_hashes
|
||||||
|
case "no-debug":
|
||||||
|
no_debug := types.CustomBool(v[1] == "1")
|
||||||
|
r.NoDebug = &no_debug
|
||||||
|
case "no-key-sharing":
|
||||||
|
no_key_sharing := types.CustomBool(v[1] == "1")
|
||||||
|
r.NoKeySharing = &no_key_sharing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
@ -47,6 +47,7 @@ type CloneRequestBody struct {
|
|||||||
type CreateRequestBody struct {
|
type CreateRequestBody struct {
|
||||||
ACPI *types.CustomBool `json:"acpi,omitempty" url:"acpi,omitempty,int"`
|
ACPI *types.CustomBool `json:"acpi,omitempty" url:"acpi,omitempty,int"`
|
||||||
Agent *CustomAgent `json:"agent,omitempty" url:"agent,omitempty"`
|
Agent *CustomAgent `json:"agent,omitempty" url:"agent,omitempty"`
|
||||||
|
AMDSEV *CustomAMDSEV `json:"amd-sev,omitempty" url:"amd-sev,omitempty"`
|
||||||
AllowReboot *types.CustomBool `json:"reboot,omitempty" url:"reboot,omitempty,int"`
|
AllowReboot *types.CustomBool `json:"reboot,omitempty" url:"reboot,omitempty,int"`
|
||||||
AudioDevices CustomAudioDevices `json:"audio,omitempty" url:"audio,omitempty"`
|
AudioDevices CustomAudioDevices `json:"audio,omitempty" url:"audio,omitempty"`
|
||||||
Autostart *types.CustomBool `json:"autostart,omitempty" url:"autostart,omitempty,int"`
|
Autostart *types.CustomBool `json:"autostart,omitempty" url:"autostart,omitempty,int"`
|
||||||
@ -183,6 +184,7 @@ type GetResponseBody struct {
|
|||||||
type GetResponseData struct {
|
type GetResponseData struct {
|
||||||
ACPI *types.CustomBool `json:"acpi,omitempty"`
|
ACPI *types.CustomBool `json:"acpi,omitempty"`
|
||||||
Agent *CustomAgent `json:"agent,omitempty"`
|
Agent *CustomAgent `json:"agent,omitempty"`
|
||||||
|
AMDSEV *CustomAMDSEV `json:"amd-sev,omitempty"`
|
||||||
AllowReboot *types.CustomBool `json:"reboot,omitempty"`
|
AllowReboot *types.CustomBool `json:"reboot,omitempty"`
|
||||||
AudioDevice *CustomAudioDevice `json:"audio0,omitempty"`
|
AudioDevice *CustomAudioDevice `json:"audio0,omitempty"`
|
||||||
Autostart *types.CustomBool `json:"autostart,omitempty"`
|
Autostart *types.CustomBool `json:"autostart,omitempty"`
|
||||||
|
@ -158,6 +158,11 @@ func QEMUAgentTypeValidator() schema.SchemaValidateDiagFunc {
|
|||||||
return validation.ToDiagFunc(validation.StringInSlice([]string{"isa", "virtio"}, false))
|
return validation.ToDiagFunc(validation.StringInSlice([]string{"isa", "virtio"}, false))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AMDSEVTypeValidator is a schema validation function for AMDSEV types.
|
||||||
|
func AMDSEVTypeValidator() schema.SchemaValidateDiagFunc {
|
||||||
|
return validation.ToDiagFunc(validation.StringInSlice([]string{"std", "es", "snp"}, false))
|
||||||
|
}
|
||||||
|
|
||||||
// KeyboardLayoutValidator is a schema validation function for keyboard layouts.
|
// KeyboardLayoutValidator is a schema validation function for keyboard layouts.
|
||||||
func KeyboardLayoutValidator() schema.SchemaValidateDiagFunc {
|
func KeyboardLayoutValidator() schema.SchemaValidateDiagFunc {
|
||||||
return validation.ToDiagFunc(validation.StringInSlice([]string{
|
return validation.ToDiagFunc(validation.StringInSlice([]string{
|
||||||
|
@ -49,6 +49,11 @@ const (
|
|||||||
dvAgentTimeout = "15m"
|
dvAgentTimeout = "15m"
|
||||||
dvAgentTrim = false
|
dvAgentTrim = false
|
||||||
dvAgentType = "virtio"
|
dvAgentType = "virtio"
|
||||||
|
dvAMDSEVType = "std"
|
||||||
|
dvAMDSEVAllowSMT = true
|
||||||
|
dvAMDSEVKernelHashes = false
|
||||||
|
dvAMDSEVNoDebug = false
|
||||||
|
dvAMDSEVNoKeySharing = false
|
||||||
dvAudioDeviceDevice = "intel-hda"
|
dvAudioDeviceDevice = "intel-hda"
|
||||||
dvAudioDeviceDriver = "spice"
|
dvAudioDeviceDriver = "spice"
|
||||||
dvAudioDeviceEnabled = true
|
dvAudioDeviceEnabled = true
|
||||||
@ -153,6 +158,12 @@ const (
|
|||||||
mkAgentTimeout = "timeout"
|
mkAgentTimeout = "timeout"
|
||||||
mkAgentTrim = "trim"
|
mkAgentTrim = "trim"
|
||||||
mkAgentType = "type"
|
mkAgentType = "type"
|
||||||
|
mkAMDSEV = "amd_sev"
|
||||||
|
mkAMDSEVType = "type"
|
||||||
|
mkAMDSEVAllowSMT = "allow_smt"
|
||||||
|
mkAMDSEVKernelHashes = "kernel_hashes"
|
||||||
|
mkAMDSEVNoDebug = "no_debug"
|
||||||
|
mkAMDSEVNoKeySharing = "no_key_sharing"
|
||||||
mkAudioDevice = "audio_device"
|
mkAudioDevice = "audio_device"
|
||||||
mkAudioDeviceDevice = "device"
|
mkAudioDeviceDevice = "device"
|
||||||
mkAudioDeviceDriver = "driver"
|
mkAudioDeviceDriver = "driver"
|
||||||
@ -389,6 +400,53 @@ func VM() *schema.Resource {
|
|||||||
MaxItems: 1,
|
MaxItems: 1,
|
||||||
MinItems: 0,
|
MinItems: 0,
|
||||||
},
|
},
|
||||||
|
mkAMDSEV: {
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Description: "Secure Encrypted Virtualization (SEV) features by AMD CPUs",
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
DefaultFunc: func() (interface{}, error) {
|
||||||
|
return []interface{}{}, nil
|
||||||
|
},
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
mkAMDSEVType: {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Description: "Enable standard SEV with type=std or enable experimental SEV-ES with the es option" +
|
||||||
|
"or enable experimental SEV-SNP with the snp option.",
|
||||||
|
Optional: true,
|
||||||
|
Default: dvAMDSEVType,
|
||||||
|
ValidateDiagFunc: AMDSEVTypeValidator(),
|
||||||
|
},
|
||||||
|
mkAMDSEVAllowSMT: {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Description: "Sets policy bit to allow Simultaneous Multi Threading (SMT) (Ignored unless for SEV-SNP)",
|
||||||
|
Optional: true,
|
||||||
|
Default: dvAMDSEVAllowSMT,
|
||||||
|
},
|
||||||
|
mkAMDSEVKernelHashes: {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Description: "Add kernel hashes to guest firmware for measured linux kernel launch",
|
||||||
|
Optional: true,
|
||||||
|
Default: dvAMDSEVKernelHashes,
|
||||||
|
},
|
||||||
|
mkAMDSEVNoDebug: {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Description: "Sets policy bit to disallow debugging of guest",
|
||||||
|
Optional: true,
|
||||||
|
Default: dvAMDSEVNoDebug,
|
||||||
|
},
|
||||||
|
mkAMDSEVNoKeySharing: {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Description: "Sets policy bit to disallow key sharing with other guests (Ignored for SEV-SNP)",
|
||||||
|
Optional: true,
|
||||||
|
Default: dvAMDSEVNoKeySharing,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MaxItems: 1,
|
||||||
|
MinItems: 0,
|
||||||
|
},
|
||||||
mkKVMArguments: {
|
mkKVMArguments: {
|
||||||
Type: schema.TypeString,
|
Type: schema.TypeString,
|
||||||
Description: "The args implementation",
|
Description: "The args implementation",
|
||||||
@ -1932,6 +1990,7 @@ func vmCreateClone(ctx context.Context, d *schema.ResourceData, m interface{}) d
|
|||||||
|
|
||||||
acpi := types.CustomBool(d.Get(mkACPI).(bool))
|
acpi := types.CustomBool(d.Get(mkACPI).(bool))
|
||||||
agent := d.Get(mkAgent).([]interface{})
|
agent := d.Get(mkAgent).([]interface{})
|
||||||
|
amdsev := d.Get(mkAMDSEV).([]interface{})
|
||||||
bios := d.Get(mkBIOS).(string)
|
bios := d.Get(mkBIOS).(string)
|
||||||
cdrom := d.Get(mkCDROM).([]interface{})
|
cdrom := d.Get(mkCDROM).([]interface{})
|
||||||
cpu := d.Get(mkCPU).([]interface{})
|
cpu := d.Get(mkCPU).([]interface{})
|
||||||
@ -1982,6 +2041,32 @@ func vmCreateClone(ctx context.Context, d *schema.ResourceData, m interface{}) d
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(amdsev) > 0 && amdsev[0] != nil {
|
||||||
|
amdsevBlock := amdsev[0].(map[string]interface{})
|
||||||
|
|
||||||
|
amdsevType := amdsevBlock[mkAMDSEVType].(string)
|
||||||
|
amdsevAllowSMT := types.CustomBool(
|
||||||
|
amdsevBlock[mkAMDSEVAllowSMT].(bool),
|
||||||
|
)
|
||||||
|
amdsevKernelHashes := types.CustomBool(
|
||||||
|
amdsevBlock[mkAMDSEVKernelHashes].(bool),
|
||||||
|
)
|
||||||
|
amdsevNoDebug := types.CustomBool(
|
||||||
|
amdsevBlock[mkAMDSEVNoDebug].(bool),
|
||||||
|
)
|
||||||
|
amdsevNoKeySharing := types.CustomBool(
|
||||||
|
amdsevBlock[mkAMDSEVNoKeySharing].(bool),
|
||||||
|
)
|
||||||
|
|
||||||
|
updateBody.AMDSEV = &vms.CustomAMDSEV{
|
||||||
|
Type: amdsevType,
|
||||||
|
AllowSMT: &amdsevAllowSMT,
|
||||||
|
KernelHashes: &amdsevKernelHashes,
|
||||||
|
NoDebug: &amdsevNoDebug,
|
||||||
|
NoKeySharing: &amdsevNoKeySharing,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if kvmArguments != dvKVMArguments {
|
if kvmArguments != dvKVMArguments {
|
||||||
updateBody.KVMArguments = &kvmArguments
|
updateBody.KVMArguments = &kvmArguments
|
||||||
}
|
}
|
||||||
@ -2437,6 +2522,8 @@ func vmCreateCustom(ctx context.Context, d *schema.ResourceData, m interface{})
|
|||||||
agentTrim := types.CustomBool(agentBlock[mkAgentTrim].(bool))
|
agentTrim := types.CustomBool(agentBlock[mkAgentTrim].(bool))
|
||||||
agentType := agentBlock[mkAgentType].(string)
|
agentType := agentBlock[mkAgentType].(string)
|
||||||
|
|
||||||
|
amdsev := vmGetAMDSEVObject(d)
|
||||||
|
|
||||||
kvmArguments := d.Get(mkKVMArguments).(string)
|
kvmArguments := d.Get(mkKVMArguments).(string)
|
||||||
|
|
||||||
audioDevices := vmGetAudioDeviceList(d)
|
audioDevices := vmGetAudioDeviceList(d)
|
||||||
@ -2718,6 +2805,7 @@ func vmCreateCustom(ctx context.Context, d *schema.ResourceData, m interface{})
|
|||||||
TrimClonedDisks: &agentTrim,
|
TrimClonedDisks: &agentTrim,
|
||||||
Type: &agentType,
|
Type: &agentType,
|
||||||
},
|
},
|
||||||
|
AMDSEV: amdsev,
|
||||||
AudioDevices: audioDevices,
|
AudioDevices: audioDevices,
|
||||||
BIOS: &bios,
|
BIOS: &bios,
|
||||||
Boot: &vms.CustomBoot{
|
Boot: &vms.CustomBoot{
|
||||||
@ -2869,6 +2957,39 @@ func vmCreateStart(ctx context.Context, d *schema.ResourceData, m interface{}) d
|
|||||||
return vmRead(ctx, d, m)
|
return vmRead(ctx, d, m)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func vmGetAMDSEVObject(d *schema.ResourceData) *vms.CustomAMDSEV {
|
||||||
|
var amdsev *vms.CustomAMDSEV
|
||||||
|
|
||||||
|
amdsevBlock := d.Get(mkAMDSEV).([]interface{})
|
||||||
|
if len(amdsevBlock) > 0 && amdsevBlock[0] != nil {
|
||||||
|
block := amdsevBlock[0].(map[string]interface{})
|
||||||
|
|
||||||
|
amdsevType := block[mkAMDSEVType].(string)
|
||||||
|
amdsevAllowSMT := types.CustomBool(
|
||||||
|
block[mkAMDSEVAllowSMT].(bool),
|
||||||
|
)
|
||||||
|
amdsevKernelHashes := types.CustomBool(
|
||||||
|
block[mkAMDSEVKernelHashes].(bool),
|
||||||
|
)
|
||||||
|
amdsevNoDebug := types.CustomBool(
|
||||||
|
block[mkAMDSEVNoDebug].(bool),
|
||||||
|
)
|
||||||
|
amdsevNoKeySharing := types.CustomBool(
|
||||||
|
block[mkAMDSEVNoKeySharing].(bool),
|
||||||
|
)
|
||||||
|
|
||||||
|
amdsev = &vms.CustomAMDSEV{
|
||||||
|
Type: amdsevType,
|
||||||
|
AllowSMT: &amdsevAllowSMT,
|
||||||
|
KernelHashes: &amdsevKernelHashes,
|
||||||
|
NoDebug: &amdsevNoDebug,
|
||||||
|
NoKeySharing: &amdsevNoKeySharing,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return amdsev
|
||||||
|
}
|
||||||
|
|
||||||
func vmGetAudioDeviceList(d *schema.ResourceData) vms.CustomAudioDevices {
|
func vmGetAudioDeviceList(d *schema.ResourceData) vms.CustomAudioDevices {
|
||||||
devices := d.Get(mkAudioDevice).([]interface{})
|
devices := d.Get(mkAudioDevice).([]interface{})
|
||||||
list := make(vms.CustomAudioDevices, len(devices))
|
list := make(vms.CustomAudioDevices, len(devices))
|
||||||
@ -3628,6 +3749,65 @@ func vmReadCustom(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Compare the amdsev configuration to the one stored in the state.
|
||||||
|
currentAMDSEV := d.Get(mkAMDSEV).([]interface{})
|
||||||
|
|
||||||
|
//nolint:gocritic
|
||||||
|
if len(clone) == 0 || len(currentAMDSEV) > 0 {
|
||||||
|
if vmConfig.AMDSEV != nil {
|
||||||
|
amdsev := map[string]interface{}{}
|
||||||
|
|
||||||
|
amdsev[mkAMDSEVType] = vmConfig.AMDSEV.Type
|
||||||
|
|
||||||
|
if vmConfig.AMDSEV.AllowSMT != nil {
|
||||||
|
amdsev[mkAMDSEVAllowSMT] = bool(*vmConfig.AMDSEV.AllowSMT)
|
||||||
|
} else {
|
||||||
|
amdsev[mkAMDSEVAllowSMT] = false
|
||||||
|
}
|
||||||
|
|
||||||
|
if vmConfig.AMDSEV.KernelHashes != nil {
|
||||||
|
amdsev[mkAMDSEVKernelHashes] = bool(*vmConfig.AMDSEV.KernelHashes)
|
||||||
|
} else {
|
||||||
|
amdsev[mkAMDSEVKernelHashes] = false
|
||||||
|
}
|
||||||
|
|
||||||
|
if vmConfig.AMDSEV.NoDebug != nil {
|
||||||
|
amdsev[mkAMDSEVNoDebug] = bool(*vmConfig.AMDSEV.NoDebug)
|
||||||
|
} else {
|
||||||
|
amdsev[mkAMDSEVNoDebug] = false
|
||||||
|
}
|
||||||
|
|
||||||
|
if vmConfig.AMDSEV.NoKeySharing != nil {
|
||||||
|
amdsev[mkAMDSEVNoKeySharing] = bool(*vmConfig.AMDSEV.NoKeySharing)
|
||||||
|
} else {
|
||||||
|
amdsev[mkAMDSEVNoKeySharing] = false
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(clone) > 0 {
|
||||||
|
if len(currentAMDSEV) > 0 {
|
||||||
|
err := d.Set(mkAMDSEV, []interface{}{amdsev})
|
||||||
|
diags = append(diags, diag.FromErr(err)...)
|
||||||
|
}
|
||||||
|
} else if len(currentAMDSEV) > 0 ||
|
||||||
|
amdsev[mkAMDSEVType] != dvAMDSEVType ||
|
||||||
|
amdsev[mkAMDSEVAllowSMT] != dvAMDSEVAllowSMT ||
|
||||||
|
amdsev[mkAMDSEVKernelHashes] != dvAMDSEVKernelHashes ||
|
||||||
|
amdsev[mkAMDSEVNoDebug] != dvAMDSEVNoDebug ||
|
||||||
|
amdsev[mkAMDSEVNoKeySharing] != dvAMDSEVNoKeySharing {
|
||||||
|
err := d.Set(mkAMDSEV, []interface{}{amdsev})
|
||||||
|
diags = append(diags, diag.FromErr(err)...)
|
||||||
|
}
|
||||||
|
} else if len(clone) > 0 {
|
||||||
|
if len(currentAMDSEV) > 0 {
|
||||||
|
err := d.Set(mkAMDSEV, []interface{}{})
|
||||||
|
diags = append(diags, diag.FromErr(err)...)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
err := d.Set(mkAMDSEV, []interface{}{})
|
||||||
|
diags = append(diags, diag.FromErr(err)...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Compare the audio devices to those stored in the state.
|
// Compare the audio devices to those stored in the state.
|
||||||
currentAudioDevice := d.Get(mkAudioDevice).([]interface{})
|
currentAudioDevice := d.Get(mkAudioDevice).([]interface{})
|
||||||
|
|
||||||
@ -5061,6 +5241,15 @@ func vmUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.D
|
|||||||
rebootRequired = true
|
rebootRequired = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Prepare the new amdsev configuration.
|
||||||
|
if d.HasChange(mkAMDSEV) {
|
||||||
|
amdsev := vmGetAMDSEVObject(d)
|
||||||
|
|
||||||
|
updateBody.AMDSEV = amdsev
|
||||||
|
|
||||||
|
rebootRequired = true
|
||||||
|
}
|
||||||
|
|
||||||
// Prepare the new audio devices.
|
// Prepare the new audio devices.
|
||||||
if d.HasChange(mkAudioDevice) {
|
if d.HasChange(mkAudioDevice) {
|
||||||
updateBody.AudioDevices = vmGetAudioDeviceList(d)
|
updateBody.AudioDevices = vmGetAudioDeviceList(d)
|
||||||
|
Loading…
Reference in New Issue
Block a user