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:
parent
014b59e04f
commit
cea65a8a12
@ -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.
|
||||||
|
@ -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,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -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"`
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user