From 47abbdb63acf9e50fd3a286380b1646dd4a4b7ab Mon Sep 17 00:00:00 2001 From: Marco Attia <54147992+Vaneixus@users.noreply.github.com> Date: Sun, 7 Sep 2025 03:18:24 +0000 Subject: [PATCH 01/12] fix(disk): restore updating boot disk. Signed-off-by: Marco Attia <54147992+Vaneixus@users.noreply.github.com> --- proxmoxtf/resource/vm/disk/disk.go | 18 ++++++++++++------ proxmoxtf/resource/vm/disk/disk_test.go | 2 +- proxmoxtf/resource/vm/vm.go | 15 +++++++-------- 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/proxmoxtf/resource/vm/disk/disk.go b/proxmoxtf/resource/vm/disk/disk.go index 53a1a647a..872d9e04b 100644 --- a/proxmoxtf/resource/vm/disk/disk.go +++ b/proxmoxtf/resource/vm/disk/disk.go @@ -582,8 +582,9 @@ func Update( planDisks vms.CustomStorageDevices, currentDisks vms.CustomStorageDevices, updateBody *vms.UpdateRequestBody, -) (bool, error) { +) (bool, bool, error) { rebootRequired := false + shutdownBeforeUpdate := false if d.HasChange(MkDisk) { for iface, disk := range planDisks { @@ -595,7 +596,7 @@ func Update( // only disks with defined file ID are custom image disks that need to be created via import. err := createCustomDisk(ctx, client, nodeName, vmID, iface, *disk) if err != nil { - return false, fmt.Errorf("creating custom disk: %w", err) + return false, false, fmt.Errorf("creating custom disk: %w", err) } } else { // otherwise this is a blank disk that can be added directly via update API @@ -611,7 +612,7 @@ func Update( tmp = currentDisks[iface] default: // something went wrong - return false, fmt.Errorf("missing device %s", iface) + return false, false, fmt.Errorf("missing device %s", iface) } if tmp == nil || disk == nil { @@ -623,8 +624,13 @@ func Update( tmp.AIO = disk.AIO } - // Never send ImportFrom for existing disks - it triggers re-import which fails for boot disks - // ImportFrom is only for initial disk creation, not updates + if disk.ImportFrom != nil && *disk.ImportFrom != "" { + rebootRequired = true + shutdownBeforeUpdate = true + tmp.DatastoreID = disk.DatastoreID + tmp.ImportFrom = disk.ImportFrom + tmp.Size = disk.Size + } tmp.Backup = disk.Backup tmp.BurstableReadSpeedMbps = disk.BurstableReadSpeedMbps @@ -646,5 +652,5 @@ func Update( } } - return rebootRequired, nil + return shutdownBeforeUpdate, rebootRequired, nil } diff --git a/proxmoxtf/resource/vm/disk/disk_test.go b/proxmoxtf/resource/vm/disk/disk_test.go index 3708770a0..2c49d51ec 100644 --- a/proxmoxtf/resource/vm/disk/disk_test.go +++ b/proxmoxtf/resource/vm/disk/disk_test.go @@ -337,7 +337,7 @@ func TestDiskUpdateSkipsUnchangedDisks(t *testing.T) { require.NoError(t, err) // Call the Update function - _, err = Update(ctx, client, nodeName, vmID, resourceData, planDisks, currentDisks, updateBody) + _, _, err = Update(ctx, client, nodeName, vmID, resourceData, planDisks, currentDisks, updateBody) require.NoError(t, err) // Check that only the changed disk (scsi1) is in the update body diff --git a/proxmoxtf/resource/vm/vm.go b/proxmoxtf/resource/vm/vm.go index d2e053c3f..0cc8998f8 100644 --- a/proxmoxtf/resource/vm/vm.go +++ b/proxmoxtf/resource/vm/vm.go @@ -5426,7 +5426,7 @@ func vmUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.D return diag.FromErr(err) } - rr, err := disk.Update(ctx, client, nodeName, vmID, d, planDisks, allDiskInfo, updateBody) + stoppedBeforeUpdate, rr, err := disk.Update(ctx, client, nodeName, vmID, d, planDisks, allDiskInfo, updateBody) if err != nil { return diag.FromErr(err) } @@ -5461,7 +5461,6 @@ func vmUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.D } // Prepare the new cloud-init configuration. - stoppedBeforeUpdate := false cloudInitRebuildRequired := false if d.HasChange(mkInitialization) { @@ -5750,16 +5749,11 @@ func vmUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.D // Update the configuration now that everything has been prepared. updateBody.Delete = del - e = vmAPI.UpdateVM(ctx, updateBody) - if e != nil { - return diag.FromErr(e) - } - // Determine if the state of the virtual machine state needs to be changed. //nolint: nestif if (d.HasChange(mkStarted) || stoppedBeforeUpdate) && !bool(template) { started := d.Get(mkStarted).(bool) - if started { + if started && !stoppedBeforeUpdate { if diags := vmStart(ctx, vmAPI, d); diags != nil { return diags } @@ -5772,6 +5766,11 @@ func vmUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.D } } + e = vmAPI.UpdateVM(ctx, updateBody) + if e != nil { + return diag.FromErr(e) + } + if cloudInitRebuildRequired { if er := vmAPI.RebuildCloudInitDisk(ctx); er != nil { return diag.FromErr(err) From b48de3e03e57539fc329c2ecd99f54c651e3918d Mon Sep 17 00:00:00 2001 From: Marco Attia <54147992+Vaneixus@users.noreply.github.com> Date: Sun, 7 Sep 2025 03:23:03 +0000 Subject: [PATCH 02/12] fix(vm): restart vm after update is done. Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> Signed-off-by: Marco Attia <54147992+Vaneixus@users.noreply.github.com> --- proxmoxtf/resource/vm/vm.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/proxmoxtf/resource/vm/vm.go b/proxmoxtf/resource/vm/vm.go index 0cc8998f8..2d53a5c0a 100644 --- a/proxmoxtf/resource/vm/vm.go +++ b/proxmoxtf/resource/vm/vm.go @@ -5769,6 +5769,14 @@ func vmUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.D e = vmAPI.UpdateVM(ctx, updateBody) if e != nil { return diag.FromErr(e) +} + + if stoppedBeforeUpdate && d.Get(mkStarted).(bool) { + if diags := vmStart(ctx, vmAPI, d); diags != nil { + return diags + } + // The VM has been started, so a reboot is no longer required. + rebootRequired = false } if cloudInitRebuildRequired { From 7d3248760d73788543f71e4c65d87a0723e399b6 Mon Sep 17 00:00:00 2001 From: Marco Attia <54147992+Vaneixus@users.noreply.github.com> Date: Sun, 7 Sep 2025 03:28:36 +0000 Subject: [PATCH 03/12] fix(lint): curly bracket indentation. Signed-off-by: Marco Attia <54147992+Vaneixus@users.noreply.github.com> --- proxmoxtf/resource/vm/vm.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proxmoxtf/resource/vm/vm.go b/proxmoxtf/resource/vm/vm.go index 2d53a5c0a..137dba98a 100644 --- a/proxmoxtf/resource/vm/vm.go +++ b/proxmoxtf/resource/vm/vm.go @@ -5769,7 +5769,7 @@ func vmUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.D e = vmAPI.UpdateVM(ctx, updateBody) if e != nil { return diag.FromErr(e) -} + } if stoppedBeforeUpdate && d.Get(mkStarted).(bool) { if diags := vmStart(ctx, vmAPI, d); diags != nil { From 43d1733b2a0fa1eef3891377d4b231acf8efe093 Mon Sep 17 00:00:00 2001 From: Marco Attia <54147992+Vaneixus@users.noreply.github.com> Date: Sun, 21 Sep 2025 16:01:51 +0000 Subject: [PATCH 04/12] fix(vm): shutdown vm before updating boot disk. Signed-off-by: Marco Attia <54147992+Vaneixus@users.noreply.github.com> --- proxmoxtf/resource/vm/vm.go | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/proxmoxtf/resource/vm/vm.go b/proxmoxtf/resource/vm/vm.go index 137dba98a..8882a7847 100644 --- a/proxmoxtf/resource/vm/vm.go +++ b/proxmoxtf/resource/vm/vm.go @@ -5431,6 +5431,12 @@ func vmUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.D return diag.FromErr(err) } + if stoppedBeforeUpdate { + if er := vmShutdown(ctx, vmAPI, d); er != nil { + return er + } + } + rebootRequired = rebootRequired || rr // Prepare the new efi disk configuration. @@ -5507,8 +5513,10 @@ func vmUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.D if mustMove || mustChangeDatastore || existingInterface == "" { // CloudInit must be moved, either from a device to another or from a datastore // to another (or both). This requires the VM to be stopped. - if er := vmShutdown(ctx, vmAPI, d); er != nil { - return er + if !stoppedBeforeUpdate { + if er := vmShutdown(ctx, vmAPI, d); er != nil { + return er + } } if er := deleteIdeDrives(ctx, vmAPI, initializationInterface, existingInterface); er != nil { @@ -5749,6 +5757,11 @@ func vmUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.D // Update the configuration now that everything has been prepared. updateBody.Delete = del + e = vmAPI.UpdateVM(ctx, updateBody) + if e != nil { + return diag.FromErr(e) + } + // Determine if the state of the virtual machine state needs to be changed. //nolint: nestif if (d.HasChange(mkStarted) || stoppedBeforeUpdate) && !bool(template) { @@ -5766,11 +5779,6 @@ func vmUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.D } } - e = vmAPI.UpdateVM(ctx, updateBody) - if e != nil { - return diag.FromErr(e) - } - if stoppedBeforeUpdate && d.Get(mkStarted).(bool) { if diags := vmStart(ctx, vmAPI, d); diags != nil { return diags From c67b9109e7c0bdbfd51d0606df274bc70051353d Mon Sep 17 00:00:00 2001 From: Marco Attia <54147992+Vaneixus@users.noreply.github.com> Date: Sun, 21 Sep 2025 21:08:51 -0400 Subject: [PATCH 05/12] Remove blank line in vm.go Signed-off-by: Marco Attia <54147992+Vaneixus@users.noreply.github.com> --- proxmoxtf/resource/vm/vm.go | 1 - 1 file changed, 1 deletion(-) diff --git a/proxmoxtf/resource/vm/vm.go b/proxmoxtf/resource/vm/vm.go index 41ef44b4d..b1dd76840 100644 --- a/proxmoxtf/resource/vm/vm.go +++ b/proxmoxtf/resource/vm/vm.go @@ -5426,7 +5426,6 @@ func vmUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.D return diag.FromErr(err) } - // Handle disk deletion before applying other changes if d.HasChange(disk.MkDisk) { bootOrder := d.Get(mkBootOrder).([]interface{}) From 911c59162cc34976b1acfb8a5d8ae80532393e24 Mon Sep 17 00:00:00 2001 From: Marco Attia <54147992+Vaneixus@users.noreply.github.com> Date: Sat, 8 Nov 2025 18:57:06 +0000 Subject: [PATCH 06/12] fix(vm): vm start happening twice. Signed-off-by: Marco Attia <54147992+Vaneixus@users.noreply.github.com> --- proxmoxtf/resource/vm/disk/disk.go | 1 - proxmoxtf/resource/vm/vm.go | 12 ++---------- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/proxmoxtf/resource/vm/disk/disk.go b/proxmoxtf/resource/vm/disk/disk.go index 872d9e04b..d7ec23394 100644 --- a/proxmoxtf/resource/vm/disk/disk.go +++ b/proxmoxtf/resource/vm/disk/disk.go @@ -625,7 +625,6 @@ func Update( } if disk.ImportFrom != nil && *disk.ImportFrom != "" { - rebootRequired = true shutdownBeforeUpdate = true tmp.DatastoreID = disk.DatastoreID tmp.ImportFrom = disk.ImportFrom diff --git a/proxmoxtf/resource/vm/vm.go b/proxmoxtf/resource/vm/vm.go index f050cb3c5..0b1594dd2 100644 --- a/proxmoxtf/resource/vm/vm.go +++ b/proxmoxtf/resource/vm/vm.go @@ -5800,11 +5800,11 @@ func vmUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.D //nolint: nestif if (d.HasChange(mkStarted) || stoppedBeforeUpdate) && !bool(template) { started := d.Get(mkStarted).(bool) - if started && !stoppedBeforeUpdate { + if started { if diags := vmStart(ctx, vmAPI, d); diags != nil { return diags } - } else { + } else if !stoppedBeforeUpdate { if er := vmShutdown(ctx, vmAPI, d); er != nil { return er } @@ -5813,14 +5813,6 @@ func vmUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.D } } - if stoppedBeforeUpdate && d.Get(mkStarted).(bool) { - if diags := vmStart(ctx, vmAPI, d); diags != nil { - return diags - } - // The VM has been started, so a reboot is no longer required. - rebootRequired = false - } - if cloudInitRebuildRequired { if er := vmAPI.RebuildCloudInitDisk(ctx); er != nil { return diag.FromErr(err) From 21b9694815b0a536e5d87b999821724b96001421 Mon Sep 17 00:00:00 2001 From: Marco Attia <54147992+Vaneixus@users.noreply.github.com> Date: Sun, 9 Nov 2025 03:40:42 +0000 Subject: [PATCH 07/12] fix(docs): update documentation for `import-from`. Signed-off-by: Marco Attia <54147992+Vaneixus@users.noreply.github.com> --- docs/resources/virtual_environment_vm.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/resources/virtual_environment_vm.md b/docs/resources/virtual_environment_vm.md index 07cab6354..2f66d1abd 100755 --- a/docs/resources/virtual_environment_vm.md +++ b/docs/resources/virtual_environment_vm.md @@ -301,7 +301,8 @@ output "ubuntu_vm_public_key" { `proxmox_virtual_environment_download_file` resource. *Deprecated*, use `import_from` instead. - `import_from` - (Optional) The file ID for a disk image to import into VM. The image must be of `import` content type. The ID format is `:import/`, for example `local:import/centos8.qcow2`. Can be also taken from - `proxmox_virtual_environment_download_file` resource. + `proxmox_virtual_environment_download_file` resource. **Note:** Any changes to the value of this field will trigger + a disk replacement operation, which will require a VM reboot. Your original disks will remain as deattached disks. - `interface` - (Required) The disk interface for Proxmox, currently `scsi`, `sata` and `virtio` interfaces are supported. Append the disk index at the end, for example, `virtio0` for the first virtio disk, `virtio1` for From 58bb9c0a03a9f88ee55b58e189a131ead30d26a3 Mon Sep 17 00:00:00 2001 From: Marco Attia <54147992+Vaneixus@users.noreply.github.com> Date: Mon, 10 Nov 2025 02:23:44 +0000 Subject: [PATCH 08/12] feat(disk): improved import-from disk testing. Signed-off-by: Marco Attia <54147992+Vaneixus@users.noreply.github.com> --- proxmoxtf/resource/vm/disk/disk_test.go | 68 ++++++++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) diff --git a/proxmoxtf/resource/vm/disk/disk_test.go b/proxmoxtf/resource/vm/disk/disk_test.go index 20ed1b497..e324912d3 100644 --- a/proxmoxtf/resource/vm/disk/disk_test.go +++ b/proxmoxtf/resource/vm/disk/disk_test.go @@ -209,12 +209,15 @@ func TestDiskDevicesEqual(t *testing.T) { size2 := types.DiskSizeFromGigabytes(10) datastore1 := "local" datastore2 := "local" + importFrom1 := "local:import/test.qcow2" + importFrom2 := "local:import/test.qcow2" disk1 := &vms.CustomStorageDevice{ AIO: &aio1, Cache: &cache1, Size: size1, DatastoreID: &datastore1, + ImportFrom: &importFrom1, } disk2 := &vms.CustomStorageDevice{ @@ -222,6 +225,7 @@ func TestDiskDevicesEqual(t *testing.T) { Cache: &cache2, Size: size2, DatastoreID: &datastore2, + ImportFrom: &importFrom2, } // Test identical disks @@ -246,6 +250,17 @@ func TestDiskDevicesEqual(t *testing.T) { DatastoreID: &datastore2, } require.False(t, disk1.Equals(disk2SizeChanged)) + + // Test different ImportFrom values + importFrom2Changed := "local:import/test2.qcow2" + disk2ImportFromChanged := &vms.CustomStorageDevice{ + AIO: &aio2, + Cache: &cache2, + Size: size2, + ImportFrom: &importFrom2Changed, + DatastoreID: &datastore2, + } + require.False(t, disk1.Equals(disk2ImportFromChanged)) } // TestDiskUpdateSkipsUnchangedDisks tests that the Update function only updates changed disks. @@ -338,8 +353,9 @@ func TestDiskUpdateSkipsUnchangedDisks(t *testing.T) { require.NoError(t, err) // Call the Update function - _, _, err = Update(ctx, client, nodeName, vmID, resourceData, planDisks, currentDisks, updateBody) + shutdownBeforeUpdate, _, err := Update(ctx, client, nodeName, vmID, resourceData, planDisks, currentDisks, updateBody) require.NoError(t, err) + require.False(t, shutdownBeforeUpdate) // Check that only the changed disk (scsi1) is in the update body // scsi0 should NOT be in the update body since it hasn't changed @@ -349,6 +365,56 @@ func TestDiskUpdateSkipsUnchangedDisks(t *testing.T) { // This prevents the "can't unplug bootdisk 'scsi0'" error // Note: We can't directly inspect the updateBody content in this test framework, // but the fact that no error occurred means the logic worked correctly + + // Create plan disks (what terraform wants) + importFrom2 := "local:import/test2.qcow2" + planDisks2 := vms.CustomStorageDevices{ + "scsi0": &vms.CustomStorageDevice{ + Size: types.DiskSizeFromGigabytes(10), // Same as current + DatastoreID: &datastoreID, + ImportFrom: &importFrom2, + }, + "scsi1": &vms.CustomStorageDevice{ + Size: types.DiskSizeFromGigabytes(5), // Different from current (5 -> 20) + DatastoreID: &datastoreID, + }, + } + + // Mock update body to capture what gets sent to the API + updateBody2 := &vms.UpdateRequestBody{} + + // Force HasChange to return true by setting old and new values + err = resourceData.Set(MkDisk, []interface{}{ + map[string]interface{}{ + mkDiskInterface: "scsi1", + mkDiskDatastoreID: "local", + mkDiskSize: 5, // Old size + mkDiskSpeed: []interface{}{}, + }, + }) + require.NoError(t, err) + + err = resourceData.Set(MkDisk, []interface{}{ + map[string]interface{}{ + mkDiskInterface: "scsi1", + mkDiskDatastoreID: "local", + mkDiskSize: 20, // New size + mkDiskSpeed: []interface{}{}, + }, + }) + require.NoError(t, err) + + // Call the Update function + shutdownBeforeUpdate, _, err = Update(ctx, client, nodeName, vmID, resourceData, planDisks2, currentDisks, updateBody2) + require.NoError(t, err) + require.True(t, shutdownBeforeUpdate) + + // Check that only the changed disk (scsi1) is in the update body + // scsi0 should NOT be in the update body since it hasn't changed + require.NotNil(t, updateBody) + + // The update body should only contain scsi0, not scsi1 + // Note: We can't directly inspect the updateBody content in this test framework, } func TestDiskDeletionDetectionInGetDiskDeviceObjects(t *testing.T) { From a407f4f2b4bca14eb373b1255847a8556a96751d Mon Sep 17 00:00:00 2001 From: Marco Attia <54147992+Vaneixus@users.noreply.github.com> Date: Sun, 9 Nov 2025 21:32:44 -0500 Subject: [PATCH 09/12] Update docs/resources/virtual_environment_vm.md Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> Signed-off-by: Marco Attia <54147992+Vaneixus@users.noreply.github.com> --- docs/resources/virtual_environment_vm.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/resources/virtual_environment_vm.md b/docs/resources/virtual_environment_vm.md index 2f66d1abd..10f7dbf79 100755 --- a/docs/resources/virtual_environment_vm.md +++ b/docs/resources/virtual_environment_vm.md @@ -301,8 +301,7 @@ output "ubuntu_vm_public_key" { `proxmox_virtual_environment_download_file` resource. *Deprecated*, use `import_from` instead. - `import_from` - (Optional) The file ID for a disk image to import into VM. The image must be of `import` content type. The ID format is `:import/`, for example `local:import/centos8.qcow2`. Can be also taken from - `proxmox_virtual_environment_download_file` resource. **Note:** Any changes to the value of this field will trigger - a disk replacement operation, which will require a VM reboot. Your original disks will remain as deattached disks. + a disk replacement operation, which will require a VM reboot. Your original disks will remain as detached disks. - `interface` - (Required) The disk interface for Proxmox, currently `scsi`, `sata` and `virtio` interfaces are supported. Append the disk index at the end, for example, `virtio0` for the first virtio disk, `virtio1` for From 45847b0b38ae7e531b4fd88523ec2b9ca1142509 Mon Sep 17 00:00:00 2001 From: Marco Attia <54147992+Vaneixus@users.noreply.github.com> Date: Mon, 10 Nov 2025 02:36:17 +0000 Subject: [PATCH 10/12] feat(disk): improved import-from disk testing. Signed-off-by: Marco Attia <54147992+Vaneixus@users.noreply.github.com> --- proxmoxtf/resource/vm/disk/disk_test.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/proxmoxtf/resource/vm/disk/disk_test.go b/proxmoxtf/resource/vm/disk/disk_test.go index e324912d3..57ab90fd8 100644 --- a/proxmoxtf/resource/vm/disk/disk_test.go +++ b/proxmoxtf/resource/vm/disk/disk_test.go @@ -372,10 +372,10 @@ func TestDiskUpdateSkipsUnchangedDisks(t *testing.T) { "scsi0": &vms.CustomStorageDevice{ Size: types.DiskSizeFromGigabytes(10), // Same as current DatastoreID: &datastoreID, - ImportFrom: &importFrom2, + ImportFrom: &importFrom2, // Different Import file. }, "scsi1": &vms.CustomStorageDevice{ - Size: types.DiskSizeFromGigabytes(5), // Different from current (5 -> 20) + Size: types.DiskSizeFromGigabytes(5), // Same as current DatastoreID: &datastoreID, }, } @@ -411,7 +411,10 @@ func TestDiskUpdateSkipsUnchangedDisks(t *testing.T) { // Check that only the changed disk (scsi1) is in the update body // scsi0 should NOT be in the update body since it hasn't changed - require.NotNil(t, updateBody) + require.NotNil(t, updateBody2) + require.Contains(t, updateBody2.CustomStorageDevices, "scsi0", "Update body should contain the changed disk scsi0") + require.NotContains(t, updateBody2.CustomStorageDevices, "scsi1", "Update body should not contain the unchanged disk scsi1") + require.Equal(t, importFrom2, *updateBody2.CustomStorageDevices["scsi0"].ImportFrom) // The update body should only contain scsi0, not scsi1 // Note: We can't directly inspect the updateBody content in this test framework, From 40b4a5581c8f3357deb23341a38750387b917c71 Mon Sep 17 00:00:00 2001 From: Pavel Boldyrev <627562+bpg@users.noreply.github.com> Date: Thu, 27 Nov 2025 11:23:00 -0500 Subject: [PATCH 11/12] fix linter errors Signed-off-by: Pavel Boldyrev <627562+bpg@users.noreply.github.com> --- proxmoxtf/resource/vm/disk/disk_test.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/proxmoxtf/resource/vm/disk/disk_test.go b/proxmoxtf/resource/vm/disk/disk_test.go index bb99f97a0..4f85b68f7 100644 --- a/proxmoxtf/resource/vm/disk/disk_test.go +++ b/proxmoxtf/resource/vm/disk/disk_test.go @@ -385,22 +385,22 @@ func TestDiskUpdateSkipsUnchangedDisks(t *testing.T) { updateBody2 := &vms.UpdateRequestBody{} // Force HasChange to return true by setting old and new values - err = resourceData.Set(MkDisk, []interface{}{ - map[string]interface{}{ + err = resourceData.Set(MkDisk, []any{ + map[string]any{ mkDiskInterface: "scsi1", mkDiskDatastoreID: "local", mkDiskSize: 5, // Old size - mkDiskSpeed: []interface{}{}, + mkDiskSpeed: []any{}, }, }) require.NoError(t, err) - err = resourceData.Set(MkDisk, []interface{}{ - map[string]interface{}{ + err = resourceData.Set(MkDisk, []any{ + map[string]any{ mkDiskInterface: "scsi1", mkDiskDatastoreID: "local", mkDiskSize: 20, // New size - mkDiskSpeed: []interface{}{}, + mkDiskSpeed: []any{}, }, }) require.NoError(t, err) From ac7ac6fb3418bdef07776d0c478fb97a55ffe50f Mon Sep 17 00:00:00 2001 From: Pavel Boldyrev <627562+bpg@users.noreply.github.com> Date: Thu, 27 Nov 2025 15:28:27 -0500 Subject: [PATCH 12/12] fix state population if disk size is 0 Signed-off-by: Pavel Boldyrev <627562+bpg@users.noreply.github.com> --- proxmoxtf/resource/vm/disk/disk.go | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/proxmoxtf/resource/vm/disk/disk.go b/proxmoxtf/resource/vm/disk/disk.go index f31f3824f..3faf9b452 100644 --- a/proxmoxtf/resource/vm/disk/disk.go +++ b/proxmoxtf/resource/vm/disk/disk.go @@ -549,13 +549,19 @@ func Read( if len(currentDiskList) > 0 { currentDiskMap := utils.MapResourcesByAttribute(currentDiskList, mkDiskInterface) - // copy import_from from the current disk if it exists + // copy import_from and size from the current disk if it exists for k, v := range currentDiskMap { if disk, ok := v.(map[string]any); ok { - if importFrom, ok := disk[mkDiskImportFrom].(string); ok && importFrom != "" { - if _, exists := diskMap[k]; exists { + if _, exists := diskMap[k]; exists { + if importFrom, ok := disk[mkDiskImportFrom].(string); ok && importFrom != "" { diskMap[k].(map[string]any)[mkDiskImportFrom] = importFrom } + // preserve size from state when API returns zero size (for disks with import_from or file_id) + if currentSize, ok := disk[mkDiskSize].(int); ok && currentSize > 0 { + if apiSize, ok := diskMap[k].(map[string]any)[mkDiskSize].(int64); ok && apiSize == 0 { + diskMap[k].(map[string]any)[mkDiskSize] = currentSize + } + } } } }