Skip to content

Commit

Permalink
feat(vm): support for migration when the node name is modified (#501)
Browse files Browse the repository at this point in the history
* feat(vm): support for migration when the node name is modified

  * Added a `migrate` VM flag which changes the provider's behaviour
    when the VM's `node_name` is updated. If `true`, the VM will be
    migrated to the specified node instead of being re-created.

  * Added a `timeout_migrate` setting to control the timeout for VM
    migration.

  * Fixed a bug in the API's migration data structure that prevented
    the online migration flag to be set.

* fix: update description

---------

Co-authored-by: Pavel Boldyrev <627562+bpg@users.noreply.github.com>
  • Loading branch information
tseeker and bpg authored Aug 19, 2023
1 parent e6c15ec commit a285360
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 2 deletions.
4 changes: 4 additions & 0 deletions docs/resources/virtual_environment_vm.md
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,8 @@ output "ubuntu_vm_public_key" {
- `floating` - (Optional) The floating memory in megabytes (defaults
to `0`).
- `shared` - (Optional) The shared memory in megabytes (defaults to `0`).
- `migrate` - (Optional) Migrate the VM on node change instead of re-creating
it (defaults to `false`).
- `name` - (Optional) The virtual machine name.
- `network_device` - (Optional) A network device (multiple blocks supported).
- `bridge` - (Optional) The name of the network bridge (defaults
Expand Down Expand Up @@ -446,6 +448,8 @@ output "ubuntu_vm_public_key" {
1800).
- `timeout_move_disk` - (Optional) Timeout for moving the disk of a VM in
seconds (defaults to 1800).
- `timeout_migrate` - (Optional) Timeout for migrating the VM (defaults to
1800).
- `timeout_reboot` - (Optional) Timeout for rebooting a VM in seconds (defaults
to 1800).
- `timeout_shutdown_vm` - (Optional) Timeout for shutting down a VM in seconds (
Expand Down
1 change: 1 addition & 0 deletions example/resource_virtual_environment_vm.tf
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ resource "proxmox_virtual_environment_vm" "example_template" {
resource "proxmox_virtual_environment_vm" "example" {
name = "terraform-provider-proxmox-example"
node_name = data.proxmox_virtual_environment_nodes.example.names[0]
migrate = true // migrate the VM on node change
pool_id = proxmox_virtual_environment_pool.example.id
vm_id = 2041
tags = ["terraform", "ubuntu"]
Expand Down
2 changes: 1 addition & 1 deletion proxmox/nodes/vms/vms_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -526,7 +526,7 @@ type ListResponseData struct {

// MigrateRequestBody contains the body for a VM migration request.
type MigrateRequestBody struct {
OnlineMigration *types.CustomBool `json:"online,omitempty" url:"online,omitempty"`
OnlineMigration *types.CustomBool `json:"online,omitempty" url:"online,omitempty,int"`
TargetNode string `json:"target" url:"target"`
TargetStorage *string `json:"targetstorage,omitempty" url:"targetstorage,omitempty"`
WithLocalDisks *types.CustomBool `json:"with-local-disks,omitempty" url:"with-local-disks,omitempty,int"`
Expand Down
43 changes: 42 additions & 1 deletion proxmoxtf/resource/vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ const (
dvResourceVirtualEnvironmentVMMemoryDedicated = 512
dvResourceVirtualEnvironmentVMMemoryFloating = 0
dvResourceVirtualEnvironmentVMMemoryShared = 0
dvResourceVirtualEnvironmentVMMigrate = false
dvResourceVirtualEnvironmentVMName = ""
dvResourceVirtualEnvironmentVMNetworkDeviceBridge = "vmbr0"
dvResourceVirtualEnvironmentVMNetworkDeviceEnabled = true
Expand All @@ -123,6 +124,7 @@ const (
dvResourceVirtualEnvironmentVMTemplate = false
dvResourceVirtualEnvironmentVMTimeoutClone = 1800
dvResourceVirtualEnvironmentVMTimeoutMoveDisk = 1800
dvResourceVirtualEnvironmentVMTimeoutMigrate = 1800
dvResourceVirtualEnvironmentVMTimeoutReboot = 1800
dvResourceVirtualEnvironmentVMTimeoutShutdownVM = 1800
dvResourceVirtualEnvironmentVMTimeoutStartVM = 1800
Expand Down Expand Up @@ -230,6 +232,7 @@ const (
mkResourceVirtualEnvironmentVMMemoryDedicated = "dedicated"
mkResourceVirtualEnvironmentVMMemoryFloating = "floating"
mkResourceVirtualEnvironmentVMMemoryShared = "shared"
mkResourceVirtualEnvironmentVMMigrate = "migrate"
mkResourceVirtualEnvironmentVMName = "name"
mkResourceVirtualEnvironmentVMNetworkDevice = "network_device"
mkResourceVirtualEnvironmentVMNetworkDeviceBridge = "bridge"
Expand Down Expand Up @@ -265,6 +268,7 @@ const (
mkResourceVirtualEnvironmentVMTemplate = "template"
mkResourceVirtualEnvironmentVMTimeoutClone = "timeout_clone"
mkResourceVirtualEnvironmentVMTimeoutMoveDisk = "timeout_move_disk"
mkResourceVirtualEnvironmentVMTimeoutMigrate = "timeout_migrate"
mkResourceVirtualEnvironmentVMTimeoutReboot = "timeout_reboot"
mkResourceVirtualEnvironmentVMTimeoutShutdownVM = "timeout_shutdown_vm"
mkResourceVirtualEnvironmentVMTimeoutStartVM = "timeout_start_vm"
Expand Down Expand Up @@ -1183,7 +1187,12 @@ func VM() *schema.Resource {
Type: schema.TypeString,
Description: "The node name",
Required: true,
ForceNew: true,
},
mkResourceVirtualEnvironmentVMMigrate: {
Type: schema.TypeBool,
Description: "Whether to migrate the VM on node change instead of re-creating it",
Optional: true,
Default: dvResourceVirtualEnvironmentVMMigrate,
},
mkResourceVirtualEnvironmentVMOperatingSystem: {
Type: schema.TypeList,
Expand Down Expand Up @@ -1368,6 +1377,12 @@ func VM() *schema.Resource {
Optional: true,
Default: dvResourceVirtualEnvironmentVMTimeoutMoveDisk,
},
mkResourceVirtualEnvironmentVMTimeoutMigrate: {
Type: schema.TypeInt,
Description: "Migrate VM timeout",
Optional: true,
Default: dvResourceVirtualEnvironmentVMTimeoutMigrate,
},
mkResourceVirtualEnvironmentVMTimeoutReboot: {
Type: schema.TypeInt,
Description: "Reboot timeout",
Expand Down Expand Up @@ -1485,6 +1500,12 @@ func VM() *schema.Resource {
return strconv.Itoa(newValue.(int)) != d.Id()
},
),
customdiff.ForceNewIf(
mkResourceVirtualEnvironmentVMNodeName,
func(ctx context.Context, d *schema.ResourceDiff, meta interface{}) bool {
return !d.Get(mkResourceVirtualEnvironmentVMMigrate).(bool)
},
),
),
Importer: &schema.ResourceImporter{
StateContext: func(ctx context.Context, d *schema.ResourceData, i interface{}) ([]*schema.ResourceData, error) {
Expand Down Expand Up @@ -4847,6 +4868,26 @@ func vmUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.D
return diag.FromErr(e)
}

// If the node name has changed we need to migrate the VM to the new node before we do anything else.
if d.HasChange(mkResourceVirtualEnvironmentVMNodeName) {
oldNodeNameValue, _ := d.GetChange(mkResourceVirtualEnvironmentVMNodeName)
oldNodeName := oldNodeNameValue.(string)
vmAPI := api.Node(oldNodeName).VM(vmID)

migrateTimeout := d.Get(mkResourceVirtualEnvironmentVMTimeoutMigrate).(int)
trueValue := types.CustomBool(true)
migrateBody := &vms.MigrateRequestBody{
TargetNode: nodeName,
WithLocalDisks: &trueValue,
OnlineMigration: &trueValue,
}

err := vmAPI.MigrateVM(ctx, migrateBody, migrateTimeout)
if err != nil {
return diag.FromErr(err)
}
}

vmAPI := api.Node(nodeName).VM(vmID)

updateBody := &vms.UpdateRequestBody{
Expand Down

0 comments on commit a285360

Please sign in to comment.