Repository: Telmate/terraform-provider-proxmox

Issue:
Provider produced inconsistent final plan - Failure to properly pass created vmid
When attempting to use the output vmid of a `proxmox_vm_qemu` resource with a vmid of 0 the plan initially shows that the vmid of the first resource will indeed be 0. This is incorrect however since using 0 will assign the vmid automatically to the next available vmid in Proxmox. This results in a runtime difference where during execution on the referencing resource it (accurately) becomes the automatically assigned vmid for the first resource. This is the error:

```
│ Error: Provider produced inconsistent final plan
│ 
│ When expanding the plan for proxmox_vm_qemu.vm to include new values learned so far during apply, provider "registry.terraform.io/telmate/proxmox" produced an invalid new value for .disk[2].disk_file: was
│ cty.StringVal("vm:vm-0-disk-5"), but now cty.StringVal("vm:vm-112-disk-5").
│ 
│ This is a bug in the provider, which should be reported in the provider's own issue tracker.
```

The variable being referenced is `proxmox_vm_qemu.vm.vmid`.

I understand that this is a functionality of Proxmox causing this problem. Is this something that can be fixed? Is there a way to sort of "prefetch" the next available vmid before execution so that the plan can be accurately reported?

Note: This seems to be an issue on the most recent version `3.0.2-rc03` as well as older versions.

