mirror of
https://github.com/bpg/terraform-provider-proxmox.git
synced 2025-07-10 15:55:01 +00:00
Add vga argument to VM resource
This commit is contained in:
parent
87d8652d37
commit
7344300126
@ -1,3 +1,9 @@
|
|||||||
|
## 0.2.0 (UNRELEASED)
|
||||||
|
|
||||||
|
ENHANCEMENTS:
|
||||||
|
|
||||||
|
resource/virtual_environment_vm: Add `vga` argument
|
||||||
|
|
||||||
## 0.1.0
|
## 0.1.0
|
||||||
|
|
||||||
FEATURES:
|
FEATURES:
|
||||||
|
16
README.md
16
README.md
@ -433,6 +433,22 @@ This resource doesn't expose any additional attributes.
|
|||||||
* `wxp` - Windows XP
|
* `wxp` - Windows XP
|
||||||
* `pool_id` - (Optional) The ID of a pool to assign the virtual machine to
|
* `pool_id` - (Optional) The ID of a pool to assign the virtual machine to
|
||||||
* `started` - (Optional) Whether to start the virtual machine (defaults to `true`)
|
* `started` - (Optional) Whether to start the virtual machine (defaults to `true`)
|
||||||
|
* `vga` - (Optional) The VGA configuration
|
||||||
|
* `enabled` - (Optional) Whether to enable the VGA device (defaults to `true`)
|
||||||
|
* `memory` - (Optional) The VGA memory in megabytes (4-512 MB)
|
||||||
|
* `type` - (Optional) The VGA type
|
||||||
|
* `cirrus` - Cirrus (deprecated since QEMU 2.2)
|
||||||
|
* `qxl` - SPICE
|
||||||
|
* `qxl2` - SPICE Dual Monitor
|
||||||
|
* `qxl3` - SPICE Triple Monitor
|
||||||
|
* `qxl4` - SPICE Quad Monitor
|
||||||
|
* `serial0` - Serial Terminal 0
|
||||||
|
* `serial1` - Serial Terminal 1
|
||||||
|
* `serial2` - Serial Terminal 2
|
||||||
|
* `serial3` - Serial Terminal 3
|
||||||
|
* `std` - Standard VGA
|
||||||
|
* `virtio` - VirtIO-GPU
|
||||||
|
* `vmware` - VMware Compatible
|
||||||
* `vm_id` - (Optional) The ID
|
* `vm_id` - (Optional) The ID
|
||||||
|
|
||||||
###### Attributes
|
###### Attributes
|
||||||
|
@ -166,7 +166,7 @@ type CustomUSBDevices []CustomUSBDevice
|
|||||||
// CustomVGADevice handles QEMU VGA device parameters.
|
// CustomVGADevice handles QEMU VGA device parameters.
|
||||||
type CustomVGADevice struct {
|
type CustomVGADevice struct {
|
||||||
Memory *int `json:"memory,omitempty" url:"memory,omitempty"`
|
Memory *int `json:"memory,omitempty" url:"memory,omitempty"`
|
||||||
Type string `json:"type" url:"type"`
|
Type *string `json:"type,omitempty" url:"type,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// CustomVirtualIODevice handles QEMU VirtIO device parameters.
|
// CustomVirtualIODevice handles QEMU VirtIO device parameters.
|
||||||
@ -950,14 +950,16 @@ func (r CustomUSBDevices) EncodeValues(key string, v *url.Values) error {
|
|||||||
|
|
||||||
// EncodeValues converts a CustomVGADevice struct to a URL vlaue.
|
// EncodeValues converts a CustomVGADevice struct to a URL vlaue.
|
||||||
func (r CustomVGADevice) EncodeValues(key string, v *url.Values) error {
|
func (r CustomVGADevice) EncodeValues(key string, v *url.Values) error {
|
||||||
values := []string{
|
values := []string{}
|
||||||
fmt.Sprintf("type=%s", r.Type),
|
|
||||||
}
|
|
||||||
|
|
||||||
if r.Memory != nil {
|
if r.Memory != nil {
|
||||||
values = append(values, fmt.Sprintf("memory=%d", *r.Memory))
|
values = append(values, fmt.Sprintf("memory=%d", *r.Memory))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if r.Type != nil {
|
||||||
|
values = append(values, fmt.Sprintf("type=%s", *r.Type))
|
||||||
|
}
|
||||||
|
|
||||||
v.Add(key, strings.Join(values, ","))
|
v.Add(key, strings.Join(values, ","))
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -1355,3 +1357,43 @@ func (r *CustomStorageDevice) UnmarshalJSON(b []byte) error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON converts a CustomVGADevice string to an object.
|
||||||
|
func (r *CustomVGADevice) UnmarshalJSON(b []byte) error {
|
||||||
|
var s string
|
||||||
|
|
||||||
|
err := json.Unmarshal(b, &s)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if s == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
pairs := strings.Split(s, ",")
|
||||||
|
|
||||||
|
for _, p := range pairs {
|
||||||
|
v := strings.Split(strings.TrimSpace(p), "=")
|
||||||
|
|
||||||
|
if len(v) == 1 {
|
||||||
|
r.Type = &v[0]
|
||||||
|
} else if len(v) == 2 {
|
||||||
|
switch v[0] {
|
||||||
|
case "memory":
|
||||||
|
m, err := strconv.Atoi(v[1])
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Memory = &m
|
||||||
|
case "type":
|
||||||
|
r.Type = &v[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -51,6 +51,9 @@ const (
|
|||||||
dvResourceVirtualEnvironmentVMOSType = "other"
|
dvResourceVirtualEnvironmentVMOSType = "other"
|
||||||
dvResourceVirtualEnvironmentVMPoolID = ""
|
dvResourceVirtualEnvironmentVMPoolID = ""
|
||||||
dvResourceVirtualEnvironmentVMStarted = true
|
dvResourceVirtualEnvironmentVMStarted = true
|
||||||
|
dvResourceVirtualEnvironmentVMVGAEnabled = true
|
||||||
|
dvResourceVirtualEnvironmentVMVGAMemory = 0
|
||||||
|
dvResourceVirtualEnvironmentVMVGAType = "std"
|
||||||
dvResourceVirtualEnvironmentVMVMID = -1
|
dvResourceVirtualEnvironmentVMVMID = -1
|
||||||
|
|
||||||
mkResourceVirtualEnvironmentVMAgent = "agent"
|
mkResourceVirtualEnvironmentVMAgent = "agent"
|
||||||
@ -112,6 +115,10 @@ const (
|
|||||||
mkResourceVirtualEnvironmentVMOSType = "os_type"
|
mkResourceVirtualEnvironmentVMOSType = "os_type"
|
||||||
mkResourceVirtualEnvironmentVMPoolID = "pool_id"
|
mkResourceVirtualEnvironmentVMPoolID = "pool_id"
|
||||||
mkResourceVirtualEnvironmentVMStarted = "started"
|
mkResourceVirtualEnvironmentVMStarted = "started"
|
||||||
|
mkResourceVirtualEnvironmentVMVGA = "vga"
|
||||||
|
mkResourceVirtualEnvironmentVMVGAEnabled = "enabled"
|
||||||
|
mkResourceVirtualEnvironmentVMVGAMemory = "memory"
|
||||||
|
mkResourceVirtualEnvironmentVMVGAType = "type"
|
||||||
mkResourceVirtualEnvironmentVMVMID = "vm_id"
|
mkResourceVirtualEnvironmentVMVMID = "vm_id"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -669,6 +676,49 @@ func resourceVirtualEnvironmentVM() *schema.Resource {
|
|||||||
Optional: true,
|
Optional: true,
|
||||||
Default: dvResourceVirtualEnvironmentVMStarted,
|
Default: dvResourceVirtualEnvironmentVMStarted,
|
||||||
},
|
},
|
||||||
|
mkResourceVirtualEnvironmentVMVGA: &schema.Schema{
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Description: "The VGA configuration",
|
||||||
|
Optional: true,
|
||||||
|
DefaultFunc: func() (interface{}, error) {
|
||||||
|
defaultList := make([]interface{}, 1)
|
||||||
|
defaultMap := map[string]interface{}{}
|
||||||
|
|
||||||
|
defaultMap[mkResourceVirtualEnvironmentVMVGAEnabled] = dvResourceVirtualEnvironmentVMVGAEnabled
|
||||||
|
defaultMap[mkResourceVirtualEnvironmentVMVGAMemory] = dvResourceVirtualEnvironmentVMVGAMemory
|
||||||
|
defaultMap[mkResourceVirtualEnvironmentVMVGAType] = dvResourceVirtualEnvironmentVMVGAType
|
||||||
|
|
||||||
|
defaultList[0] = defaultMap
|
||||||
|
|
||||||
|
return defaultList, nil
|
||||||
|
},
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
mkResourceVirtualEnvironmentVMVGAEnabled: {
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Description: "Whether to enable the VGA device",
|
||||||
|
Optional: true,
|
||||||
|
Default: dvResourceVirtualEnvironmentVMVGAEnabled,
|
||||||
|
},
|
||||||
|
mkResourceVirtualEnvironmentVMVGAMemory: {
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Description: "The VGA memory in megabytes (4-512 MB)",
|
||||||
|
Optional: true,
|
||||||
|
Default: dvResourceVirtualEnvironmentVMVGAMemory,
|
||||||
|
ValidateFunc: getVGAMemoryValidator(),
|
||||||
|
},
|
||||||
|
mkResourceVirtualEnvironmentVMVGAType: {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Description: "The VGA type",
|
||||||
|
Optional: true,
|
||||||
|
Default: dvResourceVirtualEnvironmentVMVGAType,
|
||||||
|
ValidateFunc: getVGATypeValidator(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MaxItems: 1,
|
||||||
|
MinItems: 0,
|
||||||
|
},
|
||||||
mkResourceVirtualEnvironmentVMVMID: {
|
mkResourceVirtualEnvironmentVMVMID: {
|
||||||
Type: schema.TypeInt,
|
Type: schema.TypeInt,
|
||||||
Description: "The VM identifier",
|
Description: "The VM identifier",
|
||||||
@ -769,6 +819,13 @@ func resourceVirtualEnvironmentVMCreate(d *schema.ResourceData, m interface{}) e
|
|||||||
osType := d.Get(mkResourceVirtualEnvironmentVMOSType).(string)
|
osType := d.Get(mkResourceVirtualEnvironmentVMOSType).(string)
|
||||||
poolID := d.Get(mkResourceVirtualEnvironmentVMPoolID).(string)
|
poolID := d.Get(mkResourceVirtualEnvironmentVMPoolID).(string)
|
||||||
started := proxmox.CustomBool(d.Get(mkResourceVirtualEnvironmentVMStarted).(bool))
|
started := proxmox.CustomBool(d.Get(mkResourceVirtualEnvironmentVMStarted).(bool))
|
||||||
|
|
||||||
|
vgaDevice, err := resourceVirtualEnvironmentVMGetVGADeviceObject(d, m)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
vmID := d.Get(mkResourceVirtualEnvironmentVMVMID).(int)
|
vmID := d.Get(mkResourceVirtualEnvironmentVMVMID).(int)
|
||||||
|
|
||||||
if vmID == -1 {
|
if vmID == -1 {
|
||||||
@ -840,6 +897,7 @@ func resourceVirtualEnvironmentVMCreate(d *schema.ResourceData, m interface{}) e
|
|||||||
SharedMemory: memorySharedObject,
|
SharedMemory: memorySharedObject,
|
||||||
StartOnBoot: &started,
|
StartOnBoot: &started,
|
||||||
TabletDeviceEnabled: &tabletDeviceEnabled,
|
TabletDeviceEnabled: &tabletDeviceEnabled,
|
||||||
|
VGADevice: vgaDevice,
|
||||||
VMID: &vmID,
|
VMID: &vmID,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1228,6 +1286,38 @@ func resourceVirtualEnvironmentVMGetNetworkDeviceObjects(d *schema.ResourceData,
|
|||||||
return networkDeviceObjects, nil
|
return networkDeviceObjects, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func resourceVirtualEnvironmentVMGetVGADeviceObject(d *schema.ResourceData, m interface{}) (*proxmox.CustomVGADevice, error) {
|
||||||
|
resource := resourceVirtualEnvironmentVM()
|
||||||
|
|
||||||
|
vgaBlock, err := getSchemaBlock(resource, d, m, []string{mkResourceVirtualEnvironmentVMVGA}, 0, true)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
vgaEnabled := proxmox.CustomBool(vgaBlock[mkResourceVirtualEnvironmentVMAgentEnabled].(bool))
|
||||||
|
vgaMemory := vgaBlock[mkResourceVirtualEnvironmentVMVGAMemory].(int)
|
||||||
|
vgaType := vgaBlock[mkResourceVirtualEnvironmentVMVGAType].(string)
|
||||||
|
|
||||||
|
vgaDevice := &proxmox.CustomVGADevice{}
|
||||||
|
|
||||||
|
if vgaEnabled {
|
||||||
|
if vgaMemory > 0 {
|
||||||
|
vgaDevice.Memory = &vgaMemory
|
||||||
|
}
|
||||||
|
|
||||||
|
vgaDevice.Type = &vgaType
|
||||||
|
} else {
|
||||||
|
vgaType = "none"
|
||||||
|
|
||||||
|
vgaDevice = &proxmox.CustomVGADevice{
|
||||||
|
Type: &vgaType,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return vgaDevice, nil
|
||||||
|
}
|
||||||
|
|
||||||
func resourceVirtualEnvironmentVMRead(d *schema.ResourceData, m interface{}) error {
|
func resourceVirtualEnvironmentVMRead(d *schema.ResourceData, m interface{}) error {
|
||||||
config := m.(providerConfiguration)
|
config := m.(providerConfiguration)
|
||||||
veClient, err := config.GetVEClient()
|
veClient, err := config.GetVEClient()
|
||||||
@ -1715,6 +1805,48 @@ func resourceVirtualEnvironmentVMRead(d *schema.ResourceData, m interface{}) err
|
|||||||
d.Set(mkResourceVirtualEnvironmentVMPoolID, *vmConfig.PoolID)
|
d.Set(mkResourceVirtualEnvironmentVMPoolID, *vmConfig.PoolID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Compare the VGA configuration to the one stored in the state.
|
||||||
|
vga := map[string]interface{}{}
|
||||||
|
|
||||||
|
if vmConfig.VGADevice != nil {
|
||||||
|
vgaEnabled := true
|
||||||
|
|
||||||
|
if vmConfig.VGADevice.Type != nil {
|
||||||
|
vgaEnabled = *vmConfig.VGADevice.Type != "none"
|
||||||
|
}
|
||||||
|
|
||||||
|
vga[mkResourceVirtualEnvironmentVMVGAEnabled] = vgaEnabled
|
||||||
|
|
||||||
|
if vmConfig.VGADevice.Memory != nil {
|
||||||
|
vga[mkResourceVirtualEnvironmentVMVGAMemory] = *vmConfig.VGADevice.Memory
|
||||||
|
} else {
|
||||||
|
vga[mkResourceVirtualEnvironmentVMVGAMemory] = dvResourceVirtualEnvironmentVMVGAMemory
|
||||||
|
}
|
||||||
|
|
||||||
|
if vgaEnabled {
|
||||||
|
if vmConfig.VGADevice.Type != nil {
|
||||||
|
vga[mkResourceVirtualEnvironmentVMVGAType] = *vmConfig.VGADevice.Type
|
||||||
|
} else {
|
||||||
|
vga[mkResourceVirtualEnvironmentVMVGAType] = dvResourceVirtualEnvironmentVMVGAType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
vga[mkResourceVirtualEnvironmentVMVGAEnabled] = true
|
||||||
|
vga[mkResourceVirtualEnvironmentVMVGAMemory] = dvResourceVirtualEnvironmentVMVGAMemory
|
||||||
|
vga[mkResourceVirtualEnvironmentVMVGAType] = dvResourceVirtualEnvironmentVMVGAType
|
||||||
|
}
|
||||||
|
|
||||||
|
currentVGA := d.Get(mkResourceVirtualEnvironmentVMVGA).([]interface{})
|
||||||
|
|
||||||
|
if len(currentVGA) > 0 ||
|
||||||
|
vga[mkResourceVirtualEnvironmentVMVGAEnabled] != dvResourceVirtualEnvironmentVMVGAEnabled ||
|
||||||
|
vga[mkResourceVirtualEnvironmentVMVGAMemory] != dvResourceVirtualEnvironmentVMVGAMemory ||
|
||||||
|
vga[mkResourceVirtualEnvironmentVMVGAType] != dvResourceVirtualEnvironmentVMVGAType {
|
||||||
|
d.Set(mkResourceVirtualEnvironmentVMVGA, []interface{}{vga})
|
||||||
|
} else {
|
||||||
|
d.Set(mkResourceVirtualEnvironmentVMVGA, make([]interface{}, 0))
|
||||||
|
}
|
||||||
|
|
||||||
// Determine the state of the virtual machine in order to update the "started" argument.
|
// Determine the state of the virtual machine in order to update the "started" argument.
|
||||||
status, err := veClient.GetVMStatus(nodeName, vmID)
|
status, err := veClient.GetVMStatus(nodeName, vmID)
|
||||||
|
|
||||||
@ -2006,6 +2138,17 @@ func resourceVirtualEnvironmentVMUpdate(d *schema.ResourceData, m interface{}) e
|
|||||||
rebootRequired = true
|
rebootRequired = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Prepare the new VGA configuration.
|
||||||
|
if d.HasChange(mkResourceVirtualEnvironmentVMVGA) {
|
||||||
|
body.VGADevice, err = resourceVirtualEnvironmentVMGetVGADeviceObject(d, m)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
rebootRequired = true
|
||||||
|
}
|
||||||
|
|
||||||
// Update the configuration now that everything has been prepared.
|
// Update the configuration now that everything has been prepared.
|
||||||
err = veClient.UpdateVM(nodeName, vmID, body)
|
err = veClient.UpdateVM(nodeName, vmID, body)
|
||||||
|
|
||||||
|
@ -327,4 +327,22 @@ func TestResourceVirtualEnvironmentVMSchema(t *testing.T) {
|
|||||||
schema.TypeFloat,
|
schema.TypeFloat,
|
||||||
schema.TypeInt,
|
schema.TypeInt,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
vgaSchema := testNestedSchemaExistence(t, s, mkResourceVirtualEnvironmentVMVGA)
|
||||||
|
|
||||||
|
testOptionalArguments(t, vgaSchema, []string{
|
||||||
|
mkResourceVirtualEnvironmentVMVGAEnabled,
|
||||||
|
mkResourceVirtualEnvironmentVMVGAMemory,
|
||||||
|
mkResourceVirtualEnvironmentVMVGAType,
|
||||||
|
})
|
||||||
|
|
||||||
|
testSchemaValueTypes(t, vgaSchema, []string{
|
||||||
|
mkResourceVirtualEnvironmentVMVGAEnabled,
|
||||||
|
mkResourceVirtualEnvironmentVMVGAMemory,
|
||||||
|
mkResourceVirtualEnvironmentVMVGAType,
|
||||||
|
}, []schema.ValueType{
|
||||||
|
schema.TypeBool,
|
||||||
|
schema.TypeInt,
|
||||||
|
schema.TypeString,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
@ -175,6 +175,41 @@ func getSchemaBlock(r *schema.Resource, d *schema.ResourceData, m interface{}, k
|
|||||||
return resourceBlock, nil
|
return resourceBlock, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getVGAMemoryValidator() schema.SchemaValidateFunc {
|
||||||
|
return func(i interface{}, k string) ([]string, []error) {
|
||||||
|
v, ok := i.(int)
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
return []string{}, []error{fmt.Errorf("expected type of %s to be []interface{}", k)}
|
||||||
|
}
|
||||||
|
|
||||||
|
if v == 0 {
|
||||||
|
return []string{}, []error{}
|
||||||
|
}
|
||||||
|
|
||||||
|
validator := validation.IntBetween(4, 512)
|
||||||
|
|
||||||
|
return validator(i, k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getVGATypeValidator() schema.SchemaValidateFunc {
|
||||||
|
return validation.StringInSlice([]string{
|
||||||
|
"cirrus",
|
||||||
|
"qxl",
|
||||||
|
"qxl2",
|
||||||
|
"qxl3",
|
||||||
|
"qxl4",
|
||||||
|
"serial0",
|
||||||
|
"serial1",
|
||||||
|
"serial2",
|
||||||
|
"serial3",
|
||||||
|
"std",
|
||||||
|
"virtio",
|
||||||
|
"vmware",
|
||||||
|
}, false)
|
||||||
|
}
|
||||||
|
|
||||||
func getVLANIDsValidator() schema.SchemaValidateFunc {
|
func getVLANIDsValidator() schema.SchemaValidateFunc {
|
||||||
return func(i interface{}, k string) (ws []string, es []error) {
|
return func(i interface{}, k string) (ws []string, es []error) {
|
||||||
min := 1
|
min := 1
|
||||||
|
Loading…
Reference in New Issue
Block a user