0
0
mirror of https://github.com/bpg/terraform-provider-proxmox.git synced 2025-07-01 19:12:59 +00:00

feat(vm): add support for protection attribute (#1126)

Signed-off-by: Pavel Boldyrev <627562+bpg@users.noreply.github.com>
This commit is contained in:
Pavel Boldyrev 2024-03-14 22:23:02 -04:00 committed by GitHub
parent 014b59e04f
commit cea65a8a12
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 75 additions and 13 deletions

View File

@ -447,10 +447,9 @@ output "ubuntu_vm_public_key" {
- `win11` - Windows 11 - `win11` - Windows 11
- `wvista` - Windows Vista. - `wvista` - Windows Vista.
- `wxp` - Windows XP. - `wxp` - Windows XP.
- `pool_id` - (Optional) The identifier for a pool to assign the virtual machine - `pool_id` - (Optional) The identifier for a pool to assign the virtual machine to.
to. - `protection` - (Optional) Sets the protection flag of the VM. This will disable the remove VM and remove disk operations (defaults to `false`).
- `reboot` - (Optional) Reboot the VM after initial creation. (defaults - `reboot` - (Optional) Reboot the VM after initial creation. (defaults to `false`)
to `false`)
- `serial_device` - (Optional) A serial device (multiple blocks supported). - `serial_device` - (Optional) A serial device (multiple blocks supported).
- `device` - (Optional) The device (defaults to `socket`). - `device` - (Optional) The device (defaults to `socket`).
- `/dev/*` - A host serial device. - `/dev/*` - A host serial device.

View File

@ -20,9 +20,9 @@ func TestAccResourceVM(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
step resource.TestStep step []resource.TestStep
}{ }{
{"multiline description", resource.TestStep{ {"multiline description", []resource.TestStep{{
Config: providerConfig + ` Config: providerConfig + `
resource "proxmox_virtual_environment_vm" "test_vm1" { resource "proxmox_virtual_environment_vm" "test_vm1" {
node_name = "pve" node_name = "pve"
@ -37,8 +37,8 @@ func TestAccResourceVM(t *testing.T) {
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("proxmox_virtual_environment_vm.test_vm1", "description", "my\ndescription\nvalue"), resource.TestCheckResourceAttr("proxmox_virtual_environment_vm.test_vm1", "description", "my\ndescription\nvalue"),
), ),
}}, }}},
{"single line description", resource.TestStep{ {"single line description", []resource.TestStep{{
Config: providerConfig + ` Config: providerConfig + `
resource "proxmox_virtual_environment_vm" "test_vm2" { resource "proxmox_virtual_environment_vm" "test_vm2" {
node_name = "pve" node_name = "pve"
@ -49,8 +49,8 @@ func TestAccResourceVM(t *testing.T) {
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("proxmox_virtual_environment_vm.test_vm2", "description", "my description value"), resource.TestCheckResourceAttr("proxmox_virtual_environment_vm.test_vm2", "description", "my description value"),
), ),
}}, }}},
{"no description", resource.TestStep{ {"no description", []resource.TestStep{{
Config: ` Config: `
resource "proxmox_virtual_environment_vm" "test_vm3" { resource "proxmox_virtual_environment_vm" "test_vm3" {
node_name = "pve" node_name = "pve"
@ -61,7 +61,32 @@ func TestAccResourceVM(t *testing.T) {
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("proxmox_virtual_environment_vm.test_vm3", "description", ""), resource.TestCheckResourceAttr("proxmox_virtual_environment_vm.test_vm3", "description", ""),
), ),
}}, }}},
{
"protection", []resource.TestStep{{
Config: `
resource "proxmox_virtual_environment_vm" "test_vm4" {
node_name = "pve"
started = false
protection = true
}`,
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("proxmox_virtual_environment_vm.test_vm4", "protection", "true"),
),
}, {
Config: `
resource "proxmox_virtual_environment_vm" "test_vm4" {
node_name = "pve"
started = false
protection = false
}`,
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("proxmox_virtual_environment_vm.test_vm4", "protection", "false"),
),
}},
},
} }
accProviders := testAccMuxProviders(context.Background(), t) accProviders := testAccMuxProviders(context.Background(), t)
@ -73,7 +98,7 @@ func TestAccResourceVM(t *testing.T) {
resource.Test(t, resource.TestCase{ resource.Test(t, resource.TestCase{
ProtoV6ProviderFactories: accProviders, ProtoV6ProviderFactories: accProviders,
Steps: []resource.TestStep{tt.step}, Steps: tt.step,
}) })
}) })
} }