Hints from issue comments:
@p0rtL6: I believe this could be fixed with a plan modifier according to Terraform [docs](https://developer.hashicorp.com/terraform/plugin/framework/resources/plan-modification). If querying Proxmox for the next available id is not an option it should be able to be marked as `unknown` in the planning stage to at the very least prevent this error. I am not familiar with Terraform enough to be able to know where to look to modify this, but if there is help wanted and someone could point me to the correct files that need modification I could attempt to fix and make a pr for this.@Tinyblargon: @p0rtL6 When I don't set `vmid` the plan output is `+ vmid = (known after apply)`, if `vmid = 0` then this error occurs. For some reason we currently only do validation when the `vmid != 0`  meaning that we allow a statically set `0`, but we shouldn't.@Tinyblargon: @p0rtL6 Would you be able to test the change in #1386?

Solution patch:
diff --git a/docs/guides/cloud-init getting started.md b/docs/guides/cloud-init getting started.md
index 511aa0f..8c94462 100644
--- a/docs/guides/cloud-init getting started.md	
+++ b/docs/guides/cloud-init getting started.md	
@@ -125,7 +125,7 @@ terraform {
   required_providers {
     proxmox = {
       source = "Telmate/proxmox"
-      version = ">=3.0.1rc4"
+      version = "3.0.1rc4"
     }
   }
 }
diff --git a/docs/resources/vm_qemu.md b/docs/resources/vm_qemu.md
index 27ca6aa..37c7f70 100644
--- a/docs/resources/vm_qemu.md
+++ b/docs/resources/vm_qemu.md
@@ -94,7 +94,7 @@ The following arguments are supported in the top level resource block.
 | `name`                        | `str`    |                      | **Required** The name of the VM within Proxmox. |
 | `target_node`                 | `str`    |                      | The name of the PVE Node on which to place the VM.|
 | `target_nodes`                | `str`    |                      | A list of PVE node names on which to place the VM.|
-| `vmid`                        | `int`    | `0`                  | The ID of the VM in Proxmox. The default value of `0` indicates it should use the next available ID in the sequence. |
+| `vmid`                        | `int`    |                      | The ID of the VM in Proxmox. When unset it should use the next available ID in the sequence. |
 | `desc`                        | `str`    |                      | The description of the VM. Shows as the 'Notes' field in the Proxmox GUI. |
 | `define_connection_info`      | `bool`   | `true`               | Whether to let terraform define the (SSH) connection parameters for preprovisioners, see config block below. |
 | `bios`                        | `str`    | `"seabios"`          | The BIOS to use, options are `seabios` or `ovmf` for UEFI. |
diff --git a/go.mod b/go.mod
index 8de222f..908be2a 100644
--- a/go.mod
+++ b/go.mod
@@ -3,7 +3,7 @@ module github.com/Telmate/terraform-provider-proxmox/v2
 go 1.24
 
 require (
-	github.com/Telmate/proxmox-api-go v0.0.0-20250822215835-17334f99d611
+	github.com/Telmate/proxmox-api-go v0.0.0-20250909211818-e783370fc8ea
 	github.com/google/uuid v1.6.0
 	github.com/hashicorp/go-cty v1.5.0
 	github.com/hashicorp/terraform-plugin-sdk/v2 v2.37.0
diff --git a/go.sum b/go.sum
index bd4e650..0134ad3 100644
--- a/go.sum
+++ b/go.sum
@@ -4,8 +4,8 @@ github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERo
 github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
 github.com/ProtonMail/go-crypto v1.2.0 h1:+PhXXn4SPGd+qk76TlEePBfOfivE0zkWFenhGhFLzWs=
 github.com/ProtonMail/go-crypto v1.2.0/go.mod h1:9whxjD8Rbs29b4XWbB8irEcE8KHMqaR2e7GWU1R+/PE=
-github.com/Telmate/proxmox-api-go v0.0.0-20250822215835-17334f99d611 h1:F2yIhAUc89Mr0Bhhs5ttAjDcABmcJrFuqDntNH/INYU=
-github.com/Telmate/proxmox-api-go v0.0.0-20250822215835-17334f99d611/go.mod h1:HGPbpwiVsrpYYuQAygnnU04ZdGLYc8fdP9qhJIBw2Bg=
+github.com/Telmate/proxmox-api-go v0.0.0-20250909211818-e783370fc8ea h1:/g6SFJtTQO5H6RUbN2EirwY/uMFAG8w574RtQE4EizU=
+github.com/Telmate/proxmox-api-go v0.0.0-20250909211818-e783370fc8ea/go.mod h1:HGPbpwiVsrpYYuQAygnnU04ZdGLYc8fdP9qhJIBw2Bg=
 github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo=
 github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
 github.com/apparentlymart/go-textseg/v12 v12.0.0/go.mod h1:S/4uRK2UtaQttw1GenVJEynmyUenKwP++x/+DdGV/Ec=
diff --git a/proxmox/Internal/resource/guest/lxc/_sub/acl/schema.go b/proxmox/Internal/resource/guest/lxc/_sub/acl/schema.go
index 1de003f..4842d76 100644
--- a/proxmox/Internal/resource/guest/lxc/_sub/acl/schema.go
+++ b/proxmox/Internal/resource/guest/lxc/_sub/acl/schema.go
@@ -27,7 +27,10 @@ func Schema() *schema.Schema {
 			}
 			switch new {
 			case flagDefault, "":
-				return true
+				switch old {
+				case flagDefault, "":
+					return true
+				}
 			}
 			return false
 		},
diff --git a/proxmox/Internal/resource/guest/lxc/features/schema.go b/proxmox/Internal/resource/guest/lxc/features/schema.go
new file mode 100644
index 0000000..217d861
--- /dev/null
+++ b/proxmox/Internal/resource/guest/lxc/features/schema.go
@@ -0,0 +1,70 @@
+package features
+
+import (
+	"github.com/Telmate/terraform-provider-proxmox/v2/proxmox/Internal/resource/guest/lxc/privilege"
+	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
+)
+
+const (
+	Root = "features"
+
+	schemaPrivileged   = "privileged"
+	schemaUnprivileged = "unprivileged"
+
+	schemaCreateDeviceNodes = "create_device_nodes"
+	schemaFUSE              = "fuse"
+	schemaNFS               = "nfs"
+	schemaNesting           = "nesting"
+	schemaSMB               = "smb"
+	schemeKeyCtl            = "keyctl"
+
+	defaultCreateDeviceNodes = false
+	defaultFUSE              = false
+	defaultKeyCtl            = false
+	defaultNFS               = false
+	defaultNesting           = false
+	defaultSMB               = false
+)
+
+func Schema() *schema.Schema {
+	return &schema.Schema{
+		Type:     schema.TypeList,
+		Optional: true,
+		MaxItems: 1,
+		Elem: &schema.Resource{
+			Schema: map[string]*schema.Schema{
+				schemaPrivileged: {
+					Type:         schema.TypeList,
+					Optional:     true,
+					MaxItems:     1,
+					RequiredWith: []string{privilege.RootPrivileged},
+					ConflictsWith: []string{
+						Root + ".0." + schemaUnprivileged,
+						privilege.RootUnprivileged},
+					Elem: &schema.Resource{
+						Schema: map[string]*schema.Schema{
+							schemaCreateDeviceNodes: subSchemaBool(defaultCreateDeviceNodes),
+							schemaFUSE:              subSchemaBool(defaultFUSE),
+							schemaNFS:               subSchemaBool(defaultNFS),
+							schemaNesting:           subSchemaBool(defaultNesting),
+							schemaSMB:               subSchemaBool(defaultSMB)}}},
+				schemaUnprivileged: {
+					Type:     schema.TypeList,
+					Optional: true,
+					MaxItems: 1,
+					ConflictsWith: []string{
+						Root + ".0." + schemaPrivileged,
+						privilege.RootPrivileged},
+					Elem: &schema.Resource{Schema: map[string]*schema.Schema{
+						schemaCreateDeviceNodes: subSchemaBool(defaultCreateDeviceNodes),
+						schemaFUSE:              subSchemaBool(defaultFUSE),
+						schemaNesting:           subSchemaBool(defaultNesting),
+						schemeKeyCtl:            subSchemaBool(defaultKeyCtl)}}}}}}
+}
+
+func subSchemaBool(Default bool) *schema.Schema {
+	return &schema.Schema{
+		Type:     schema.TypeBool,
+		Optional: true,
+		Default:  Default}
+}
diff --git a/proxmox/Internal/resource/guest/lxc/features/sdk.go b/proxmox/Internal/resource/guest/lxc/features/sdk.go
new file mode 100644
index 0000000..3b73810
--- /dev/null
+++ b/proxmox/Internal/resource/guest/lxc/features/sdk.go
@@ -0,0 +1,60 @@
+package features
+
+import (
+	pveSDK "github.com/Telmate/proxmox-api-go/proxmox"
+	"github.com/Telmate/terraform-provider-proxmox/v2/proxmox/Internal/util"
+	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
+)
+
+func SDK(Privileged bool, d *schema.ResourceData) *pveSDK.LxcFeatures {
+	schemaItem, ok := d.GetOk(Root)
+	if !ok {
+		return defaults(Privileged)
+	}
+	schemaFeatures, ok := schemaItem.([]any)
+	if ok && len(schemaFeatures) != 1 {
+		return defaults(Privileged)
+	}
+	settings, ok := schemaFeatures[0].(map[string]any)
+	if !ok {
+		return defaults(Privileged)
+	}
+	if v, ok := settings[schemaPrivileged].([]any); ok && len(v) == 1 && v[0] != nil {
+		features := v[0].(map[string]any)
+		return &pveSDK.LxcFeatures{
+			Privileged: &pveSDK.PrivilegedFeatures{
+				CreateDeviceNodes: util.Pointer(features[schemaCreateDeviceNodes].(bool)),
+				FUSE:              util.Pointer(features[schemaFUSE].(bool)),
+				NFS:               util.Pointer(features[schemaNFS].(bool)),
+				Nesting:           util.Pointer(features[schemaNesting].(bool)),
+				SMB:               util.Pointer(features[schemaSMB].(bool))}}
+	}
+	if v, ok := settings[schemaUnprivileged].([]any); ok && len(v) == 1 && v[0] != nil {
+		features := v[0].(map[string]any)
+		return &pveSDK.LxcFeatures{
+			Unprivileged: &pveSDK.UnprivilegedFeatures{
+				CreateDeviceNodes: util.Pointer(features[schemaCreateDeviceNodes].(bool)),
+				FUSE:              util.Pointer(features[schemaFUSE].(bool)),
+				KeyCtl:            util.Pointer(features[schemeKeyCtl].(bool)),
+				Nesting:           util.Pointer(features[schemaNesting].(bool))}}
+	}
+	return defaults(Privileged)
+}
+
+func defaults(Privileged bool) *pveSDK.LxcFeatures {
+	if Privileged {
+		return &pveSDK.LxcFeatures{
+			Privileged: &pveSDK.PrivilegedFeatures{
+				CreateDeviceNodes: util.Pointer(defaultCreateDeviceNodes),
+				FUSE:              util.Pointer(defaultFUSE),
+				NFS:               util.Pointer(defaultNFS),
+				Nesting:           util.Pointer(defaultNesting),
+				SMB:               util.Pointer(defaultSMB)}}
+	}
+	return &pveSDK.LxcFeatures{
+		Unprivileged: &pveSDK.UnprivilegedFeatures{
+			CreateDeviceNodes: util.Pointer(defaultCreateDeviceNodes),
+			FUSE:              util.Pointer(defaultFUSE),
+			KeyCtl:            util.Pointer(defaultKeyCtl),
+			Nesting:           util.Pointer(defaultNesting)}}
+}
diff --git a/proxmox/Internal/resource/guest/lxc/features/terraform.go b/proxmox/Internal/resource/guest/lxc/features/terraform.go
new file mode 100644
index 0000000..b5b819c
--- /dev/null
+++ b/proxmox/Internal/resource/guest/lxc/features/terraform.go
@@ -0,0 +1,30 @@
+package features
+
+import (
+	pveSDK "github.com/Telmate/proxmox-api-go/proxmox"
+	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
+)
+
+func Terraform(features *pveSDK.LxcFeatures, d *schema.ResourceData) {
+	if features == nil {
+		return
+	}
+	var settings map[string]any
+	if features.Privileged != nil {
+		settings = map[string]any{
+			schemaPrivileged: []map[string]any{{
+				schemaCreateDeviceNodes: features.Privileged.CreateDeviceNodes,
+				schemaFUSE:              features.Privileged.FUSE,
+				schemaNFS:               features.Privileged.NFS,
+				schemaNesting:           features.Privileged.Nesting,
+				schemaSMB:               features.Privileged.SMB}}}
+	} else if features.Unprivileged != nil {
+		settings = map[string]any{
+			schemaUnprivileged: []map[string]any{{
+				schemaCreateDeviceNodes: features.Unprivileged.CreateDeviceNodes,
+				schemaFUSE:              features.Unprivileged.FUSE,
+				schemaNesting:           features.Unprivileged.Nesting,
+				schemeKeyCtl:            features.Unprivileged.KeyCtl}}}
+	}
+	d.Set(Root, []map[string]any{settings})
+}
diff --git a/proxmox/Internal/resource/guest/lxc/mounts/sdk_mount.go b/proxmox/Internal/resource/guest/lxc/mounts/sdk_mount.go
index 131754a..4c0d412 100644
--- a/proxmox/Internal/resource/guest/lxc/mounts/sdk_mount.go
+++ b/proxmox/Internal/resource/guest/lxc/mounts/sdk_mount.go
@@ -40,7 +40,9 @@ func sdkMount(privileged bool, schema []any) (pveSDK.LxcMounts, diag.Diagnostics
 					Severity: diag.Error})
 			}
 			// warnings for unused settings
