diff --git a/docs/resources/virtual_environment_vm.md b/docs/resources/virtual_environment_vm.md index 05e63d85..c15d4ec4 100644 --- a/docs/resources/virtual_environment_vm.md +++ b/docs/resources/virtual_environment_vm.md @@ -527,11 +527,10 @@ output "ubuntu_vm_public_key" { - `timeout_stop_vm` - (Optional) Timeout for stopping a VM in seconds (defaults to 300). - `vga` - (Optional) The VGA configuration. - - `enabled` - (Optional) Whether to enable the VGA device (defaults - to `true`). - `memory` - (Optional) The VGA memory in megabytes (defaults to `16`). - `type` - (Optional) The VGA type (defaults to `std`). - `cirrus` - Cirrus (deprecated since QEMU 2.2). + - `none` - No VGA device. - `qxl` - SPICE. - `qxl2` - SPICE Dual Monitor. - `qxl3` - SPICE Triple Monitor. @@ -542,7 +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. - `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. - `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/fwprovider/test/resource_vm_test.go b/fwprovider/test/resource_vm_test.go index 8b1f2f7f..60fae670 100644 --- a/fwprovider/test/resource_vm_test.go +++ b/fwprovider/test/resource_vm_test.go @@ -162,6 +162,41 @@ func TestAccResourceVM(t *testing.T) { ), }}, }, + { + "update vga block", []resource.TestStep{{ + Config: te.RenderConfig(` + resource "proxmox_virtual_environment_vm" "test_vm" { + node_name = "{{.NodeName}}" + started = false + + vga { + type = "none" + } + }`), + Check: resource.ComposeTestCheckFunc( + ResourceAttributes("proxmox_virtual_environment_vm.test_vm", map[string]string{ + "vga.0.type": "none", + }), + ), + }, { + Config: te.RenderConfig(` + resource "proxmox_virtual_environment_vm" "test_vm" { + node_name = "{{.NodeName}}" + started = false + + vga { + type = "virtio-gl" + clipboard = "vnc" + } + }`), + Check: resource.ComposeTestCheckFunc( + ResourceAttributes("proxmox_virtual_environment_vm.test_vm", map[string]string{ + "vga.0.type": "virtio-gl", + "vga.0.clipboard": "vnc", + }), + ), + }}, + }, } for _, tt := range tests { diff --git a/proxmox/nodes/vms/vms_types.go b/proxmox/nodes/vms/vms_types.go index 46747203..ae53fa91 100644 --- a/proxmox/nodes/vms/vms_types.go +++ b/proxmox/nodes/vms/vms_types.go @@ -185,8 +185,9 @@ type CustomUSBDevices []CustomUSBDevice // CustomVGADevice handles QEMU VGA device parameters. type CustomVGADevice struct { - Memory *int `json:"memory,omitempty" url:"memory,omitempty"` - Type *string `json:"type,omitempty" url:"type,omitempty"` + Clipboard *string `json:"clipboard,omitempty" url:"memory,omitempty"` + Memory *int `json:"memory,omitempty" url:"memory,omitempty"` + Type *string `json:"type,omitempty" url:"type,omitempty"` } // CustomVirtualIODevice handles QEMU VirtIO device parameters. @@ -1242,6 +1243,10 @@ func (r CustomUSBDevices) EncodeValues(key string, v *url.Values) error { func (r CustomVGADevice) EncodeValues(key string, v *url.Values) error { var values []string + if r.Clipboard != nil { + values = append(values, fmt.Sprintf("clipboard=%s", *r.Clipboard)) + } + if r.Memory != nil { values = append(values, fmt.Sprintf("memory=%d", *r.Memory)) } @@ -2038,6 +2043,9 @@ func (r *CustomVGADevice) UnmarshalJSON(b []byte) error { r.Type = &v[0] } else if len(v) == 2 { switch v[0] { + case "clipboard": + r.Clipboard = &v[1] + case "memory": m, err := strconv.Atoi(v[1]) if err != nil { diff --git a/proxmoxtf/resource/vm/validators.go b/proxmoxtf/resource/vm/validators.go index f7a2192a..9bf6940c 100644 --- a/proxmoxtf/resource/vm/validators.go +++ b/proxmoxtf/resource/vm/validators.go @@ -228,6 +228,7 @@ func VGAMemoryValidator() schema.SchemaValidateDiagFunc { func VGATypeValidator() schema.SchemaValidateDiagFunc { return validation.ToDiagFunc(validation.StringInSlice([]string{ "cirrus", + "none", "qxl", "qxl2", "qxl3", @@ -238,6 +239,7 @@ func VGATypeValidator() schema.SchemaValidateDiagFunc { "serial3", "std", "virtio", + "virtio-gl", "vmware", }, false)) } diff --git a/proxmoxtf/resource/vm/vm.go b/proxmoxtf/resource/vm/vm.go index e2199a47..e46b2c0a 100644 --- a/proxmoxtf/resource/vm/vm.go +++ b/proxmoxtf/resource/vm/vm.go @@ -124,7 +124,7 @@ const ( dvTimeoutShutdownVM = 1800 dvTimeoutStartVM = 1800 dvTimeoutStopVM = 300 - dvVGAEnabled = true + dvVGAClipboard = "" dvVGAMemory = 16 dvVGAType = "std" dvSCSIHardware = "virtio-scsi-pci" @@ -271,6 +271,7 @@ const ( mkHostUSBDeviceMapping = "mapping" mkHostUSBDeviceUSB3 = "usb3" mkVGA = "vga" + mkVGAClipboard = "clipboard" mkVGAEnabled = "enabled" mkVGAMemory = "memory" mkVGAType = "type" @@ -1388,19 +1389,29 @@ func VM() *schema.Resource { DefaultFunc: func() (interface{}, error) { return []interface{}{ map[string]interface{}{ - mkVGAEnabled: dvVGAEnabled, - mkVGAMemory: dvVGAMemory, - mkVGAType: dvVGAType, + mkVGAClipboard: dvVGAClipboard, + mkVGAMemory: dvVGAMemory, + mkVGAType: dvVGAType, }, }, nil }, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ + mkVGAClipboard: { + Type: schema.TypeString, + Description: "Enable clipboard support. Set to `vnc` to enable clipboard support for VNC.", + Optional: true, + Default: dvVGAClipboard, + ValidateDiagFunc: validation.ToDiagFunc(validation.StringInSlice([]string{ + "vnc", + }, true)), + }, mkVGAEnabled: { - Type: schema.TypeBool, + Type: schema.TypeBool, + Deprecated: "The `enabled` attribute is deprecated and will be removed in a future release. " + + "Use type `none` instead.", Description: "Whether to enable the VGA device", Optional: true, - Default: dvVGAEnabled, }, mkVGAMemory: { Type: schema.TypeInt, @@ -3335,24 +3346,22 @@ func vmGetVGADeviceObject(d *schema.ResourceData) (*vms.CustomVGADevice, error) return nil, fmt.Errorf("error getting VGA block: %w", err) } - vgaEnabled := types.CustomBool(vgaBlock[mkAgentEnabled].(bool)) + vgaClipboard := vgaBlock[mkVGAClipboard].(string) vgaMemory := vgaBlock[mkVGAMemory].(int) vgaType := vgaBlock[mkVGAType].(string) vgaDevice := &vms.CustomVGADevice{} - if vgaEnabled { - if vgaMemory > 0 { - vgaDevice.Memory = &vgaMemory - } + if vgaClipboard != "" { + vgaDevice.Clipboard = &vgaClipboard + } + if vgaMemory > 0 { + vgaDevice.Memory = &vgaMemory + } + + if vgaType != "" { vgaDevice.Type = &vgaType - } else { - vgaType = "none" - - vgaDevice = &vms.CustomVGADevice{ - Type: &vgaType, - } } return vgaDevice, nil @@ -4413,29 +4422,23 @@ func vmReadCustom( vga := map[string]interface{}{} if vmConfig.VGADevice != nil { - vgaEnabled := true - - if vmConfig.VGADevice.Type != nil { - vgaEnabled = *vmConfig.VGADevice.Type != "none" + if vmConfig.VGADevice.Clipboard != nil { + vga[mkVGAClipboard] = *vmConfig.VGADevice.Clipboard + } else { + vga[mkVGAClipboard] = dvVGAClipboard } - vga[mkVGAEnabled] = vgaEnabled - if vmConfig.VGADevice.Memory != nil { vga[mkVGAMemory] = *vmConfig.VGADevice.Memory } else { - vga[mkVGAMemory] = 0 + vga[mkVGAMemory] = dvVGAMemory } - if vgaEnabled { - if vmConfig.VGADevice.Type != nil { - vga[mkVGAType] = *vmConfig.VGADevice.Type - } else { - vga[mkVGAType] = "" - } + if vmConfig.VGADevice.Type != nil { + vga[mkVGAType] = *vmConfig.VGADevice.Type } } else { - vga[mkVGAEnabled] = true + vga[mkVGAClipboard] = "" vga[mkVGAMemory] = 0 vga[mkVGAType] = "" } @@ -4447,7 +4450,7 @@ func vmReadCustom( err := d.Set(mkVGA, []interface{}{vga}) diags = append(diags, diag.FromErr(err)...) case len(currentVGA) > 0 || - vga[mkVGAEnabled] != dvVGAEnabled || + vga[mkVGAClipboard] != dvVGAClipboard || vga[mkVGAMemory] != dvVGAMemory || vga[mkVGAType] != dvVGAType: err := d.Set(mkVGA, []interface{}{vga})