diff --git a/docs/resources/virtual_environment_vm.md b/docs/resources/virtual_environment_vm.md index 78d535a4e..354a4f9eb 100644 --- a/docs/resources/virtual_environment_vm.md +++ b/docs/resources/virtual_environment_vm.md @@ -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 @@ -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 ( diff --git a/example/resource_virtual_environment_vm.tf b/example/resource_virtual_environment_vm.tf index a7fba1384..df3cbde80 100644 --- a/example/resource_virtual_environment_vm.tf +++ b/example/resource_virtual_environment_vm.tf @@ -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"] diff --git a/proxmox/nodes/vms/vms_types.go b/proxmox/nodes/vms/vms_types.go index 5dafd9aed..34dc74eb4 100644 --- a/proxmox/nodes/vms/vms_types.go +++ b/proxmox/nodes/vms/vms_types.go @@ -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"` diff --git a/proxmoxtf/resource/vm.go b/proxmoxtf/resource/vm.go index 64e7cd404..2ee3956d4 100644 --- a/proxmoxtf/resource/vm.go +++ b/proxmoxtf/resource/vm.go @@ -98,6 +98,7 @@ const ( dvResourceVirtualEnvironmentVMMemoryDedicated = 512 dvResourceVirtualEnvironmentVMMemoryFloating = 0 dvResourceVirtualEnvironmentVMMemoryShared = 0 + dvResourceVirtualEnvironmentVMMigrate = false dvResourceVirtualEnvironmentVMName = "" dvResourceVirtualEnvironmentVMNetworkDeviceBridge = "vmbr0" dvResourceVirtualEnvironmentVMNetworkDeviceEnabled = true @@ -123,6 +124,7 @@ const ( dvResourceVirtualEnvironmentVMTemplate = false dvResourceVirtualEnvironmentVMTimeoutClone = 1800 dvResourceVirtualEnvironmentVMTimeoutMoveDisk = 1800 + dvResourceVirtualEnvironmentVMTimeoutMigrate = 1800 dvResourceVirtualEnvironmentVMTimeoutReboot = 1800 dvResourceVirtualEnvironmentVMTimeoutShutdownVM = 1800 dvResourceVirtualEnvironmentVMTimeoutStartVM = 1800 @@ -230,6 +232,7 @@ const ( mkResourceVirtualEnvironmentVMMemoryDedicated = "dedicated" mkResourceVirtualEnvironmentVMMemoryFloating = "floating" mkResourceVirtualEnvironmentVMMemoryShared = "shared" + mkResourceVirtualEnvironmentVMMigrate = "migrate" mkResourceVirtualEnvironmentVMName = "name" mkResourceVirtualEnvironmentVMNetworkDevice = "network_device" mkResourceVirtualEnvironmentVMNetworkDeviceBridge = "bridge" @@ -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" @@ -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, @@ -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", @@ -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) { @@ -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{