-			if schemaMap[schemaACL].(string) != acl.Default {
+			switch schemaMap[schemaACL].(string) {
+			case acl.Default, "":
+			default:
 				diags = append(diags, warning(schemaACL, typeBindMount))
 			}
 			if !schemaMap[schemaBackup].(bool) {
diff --git a/proxmox/Internal/resource/guest/lxc/mounts/terraform_mount.go b/proxmox/Internal/resource/guest/lxc/mounts/terraform_mount.go
index 5f6ae91..0dc5b18 100644
--- a/proxmox/Internal/resource/guest/lxc/mounts/terraform_mount.go
+++ b/proxmox/Internal/resource/guest/lxc/mounts/terraform_mount.go
@@ -10,12 +10,18 @@ import (
 
 func terraformMount(config pveSDK.LxcMounts, tfConfig []any) []map[string]any {
 	mounts := make([]map[string]any, len(config))
+	configMap := make(map[string]map[string]any, len(tfConfig))
+	for i := range tfConfig {
+		subMap := tfConfig[i].(map[string]any)
+		configMap[subMap[schemaID].(string)] = subMap
+	}
 	var index int
 	for i := range pveSDK.LxcMountID(maximumID) {
 		v, ok := config[i]
 		if !ok {
 			continue
 		}
+		id := prefixSchemaID + strconv.Itoa(int(i))
 		var params map[string]any
 		if v.DataMount != nil {
 			var quota bool
@@ -30,17 +36,21 @@ func terraformMount(config pveSDK.LxcMounts, tfConfig []any) []map[string]any {
 				schemaReadOnly:  *v.DataMount.ReadOnly,
 				schemaReplicate: *v.DataMount.Replicate,
 				schemaSize:      size.String(int64(*v.DataMount.SizeInKibibytes)),
-				schemaStorage:   *v.DataMount.Storage}
+				schemaStorage:   *v.DataMount.Storage,
+				schemaType:      typeDataMount}
 			terraformSetOptions(params, v.DataMount.Options)
 		} else if v.BindMount != nil {
+			localMap := configMap[id]
 			params = map[string]any{
+				schemaBackup:    localMap[schemaBackup].(bool),
 				schemaGuestPath: v.BindMount.GuestPath.String(),
 				schemaHostPath:  v.BindMount.HostPath.String(),
 				schemaReadOnly:  *v.BindMount.ReadOnly,
-				schemaReplicate: *v.BindMount.Replicate}
+				schemaReplicate: *v.BindMount.Replicate,
+				schemaType:      typeBindMount}
 			terraformSetOptions(params, v.BindMount.Options)
 		}
-		params[schemaID] = prefixSchemaID + strconv.Itoa(int(i))
+		params[schemaID] = id
 		mounts[index] = params
 		index++
 	}
diff --git a/proxmox/Internal/resource/guest/node/sdk.go b/proxmox/Internal/resource/guest/node/sdk.go
index 71b686b..359cb56 100644
--- a/proxmox/Internal/resource/guest/node/sdk.go
+++ b/proxmox/Internal/resource/guest/node/sdk.go
@@ -33,6 +33,7 @@ func SdkUpdate(d *schema.ResourceData, current pveAPI.NodeName) (pveAPI.NodeName
 	return pveAPI.NodeName(nodes[randomIndex].(string)), nil
 }
 
+// SdkCreate selects a node for resource creation.
 func SdkCreate(d *schema.ResourceData) (pveAPI.NodeName, error) {
 	if node, ok := d.GetOk(RootNode); ok {
 		return pveAPI.NodeName(node.(string)), nil
diff --git a/proxmox/Internal/resource/guest/vmid/schema.go b/proxmox/Internal/resource/guest/vmid/schema.go
index 4b7ab7d..ebd242c 100644
--- a/proxmox/Internal/resource/guest/vmid/schema.go
+++ b/proxmox/Internal/resource/guest/vmid/schema.go
@@ -25,10 +25,8 @@ func Schema() *schema.Schema {
 			if !ok {
 				return diag.Errorf("expected type of %v to be int", k)
 			}
-			if val != 0 {
-				if val < minID || val > maxID {
-					return diag.Errorf("proxmox %s must be in the range (%d - %d) or 0 for next available ID, got %d", k, minID, maxID, val)
-				}
+			if val < minID || val > maxID {
+				return diag.Errorf("proxmox %s must be in the range (%d - %d) or 0 for next available ID, got %d", k, minID, maxID, val)
 			}
 			return nil
 		},
diff --git a/proxmox/helper_guest.go b/proxmox/helper_guest.go
index 8eb6918..a7fde59 100644
--- a/proxmox/helper_guest.go
+++ b/proxmox/helper_guest.go
@@ -28,3 +28,55 @@ func guestDelete(ctx context.Context, d *schema.ResourceData, meta any, kind str
 	}
 	return nil
 }
+
+func guestGetSourceVmr(ctx context.Context, client *pveSDK.Client, name pveSDK.GuestName, id pveSDK.GuestID, preferredNode pveSDK.NodeName, guest pveSDK.GuestType) (*pveSDK.VmRef, error) {
+	if name != "" {
+		rawGuests, err := pveSDK.ListGuests(ctx, client)
+		if err != nil {
+			return nil, err
+		}
+		return guestGetSourceVmrByNode(rawGuests, name, preferredNode, guest)
+	} else if id != 0 {
+		rawGuests, err := pveSDK.ListGuests(ctx, client)
+		if err != nil {
+			return nil, err
+		}
+		rawGuest, err := rawGuests.SelectID(id)
+		if err != nil {
+			return nil, err
+		}
+		if rawGuest.GetType() != guest {
+			return nil, errors.New("guest with ID '" + id.String() + "' is not of type '" + string(guest) + "'")
+		}
+		guestRef := pveSDK.NewVmRef(rawGuest.GetID())
+		guestRef.SetNode(string(rawGuest.GetNode()))
+		guestRef.SetVmType(guest)
+		return guestRef, nil
+	}
+	return nil, errors.New("either 'clone' name or 'clone_id' must be specified")
+}
+
+func guestGetSourceVmrByNode(raw pveSDK.RawGuestResources, name pveSDK.GuestName, preferredNode pveSDK.NodeName, guest pveSDK.GuestType) (*pveSDK.VmRef, error) {
+	var guestRef *pveSDK.VmRef
+	for i := range raw {
+		if raw[i].GetName() == name {
+			if raw[i].GetType() == guest {
+				if node := raw[i].GetNode(); node == preferredNode { // Prefer source VM on the same node
+					guestRef = pveSDK.NewVmRef(raw[i].GetID())
+					guestRef.SetNode(string(node))
+					guestRef.SetVmType(guest)
+					return guestRef, nil
+				}
+				if guestRef == nil { // remember the first we find
+					guestRef = pveSDK.NewVmRef(raw[i].GetID())
+					guestRef.SetNode(string(raw[i].GetNode()))
+					guestRef.SetVmType(guest)
+				}
+			}
+		}
+	}
+	if guestRef == nil {
+		return nil, errors.New("no guest with name '" + name.String() + "' found")
+	}
+	return guestRef, nil
+}
diff --git a/proxmox/resource_cloud_init_disk.go b/proxmox/resource_cloud_init_disk.go
index 6fb7feb..f5565fd 100644
--- a/proxmox/resource_cloud_init_disk.go
+++ b/proxmox/resource_cloud_init_disk.go
@@ -8,7 +8,7 @@ import (
 	"io"
 	"strings"
 
-	"github.com/Telmate/proxmox-api-go/proxmox"
+	pveSDK "github.com/Telmate/proxmox-api-go/proxmox"
 	"github.com/kdomanski/iso9660"
 
 	"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
@@ -150,11 +150,7 @@ func resourceCloudInitDiskRead(ctx context.Context, d *schema.ResourceData, m in
 	client := pconf.Client
 
 	var isoFound bool
-	pveNode := d.Get("pve_node").(string)
-	vmRef := &proxmox.VmRef{}
-	vmRef.SetNode(pveNode)
-	vmRef.SetVmType("qemu")
-	storageContent, err := client.GetStorageContent(ctx, vmRef, d.Get("storage").(string))
+	storageContent, err := client.GetStorageContent(ctx, d.Get("storage").(string), pveSDK.NodeName(d.Get("pve_node").(string)))
 	if err != nil {
 		return diag.FromErr(err)
 	}
diff --git a/proxmox/resource_lxc.go b/proxmox/resource_lxc.go
index 52bd0e7..8756593 100644
--- a/proxmox/resource_lxc.go
+++ b/proxmox/resource_lxc.go
@@ -519,7 +519,7 @@ func resourceLxcCreate(ctx context.Context, d *schema.ResourceData, meta interfa
 	var vmr *pveSDK.VmRef
 	if d.Get("clone").(string) != "" { // Clone
 		var sourceVmr *pveSDK.VmRef
-		sourceVmr, err = getSourceVmr(ctx, client, pveSDK.GuestName(d.Get("clone").(string)), 0, targetNode)
+		sourceVmr, err = guestGetSourceVmr(ctx, client, pveSDK.GuestName(d.Get("clone").(string)), 0, targetNode, pveSDK.GuestLxc)
 		if err != nil {
 			return append(diags, diag.FromErr(err)...)
 		}
@@ -964,7 +964,7 @@ func processLxcDiskChanges(
 		}
 		params := map[string]interface{}{}
 		params["delete"] = strings.Join(deleteDiskKeys, ", ")
-		if vmr.GetVmType() == "lxc" {
+		if vmr.GetVmType() == pveSDK.GuestLxc {
 			if _, err := pconf.Client.SetLxcConfig(ctx, vmr, params); err != nil {
 				return err
 			}
@@ -995,7 +995,7 @@ func processLxcDiskChanges(
 		}
 	}
 	if len(newParams) > 0 {
-		if vmr.GetVmType() == "lxc" {
+		if vmr.GetVmType() == pveSDK.GuestLxc {
 			if _, err := pconf.Client.SetLxcConfig(ctx, vmr, newParams); err != nil {
 				return err
 			}
@@ -1014,7 +1014,7 @@ func processLxcDiskChanges(
 			// 2. Move disks with mismatching storage
 			newStorage, ok := newDisk["storage"].(string)
 			if ok && newStorage != prevDisk["storage"] {
-				if vmr.GetVmType() == "lxc" {
+				if vmr.GetVmType() == pveSDK.GuestLxc {
 					_, err := pconf.Client.MoveLxcDisk(ctx, vmr, diskSlotName(prevDisk), newStorage)
 					if err != nil {
 						return err
@@ -1107,7 +1107,7 @@ func processLxcNetworkChanges(ctx context.Context, prevNetworks []map[string]int
 		params := map[string]interface{}{
 			"delete": strings.Join(deleteNetKeys, ", "),
 		}
-		if vmr.GetVmType() == "lxc" {
+		if vmr.GetVmType() == pveSDK.GuestLxc {
 			if _, err := pconf.Client.SetLxcConfig(ctx, vmr, params); err != nil {
 				return err
 			}
diff --git a/proxmox/resource_lxc_disk.go b/proxmox/resource_lxc_disk.go
index 40ab061..e5577ef 100644
--- a/proxmox/resource_lxc_disk.go
+++ b/proxmox/resource_lxc_disk.go
@@ -123,7 +123,7 @@ func resourceLxcDiskCreate(ctx context.Context, d *schema.ResourceData, meta int
 
 	client := pconf.Client
 	vmr := pveSDK.NewVmRef(vmID)
-	vmr.SetVmType("lxc")
+	vmr.SetVmType(pveSDK.GuestLxc)
 	_, err = client.GetVmInfo(ctx, vmr)
 	if err != nil {
 		return diag.FromErr(err)
diff --git a/proxmox/resource_lxc_new.go b/proxmox/resource_lxc_new.go
index 040e755..5912b6f 100644
--- a/proxmox/resource_lxc_new.go
+++ b/proxmox/resource_lxc_new.go
@@ -8,6 +8,7 @@ import (
 	"github.com/Telmate/terraform-provider-proxmox/v2/proxmox/Internal/resource/guest/dns"
 	"github.com/Telmate/terraform-provider-proxmox/v2/proxmox/Internal/resource/guest/lxc/architecture"
 	"github.com/Telmate/terraform-provider-proxmox/v2/proxmox/Internal/resource/guest/lxc/cpu"
+	"github.com/Telmate/terraform-provider-proxmox/v2/proxmox/Internal/resource/guest/lxc/features"
 	"github.com/Telmate/terraform-provider-proxmox/v2/proxmox/Internal/resource/guest/lxc/memory"
 	"github.com/Telmate/terraform-provider-proxmox/v2/proxmox/Internal/resource/guest/lxc/mounts"
 	"github.com/Telmate/terraform-provider-proxmox/v2/proxmox/Internal/resource/guest/lxc/networks"
@@ -43,6 +44,7 @@ func ResourceLxcNew() *schema.Resource {
 			cpu.Root:                   cpu.Schema(),
 			description.Root:           description.Schema(),
 			dns.Root:                   dns.Schema(),
+			features.Root:              features.Schema(),
 			memory.Root:                memory.Schema(),
 			mounts.RootMount:           mounts.SchemaMount(),
 			mounts.RootMounts:          mounts.SchemaMounts(),
@@ -189,6 +191,7 @@ func resourceLxcNewRead(ctx context.Context, d *schema.ResourceData, meta any, v
 	cpu.Terraform(config.CPU, d)
 	description.Terraform(config.Description, false, d)
 	dns.Terraform(config.DNS, d)
+	features.Terraform(config.Features, d)
 	memory.Terraform(config.Memory, d)
 	mounts.Terraform(config.Mounts, d)
 	name.Terraform_Unsafe(config.Name, d)
@@ -217,6 +220,7 @@ func lxcSDK(privilidged bool, d *schema.ResourceData) (pveSDK.ConfigLXC, diag.Di
 		CPU:         cpu.SDK(d),
 		DNS:         dns.SDK(d),
 		Description: description.SDK(false, d),
+		Features:    features.SDK(privilidged, d),
 		Memory:      memory.SDK(d),
 		Name:        guestName,
 		State:       powerstate.SDK(d),
diff --git a/proxmox/resource_pool.go b/proxmox/resource_pool.go
index 8ce7852..0a450b9 100644
--- a/proxmox/resource_pool.go
+++ b/proxmox/resource_pool.go
@@ -85,20 +85,17 @@ func _resourcePoolRead(ctx context.Context, d *schema.ResourceData, meta interfa
 	logger, _ := CreateSubLogger("resource_pool_read")
 	logger.Info().Str("poolid", poolID).Msg("Reading configuration for poolid")
 
-	poolInfo, err := pool.Get(ctx, client)
+	rawPool, err := pool.Get(ctx, client)
 	if err != nil {
 		d.SetId("")
 		return nil
 	}
 
 	d.SetId(clusterResourceId("pools", poolID))
-	d.Set("comment", "")
-	if poolInfo.Comment != nil {
-		d.Set("comment", poolInfo.Comment)
-	}
+	d.Set("comment", rawPool.GetComment())
 
 	// DEBUG print the read result
-	logger.Debug().Str("poolid", poolID).Msgf("Finished pool read resulting in data: '%+v'", poolInfo)
+	logger.Debug().Str("poolid", poolID).Msgf("Finished pool read resulting in data: '%+v'", rawPool.Get())
 	return nil
 }
 
diff --git a/proxmox/resource_storage_iso.go b/proxmox/resource_storage_iso.go
index bb0393d..8488358 100644
--- a/proxmox/resource_storage_iso.go
+++ b/proxmox/resource_storage_iso.go
@@ -8,7 +8,7 @@ import (
 	"os"
 	"strings"
 
-	"github.com/Telmate/proxmox-api-go/proxmox"
+	pveSDK "github.com/Telmate/proxmox-api-go/proxmox"
 	"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
 	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
 )
@@ -115,11 +115,7 @@ func resourceStorageIsoRead(ctx context.Context, d *schema.ResourceData, meta in
 	client := pconf.Client
 
 	var isoFound bool
-	pveNode := d.Get("pve_node").(string)
-	vmRef := &proxmox.VmRef{}
-	vmRef.SetNode(pveNode)
-	vmRef.SetVmType(isoContentType)
-	storageContent, err := client.GetStorageContent(ctx, vmRef, d.Get("storage").(string))
+	storageContent, err := client.GetStorageContent(ctx, d.Get("storage").(string), pveSDK.NodeName(d.Get("pve_node").(string)))
 	if err != nil {
 		return diag.FromErr(err)
 	}
diff --git a/proxmox/resource_vm_qemu.go b/proxmox/resource_vm_qemu.go
index c9ca73d..48e6cfe 100755
--- a/proxmox/resource_vm_qemu.go
+++ b/proxmox/resource_vm_qemu.go
@@ -4,7 +4,6 @@ import (
 	"context"
 	"encoding/base64"
 	"encoding/json"
-	"errors"
 	"fmt"
 	"log"
 	"net"
@@ -536,27 +535,6 @@ func resourceVmQemu() *schema.Resource {
 	return thisResource
 }
 
-func getSourceVmr(ctx context.Context, client *pveSDK.Client, name pveSDK.GuestName, id pveSDK.GuestID, preferredNode pveSDK.NodeName) (*pveSDK.VmRef, error) {
-	if name != "" {
-		sourceVmrs, err := client.GetVmRefsByName(ctx, name)
-		if err != nil {
-			return nil, err
-		}
-		// Prefer source VM on the same node
-		sourceVmr := sourceVmrs[0]
-		for _, candVmr := range sourceVmrs {
-			if candVmr.Node() == preferredNode {
-				sourceVmr = candVmr
-			}
-		}
-		return sourceVmr, nil
-	} else if id != 0 {
-		return client.GetVmRefById(ctx, id)
-	}
-
-	return nil, errors.New("either 'clone' name or 'clone_id' must be specified")
-}
-
 func resourceVmQemuCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
 	// create a logger for this function
 	logger, _ := CreateSubLogger("resource_vm_create")
@@ -668,7 +646,7 @@ func resourceVmQemuCreate(ctx context.Context, d *schema.ResourceData, meta inte
 		// check if clone, or PXE boot
 		if d.Get("clone").(string) != "" || d.Get("clone_id").(int) != 0 { // Clone
 
-			sourceVmr, err := getSourceVmr(ctx, client, pveSDK.GuestName(d.Get("clone").(string)), pveSDK.GuestID(d.Get("clone_id").(int)), targetNode)
+			sourceVmr, err := guestGetSourceVmr(ctx, client, pveSDK.GuestName(d.Get("clone").(string)), pveSDK.GuestID(d.Get("clone_id").(int)), targetNode, pveSDK.GuestQemu)
 			if err != nil {
 				return append(diags, diag.FromErr(err)...)
 			}



Test patch:
diff --git a/proxmox/helper_guest_test.go b/proxmox/helper_guest_test.go
new file mode 100644
index 0000000..6e14dcb
--- /dev/null
+++ b/proxmox/helper_guest_test.go
@@ -0,0 +1,80 @@
+package proxmox
+
+import (
+	"errors"
+	"testing"
+
+	pveSDK "github.com/Telmate/proxmox-api-go/proxmox"
+	"github.com/stretchr/testify/require"
+)
+
+func Test_UserID_Validate(t *testing.T) {
+	newGuestRef := func(id pveSDK.GuestID, node pveSDK.NodeName, guest pveSDK.GuestType) *pveSDK.VmRef {
+		ref := pveSDK.NewVmRef(id)
+		ref.SetNode(string(node))
+		ref.SetVmType(guest)
+		return ref
+	}
+	guestBuilder := func(ID pveSDK.GuestID, Name pveSDK.GuestName, Node pveSDK.NodeName, Type pveSDK.GuestType) pveSDK.RawGuestResource {
+		return &pveSDK.RawGuestResourceMock{
+			GetIDFunc: func() pveSDK.GuestID {
+				return ID
+			},
+			GetNameFunc: func() pveSDK.GuestName {
+				return Name
+			},
+			GetNodeFunc: func() pveSDK.NodeName {
+				return Node
+			},
+			GetTypeFunc: func() pveSDK.GuestType {
+				return Type
+			}}
+	}
+	raw := []pveSDK.RawGuestResource{
+		guestBuilder(100, "test", "node1", pveSDK.GuestQemu),
+		guestBuilder(101, "test", "node1", pveSDK.GuestLxc),
+		guestBuilder(102, "test", "node2", pveSDK.GuestQemu),
+		guestBuilder(103, "test", "node2", pveSDK.GuestLxc),
+		guestBuilder(104, "test", "node3", pveSDK.GuestQemu),
+		guestBuilder(105, "test", "node3", pveSDK.GuestLxc),
+		guestBuilder(200, "single-node", "node3", pveSDK.GuestLxc),
+	}
+	type testInput struct {
+		guestType     pveSDK.GuestType
+		name          pveSDK.GuestName
+		preferredNode pveSDK.NodeName
+	}
+	tests := []struct {
+		name   string
+		input  testInput
+		output *pveSDK.VmRef
+		err    error
+	}{
+		{name: `no vm found`,
+			input: testInput{
+				guestType:     pveSDK.GuestQemu,
+				name:          "non-existing-vm",
+				preferredNode: "node1"},
+			output: nil,
+			err:    errors.New("no guest with name 'non-existing-vm' found")},
+		{name: `preferred node found`,
+			input: testInput{
+				guestType:     pveSDK.GuestQemu,
+				name:          "test",
+				preferredNode: "node2"},
+			output: newGuestRef(102, "node2", pveSDK.GuestQemu)},
+		{name: `preferred node not found, pick first`,
+			input: testInput{
+				guestType:     pveSDK.GuestLxc,
+				name:          "single-node",
+				preferredNode: "nodeX"},
+			output: newGuestRef(200, "node3", pveSDK.GuestLxc)},
+	}
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+			vmref, err := guestGetSourceVmrByNode(raw, test.input.name, test.input.preferredNode, test.input.guestType)
+			require.Equal(t, test.output, vmref)
+			require.Equal(t, test.err, err)
+		})
+	}
+}