0
0
mirror of https://github.com/bpg/terraform-provider-proxmox.git synced 2025-08-23 11:58:34 +00:00

misc(vm2): add support for vga (#1328)

* misc(vm2): add support for `vga`
* fix: use random VM IDs in parallel acc tests

---------

Signed-off-by: Pavel Boldyrev <627562+bpg@users.noreply.github.com>
This commit is contained in:
Pavel Boldyrev 2024-05-27 21:30:12 -04:00 committed by GitHub
parent e0097d9880
commit d843e46b37
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
36 changed files with 564 additions and 86 deletions

View File

@ -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))
<a id="nestedatt--clone"></a>
### 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.
<a id="nestedatt--vga"></a>
### 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.

View File

@ -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 arent 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 arent 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).

View File

@ -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))
<a id="nestedatt--clone"></a>
### 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).
<a id="nestedatt--vga"></a>
### 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`).

View File

@ -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,

View File

@ -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 `<user_id>!<token_name>`."),
"id": attribute.ID("Unique token identifier with format `<user_id>!<token_name>`."),
"privileges_separation": schema.BoolAttribute{
Description: "Restrict API token privileges with separate ACLs (default)",
MarkdownDescription: "Restrict API token privileges with separate ACLs (default), " +

View File

@ -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()
}

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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.",

View File

@ -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,

View File

@ -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,

View File

@ -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{

View File

@ -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.",
),
},

View File

@ -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.",
),
},

View File

@ -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.",
),
},

View File

@ -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.",
),
},

View File

@ -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 `<node name>:<iface>`"),
"id": attribute.ID("A unique identifier with format `<node name>:<iface>`"),
"node_name": schema.StringAttribute{
Description: "The name of the node.",
Required: true,

View File

@ -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 `<node name>:<iface>`."),
"id": attribute.ID("A unique identifier with format `<node name>:<iface>`."),
"node_name": schema.StringAttribute{
Description: "The name of the node.",
Required: true,

View File

@ -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,

View File

@ -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,

View File

@ -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)

View File

@ -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()
}

View File

@ -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

View File

@ -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(),
},
}
}

View File

@ -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())

View File

@ -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(),
},
}
}

View File

@ -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
}

View File

@ -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,
},
},
}
}

View File

@ -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
}
}

View File

@ -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,
}
}

View File

@ -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),
},
},
},
}
}

View File

@ -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,
})
})
}
}

View File

@ -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
}

View File

@ -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)
}

View File

@ -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
}