Skip to content

Commit

Permalink
feat(vm): add support for start/shutdown order configuration (#445)
Browse files Browse the repository at this point in the history
  • Loading branch information
bpg authored Jul 30, 2023
1 parent cfe3d96 commit b045746
Show file tree
Hide file tree
Showing 3 changed files with 149 additions and 3 deletions.
13 changes: 13 additions & 0 deletions docs/resources/virtual_environment_vm.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ resource "proxmox_virtual_environment_vm" "ubuntu_vm" {
enabled = true
}
startup {
order = "3"
up_delay = "60"
down_delay = "60"
}
disk {
datastore_id = "local-lvm"
file_id = proxmox_virtual_environment_file.ubuntu_cloud_image.id
Expand Down Expand Up @@ -410,6 +416,13 @@ output "ubuntu_vm_public_key" {
- `pvscsi` - VMware Paravirtual SCSI.
- `started` - (Optional) Whether to start the virtual machine (defaults
to `true`).
- `startup` - (Optional) Defines startup and shutdown behavior of the VM.
- `order` - (Required) A non-negative number defining the general startup
order.
- `up` - (Optional) A non-negative number defining the delay in seconds
before the next VM is started.
- `down` - (Optional) A non-negative number defining the delay in seconds
before the next VM is shut down.
- `tablet_device` - (Optional) Whether to enable the USB tablet device (defaults
to `true`).
- `tags` - (Optional) A list of tags of the VM. This is only meta information (
Expand Down
12 changes: 9 additions & 3 deletions example/resource_virtual_environment_vm.tf
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,16 @@ resource "proxmox_virtual_environment_vm" "example_template" {
numa = true
}

startup {
order = "3"
up_delay = "60"
down_delay = "60"
}

efi_disk {
datastore_id = local.datastore_id
file_format = "raw"
type = "4m"
datastore_id = local.datastore_id
file_format = "raw"
type = "4m"
}

# disk {
Expand Down
127 changes: 127 additions & 0 deletions proxmoxtf/resource/vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,9 @@ const (
dvResourceVirtualEnvironmentVMPoolID = ""
dvResourceVirtualEnvironmentVMSerialDeviceDevice = "socket"
dvResourceVirtualEnvironmentVMStarted = true
dvResourceVirtualEnvironmentVMStartupOrder = -1
dvResourceVirtualEnvironmentVMStartupUpDelay = -1
dvResourceVirtualEnvironmentVMStartupDownDelay = -1
dvResourceVirtualEnvironmentVMTabletDevice = true
dvResourceVirtualEnvironmentVMTemplate = false
dvResourceVirtualEnvironmentVMTimeoutClone = 1800
Expand Down Expand Up @@ -232,6 +235,10 @@ const (
mkResourceVirtualEnvironmentVMSerialDevice = "serial_device"
mkResourceVirtualEnvironmentVMSerialDeviceDevice = "device"
mkResourceVirtualEnvironmentVMStarted = "started"
mkResourceVirtualEnvironmentVMStartup = "startup"
mkResourceVirtualEnvironmentVMStartupOrder = "order"
mkResourceVirtualEnvironmentVMStartupUpDelay = "up_delay"
mkResourceVirtualEnvironmentVMStartupDownDelay = "down_delay"
mkResourceVirtualEnvironmentVMTabletDevice = "tablet_device"
mkResourceVirtualEnvironmentVMTags = "tags"
mkResourceVirtualEnvironmentVMTemplate = "template"
Expand Down Expand Up @@ -1214,6 +1221,47 @@ func VM() *schema.Resource {
return d.Get(mkResourceVirtualEnvironmentVMTemplate).(bool)
},
},
mkResourceVirtualEnvironmentVMStartup: {
Type: schema.TypeList,
Description: "Defines startup and shutdown behavior of the VM",
Optional: true,
DefaultFunc: func() (interface{}, error) {
return []interface{}{
map[string]interface{}{
mkResourceVirtualEnvironmentVMStartupOrder: dvResourceVirtualEnvironmentVMStartupOrder,
mkResourceVirtualEnvironmentVMVGAMemory: dvResourceVirtualEnvironmentVMVGAMemory,
mkResourceVirtualEnvironmentVMVGAType: dvResourceVirtualEnvironmentVMVGAType,
},
}, nil
},
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
mkResourceVirtualEnvironmentVMStartupOrder: {
Type: schema.TypeInt,
Description: "A non-negative number defining the general startup order",
Optional: true,
Default: dvResourceVirtualEnvironmentVMStartupOrder,
},
mkResourceVirtualEnvironmentVMStartupUpDelay: {
Type: schema.TypeInt,
Description: "A non-negative number defining the delay in seconds before the next VM is started",
Optional: true,
Default: dvResourceVirtualEnvironmentVMStartupUpDelay,
ValidateDiagFunc: validation.ToDiagFunc(validation.IntAtLeast(0)),
},
mkResourceVirtualEnvironmentVMStartupDownDelay: {
Type: schema.TypeInt,
Description: "A non-negative number defining the delay in seconds before the next VM is shut down",
Optional: true,
Default: dvResourceVirtualEnvironmentVMStartupDownDelay,
ValidateDiagFunc: validation.ToDiagFunc(validation.IntAtLeast(0)),
},
},
},
MaxItems: 1,
MinItems: 0,
},

mkResourceVirtualEnvironmentVMTabletDevice: {
Type: schema.TypeBool,
Description: "Whether to enable the USB tablet device",
Expand Down Expand Up @@ -1778,6 +1826,8 @@ func vmCreateClone(ctx context.Context, d *schema.ResourceData, m interface{}) d

updateBody.StartOnBoot = &onBoot

updateBody.StartupOrder = vmGetStartupOrder(d)

//nolint:gosimple
if tabletDevice != dvResourceVirtualEnvironmentVMTabletDevice {
updateBody.TabletDeviceEnabled = &tabletDevice
Expand Down Expand Up @@ -2148,6 +2198,8 @@ func vmCreateCustom(ctx context.Context, d *schema.ResourceData, m interface{})

serialDevices := vmGetSerialDeviceList(d)

startupOrder := vmGetStartupOrder(d)

onBoot := types.CustomBool(d.Get(mkResourceVirtualEnvironmentVMOnBoot).(bool))
tabletDevice := types.CustomBool(d.Get(mkResourceVirtualEnvironmentVMTabletDevice).(bool))
template := types.CustomBool(d.Get(mkResourceVirtualEnvironmentVMTemplate).(bool))
Expand Down Expand Up @@ -2268,6 +2320,7 @@ func vmCreateCustom(ctx context.Context, d *schema.ResourceData, m interface{})
SerialDevices: serialDevices,
SharedMemory: memorySharedObject,
StartOnBoot: &onBoot,
StartupOrder: startupOrder,
TabletDeviceEnabled: &tabletDevice,
Template: &template,
VGADevice: vgaDevice,
Expand Down Expand Up @@ -3009,6 +3062,33 @@ func vmGetSerialDeviceList(d *schema.ResourceData) vms.CustomSerialDevices {
return list
}

func vmGetStartupOrder(d *schema.ResourceData) *vms.CustomStartupOrder {
startup := d.Get(mkResourceVirtualEnvironmentVMStartup).([]interface{})
if len(startup) > 0 {
startupBlock := startup[0].(map[string]interface{})
startupOrder := startupBlock[mkResourceVirtualEnvironmentVMStartupOrder].(int)
startupUpDelay := startupBlock[mkResourceVirtualEnvironmentVMStartupUpDelay].(int)
startupDownDelay := startupBlock[mkResourceVirtualEnvironmentVMStartupDownDelay].(int)

order := vms.CustomStartupOrder{}

if startupUpDelay >= 0 {
order.Up = &startupUpDelay
}

if startupDownDelay >= 0 {
order.Down = &startupDownDelay
}

if startupOrder >= 0 {
order.Order = &startupOrder
return &order
}
}

return nil
}

func vmGetTagsString(d *schema.ResourceData) string {
tags := d.Get(mkResourceVirtualEnvironmentVMTags).([]interface{})
var sanitizedTags []string
Expand Down Expand Up @@ -4064,6 +4144,53 @@ func vmReadCustom(
diags = append(diags, diag.FromErr(err)...)
}

// Compare the startup order to the one stored in the state.
startup := map[string]interface{}{}

//nolint:nestif
if vmConfig.StartupOrder != nil {
if vmConfig.StartupOrder.Order != nil {
startup[mkResourceVirtualEnvironmentVMStartupOrder] = *vmConfig.StartupOrder.Order
} else {
startup[mkResourceVirtualEnvironmentVMStartupOrder] = dvResourceVirtualEnvironmentVMStartupOrder
}

if vmConfig.StartupOrder.Up != nil {
startup[mkResourceVirtualEnvironmentVMStartupUpDelay] = *vmConfig.StartupOrder.Up
} else {
startup[mkResourceVirtualEnvironmentVMStartupUpDelay] = dvResourceVirtualEnvironmentVMStartupUpDelay
}

if vmConfig.StartupOrder.Down != nil {
startup[mkResourceVirtualEnvironmentVMStartupDownDelay] = *vmConfig.StartupOrder.Down
} else {
startup[mkResourceVirtualEnvironmentVMStartupDownDelay] = dvResourceVirtualEnvironmentVMStartupDownDelay
}
} else {
startup[mkResourceVirtualEnvironmentVMStartupOrder] = dvResourceVirtualEnvironmentVMStartupOrder
startup[mkResourceVirtualEnvironmentVMStartupUpDelay] = dvResourceVirtualEnvironmentVMStartupUpDelay
startup[mkResourceVirtualEnvironmentVMStartupDownDelay] = dvResourceVirtualEnvironmentVMStartupDownDelay
}

currentStartup := d.Get(mkResourceVirtualEnvironmentVMStartup).([]interface{})

//nolint:gocritic
if len(clone) > 0 {
if len(currentStartup) > 0 {
err := d.Set(mkResourceVirtualEnvironmentVMStartup, []interface{}{startup})
diags = append(diags, diag.FromErr(err)...)
}
} else if len(currentStartup) > 0 ||
startup[mkResourceVirtualEnvironmentVMStartupOrder] != mkResourceVirtualEnvironmentVMStartupOrder ||
startup[mkResourceVirtualEnvironmentVMStartupUpDelay] != dvResourceVirtualEnvironmentVMStartupUpDelay ||
startup[mkResourceVirtualEnvironmentVMStartupDownDelay] != dvResourceVirtualEnvironmentVMStartupDownDelay {
err := d.Set(mkResourceVirtualEnvironmentVMStartup, []interface{}{startup})
diags = append(diags, diag.FromErr(err)...)
} else {
err := d.Set(mkResourceVirtualEnvironmentVMStartup, []interface{}{})
diags = append(diags, diag.FromErr(err)...)
}

// Compare the VGA configuration to the one stored in the state.
vga := map[string]interface{}{}

Expand Down

0 comments on commit b045746

Please sign in to comment.