diff --git a/docs/data-sources/virtual_environment_vm2.md b/docs/data-sources/virtual_environment_vm2.md
index 25745dc0..2a348629 100644
--- a/docs/data-sources/virtual_environment_vm2.md
+++ b/docs/data-sources/virtual_environment_vm2.md
@@ -31,6 +31,7 @@ This is an experimental implementation of a Proxmox VM datasource using Plugin F
- `tags` (Set of String) The tags assigned to the VM.
- `template` (Boolean) Whether the VM is a template.
- `timeouts` (Attributes) (see [below for nested schema](#nestedatt--timeouts))
+- `vga` (Attributes) The VGA configuration. (see [below for nested schema](#nestedatt--vga))
### Nested Schema for `clone`
@@ -67,3 +68,13 @@ Optional:
Optional:
- `read` (String) A string that can be [parsed as a duration](https://pkg.go.dev/time#ParseDuration) consisting of numbers and unit suffixes, such as "30s" or "2h45m". Valid time units are "s" (seconds), "m" (minutes), "h" (hours). Read operations occur during any refresh or planning operation when refresh is enabled.
+
+
+
+### Nested Schema for `vga`
+
+Optional:
+
+- `clipboard` (String) Enable a specific clipboard.
+- `memory` (Number) The VGA memory in megabytes (4-512 MB). Has no effect with serial display.
+- `type` (String) The VGA type.
diff --git a/docs/resources/virtual_environment_vm.md b/docs/resources/virtual_environment_vm.md
index c15d4ec4..bbcbb991 100644
--- a/docs/resources/virtual_environment_vm.md
+++ b/docs/resources/virtual_environment_vm.md
@@ -541,9 +541,9 @@ output "ubuntu_vm_public_key" {
- `serial3` - Serial Terminal 3.
- `std` - Standard VGA.
- `virtio` - VirtIO-GPU.
- - `virtio-gl` - VirtIO-GPU with 3D acceleration (VirGL). VirGL support needs some extra libraries that aren’t installed by default. See the [Proxmox documentation](https://pve.proxmox.com/pve-docs/pve-admin-guide.html#qm_virtual_machines_settings) section 10.2.8.for more information.
+ - `virtio-gl` - VirtIO-GPU with 3D acceleration (VirGL). VirGL support needs some extra libraries that aren’t installed by default. See the [Proxmox documentation](https://pve.proxmox.com/pve-docs/pve-admin-guide.html#qm_virtual_machines_settings) section 10.2.8 for more information.
- `vmware` - VMware Compatible.
- - `clipboard` - (Optional) Enable VNC clipboard by setting to `vnc`. See the [Proxmox documentation](https://pve.proxmox.com/pve-docs/pve-admin-guide.html#qm_virtual_machines_settings) section 10.2.8.for more information.
+ - `clipboard` - (Optional) Enable VNC clipboard by setting to `vnc`. See the [Proxmox documentation](https://pve.proxmox.com/pve-docs/pve-admin-guide.html#qm_virtual_machines_settings) section 10.2.8 for more information.
- `vm_id` - (Optional) The VM identifier.
- `hook_script_file_id` - (Optional) The identifier for a file containing a hook script (needs to be executable).
diff --git a/docs/resources/virtual_environment_vm2.md b/docs/resources/virtual_environment_vm2.md
index 77f614c1..375326f9 100644
--- a/docs/resources/virtual_environment_vm2.md
+++ b/docs/resources/virtual_environment_vm2.md
@@ -38,6 +38,7 @@ The attributes are also marked as optional to allow the practitioner to set (or
- `tags` (Set of String) The tags assigned to the VM.
- `template` (Boolean) Set to true to create a VM template.
- `timeouts` (Attributes) (see [below for nested schema](#nestedatt--timeouts))
+- `vga` (Attributes) Configure the VGA Hardware. If you want to use high resolution modes (>= 1280x1024x16) you may need to increase the vga memory option. Since QEMU 2.9 the default VGA display type is `std` for all OS types besides some Windows versions (XP and older) which use `cirrus`. The `qxl` option enables the SPICE display server. For win* OS you can select how many independent displays you want, Linux guests can add displays themself. You can also run without any graphic card, using a serial device as terminal. See the [Proxmox documentation](https://pve.proxmox.com/pve-docs/pve-admin-guide.html#qm_virtual_machines_settings) section 10.2.8 for more information and available configuration parameters. (see [below for nested schema](#nestedatt--vga))
### Nested Schema for `clone`
@@ -77,3 +78,13 @@ Optional:
- `delete` (String) A string that can be [parsed as a duration](https://pkg.go.dev/time#ParseDuration) consisting of numbers and unit suffixes, such as "30s" or "2h45m". Valid time units are "s" (seconds), "m" (minutes), "h" (hours). Setting a timeout for a Delete operation is only applicable if changes are saved into state before the destroy operation occurs.
- `read` (String) A string that can be [parsed as a duration](https://pkg.go.dev/time#ParseDuration) consisting of numbers and unit suffixes, such as "30s" or "2h45m". Valid time units are "s" (seconds), "m" (minutes), "h" (hours). Read operations occur during any refresh or planning operation when refresh is enabled.
- `update` (String) A string that can be [parsed as a duration](https://pkg.go.dev/time#ParseDuration) consisting of numbers and unit suffixes, such as "30s" or "2h45m". Valid time units are "s" (seconds), "m" (minutes), "h" (hours).
+
+
+
+### Nested Schema for `vga`
+
+Optional:
+
+- `clipboard` (String) Enable a specific clipboard. If not set, depending on the display type the SPICE one will be added. Currently only `vnc` is available. Migration with VNC clipboard is not supported by Proxmox.
+- `memory` (Number) The VGA memory in megabytes (4-512 MB). Has no effect with serial display.
+- `type` (String) The VGA type (defaults to `std`).
diff --git a/fwprovider/access/resource_acl.go b/fwprovider/access/resource_acl.go
index c36acf8b..59960400 100644
--- a/fwprovider/access/resource_acl.go
+++ b/fwprovider/access/resource_acl.go
@@ -18,7 +18,7 @@ import (
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/bpg/terraform-provider-proxmox/fwprovider/structure"
+ "github.com/bpg/terraform-provider-proxmox/fwprovider/attribute"
"github.com/bpg/terraform-provider-proxmox/proxmox"
"github.com/bpg/terraform-provider-proxmox/proxmox/helpers/ptr"
proxmoxtypes "github.com/bpg/terraform-provider-proxmox/proxmox/types"
@@ -54,7 +54,7 @@ func (r *aclResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *
stringplanmodifier.RequiresReplace(),
},
},
- "id": structure.IDAttribute(),
+ "id": attribute.ID(),
"path": schema.StringAttribute{
Description: "Access control path",
Required: true,
diff --git a/fwprovider/access/resource_user_token.go b/fwprovider/access/resource_user_token.go
index 7813ec6d..bd0aafc4 100644
--- a/fwprovider/access/resource_user_token.go
+++ b/fwprovider/access/resource_user_token.go
@@ -16,7 +16,7 @@ import (
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-framework/types"
- "github.com/bpg/terraform-provider-proxmox/fwprovider/structure"
+ "github.com/bpg/terraform-provider-proxmox/fwprovider/attribute"
"github.com/bpg/terraform-provider-proxmox/fwprovider/validators"
"github.com/bpg/terraform-provider-proxmox/proxmox"
"github.com/bpg/terraform-provider-proxmox/proxmox/access"
@@ -69,7 +69,7 @@ func (r *userTokenResource) Schema(
}, "must be a valid RFC3339 date"),
},
},
- "id": structure.IDAttribute("Unique token identifier with format `!`."),
+ "id": attribute.ID("Unique token identifier with format `!`."),
"privileges_separation": schema.BoolAttribute{
Description: "Restrict API token privileges with separate ACLs (default)",
MarkdownDescription: "Restrict API token privileges with separate ACLs (default), " +
diff --git a/fwprovider/structure/attribute.go b/fwprovider/attribute/attribute.go
similarity index 50%
rename from fwprovider/structure/attribute.go
rename to fwprovider/attribute/attribute.go
index 142c05e6..25793050 100644
--- a/fwprovider/structure/attribute.go
+++ b/fwprovider/attribute/attribute.go
@@ -4,17 +4,18 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
-package structure
+package attribute
import (
+ "github.com/hashicorp/terraform-plugin-framework/attr"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
)
-// IDAttribute generates an attribute definition suitable for the always-present `id` attribute.
-func IDAttribute(desc ...string) schema.StringAttribute {
- attr := schema.StringAttribute{
+// ID generates an attribute definition suitable for the always-present `id` attribute.
+func ID(desc ...string) schema.StringAttribute {
+ a := schema.StringAttribute{
Computed: true,
Description: "The unique identifier of this resource.",
PlanModifiers: []planmodifier.String{
@@ -23,8 +24,18 @@ func IDAttribute(desc ...string) schema.StringAttribute {
}
if len(desc) > 0 {
- attr.Description = desc[0]
+ a.Description = desc[0]
}
- return attr
+ return a
+}
+
+// ShouldBeRemoved evaluates if an attribute should be removed from the plan during update.
+func ShouldBeRemoved(plan attr.Value, state attr.Value, isClone bool) bool {
+ return !IsDefined(plan) && IsDefined(state) && !isClone
+}
+
+// IsDefined returns true if attribute is known and not null.
+func IsDefined(v attr.Value) bool {
+ return !v.IsNull() && !v.IsUnknown()
}
diff --git a/fwprovider/ha/datasource_hagroup.go b/fwprovider/ha/datasource_hagroup.go
index 889fb86e..c803bf15 100644
--- a/fwprovider/ha/datasource_hagroup.go
+++ b/fwprovider/ha/datasource_hagroup.go
@@ -14,7 +14,7 @@ import (
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/types"
- "github.com/bpg/terraform-provider-proxmox/fwprovider/structure"
+ "github.com/bpg/terraform-provider-proxmox/fwprovider/attribute"
"github.com/bpg/terraform-provider-proxmox/proxmox"
hagroups "github.com/bpg/terraform-provider-proxmox/proxmox/cluster/ha/groups"
@@ -51,7 +51,7 @@ func (d *haGroupDatasource) Schema(_ context.Context, _ datasource.SchemaRequest
resp.Schema = schema.Schema{
Description: "Retrieves information about a specific High Availability group.",
Attributes: map[string]schema.Attribute{
- "id": structure.IDAttribute(),
+ "id": attribute.ID(),
"group": schema.StringAttribute{
Description: "The identifier of the High Availability group to read.",
Required: true,
diff --git a/fwprovider/ha/datasource_hagroups.go b/fwprovider/ha/datasource_hagroups.go
index 16edeb96..7814ac3b 100644
--- a/fwprovider/ha/datasource_hagroups.go
+++ b/fwprovider/ha/datasource_hagroups.go
@@ -15,7 +15,7 @@ import (
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/types"
- "github.com/bpg/terraform-provider-proxmox/fwprovider/structure"
+ "github.com/bpg/terraform-provider-proxmox/fwprovider/attribute"
"github.com/bpg/terraform-provider-proxmox/proxmox"
hagroups "github.com/bpg/terraform-provider-proxmox/proxmox/cluster/ha/groups"
@@ -57,7 +57,7 @@ func (d *haGroupsDatasource) Schema(_ context.Context, _ datasource.SchemaReques
resp.Schema = schema.Schema{
Description: "Retrieves the list of High Availability groups.",
Attributes: map[string]schema.Attribute{
- "id": structure.IDAttribute(),
+ "id": attribute.ID(),
"group_ids": schema.SetAttribute{
Description: "The identifiers of the High Availability groups.",
ElementType: types.StringType,
diff --git a/fwprovider/ha/datasource_haresource.go b/fwprovider/ha/datasource_haresource.go
index 95b583c9..2625302d 100644
--- a/fwprovider/ha/datasource_haresource.go
+++ b/fwprovider/ha/datasource_haresource.go
@@ -14,7 +14,7 @@ import (
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
- "github.com/bpg/terraform-provider-proxmox/fwprovider/structure"
+ "github.com/bpg/terraform-provider-proxmox/fwprovider/attribute"
"github.com/bpg/terraform-provider-proxmox/proxmox"
haresources "github.com/bpg/terraform-provider-proxmox/proxmox/cluster/ha/resources"
proxmoxtypes "github.com/bpg/terraform-provider-proxmox/proxmox/types"
@@ -50,7 +50,7 @@ func (d *haResourceDatasource) Schema(_ context.Context, _ datasource.SchemaRequ
resp.Schema = schema.Schema{
Description: "Retrieves the list of High Availability resources.",
Attributes: map[string]schema.Attribute{
- "id": structure.IDAttribute(),
+ "id": attribute.ID(),
"resource_id": schema.StringAttribute{
Description: "The identifier of the Proxmox HA resource to read.",
Required: true,
diff --git a/fwprovider/ha/datasource_haresources.go b/fwprovider/ha/datasource_haresources.go
index 4576a047..8e64cb0c 100644
--- a/fwprovider/ha/datasource_haresources.go
+++ b/fwprovider/ha/datasource_haresources.go
@@ -17,7 +17,7 @@ import (
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-framework/types"
- "github.com/bpg/terraform-provider-proxmox/fwprovider/structure"
+ "github.com/bpg/terraform-provider-proxmox/fwprovider/attribute"
"github.com/bpg/terraform-provider-proxmox/proxmox"
haresources "github.com/bpg/terraform-provider-proxmox/proxmox/cluster/ha/resources"
@@ -64,7 +64,7 @@ func (d *haResourcesDatasource) Schema(_ context.Context, _ datasource.SchemaReq
resp.Schema = schema.Schema{
Description: "Retrieves the list of High Availability resources.",
Attributes: map[string]schema.Attribute{
- "id": structure.IDAttribute(),
+ "id": attribute.ID(),
"type": schema.StringAttribute{
Description: "The type of High Availability resources to fetch (`vm` or `ct`). All resources " +
"will be fetched if this option is unset.",
diff --git a/fwprovider/ha/resource_hagroup.go b/fwprovider/ha/resource_hagroup.go
index 10bafa5f..20981a5e 100644
--- a/fwprovider/ha/resource_hagroup.go
+++ b/fwprovider/ha/resource_hagroup.go
@@ -23,7 +23,7 @@ import (
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
"github.com/hashicorp/terraform-plugin-framework/types"
- "github.com/bpg/terraform-provider-proxmox/fwprovider/structure"
+ "github.com/bpg/terraform-provider-proxmox/fwprovider/attribute"
"github.com/bpg/terraform-provider-proxmox/proxmox"
hagroups "github.com/bpg/terraform-provider-proxmox/proxmox/cluster/ha/groups"
@@ -64,7 +64,7 @@ func (r *hagroupResource) Schema(
resp.Schema = schema.Schema{
Description: "Manages a High Availability group in a Proxmox VE cluster.",
Attributes: map[string]schema.Attribute{
- "id": structure.IDAttribute(),
+ "id": attribute.ID(),
"group": schema.StringAttribute{
Description: "The identifier of the High Availability group to manage.",
Required: true,
diff --git a/fwprovider/ha/resource_haresource.go b/fwprovider/ha/resource_haresource.go
index 62db96c6..1616a0fb 100644
--- a/fwprovider/ha/resource_haresource.go
+++ b/fwprovider/ha/resource_haresource.go
@@ -12,7 +12,7 @@ import (
"regexp"
"strings"
- "github.com/bpg/terraform-provider-proxmox/fwprovider/structure"
+ "github.com/bpg/terraform-provider-proxmox/fwprovider/attribute"
"github.com/bpg/terraform-provider-proxmox/proxmox"
haresources "github.com/bpg/terraform-provider-proxmox/proxmox/cluster/ha/resources"
proxmoxtypes "github.com/bpg/terraform-provider-proxmox/proxmox/types"
@@ -68,7 +68,7 @@ func (r *haResourceResource) Schema(
resp.Schema = schema.Schema{
Description: "Manages Proxmox HA resources.",
Attributes: map[string]schema.Attribute{
- "id": structure.IDAttribute(),
+ "id": attribute.ID(),
"resource_id": schema.StringAttribute{
Description: "The Proxmox HA resource identifier",
Required: true,
diff --git a/fwprovider/hardwaremapping/datasource.go b/fwprovider/hardwaremapping/datasource.go
index 524c80cb..830a5627 100644
--- a/fwprovider/hardwaremapping/datasource.go
+++ b/fwprovider/hardwaremapping/datasource.go
@@ -19,7 +19,7 @@ import (
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-framework/types"
- "github.com/bpg/terraform-provider-proxmox/fwprovider/structure"
+ "github.com/bpg/terraform-provider-proxmox/fwprovider/attribute"
"github.com/bpg/terraform-provider-proxmox/proxmox"
"github.com/bpg/terraform-provider-proxmox/proxmox/cluster/mapping"
proxmoxtypes "github.com/bpg/terraform-provider-proxmox/proxmox/types/hardwaremapping"
@@ -179,7 +179,7 @@ func (d *dataSource) Schema(
Computed: true,
Description: "The identifiers of the hardware mappings.",
},
- schemaAttrNameTerraformID: structure.IDAttribute(
+ schemaAttrNameTerraformID: attribute.ID(
"The unique identifier of this hardware mappings data source.",
),
schemaAttrNameType: schema.StringAttribute{
diff --git a/fwprovider/hardwaremapping/datasource_pci.go b/fwprovider/hardwaremapping/datasource_pci.go
index e8e379f7..237e6fdc 100644
--- a/fwprovider/hardwaremapping/datasource_pci.go
+++ b/fwprovider/hardwaremapping/datasource_pci.go
@@ -15,7 +15,7 @@ import (
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
- "github.com/bpg/terraform-provider-proxmox/fwprovider/structure"
+ "github.com/bpg/terraform-provider-proxmox/fwprovider/attribute"
customtypes "github.com/bpg/terraform-provider-proxmox/fwprovider/types/hardwaremapping"
"github.com/bpg/terraform-provider-proxmox/fwprovider/validators"
"github.com/bpg/terraform-provider-proxmox/proxmox"
@@ -155,7 +155,7 @@ func (d *dataSourcePCI) Schema(_ context.Context, _ datasource.SchemaRequest, re
Description: "The name of this PCI hardware mapping.",
Required: true,
},
- schemaAttrNameTerraformID: structure.IDAttribute(
+ schemaAttrNameTerraformID: attribute.ID(
"The unique identifier of this PCI hardware mapping data source.",
),
},
diff --git a/fwprovider/hardwaremapping/datasource_usb.go b/fwprovider/hardwaremapping/datasource_usb.go
index fe7e3c26..4f4129fc 100644
--- a/fwprovider/hardwaremapping/datasource_usb.go
+++ b/fwprovider/hardwaremapping/datasource_usb.go
@@ -15,7 +15,7 @@ import (
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
- "github.com/bpg/terraform-provider-proxmox/fwprovider/structure"
+ "github.com/bpg/terraform-provider-proxmox/fwprovider/attribute"
customtypes "github.com/bpg/terraform-provider-proxmox/fwprovider/types/hardwaremapping"
"github.com/bpg/terraform-provider-proxmox/fwprovider/validators"
"github.com/bpg/terraform-provider-proxmox/proxmox"
@@ -137,7 +137,7 @@ func (d *datasourceUSB) Schema(_ context.Context, _ datasource.SchemaRequest, re
Description: "The name of this USB hardware mapping.",
Required: true,
},
- schemaAttrNameTerraformID: structure.IDAttribute(
+ schemaAttrNameTerraformID: attribute.ID(
"The unique identifier of this USB hardware mapping data source.",
),
},
diff --git a/fwprovider/hardwaremapping/resource_pci.go b/fwprovider/hardwaremapping/resource_pci.go
index 98b83b8a..2c908878 100644
--- a/fwprovider/hardwaremapping/resource_pci.go
+++ b/fwprovider/hardwaremapping/resource_pci.go
@@ -22,7 +22,7 @@ import (
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
"github.com/hashicorp/terraform-plugin-framework/types"
- "github.com/bpg/terraform-provider-proxmox/fwprovider/structure"
+ "github.com/bpg/terraform-provider-proxmox/fwprovider/attribute"
customtypes "github.com/bpg/terraform-provider-proxmox/fwprovider/types/hardwaremapping"
"github.com/bpg/terraform-provider-proxmox/fwprovider/validators"
"github.com/bpg/terraform-provider-proxmox/proxmox"
@@ -264,7 +264,7 @@ func (r *resourcePCI) Schema(_ context.Context, _ resource.SchemaRequest, resp *
Description: "The name of this PCI hardware mapping.",
Required: true,
},
- schemaAttrNameTerraformID: structure.IDAttribute(
+ schemaAttrNameTerraformID: attribute.ID(
"The unique identifier of this PCI hardware mapping resource.",
),
},
diff --git a/fwprovider/hardwaremapping/resource_usb.go b/fwprovider/hardwaremapping/resource_usb.go
index 023487bb..6df9e864 100644
--- a/fwprovider/hardwaremapping/resource_usb.go
+++ b/fwprovider/hardwaremapping/resource_usb.go
@@ -21,7 +21,7 @@ import (
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
"github.com/hashicorp/terraform-plugin-framework/types"
- "github.com/bpg/terraform-provider-proxmox/fwprovider/structure"
+ "github.com/bpg/terraform-provider-proxmox/fwprovider/attribute"
customtypes "github.com/bpg/terraform-provider-proxmox/fwprovider/types/hardwaremapping"
"github.com/bpg/terraform-provider-proxmox/fwprovider/validators"
"github.com/bpg/terraform-provider-proxmox/proxmox"
@@ -249,7 +249,7 @@ func (r *resourceUSB) Schema(_ context.Context, _ resource.SchemaRequest, resp *
Description: "The name of this hardware mapping.",
Required: true,
},
- schemaAttrNameTerraformID: structure.IDAttribute(
+ schemaAttrNameTerraformID: attribute.ID(
"The unique identifier of this USB hardware mapping resource.",
),
},
diff --git a/fwprovider/network/resource_linux_bridge.go b/fwprovider/network/resource_linux_bridge.go
index 8d5fd93f..159a7318 100644
--- a/fwprovider/network/resource_linux_bridge.go
+++ b/fwprovider/network/resource_linux_bridge.go
@@ -24,7 +24,7 @@ import (
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-framework/types"
- "github.com/bpg/terraform-provider-proxmox/fwprovider/structure"
+ "github.com/bpg/terraform-provider-proxmox/fwprovider/attribute"
customtypes "github.com/bpg/terraform-provider-proxmox/fwprovider/types"
"github.com/bpg/terraform-provider-proxmox/proxmox"
@@ -173,7 +173,7 @@ func (r *linuxBridgeResource) Schema(
Description: "Manages a Linux Bridge network interface in a Proxmox VE node.",
Attributes: map[string]schema.Attribute{
// Base attributes
- "id": structure.IDAttribute("A unique identifier with format `:`"),
+ "id": attribute.ID("A unique identifier with format `:`"),
"node_name": schema.StringAttribute{
Description: "The name of the node.",
Required: true,
diff --git a/fwprovider/network/resource_linux_vlan.go b/fwprovider/network/resource_linux_vlan.go
index e33e83bf..462632d0 100644
--- a/fwprovider/network/resource_linux_vlan.go
+++ b/fwprovider/network/resource_linux_vlan.go
@@ -22,7 +22,7 @@ import (
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-framework/types"
- "github.com/bpg/terraform-provider-proxmox/fwprovider/structure"
+ "github.com/bpg/terraform-provider-proxmox/fwprovider/attribute"
customtypes "github.com/bpg/terraform-provider-proxmox/fwprovider/types"
"github.com/bpg/terraform-provider-proxmox/proxmox"
@@ -146,7 +146,7 @@ func (r *linuxVLANResource) Schema(
Description: "Manages a Linux VLAN network interface in a Proxmox VE node.",
Attributes: map[string]schema.Attribute{
// Base attributes
- "id": structure.IDAttribute("A unique identifier with format `:`."),
+ "id": attribute.ID("A unique identifier with format `:`."),
"node_name": schema.StringAttribute{
Description: "The name of the node.",
Required: true,
diff --git a/fwprovider/resource_download_file.go b/fwprovider/resource_download_file.go
index 2b35bbf8..2be3c909 100644
--- a/fwprovider/resource_download_file.go
+++ b/fwprovider/resource_download_file.go
@@ -27,7 +27,7 @@ import (
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-framework/types"
- "github.com/bpg/terraform-provider-proxmox/fwprovider/structure"
+ "github.com/bpg/terraform-provider-proxmox/fwprovider/attribute"
"github.com/bpg/terraform-provider-proxmox/proxmox/api"
"github.com/bpg/terraform-provider-proxmox/proxmox"
@@ -193,7 +193,7 @@ func (r *downloadFileResource) Schema(
"It can be fully compatible and faster replacement for image files created using " +
"`proxmox_virtual_environment_file`. Supports images for VMs (ISO images) and LXC (CT Templates).",
Attributes: map[string]schema.Attribute{
- "id": structure.IDAttribute(),
+ "id": attribute.ID(),
"content_type": schema.StringAttribute{
Description: "The file content type. Must be `iso` for VM images or `vztmpl` for LXC images.",
Required: true,
diff --git a/fwprovider/resource_options.go b/fwprovider/resource_options.go
index 89c84f04..213c2ddf 100644
--- a/fwprovider/resource_options.go
+++ b/fwprovider/resource_options.go
@@ -21,7 +21,7 @@ import (
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-framework/types"
- "github.com/bpg/terraform-provider-proxmox/fwprovider/structure"
+ "github.com/bpg/terraform-provider-proxmox/fwprovider/attribute"
"github.com/bpg/terraform-provider-proxmox/fwprovider/validators"
"github.com/bpg/terraform-provider-proxmox/proxmox"
"github.com/bpg/terraform-provider-proxmox/proxmox/cluster"
@@ -456,7 +456,7 @@ func (r *clusterOptionsResource) Schema(
resp.Schema = schema.Schema{
Description: "Manages Proxmox VE Cluster Datacenter options.",
Attributes: map[string]schema.Attribute{
- "id": structure.IDAttribute(),
+ "id": attribute.ID(),
"email_from": schema.StringAttribute{
Description: "email address to send notification from (default is root@$hostname).",
Optional: true,
diff --git a/fwprovider/test/test_environment.go b/fwprovider/test/test_environment.go
index 4a064ce5..22004e4c 100644
--- a/fwprovider/test/test_environment.go
+++ b/fwprovider/test/test_environment.go
@@ -9,6 +9,7 @@ import (
"testing"
"text/template"
+ "github.com/brianvoe/gofakeit/v7"
"github.com/hashicorp/terraform-plugin-framework/providerserver"
"github.com/hashicorp/terraform-plugin-go/tfprotov5"
"github.com/hashicorp/terraform-plugin-go/tfprotov6"
@@ -105,6 +106,10 @@ func (e *Environment) RenderConfig(cfg string) string {
tmpl, err := template.New("config").Parse("{{.ProviderConfig}}" + cfg)
require.NoError(e.t, err)
+ e.templateVars["RandomVMID"] = gofakeit.IntRange(100_000, 1_000_000)
+ e.templateVars["RandomVMID1"] = gofakeit.IntRange(100_000, 1_000_000)
+ e.templateVars["RandomVMID2"] = gofakeit.IntRange(100_000, 1_000_000)
+
var buf bytes.Buffer
err = tmpl.Execute(&buf, e.templateVars)
require.NoError(e.t, err)
diff --git a/fwprovider/vm/cpu/resource.go b/fwprovider/vm/cpu/resource.go
index 3e9113a0..b7e3abf8 100644
--- a/fwprovider/vm/cpu/resource.go
+++ b/fwprovider/vm/cpu/resource.go
@@ -4,11 +4,11 @@ import (
"context"
"reflect"
- "github.com/hashicorp/terraform-plugin-framework/attr"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-framework/types/basetypes"
+ "github.com/bpg/terraform-provider-proxmox/fwprovider/attribute"
"github.com/bpg/terraform-provider-proxmox/proxmox/nodes/vms"
proxmoxtypes "github.com/bpg/terraform-provider-proxmox/proxmox/types"
)
@@ -153,65 +153,65 @@ func FillUpdateBody(
}
if !plan.Affinity.Equal(state.Affinity) {
- if shouldBeRemoved(plan.Affinity, state.Affinity, isClone) {
+ if attribute.ShouldBeRemoved(plan.Affinity, state.Affinity, isClone) {
del("CPUAffinity")
- } else if isDefined(plan.Affinity) {
+ } else if attribute.IsDefined(plan.Affinity) {
updateBody.CPUAffinity = plan.Affinity.ValueStringPointer()
}
}
if !plan.Architecture.Equal(state.Architecture) {
- if shouldBeRemoved(plan.Architecture, state.Architecture, isClone) {
+ if attribute.ShouldBeRemoved(plan.Architecture, state.Architecture, isClone) {
del("CPUArchitecture")
- } else if isDefined(plan.Architecture) {
+ } else if attribute.IsDefined(plan.Architecture) {
updateBody.CPUArchitecture = plan.Architecture.ValueStringPointer()
}
}
if !plan.Cores.Equal(state.Cores) {
- if shouldBeRemoved(plan.Cores, state.Cores, isClone) {
+ if attribute.ShouldBeRemoved(plan.Cores, state.Cores, isClone) {
del("CPUCores")
- } else if isDefined(plan.Cores) {
+ } else if attribute.IsDefined(plan.Cores) {
updateBody.CPUCores = plan.Cores.ValueInt64Pointer()
}
}
if !plan.Limit.Equal(state.Limit) {
- if shouldBeRemoved(plan.Limit, state.Limit, isClone) {
+ if attribute.ShouldBeRemoved(plan.Limit, state.Limit, isClone) {
del("CPULimit")
- } else if isDefined(plan.Sockets) {
+ } else if attribute.IsDefined(plan.Sockets) {
updateBody.CPULimit = plan.Limit.ValueInt64Pointer()
}
}
if !plan.Sockets.Equal(state.Sockets) {
- if shouldBeRemoved(plan.Sockets, state.Sockets, isClone) {
+ if attribute.ShouldBeRemoved(plan.Sockets, state.Sockets, isClone) {
del("CPUSockets")
- } else if isDefined(plan.Sockets) {
+ } else if attribute.IsDefined(plan.Sockets) {
updateBody.CPUSockets = plan.Sockets.ValueInt64Pointer()
}
}
if !plan.Units.Equal(state.Units) {
- if shouldBeRemoved(plan.Units, state.Units, isClone) {
+ if attribute.ShouldBeRemoved(plan.Units, state.Units, isClone) {
del("CPUUnits")
- } else if isDefined(plan.Units) {
+ } else if attribute.IsDefined(plan.Units) {
updateBody.CPUUnits = plan.Units.ValueInt64Pointer()
}
}
if !plan.Numa.Equal(state.Numa) {
- if shouldBeRemoved(plan.Numa, state.Numa, isClone) {
+ if attribute.ShouldBeRemoved(plan.Numa, state.Numa, isClone) {
del("NUMAEnabled")
- } else if isDefined(plan.Numa) {
+ } else if attribute.IsDefined(plan.Numa) {
updateBody.NUMAEnabled = proxmoxtypes.CustomBoolPtr(plan.Numa.ValueBoolPointer())
}
}
if !plan.Hotplugged.Equal(state.Hotplugged) {
- if shouldBeRemoved(plan.Hotplugged, state.Hotplugged, isClone) {
+ if attribute.ShouldBeRemoved(plan.Hotplugged, state.Hotplugged, isClone) {
del("VirtualCPUCount")
- } else if isDefined(plan.Hotplugged) {
+ } else if attribute.IsDefined(plan.Hotplugged) {
updateBody.VirtualCPUCount = plan.Hotplugged.ValueInt64Pointer()
}
}
@@ -221,17 +221,17 @@ func FillUpdateBody(
cpuEmulation := &vms.CustomCPUEmulation{}
if !plan.Type.Equal(state.Type) {
- if shouldBeRemoved(plan.Type, state.Type, isClone) {
+ if attribute.ShouldBeRemoved(plan.Type, state.Type, isClone) {
delType = true
- } else if isDefined(plan.Type) {
+ } else if attribute.IsDefined(plan.Type) {
cpuEmulation.Type = plan.Type.ValueString()
}
}
if !plan.Flags.Equal(state.Flags) {
- if shouldBeRemoved(plan.Flags, state.Flags, isClone) {
+ if attribute.ShouldBeRemoved(plan.Flags, state.Flags, isClone) {
delFlags = true
- } else if isDefined(plan.Flags) {
+ } else if attribute.IsDefined(plan.Flags) {
d = plan.Flags.ElementsAs(ctx, &cpuEmulation.Flags, false)
diags.Append(d...)
}
@@ -246,11 +246,3 @@ func FillUpdateBody(
updateBody.CPUEmulation = cpuEmulation
}
}
-
-func shouldBeRemoved(plan attr.Value, state attr.Value, isClone bool) bool {
- return !isDefined(plan) && isDefined(state) && !isClone
-}
-
-func isDefined(v attr.Value) bool {
- return !v.IsNull() && !v.IsUnknown()
-}
diff --git a/fwprovider/vm/cpu/resource_test.go b/fwprovider/vm/cpu/resource_test.go
index 6672027f..7ae98260 100644
--- a/fwprovider/vm/cpu/resource_test.go
+++ b/fwprovider/vm/cpu/resource_test.go
@@ -21,6 +21,7 @@ func TestAccResourceVM2CPU(t *testing.T) {
Config: te.RenderConfig(`
resource "proxmox_virtual_environment_vm2" "test_vm" {
node_name = "{{.NodeName}}"
+ id = {{.RandomVMID}}
name = "test-cpu"
}`),
Check: resource.ComposeTestCheckFunc(
@@ -36,6 +37,7 @@ func TestAccResourceVM2CPU(t *testing.T) {
Config: te.RenderConfig(`
resource "proxmox_virtual_environment_vm2" "test_vm" {
node_name = "{{.NodeName}}"
+ id = {{.RandomVMID}}
name = "test-cpu"
cpu = {
cores = 2
@@ -59,6 +61,7 @@ func TestAccResourceVM2CPU(t *testing.T) {
Config: te.RenderConfig(`
resource "proxmox_virtual_environment_vm2" "test_vm" {
node_name = "{{.NodeName}}"
+ id = {{.RandomVMID}}
name = "test-cpu"
cpu = {
# affinity = "0-1" only root can set affinity
@@ -124,6 +127,7 @@ func TestAccResourceVM2CPU(t *testing.T) {
Config: te.RenderConfig(`
resource "proxmox_virtual_environment_vm2" "template_vm" {
node_name = "{{.NodeName}}"
+ id = {{.RandomVMID1}}
name = "template-cpu"
cpu = {
cores = 2
@@ -132,7 +136,8 @@ func TestAccResourceVM2CPU(t *testing.T) {
}
}
resource "proxmox_virtual_environment_vm2" "test_vm" {
- node_name = "{{.NodeName}}"
+ node_name = "{{.NodeName}}"
+ id = {{.RandomVMID2}}
name = "test-cpu"
clone = {
id = proxmox_virtual_environment_vm2.template_vm.id
@@ -150,6 +155,7 @@ func TestAccResourceVM2CPU(t *testing.T) {
Config: te.RenderConfig(`
resource "proxmox_virtual_environment_vm2" "template_vm" {
node_name = "{{.NodeName}}"
+ id = {{.RandomVMID1}}
name = "template-cpu"
cpu = {
cores = 2
@@ -158,7 +164,8 @@ func TestAccResourceVM2CPU(t *testing.T) {
}
}
resource "proxmox_virtual_environment_vm2" "test_vm" {
- node_name = "{{.NodeName}}"
+ node_name = "{{.NodeName}}"
+ id = {{.RandomVMID2}}
name = "test-cpu"
clone = {
id = proxmox_virtual_environment_vm2.template_vm.id
diff --git a/fwprovider/vm/datasource_schema.go b/fwprovider/vm/datasource_schema.go
index 0b3d82a7..3c650969 100644
--- a/fwprovider/vm/datasource_schema.go
+++ b/fwprovider/vm/datasource_schema.go
@@ -9,6 +9,7 @@ import (
"github.com/bpg/terraform-provider-proxmox/fwprovider/types/stringset"
"github.com/bpg/terraform-provider-proxmox/fwprovider/vm/cpu"
+ "github.com/bpg/terraform-provider-proxmox/fwprovider/vm/vga"
)
// Schema defines the schema for the resource.
@@ -60,6 +61,7 @@ func (d *Datasource) Schema(
"timeouts": timeouts.Attributes(ctx, timeouts.Opts{
Read: true,
}),
+ "vga": vga.DataSourceSchema(),
},
}
}
diff --git a/fwprovider/vm/resource.go b/fwprovider/vm/resource.go
index 402a81bb..d88997ad 100644
--- a/fwprovider/vm/resource.go
+++ b/fwprovider/vm/resource.go
@@ -16,6 +16,7 @@ import (
"github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/bpg/terraform-provider-proxmox/fwprovider/vm/cpu"
+ "github.com/bpg/terraform-provider-proxmox/fwprovider/vm/vga"
"github.com/bpg/terraform-provider-proxmox/proxmox"
"github.com/bpg/terraform-provider-proxmox/proxmox/api"
"github.com/bpg/terraform-provider-proxmox/proxmox/nodes/vms"
@@ -146,6 +147,7 @@ func (r *Resource) create(ctx context.Context, plan Model, diags *diag.Diagnosti
// fill out create body fields with values from other resource blocks
cpu.FillCreateBody(ctx, plan.CPU, createBody, diags)
+ vga.FillCreateBody(ctx, plan.VGA, createBody, diags)
if diags.HasError() {
return
@@ -321,6 +323,7 @@ func (r *Resource) update(ctx context.Context, plan, state Model, isClone bool,
}
cpu.FillUpdateBody(ctx, plan.CPU, state.CPU, updateBody, isClone, diags)
+ vga.FillUpdateBody(ctx, plan.VGA, state.VGA, updateBody, isClone, diags)
if !updateBody.IsEmpty() {
updateBody.VMID = int(plan.ID.ValueInt64())
diff --git a/fwprovider/vm/resource_schema.go b/fwprovider/vm/resource_schema.go
index a0f46c97..4e270d68 100644
--- a/fwprovider/vm/resource_schema.go
+++ b/fwprovider/vm/resource_schema.go
@@ -17,6 +17,7 @@ import (
"github.com/bpg/terraform-provider-proxmox/fwprovider/types/stringset"
"github.com/bpg/terraform-provider-proxmox/fwprovider/vm/cpu"
+ "github.com/bpg/terraform-provider-proxmox/fwprovider/vm/vga"
)
// Schema defines the schema for the resource.
@@ -93,6 +94,7 @@ func (r *Resource) Schema(
Update: true,
Delete: true,
}),
+ "vga": vga.ResourceSchema(),
},
}
}
diff --git a/fwprovider/vm/resource_test.go b/fwprovider/vm/resource_test.go
index eba87901..dea698dc 100644
--- a/fwprovider/vm/resource_test.go
+++ b/fwprovider/vm/resource_test.go
@@ -62,9 +62,8 @@ func TestAccResourceVM(t *testing.T) {
Config: te.RenderConfig(`
resource "proxmox_virtual_environment_vm2" "test_vm" {
node_name = "{{.NodeName}}"
-
+ id = {{.RandomVMID}}
name = "not a valid DNS name"
-
}`),
ExpectError: regexp.MustCompile(`name must be a valid DNS name`),
}}},
@@ -73,7 +72,7 @@ func TestAccResourceVM(t *testing.T) {
Config: te.RenderConfig(`
resource "proxmox_virtual_environment_vm2" "test_vm" {
node_name = "{{.NodeName}}"
-
+ id = {{.RandomVMID}}
name = "test-vm"
description = "test description"
}`),
@@ -86,7 +85,6 @@ func TestAccResourceVM(t *testing.T) {
Config: te.RenderConfig(`
resource "proxmox_virtual_environment_vm2" "test_vm" {
node_name = "{{.NodeName}}"
-
name = "test-vm"
}`),
Check: resource.ComposeTestCheckFunc(
@@ -110,7 +108,7 @@ func TestAccResourceVM(t *testing.T) {
Config: te.RenderConfig(`
resource "proxmox_virtual_environment_vm2" "test_vm" {
node_name = "{{.NodeName}}"
-
+ id = {{.RandomVMID}}
name = "test-tags"
tags = ["tag2", "tag1"]
}`),
@@ -159,7 +157,7 @@ func TestAccResourceVM(t *testing.T) {
Config: te.RenderConfig(`
resource "proxmox_virtual_environment_vm2" "test_vm" {
node_name = "{{.NodeName}}"
-
+ id = {{.RandomVMID}}
tags = ["", "tag1"]
}`),
ExpectError: regexp.MustCompile(`string length must be at least 1, got: 0`),
@@ -168,7 +166,7 @@ func TestAccResourceVM(t *testing.T) {
Config: te.RenderConfig(`
resource "proxmox_virtual_environment_vm2" "test_vm" {
node_name = "{{.NodeName}}"
-
+ id = {{.RandomVMID}}
tags = [" ", "tag1"]
}`),
ExpectError: regexp.MustCompile(`must be a non-empty and non-whitespace string`),
@@ -177,7 +175,7 @@ func TestAccResourceVM(t *testing.T) {
Config: te.RenderConfig(`
resource "proxmox_virtual_environment_vm2" "test_vm" {
node_name = "{{.NodeName}}"
-
+ id = {{.RandomVMID}}
description = trimspace(<<-EOT
my
description
@@ -220,12 +218,14 @@ func TestAccResourceVM2Clone(t *testing.T) {
Config: te.RenderConfig(`
resource "proxmox_virtual_environment_vm2" "test_vm" {
node_name = "{{.NodeName}}"
+ id = {{.RandomVMID1}}
name = "template"
description = "template description"
template = true
}
resource "proxmox_virtual_environment_vm2" "test_vm_clone" {
node_name = "{{.NodeName}}"
+ id = {{.RandomVMID2}}
name = "clone"
clone = {
id = proxmox_virtual_environment_vm2.test_vm.id
@@ -249,11 +249,13 @@ func TestAccResourceVM2Clone(t *testing.T) {
Config: te.RenderConfig(`
resource "proxmox_virtual_environment_vm2" "test_vm" {
node_name = "{{.NodeName}}"
+ id = {{.RandomVMID1}}
template = true
tags = ["tag1", "tag2"]
}
resource "proxmox_virtual_environment_vm2" "test_vm_clone" {
node_name = "{{.NodeName}}"
+ id = {{.RandomVMID2}}
clone = {
id = proxmox_virtual_environment_vm2.test_vm.id
}
diff --git a/fwprovider/vm/vga/datasource_schema.go b/fwprovider/vm/vga/datasource_schema.go
new file mode 100644
index 00000000..fa88316d
--- /dev/null
+++ b/fwprovider/vm/vga/datasource_schema.go
@@ -0,0 +1,36 @@
+package vga
+
+import (
+ "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
+ "github.com/hashicorp/terraform-plugin-framework/types/basetypes"
+)
+
+// DataSourceSchema defines the schema for the VGA resource.
+func DataSourceSchema() schema.Attribute {
+ return schema.SingleNestedAttribute{
+ CustomType: basetypes.ObjectType{
+ AttrTypes: attributeTypes(),
+ },
+ Description: "The VGA configuration.",
+ Optional: true,
+ Computed: true,
+ Attributes: map[string]schema.Attribute{
+ "clipboard": schema.StringAttribute{
+ Description: "Enable a specific clipboard.",
+ Optional: true,
+ Computed: true,
+ },
+ "type": schema.StringAttribute{
+ Description: "The VGA type.",
+ Optional: true,
+ Computed: true,
+ },
+ "memory": schema.Int64Attribute{
+ Description: "The VGA memory in megabytes (4-512 MB)",
+ MarkdownDescription: "The VGA memory in megabytes (4-512 MB). Has no effect with serial display. ",
+ Optional: true,
+ Computed: true,
+ },
+ },
+ }
+}
diff --git a/fwprovider/vm/vga/resource.go b/fwprovider/vm/vga/resource.go
new file mode 100644
index 00000000..fc4abe24
--- /dev/null
+++ b/fwprovider/vm/vga/resource.go
@@ -0,0 +1,129 @@
+package vga
+
+import (
+ "context"
+ "reflect"
+
+ "github.com/hashicorp/terraform-plugin-framework/diag"
+ "github.com/hashicorp/terraform-plugin-framework/types"
+ "github.com/hashicorp/terraform-plugin-framework/types/basetypes"
+
+ "github.com/bpg/terraform-provider-proxmox/fwprovider/attribute"
+ "github.com/bpg/terraform-provider-proxmox/proxmox/nodes/vms"
+)
+
+// Value represents the type for VGA settings.
+type Value = types.Object
+
+// NewValue returns a new Value with the given VGA settings from the PVE API.
+func NewValue(ctx context.Context, config *vms.GetResponseData, diags *diag.Diagnostics) Value {
+ vga := Model{}
+
+ if config.VGADevice != nil {
+ vga.Clipboard = types.StringPointerValue(config.VGADevice.Clipboard)
+ vga.Type = types.StringPointerValue(config.VGADevice.Type)
+ vga.Memory = types.Int64PointerValue(config.VGADevice.Memory)
+ }
+
+ obj, d := types.ObjectValueFrom(ctx, attributeTypes(), vga)
+ diags.Append(d...)
+
+ return obj
+}
+
+// FillCreateBody fills the CreateRequestBody with the VGA settings from the Value.
+//
+// In the 'create' context, v is the plan.
+func FillCreateBody(ctx context.Context, planValue Value, body *vms.CreateRequestBody, diags *diag.Diagnostics) {
+ var plan Model
+
+ if planValue.IsNull() || planValue.IsUnknown() {
+ return
+ }
+
+ d := planValue.As(ctx, &plan, basetypes.ObjectAsOptions{})
+ diags.Append(d...)
+
+ if d.HasError() {
+ return
+ }
+
+ vgaDevice := &vms.CustomVGADevice{}
+
+ // for computed fields, we need to check if they are unknown
+ if !plan.Clipboard.IsUnknown() {
+ vgaDevice.Clipboard = plan.Clipboard.ValueStringPointer()
+ }
+
+ if !plan.Type.IsUnknown() {
+ vgaDevice.Type = plan.Type.ValueStringPointer()
+ }
+
+ if !plan.Memory.IsUnknown() {
+ vgaDevice.Memory = plan.Memory.ValueInt64Pointer()
+ }
+
+ if !reflect.DeepEqual(vgaDevice, &vms.CustomVGADevice{}) {
+ body.VGADevice = vgaDevice
+ }
+}
+
+// FillUpdateBody fills the UpdateRequestBody with the VGA settings from the Value.
+//
+// In the 'update' context, v is the plan and stateValue is the current state.
+func FillUpdateBody(
+ ctx context.Context,
+ planValue, stateValue Value,
+ updateBody *vms.UpdateRequestBody,
+ isClone bool,
+ diags *diag.Diagnostics,
+) {
+ var plan, state Model
+
+ if planValue.IsNull() || planValue.IsUnknown() || planValue.Equal(stateValue) {
+ return
+ }
+
+ d := planValue.As(ctx, &plan, basetypes.ObjectAsOptions{})
+ diags.Append(d...)
+ d = stateValue.As(ctx, &state, basetypes.ObjectAsOptions{})
+ diags.Append(d...)
+
+ if diags.HasError() {
+ return
+ }
+
+ vgaDevice := &vms.CustomVGADevice{
+ Clipboard: state.Clipboard.ValueStringPointer(),
+ Type: state.Type.ValueStringPointer(),
+ Memory: state.Memory.ValueInt64Pointer(),
+ }
+
+ if !plan.Clipboard.Equal(state.Clipboard) {
+ if attribute.ShouldBeRemoved(plan.Clipboard, state.Clipboard, isClone) {
+ vgaDevice.Clipboard = nil
+ } else if attribute.IsDefined(plan.Clipboard) {
+ vgaDevice.Clipboard = plan.Clipboard.ValueStringPointer()
+ }
+ }
+
+ if !plan.Type.Equal(state.Type) {
+ if attribute.ShouldBeRemoved(plan.Type, state.Type, isClone) {
+ vgaDevice.Type = nil
+ } else if attribute.IsDefined(plan.Type) {
+ vgaDevice.Type = plan.Type.ValueStringPointer()
+ }
+ }
+
+ if !plan.Memory.Equal(state.Memory) {
+ if attribute.ShouldBeRemoved(plan.Memory, state.Memory, isClone) {
+ vgaDevice.Memory = nil
+ } else if attribute.IsDefined(plan.Memory) {
+ vgaDevice.Memory = plan.Memory.ValueInt64Pointer()
+ }
+ }
+
+ if !reflect.DeepEqual(vgaDevice, &vms.CustomVGADevice{}) {
+ updateBody.VGADevice = vgaDevice
+ }
+}
diff --git a/fwprovider/vm/vga/resource_model.go b/fwprovider/vm/vga/resource_model.go
new file mode 100644
index 00000000..6dc310b4
--- /dev/null
+++ b/fwprovider/vm/vga/resource_model.go
@@ -0,0 +1,21 @@
+package vga
+
+import (
+ "github.com/hashicorp/terraform-plugin-framework/attr"
+ "github.com/hashicorp/terraform-plugin-framework/types"
+)
+
+// Model represents the VGA model.
+type Model struct {
+ Clipboard types.String `tfsdk:"clipboard"`
+ Type types.String `tfsdk:"type"`
+ Memory types.Int64 `tfsdk:"memory"`
+}
+
+func attributeTypes() map[string]attr.Type {
+ return map[string]attr.Type{
+ "clipboard": types.StringType,
+ "type": types.StringType,
+ "memory": types.Int64Type,
+ }
+}
diff --git a/fwprovider/vm/vga/resource_schema.go b/fwprovider/vm/vga/resource_schema.go
new file mode 100644
index 00000000..fc553133
--- /dev/null
+++ b/fwprovider/vm/vga/resource_schema.go
@@ -0,0 +1,79 @@
+package vga
+
+import (
+ "github.com/hashicorp/terraform-plugin-framework-validators/int64validator"
+ "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema/objectplanmodifier"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
+ "github.com/hashicorp/terraform-plugin-framework/schema/validator"
+ "github.com/hashicorp/terraform-plugin-framework/types/basetypes"
+)
+
+// ResourceSchema defines the schema for the CPU resource.
+func ResourceSchema() schema.Attribute {
+ return schema.SingleNestedAttribute{
+ CustomType: basetypes.ObjectType{
+ AttrTypes: attributeTypes(),
+ },
+ Description: "The VGA configuration.",
+ MarkdownDescription: "Configure the VGA Hardware. If you want to use high resolution modes (>= 1280x1024x16) " +
+ "you may need to increase the vga memory option. Since QEMU 2.9 the default VGA display type is `std` " +
+ "for all OS types besides some Windows versions (XP and older) which use `cirrus`. The `qxl` option " +
+ "enables the SPICE display server. For win* OS you can select how many independent displays you want, " +
+ "Linux guests can add displays themself. You can also run without any graphic card, using a serial device " +
+ "as terminal. See the [Proxmox documentation](https://pve.proxmox.com/pve-docs/pve-admin-guide.html#" +
+ "qm_virtual_machines_settings) section 10.2.8 for more information and available configuration parameters.",
+ Optional: true,
+ Computed: true,
+ PlanModifiers: []planmodifier.Object{
+ objectplanmodifier.UseStateForUnknown(),
+ },
+ Attributes: map[string]schema.Attribute{
+ "clipboard": schema.StringAttribute{
+ Description: "Enable a specific clipboard.",
+ MarkdownDescription: "Enable a specific clipboard. If not set, depending on the display type the SPICE " +
+ "one will be added. Currently only `vnc` is available. Migration with VNC clipboard is not " +
+ "supported by Proxmox.",
+ Optional: true,
+ Computed: true,
+ Validators: []validator.String{
+ stringvalidator.OneOf("vnc"),
+ },
+ },
+ "type": schema.StringAttribute{
+ Description: "The VGA type.",
+ MarkdownDescription: "The VGA type (defaults to `std`).",
+ Optional: true,
+ Computed: true,
+ Validators: []validator.String{
+ stringvalidator.OneOf(
+ "cirrus",
+ "none",
+ "qxl",
+ "qxl2",
+ "qxl3",
+ "qxl4",
+ "serial0",
+ "serial1",
+ "serial2",
+ "serial3",
+ "std",
+ "virtio",
+ "virtio-gl",
+ "vmware",
+ ),
+ },
+ },
+ "memory": schema.Int64Attribute{
+ Description: "The VGA memory in megabytes (4-512 MB)",
+ MarkdownDescription: "The VGA memory in megabytes (4-512 MB). Has no effect with serial display. ",
+ Optional: true,
+ Computed: true,
+ Validators: []validator.Int64{
+ int64validator.Between(4, 512),
+ },
+ },
+ },
+ }
+}
diff --git a/fwprovider/vm/vga/resource_test.go b/fwprovider/vm/vga/resource_test.go
new file mode 100644
index 00000000..096836bd
--- /dev/null
+++ b/fwprovider/vm/vga/resource_test.go
@@ -0,0 +1,162 @@
+package vga_test
+
+import (
+ "testing"
+
+ "github.com/hashicorp/terraform-plugin-testing/helper/resource"
+
+ "github.com/bpg/terraform-provider-proxmox/fwprovider/test"
+)
+
+func TestAccResourceVM2VGA(t *testing.T) {
+ t.Parallel()
+
+ te := test.InitEnvironment(t)
+
+ tests := []struct {
+ name string
+ steps []resource.TestStep
+ }{
+ {"create VM with no vga params", []resource.TestStep{{
+ Config: te.RenderConfig(`
+ resource "proxmox_virtual_environment_vm2" "test_vm" {
+ node_name = "{{.NodeName}}"
+ id = {{.RandomVMID}}
+ name = "test-vga"
+ }`),
+ Check: test.NoResourceAttributesSet("proxmox_virtual_environment_vm2.test_vm", []string{
+ // PVE does not set / return anything by default
+ "vga.type",
+ }),
+ }}},
+ {"create VM with some vga params", []resource.TestStep{{
+ Config: te.RenderConfig(`
+ resource "proxmox_virtual_environment_vm2" "test_vm" {
+ node_name = "{{.NodeName}}"
+ id = {{.RandomVMID}}
+ name = "test-vga"
+ vga = {
+ type = "std"
+ }
+ }`),
+ Check: resource.ComposeTestCheckFunc(
+ test.ResourceAttributes("proxmox_virtual_environment_vm2.test_vm", map[string]string{
+ "vga.type": "std",
+ }),
+ test.NoResourceAttributesSet("proxmox_virtual_environment_vm2.test_vm", []string{
+ "vga.clipboard",
+ "vga.memory",
+ }),
+ ),
+ }}},
+ {"create VM with VGA params and then update them", []resource.TestStep{
+ {
+ Config: te.RenderConfig(`
+ resource "proxmox_virtual_environment_vm2" "test_vm" {
+ node_name = "{{.NodeName}}"
+ id = {{.RandomVMID}}
+ name = "test-vga"
+ vga = {
+ type = "std"
+ memory = 16
+ }
+ }`),
+ Check: resource.ComposeTestCheckFunc(
+ test.ResourceAttributes("proxmox_virtual_environment_vm2.test_vm", map[string]string{
+ "vga.type": "std",
+ "vga.memory": "16",
+ }),
+ ),
+ },
+ { // now update the vga params and check if they are updated
+ Config: te.RenderConfig(`
+ resource "proxmox_virtual_environment_vm2" "test_vm" {
+ node_name = "{{.NodeName}}"
+ name = "test-cpu"
+ vga = {
+ type = "qxl"
+ clipboard = "vnc"
+ }
+ }`),
+ Check: resource.ComposeTestCheckFunc(
+ test.ResourceAttributes("proxmox_virtual_environment_vm2.test_vm", map[string]string{
+ "vga.type": "qxl",
+ "vga.clipboard": "vnc",
+ }),
+ test.NoResourceAttributesSet("proxmox_virtual_environment_vm2.test_vm", []string{
+ "vga.memory",
+ }),
+ ),
+ },
+ {
+ RefreshState: true,
+ },
+ }},
+ {"clone VM with some vga params", []resource.TestStep{{
+ Config: te.RenderConfig(`
+ resource "proxmox_virtual_environment_vm2" "template_vm" {
+ node_name = "{{.NodeName}}"
+ id = {{.RandomVMID1}}
+ name = "template-vga"
+ vga = {
+ type = "qxl"
+ clipboard = "vnc"
+ }
+ }
+ resource "proxmox_virtual_environment_vm2" "test_vm" {
+ node_name = "{{.NodeName}}"
+ id = {{.RandomVMID2}}
+ name = "test-vga"
+ clone = {
+ id = proxmox_virtual_environment_vm2.template_vm.id
+ }
+ }`),
+ Check: resource.ComposeTestCheckFunc(
+ test.ResourceAttributes("proxmox_virtual_environment_vm2.test_vm", map[string]string{
+ "vga.type": "qxl",
+ "vga.clipboard": "vnc",
+ }),
+ ),
+ }}},
+ {"clone VM with some vga params and updating them in the clone", []resource.TestStep{{
+ Config: te.RenderConfig(`
+ resource "proxmox_virtual_environment_vm2" "template_vm" {
+ node_name = "{{.NodeName}}"
+ id = {{.RandomVMID1}}
+ name = "template-vga"
+ vga = {
+ type = "qxl"
+ clipboard = "vnc"
+ }
+ }
+ resource "proxmox_virtual_environment_vm2" "test_vm" {
+ node_name = "{{.NodeName}}"
+ name = "test-cpu"
+ id = {{.RandomVMID2}}
+ clone = {
+ id = proxmox_virtual_environment_vm2.template_vm.id
+ }
+ vga = {
+ type = "std"
+ memory = 16
+ }
+ }`),
+ Check: resource.ComposeTestCheckFunc(
+ test.ResourceAttributes("proxmox_virtual_environment_vm2.test_vm", map[string]string{
+ "vga.type": "std",
+ "vga.memory": "16",
+ "vga.clipboard": "vnc",
+ }),
+ ),
+ }}},
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ resource.ParallelTest(t, resource.TestCase{
+ ProtoV6ProviderFactories: te.AccProviders,
+ Steps: tt.steps,
+ })
+ })
+ }
+}
diff --git a/fwprovider/vm/vm_model.go b/fwprovider/vm/vm_model.go
index c6c67b04..5943507d 100644
--- a/fwprovider/vm/vm_model.go
+++ b/fwprovider/vm/vm_model.go
@@ -11,6 +11,7 @@ import (
"github.com/bpg/terraform-provider-proxmox/fwprovider/types/stringset"
"github.com/bpg/terraform-provider-proxmox/fwprovider/vm/cpu"
+ "github.com/bpg/terraform-provider-proxmox/fwprovider/vm/vga"
"github.com/bpg/terraform-provider-proxmox/proxmox"
"github.com/bpg/terraform-provider-proxmox/proxmox/api"
)
@@ -32,6 +33,7 @@ type Model struct {
Tags stringset.Value `tfsdk:"tags"`
Template types.Bool `tfsdk:"template"`
Timeouts timeouts.Value `tfsdk:"timeouts"`
+ VGA vga.Value `tfsdk:"vga"`
}
// read retrieves the current state of the resource from the API and updates the state.
@@ -69,9 +71,12 @@ func read(ctx context.Context, client proxmox.Client, model *Model, diags *diag.
// Optional fields can be removed from the model, use StringPointerValue to handle removal on nil
model.Description = types.StringPointerValue(config.Description)
model.Name = types.StringPointerValue(config.Name)
- model.CPU = cpu.NewValue(ctx, config, diags)
model.Tags = stringset.NewValue(config.Tags, diags)
model.Template = types.BoolPointerValue(config.Template.PointerBool())
+ // Blocks
+ model.CPU = cpu.NewValue(ctx, config, diags)
+ model.VGA = vga.NewValue(ctx, config, diags)
+
return true
}
diff --git a/proxmox/nodes/vms/vms_types.go b/proxmox/nodes/vms/vms_types.go
index ae53fa91..527d43a7 100644
--- a/proxmox/nodes/vms/vms_types.go
+++ b/proxmox/nodes/vms/vms_types.go
@@ -186,7 +186,7 @@ type CustomUSBDevices []CustomUSBDevice
// CustomVGADevice handles QEMU VGA device parameters.
type CustomVGADevice struct {
Clipboard *string `json:"clipboard,omitempty" url:"memory,omitempty"`
- Memory *int `json:"memory,omitempty" url:"memory,omitempty"`
+ Memory *int64 `json:"memory,omitempty" url:"memory,omitempty"`
Type *string `json:"type,omitempty" url:"type,omitempty"`
}
@@ -2047,7 +2047,7 @@ func (r *CustomVGADevice) UnmarshalJSON(b []byte) error {
r.Clipboard = &v[1]
case "memory":
- m, err := strconv.Atoi(v[1])
+ m, err := strconv.ParseInt(v[1], 10, 64)
if err != nil {
return fmt.Errorf("failed to convert memory to int: %w", err)
}
diff --git a/proxmoxtf/resource/vm/vm.go b/proxmoxtf/resource/vm/vm.go
index e46b2c0a..c41e15c7 100644
--- a/proxmoxtf/resource/vm/vm.go
+++ b/proxmoxtf/resource/vm/vm.go
@@ -3357,7 +3357,7 @@ func vmGetVGADeviceObject(d *schema.ResourceData) (*vms.CustomVGADevice, error)
}
if vgaMemory > 0 {
- vgaDevice.Memory = &vgaMemory
+ vgaDevice.Memory = ptr.Ptr(int64(vgaMemory))
}
if vgaType != "" {
@@ -4429,7 +4429,7 @@ func vmReadCustom(
}
if vmConfig.VGADevice.Memory != nil {
- vga[mkVGAMemory] = *vmConfig.VGADevice.Memory
+ vga[mkVGAMemory] = int(*vmConfig.VGADevice.Memory)
} else {
vga[mkVGAMemory] = dvVGAMemory
}