0
0
mirror of https://github.com/bpg/terraform-provider-proxmox.git synced 2025-06-30 10:33:46 +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
- `wvista` - Windows Vista.
- `wxp` - Windows XP.
- `pool_id` - (Optional) The identifier for a pool to assign the virtual machine
to.
- `reboot` - (Optional) Reboot the VM after initial creation. (defaults
to `false`)
- `pool_id` - (Optional) The identifier for a pool to assign the virtual machine 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 to `false`)
- `serial_device` - (Optional) A serial device (multiple blocks supported).
- `device` - (Optional) The device (defaults to `socket`).
- `/dev/*` - A host serial device.

View File

@ -20,9 +20,9 @@ func TestAccResourceVM(t *testing.T) {
tests := []struct {
name string
step resource.TestStep
step []resource.TestStep
}{
{"multiline description", resource.TestStep{
{"multiline description", []resource.TestStep{{
Config: providerConfig + `
resource "proxmox_virtual_environment_vm" "test_vm1" {
node_name = "pve"
@ -37,8 +37,8 @@ func TestAccResourceVM(t *testing.T) {
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("proxmox_virtual_environment_vm.test_vm1", "description", "my\ndescription\nvalue"),
),
}},
{"single line description", resource.TestStep{
}}},
{"single line description", []resource.TestStep{{
Config: providerConfig + `
resource "proxmox_virtual_environment_vm" "test_vm2" {
node_name = "pve"
@ -49,8 +49,8 @@ func TestAccResourceVM(t *testing.T) {
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("proxmox_virtual_environment_vm.test_vm2", "description", "my description value"),
),
}},
{"no description", resource.TestStep{
}}},
{"no description", []resource.TestStep{{
Config: `
resource "proxmox_virtual_environment_vm" "test_vm3" {
node_name = "pve"
@ -61,7 +61,32 @@ func TestAccResourceVM(t *testing.T) {
Check: resource.ComposeTestCheckFunc(
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)
@ -73,7 +98,7 @@ func TestAccResourceVM(t *testing.T) {
resource.Test(t, resource.TestCase{
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"`
DedicatedMemory *int `json:"memory,omitempty" url:"memory,omitempty"`
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"`
EFIDisk *CustomEFIDisk `json:"efidisk0,omitempty" url:"efidisk0,omitempty"`
FloatingMemory *int `json:"balloon,omitempty" url:"balloon,omitempty"`

View File

@ -104,6 +104,7 @@ const (
dvNetworkDeviceMTU = 0
dvOperatingSystemType = "other"
dvPoolID = ""
dvProtection = false
dvSerialDeviceDevice = "socket"
dvSMBIOSFamily = ""
dvSMBIOSManufacturer = ""
@ -242,6 +243,7 @@ const (
mkOperatingSystem = "operating_system"
mkOperatingSystemType = "type"
mkPoolID = "pool_id"
mkProtection = "protection"
mkSerialDevice = "serial_device"
mkSerialDeviceDevice = "device"
mkSMBIOS = "smbios"
@ -1195,6 +1197,12 @@ func VM() *schema.Resource {
Optional: true,
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: {
Type: schema.TypeList,
Description: "The serial devices",
@ -1822,6 +1830,7 @@ func vmCreateClone(ctx context.Context, d *schema.ResourceData, m interface{}) d
serialDevice := d.Get(mkSerialDevice).([]interface{})
onBoot := types.CustomBool(d.Get(mkOnBoot).(bool))
tabletDevice := types.CustomBool(d.Get(mkTabletDevice).(bool))
protection := types.CustomBool(d.Get(mkProtection).(bool))
template := types.CustomBool(d.Get(mkTemplate).(bool))
vga := d.Get(mkVGA).([]interface{})
@ -2061,6 +2070,11 @@ func vmCreateClone(ctx context.Context, d *schema.ResourceData, m interface{}) d
updateBody.TabletDeviceEnabled = &tabletDevice
}
//nolint:gosimple
if protection != dvProtection {
updateBody.DeletionProtection = &protection
}
if len(tags) > 0 {
tagString := vmGetTagsString(d)
updateBody.Tags = &tagString
@ -2433,6 +2447,7 @@ func vmCreateCustom(ctx context.Context, d *schema.ResourceData, m interface{})
operatingSystemType := operatingSystem[mkOperatingSystemType].(string)
poolID := d.Get(mkPoolID).(string)
protection := types.CustomBool(d.Get(mkProtection).(bool))
serialDevices := vmGetSerialDeviceList(d)
@ -2548,6 +2563,7 @@ func vmCreateCustom(ctx context.Context, d *schema.ResourceData, m interface{})
CPUSockets: &cpuSockets,
CPUUnits: &cpuUnits,
DedicatedMemory: &memoryDedicated,
DeletionProtection: &protection,
EFIDisk: efiDisk,
TPMState: tpmState,
FloatingMemory: &memoryFloating,
@ -4672,6 +4688,23 @@ func vmReadPrimitiveValues(
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) {
err = d.Set(mkStarted, vmStatus.Status == "running")
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
}
if d.HasChange(mkProtection) {
protection := types.CustomBool(d.Get(mkProtection).(bool))
updateBody.DeletionProtection = &protection
}
if d.HasChange(mkTabletDevice) {
tabletDevice := types.CustomBool(d.Get(mkTabletDevice).(bool))
updateBody.TabletDeviceEnabled = &tabletDevice