diff --git a/CHANGELOG.md b/CHANGELOG.md index b994d972..cf9b7e11 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## 0.3.0 (UNRELEASED) + +ENHANCEMENTS: + +* resource/virtual_environment_vm: Add `serial_device` argument + ## 0.2.0 BREAKING CHANGES: diff --git a/README.md b/README.md index 044acb99..0ee76dea 100644 --- a/README.md +++ b/README.md @@ -621,6 +621,10 @@ This resource doesn't expose any additional attributes. * `wvista` - Windows Vista * `wxp` - Windows XP * `pool_id` - (Optional) The ID of a pool to assign the virtual machine to +* `serial_device` - (Optional) A serial device (multiple blocks supported) + * `device` - (Optional) The device (defaults to `socket`) + * `/dev/*` - A host serial device + * `socket` - A unix socket * `started` - (Optional) Whether to start the virtual machine (defaults to `true`) * `tablet_device` - (Optional) Whether to enable the USB tablet device (defaults to `true`) * `vga` - (Optional) The VGA configuration diff --git a/example/resource_virtual_environment_vm.tf b/example/resource_virtual_environment_vm.tf index ab5fd8b8..53c6694d 100644 --- a/example/resource_virtual_environment_vm.tf +++ b/example/resource_virtual_environment_vm.tf @@ -41,7 +41,10 @@ resource "proxmox_virtual_environment_vm" "example" { } pool_id = "${proxmox_virtual_environment_pool.example.id}" - vm_id = 2038 + + serial_device {} + + vm_id = 2038 connection { type = "ssh" diff --git a/proxmoxtf/resource_virtual_environment_vm.go b/proxmoxtf/resource_virtual_environment_vm.go index 439a92a6..a40b7248 100644 --- a/proxmoxtf/resource_virtual_environment_vm.go +++ b/proxmoxtf/resource_virtual_environment_vm.go @@ -59,6 +59,7 @@ const ( dvResourceVirtualEnvironmentVMNetworkDeviceVLANID = 0 dvResourceVirtualEnvironmentVMOperatingSystemType = "other" dvResourceVirtualEnvironmentVMPoolID = "" + dvResourceVirtualEnvironmentVMSerialDeviceDevice = "socket" dvResourceVirtualEnvironmentVMStarted = true dvResourceVirtualEnvironmentVMTabletDevice = true dvResourceVirtualEnvironmentVMVGAEnabled = true @@ -131,6 +132,8 @@ const ( mkResourceVirtualEnvironmentVMOperatingSystem = "operating_system" mkResourceVirtualEnvironmentVMOperatingSystemType = "type" mkResourceVirtualEnvironmentVMPoolID = "pool_id" + mkResourceVirtualEnvironmentVMSerialDevice = "serial_device" + mkResourceVirtualEnvironmentVMSerialDeviceDevice = "device" mkResourceVirtualEnvironmentVMStarted = "started" mkResourceVirtualEnvironmentVMTabletDevice = "tablet_device" mkResourceVirtualEnvironmentVMVGA = "vga" @@ -757,6 +760,31 @@ func resourceVirtualEnvironmentVM() *schema.Resource { ForceNew: true, Default: dvResourceVirtualEnvironmentVMPoolID, }, + mkResourceVirtualEnvironmentVMSerialDevice: &schema.Schema{ + Type: schema.TypeList, + Description: "The serial devices", + Optional: true, + DefaultFunc: func() (interface{}, error) { + return []interface{}{ + map[string]interface{}{ + mkResourceVirtualEnvironmentVMSerialDeviceDevice: dvResourceVirtualEnvironmentVMSerialDeviceDevice, + }, + }, nil + }, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + mkResourceVirtualEnvironmentVMSerialDeviceDevice: { + Type: schema.TypeString, + Description: "The device", + Optional: true, + Default: dvResourceVirtualEnvironmentVMSerialDeviceDevice, + ValidateFunc: resourceVirtualEnvironmentVMGetSerialDeviceValidator(), + }, + }, + }, + MaxItems: 4, + MinItems: 0, + }, mkResourceVirtualEnvironmentVMStarted: { Type: schema.TypeBool, Description: "Whether to start the virtual machine", @@ -927,6 +955,13 @@ func resourceVirtualEnvironmentVMCreate(d *schema.ResourceData, m interface{}) e operatingSystemType := operatingSystem[mkResourceVirtualEnvironmentVMOperatingSystemType].(string) poolID := d.Get(mkResourceVirtualEnvironmentVMPoolID).(string) + + serialDevices, err := resourceVirtualEnvironmentVMGetSerialDeviceList(d, m) + + if err != nil { + return err + } + started := proxmox.CustomBool(d.Get(mkResourceVirtualEnvironmentVMStarted).(bool)) tabletDevice := proxmox.CustomBool(d.Get(mkResourceVirtualEnvironmentVMTabletDevice).(bool)) @@ -1016,7 +1051,7 @@ func resourceVirtualEnvironmentVMCreate(d *schema.ResourceData, m interface{}) e PoolID: &poolID, SCSIDevices: diskDeviceObjects, SCSIHardware: &scsiHardware, - SerialDevices: []string{"socket"}, + SerialDevices: serialDevices, SharedMemory: memorySharedObject, StartOnBoot: &started, TabletDeviceEnabled: &tabletDevice, @@ -1433,6 +1468,39 @@ func resourceVirtualEnvironmentVMGetOperatingSystemTypeValidator() schema.Schema }, false) } +func resourceVirtualEnvironmentVMGetSerialDeviceList(d *schema.ResourceData, m interface{}) (proxmox.CustomSerialDevices, error) { + device := d.Get(mkResourceVirtualEnvironmentVMSerialDevice).([]interface{}) + list := make(proxmox.CustomSerialDevices, len(device)) + + for i, v := range device { + block := v.(map[string]interface{}) + + device, _ := block[mkResourceVirtualEnvironmentVMSerialDeviceDevice].(string) + + list[i] = device + } + + return list, nil +} + +func resourceVirtualEnvironmentVMGetSerialDeviceValidator() schema.SchemaValidateFunc { + return func(i interface{}, k string) (s []string, es []error) { + v, ok := i.(string) + + if !ok { + es = append(es, fmt.Errorf("expected type of %s to be string", k)) + return + } + + if !strings.HasPrefix(v, "/dev/") && v != "socket" { + es = append(es, fmt.Errorf("expected %s to be '/dev/*' or 'socket'", k)) + return + } + + return + } +} + func resourceVirtualEnvironmentVMGetVGADeviceObject(d *schema.ResourceData, m interface{}) (*proxmox.CustomVGADevice, error) { resource := resourceVirtualEnvironmentVM() @@ -2027,6 +2095,31 @@ func resourceVirtualEnvironmentVMRead(d *schema.ResourceData, m interface{}) err d.Set(mkResourceVirtualEnvironmentVMPoolID, *vmConfig.PoolID) } + // Compare the serial devices to those stored in the state. + serialDevices := make([]interface{}, 4) + serialDevicesArray := []*string{ + vmConfig.SerialDevice0, + vmConfig.SerialDevice1, + vmConfig.SerialDevice2, + vmConfig.SerialDevice3, + } + serialDevicesCount := 0 + + for sdi, sd := range serialDevicesArray { + m := map[string]interface{}{} + + if sd != nil { + m[mkResourceVirtualEnvironmentVMSerialDeviceDevice] = *sd + serialDevicesCount = sdi + 1 + } else { + m[mkResourceVirtualEnvironmentVMSerialDeviceDevice] = "" + } + + serialDevices[sdi] = m + } + + d.Set(mkResourceVirtualEnvironmentVMSerialDevice, serialDevices[:serialDevicesCount]) + // Compare the VGA configuration to the one stored in the state. vga := map[string]interface{}{} @@ -2403,6 +2496,17 @@ func resourceVirtualEnvironmentVMUpdate(d *schema.ResourceData, m interface{}) e rebootRequired = true } + // Prepare the new serial devices. + if d.HasChange(mkResourceVirtualEnvironmentVMSerialDevice) { + body.SerialDevices, err = resourceVirtualEnvironmentVMGetSerialDeviceList(d, m) + + if err != nil { + return err + } + + rebootRequired = true + } + // Prepare the new VGA configuration. if d.HasChange(mkResourceVirtualEnvironmentVMVGA) { body.VGADevice, err = resourceVirtualEnvironmentVMGetVGADeviceObject(d, m) diff --git a/proxmoxtf/resource_virtual_environment_vm_test.go b/proxmoxtf/resource_virtual_environment_vm_test.go index 46228676..c4510fc4 100644 --- a/proxmoxtf/resource_virtual_environment_vm_test.go +++ b/proxmoxtf/resource_virtual_environment_vm_test.go @@ -41,6 +41,7 @@ func TestResourceVirtualEnvironmentVMSchema(t *testing.T) { mkResourceVirtualEnvironmentVMNetworkDevice, mkResourceVirtualEnvironmentVMOperatingSystem, mkResourceVirtualEnvironmentVMPoolID, + mkResourceVirtualEnvironmentVMSerialDevice, mkResourceVirtualEnvironmentVMStarted, mkResourceVirtualEnvironmentVMTabletDevice, mkResourceVirtualEnvironmentVMVMID, @@ -72,6 +73,7 @@ func TestResourceVirtualEnvironmentVMSchema(t *testing.T) { mkResourceVirtualEnvironmentVMNetworkInterfaceNames, mkResourceVirtualEnvironmentVMOperatingSystem, mkResourceVirtualEnvironmentVMPoolID, + mkResourceVirtualEnvironmentVMSerialDevice, mkResourceVirtualEnvironmentVMStarted, mkResourceVirtualEnvironmentVMTabletDevice, mkResourceVirtualEnvironmentVMVMID, @@ -94,6 +96,7 @@ func TestResourceVirtualEnvironmentVMSchema(t *testing.T) { schema.TypeList, schema.TypeList, schema.TypeString, + schema.TypeList, schema.TypeBool, schema.TypeBool, schema.TypeInt, @@ -357,6 +360,18 @@ func TestResourceVirtualEnvironmentVMSchema(t *testing.T) { schema.TypeString, }) + serialDeviceSchema := testNestedSchemaExistence(t, s, mkResourceVirtualEnvironmentVMSerialDevice) + + testOptionalArguments(t, serialDeviceSchema, []string{ + mkResourceVirtualEnvironmentVMSerialDeviceDevice, + }) + + testSchemaValueTypes(t, serialDeviceSchema, []string{ + mkResourceVirtualEnvironmentVMSerialDeviceDevice, + }, []schema.ValueType{ + schema.TypeString, + }) + vgaSchema := testNestedSchemaExistence(t, s, mkResourceVirtualEnvironmentVMVGA) testOptionalArguments(t, vgaSchema, []string{ diff --git a/proxmoxtf/version.go b/proxmoxtf/version.go index b8637b39..06da7cd3 100644 --- a/proxmoxtf/version.go +++ b/proxmoxtf/version.go @@ -9,5 +9,5 @@ const ( TerraformProviderName = "terraform-provider-proxmox" // TerraformProviderVersion specifies the version number. - TerraformProviderVersion = "0.2.0" + TerraformProviderVersion = "0.3.0" )