mirror of
https://github.com/bpg/terraform-provider-proxmox.git
synced 2025-07-10 07:45:02 +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
|
||||
|
||||
FEATURES:
|
||||
|
16
README.md
16
README.md
@ -433,6 +433,22 @@ This resource doesn't expose any additional attributes.
|
||||
* `wxp` - Windows XP
|
||||
* `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`)
|
||||
* `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
|
||||
|
||||
###### Attributes
|
||||
|
@ -165,8 +165,8 @@ type CustomUSBDevices []CustomUSBDevice
|
||||
|
||||
// CustomVGADevice handles QEMU VGA device parameters.
|
||||
type CustomVGADevice struct {
|
||||
Memory *int `json:"memory,omitempty" url:"memory,omitempty"`
|
||||
Type string `json:"type" url:"type"`
|
||||
Memory *int `json:"memory,omitempty" url:"memory,omitempty"`
|
||||
Type *string `json:"type,omitempty" url:"type,omitempty"`
|
||||
}
|
||||
|
||||
// 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.
|
||||
func (r CustomVGADevice) EncodeValues(key string, v *url.Values) error {
|
||||
values := []string{
|
||||
fmt.Sprintf("type=%s", r.Type),
|
||||
}
|
||||
values := []string{}
|
||||
|
||||
if r.Memory != nil {
|
||||
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, ","))
|
||||
|
||||
return nil
|
||||
@ -1355,3 +1357,43 @@ func (r *CustomStorageDevice) UnmarshalJSON(b []byte) error {
|
||||
|
||||
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"
|
||||
dvResourceVirtualEnvironmentVMPoolID = ""
|
||||
dvResourceVirtualEnvironmentVMStarted = true
|
||||
dvResourceVirtualEnvironmentVMVGAEnabled = true
|
||||
dvResourceVirtualEnvironmentVMVGAMemory = 0
|
||||
dvResourceVirtualEnvironmentVMVGAType = "std"
|
||||
dvResourceVirtualEnvironmentVMVMID = -1
|
||||
|
||||
mkResourceVirtualEnvironmentVMAgent = "agent"
|
||||
@ -112,6 +115,10 @@ const (
|
||||
mkResourceVirtualEnvironmentVMOSType = "os_type"
|
||||
mkResourceVirtualEnvironmentVMPoolID = "pool_id"
|
||||
mkResourceVirtualEnvironmentVMStarted = "started"
|
||||
mkResourceVirtualEnvironmentVMVGA = "vga"
|
||||
mkResourceVirtualEnvironmentVMVGAEnabled = "enabled"
|
||||
mkResourceVirtualEnvironmentVMVGAMemory = "memory"
|
||||
mkResourceVirtualEnvironmentVMVGAType = "type"
|
||||
mkResourceVirtualEnvironmentVMVMID = "vm_id"
|
||||
)
|
||||
|
||||
@ -669,6 +676,49 @@ func resourceVirtualEnvironmentVM() *schema.Resource {
|
||||
Optional: true,
|
||||
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: {
|
||||
Type: schema.TypeInt,
|
||||
Description: "The VM identifier",
|
||||
@ -769,6 +819,13 @@ func resourceVirtualEnvironmentVMCreate(d *schema.ResourceData, m interface{}) e
|
||||
osType := d.Get(mkResourceVirtualEnvironmentVMOSType).(string)
|
||||
poolID := d.Get(mkResourceVirtualEnvironmentVMPoolID).(string)
|
||||
started := proxmox.CustomBool(d.Get(mkResourceVirtualEnvironmentVMStarted).(bool))
|
||||
|
||||
vgaDevice, err := resourceVirtualEnvironmentVMGetVGADeviceObject(d, m)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
vmID := d.Get(mkResourceVirtualEnvironmentVMVMID).(int)
|
||||
|
||||
if vmID == -1 {
|
||||
@ -840,6 +897,7 @@ func resourceVirtualEnvironmentVMCreate(d *schema.ResourceData, m interface{}) e
|
||||
SharedMemory: memorySharedObject,
|
||||
StartOnBoot: &started,
|
||||
TabletDeviceEnabled: &tabletDeviceEnabled,
|
||||
VGADevice: vgaDevice,
|
||||
VMID: &vmID,
|
||||
}
|
||||
|
||||
@ -1228,6 +1286,38 @@ func resourceVirtualEnvironmentVMGetNetworkDeviceObjects(d *schema.ResourceData,
|
||||
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 {
|
||||
config := m.(providerConfiguration)
|
||||
veClient, err := config.GetVEClient()
|
||||
@ -1715,6 +1805,48 @@ func resourceVirtualEnvironmentVMRead(d *schema.ResourceData, m interface{}) err
|
||||
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.
|
||||
status, err := veClient.GetVMStatus(nodeName, vmID)
|
||||
|
||||
@ -2006,6 +2138,17 @@ func resourceVirtualEnvironmentVMUpdate(d *schema.ResourceData, m interface{}) e
|
||||
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.
|
||||
err = veClient.UpdateVM(nodeName, vmID, body)
|
||||
|
||||
|
@ -327,4 +327,22 @@ func TestResourceVirtualEnvironmentVMSchema(t *testing.T) {
|
||||
schema.TypeFloat,
|
||||
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
|
||||
}
|
||||
|
||||
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 {
|
||||
return func(i interface{}, k string) (ws []string, es []error) {
|
||||
min := 1
|
||||
|
Loading…
Reference in New Issue
Block a user