View File

@ -238,7 +238,7 @@ type CreateRequestBody struct {
CPUUnits *int `json:"cpuunits,omitempty" url:"cpuunits,omitempty"` CPUUnits *int `json:"cpuunits,omitempty" url:"cpuunits,omitempty"`
DedicatedMemory *int `json:"memory,omitempty" url:"memory,omitempty"` DedicatedMemory *int `json:"memory,omitempty" url:"memory,omitempty"`
Delete []string `json:"delete,omitempty" url:"delete,omitempty,comma"` Delete []string `json:"delete,omitempty" url:"delete,omitempty,comma"`
DeletionProtection *types.CustomBool `json:"protection,omitempty" url:"force,omitempty,int"` DeletionProtection *types.CustomBool `json:"protection,omitempty" url:"protection,omitempty,int"`
Description *string `json:"description,omitempty" url:"description,omitempty"` Description *string `json:"description,omitempty" url:"description,omitempty"`
EFIDisk *CustomEFIDisk `json:"efidisk0,omitempty" url:"efidisk0,omitempty"` EFIDisk *CustomEFIDisk `json:"efidisk0,omitempty" url:"efidisk0,omitempty"`
FloatingMemory *int `json:"balloon,omitempty" url:"balloon,omitempty"` FloatingMemory *int `json:"balloon,omitempty" url:"balloon,omitempty"`

View File

@ -104,6 +104,7 @@ const (
dvNetworkDeviceMTU = 0 dvNetworkDeviceMTU = 0
dvOperatingSystemType = "other" dvOperatingSystemType = "other"
dvPoolID = "" dvPoolID = ""
dvProtection = false
dvSerialDeviceDevice = "socket" dvSerialDeviceDevice = "socket"
dvSMBIOSFamily = "" dvSMBIOSFamily = ""
dvSMBIOSManufacturer = "" dvSMBIOSManufacturer = ""
@ -242,6 +243,7 @@ const (
mkOperatingSystem = "operating_system" mkOperatingSystem = "operating_system"
mkOperatingSystemType = "type" mkOperatingSystemType = "type"
mkPoolID = "pool_id" mkPoolID = "pool_id"
mkProtection = "protection"
mkSerialDevice = "serial_device" mkSerialDevice = "serial_device"
mkSerialDeviceDevice = "device" mkSerialDeviceDevice = "device"
mkSMBIOS = "smbios" mkSMBIOS = "smbios"
@ -1195,6 +1197,12 @@ func VM() *schema.Resource {
Optional: true, Optional: true,
Default: dvPoolID, Default: dvPoolID,
}, },
mkProtection: {
Type: schema.TypeBool,
Description: "Sets the protection flag of the VM. This will disable the remove VM and remove disk operations",
Optional: true,
Default: dvProtection,
},
mkSerialDevice: { mkSerialDevice: {
Type: schema.TypeList, Type: schema.TypeList,
Description: "The serial devices", Description: "The serial devices",
@ -1822,6 +1830,7 @@ func vmCreateClone(ctx context.Context, d *schema.ResourceData, m interface{}) d
serialDevice := d.Get(mkSerialDevice).([]interface{}) serialDevice := d.Get(mkSerialDevice).([]interface{})
onBoot := types.CustomBool(d.Get(mkOnBoot).(bool)) onBoot := types.CustomBool(d.Get(mkOnBoot).(bool))
tabletDevice := types.CustomBool(d.Get(mkTabletDevice).(bool)) tabletDevice := types.CustomBool(d.Get(mkTabletDevice).(bool))
protection := types.CustomBool(d.Get(mkProtection).(bool))
template := types.CustomBool(d.Get(mkTemplate).(bool)) template := types.CustomBool(d.Get(mkTemplate).(bool))
vga := d.Get(mkVGA).([]interface{}) vga := d.Get(mkVGA).([]interface{})
@ -2061,6 +2070,11 @@ func vmCreateClone(ctx context.Context, d *schema.ResourceData, m interface{}) d
updateBody.TabletDeviceEnabled = &tabletDevice updateBody.TabletDeviceEnabled = &tabletDevice
} }
//nolint:gosimple
if protection != dvProtection {
updateBody.DeletionProtection = &protection
}
if len(tags) > 0 { if len(tags) > 0 {
tagString := vmGetTagsString(d) tagString := vmGetTagsString(d)
updateBody.Tags = &tagString updateBody.Tags = &tagString
@ -2433,6 +2447,7 @@ func vmCreateCustom(ctx context.Context, d *schema.ResourceData, m interface{})
operatingSystemType := operatingSystem[mkOperatingSystemType].(string) operatingSystemType := operatingSystem[mkOperatingSystemType].(string)
poolID := d.Get(mkPoolID).(string) poolID := d.Get(mkPoolID).(string)
protection := types.CustomBool(d.Get(mkProtection).(bool))
serialDevices := vmGetSerialDeviceList(d) serialDevices := vmGetSerialDeviceList(d)
@ -2548,6 +2563,7 @@ func vmCreateCustom(ctx context.Context, d *schema.ResourceData, m interface{})
CPUSockets: &cpuSockets, CPUSockets: &cpuSockets,
CPUUnits: &cpuUnits, CPUUnits: &cpuUnits,
DedicatedMemory: &memoryDedicated, DedicatedMemory: &memoryDedicated,
DeletionProtection: &protection,
EFIDisk: efiDisk, EFIDisk: efiDisk,
TPMState: tpmState, TPMState: tpmState,
FloatingMemory: &memoryFloating, FloatingMemory: &memoryFloating,
@ -4672,6 +4688,23 @@ func vmReadPrimitiveValues(
diags = append(diags, diag.FromErr(err)...) diags = append(diags, diag.FromErr(err)...)
} }
currentProtection := d.Get(mkProtection).(bool)
//nolint:gosimple
if len(clone) == 0 || currentProtection != dvProtection {
if vmConfig.DeletionProtection != nil {
err = d.Set(
mkProtection,
bool(*vmConfig.DeletionProtection),
)
} else {
// Default value of "protection" is "0" according to the API documentation.
err = d.Set(mkProtection, false)
}
diags = append(diags, diag.FromErr(err)...)
}
if !d.Get(mkTemplate).(bool) { if !d.Get(mkTemplate).(bool) {
err = d.Set(mkStarted, vmStatus.Status == "running") err = d.Set(mkStarted, vmStatus.Status == "running")
diags = append(diags, diag.FromErr(err)...) diags = append(diags, diag.FromErr(err)...)
@ -4878,6 +4911,11 @@ func vmUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.D
updateBody.Name = &name updateBody.Name = &name
} }
if d.HasChange(mkProtection) {
protection := types.CustomBool(d.Get(mkProtection).(bool))
updateBody.DeletionProtection = &protection
}
if d.HasChange(mkTabletDevice) { if d.HasChange(mkTabletDevice) {
tabletDevice := types.CustomBool(d.Get(mkTabletDevice).(bool)) tabletDevice := types.CustomBool(d.Get(mkTabletDevice).(bool))
updateBody.TabletDeviceEnabled = &tabletDevice updateBody.TabletDeviceEnabled = &tabletDevice