VMware Cloud Community
monderick
Enthusiast
Enthusiast
Jump to solution

limit vMotion operations?

We have the need for migrating numerous VMs between hosts but want to set a limit of 2 simultaneous operations and would like to not tweak advanced vCenter settings.

I'm able to get a list of VM's and sequentially migrate them between hosts pretty easy with a simple for-each loop (example below) but how to increase this to two?

Optimally, i'd like the ability to just specify the original host and evacuate the VMs (2 at a time) to other hosts in the cluster.

$vms =  get-vmhost 'host1' | get-vm *

foreach($vm in $vms){

  Move-VM -VM (Get-VM -Name $vm.name) -destination 'host2'

}

thanks for any guidance

0 Kudos
1 Solution

Accepted Solutions
LucD
Leadership
Leadership
Jump to solution

You can do something like this.

Run the vMotion in the background (RunAsync) and count if more than 2 running

$maxParallel = 2

$vms =  get-vmhost 'host1' | get-vm *

foreach($vm in $vms){

  Move-VM -VM (Get-VM -Name $vm.name) -destination 'host2' -RunAsync

  do

  {

    sleep 5

  } while((Get-Task -Status Running | where{$_.Name -eq 'RelocateVM_Task'}).Count -gt $maxParallel)

}


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

View solution in original post

10 Replies
LucD
Leadership
Leadership
Jump to solution

You can do something like this.

Run the vMotion in the background (RunAsync) and count if more than 2 running

$maxParallel = 2

$vms =  get-vmhost 'host1' | get-vm *

foreach($vm in $vms){

  Move-VM -VM (Get-VM -Name $vm.name) -destination 'host2' -RunAsync

  do

  {

    sleep 5

  } while((Get-Task -Status Running | where{$_.Name -eq 'RelocateVM_Task'}).Count -gt $maxParallel)

}


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

monderick
Enthusiast
Enthusiast
Jump to solution

awesome, LucD!

thanks for the assist

0 Kudos
JDMils_Interact
Enthusiast
Enthusiast
Jump to solution

Nice script. How does the Get-Task know the name of the task running in order to check how many concurrent processes there are of the same script? I am running it as a test from the PowerCLI command line and when I run Get-Task -Running from another PowerCLI window, it shows "RelocateVM_Task" as running!

Question: Can the script detect when the destination host reaches say 90% Memory usage and then stop the migrations?

0 Kudos
LucD
Leadership
Leadership
Jump to solution

Yes, that is normal.
These tasks run on the VCSA level and consequentially you will see them from wherever you connect to that VCSA.
You can eventually store the Task objects in a hash table, and based on the Id in those objects only look at the ones submitted from your session.

A script can detect CPU usage on an ESXi nodes, and pause the script via a loop for example


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

JDMils_Interact
Enthusiast
Enthusiast
Jump to solution

Thank you. Note that I am by no means a PowerCLI programmer, however I am migrating virtuals from Host01 to Host02 and being production, we have to migrate one server at a time else the customer's "sensitive" applications start dropping connections as soon as they see one or more PING packet drops. So instead of moving each virtual via the GUI (click, click, click, click of the mouse), I'm using your script with a slight modification.

I also added the destination server CPU & Memory free check to the script so that virtuals would only move to the destination host ONLY if the host's CPU free was 30%+ and memory free was 30%+. I think it works really well based on my testing. Here it is:

$maxParallel = 1
$vms =  get-vmhost 'SourceHostName' | get-vm *
foreach($vm in $vms)
    {
    $MyESXHostObj = Get-VMHost -Name 'DestHostName'

    $CPUTot = $MyESXHostObj.CpuTotalMhz
    $CPUUsage = $MyESXHostObj.CpuUsageMhz
    $CPUFreePC = [math]::round((($CPUTot - $CPUUsage) / $CPUTot) *100, 2)

    $MemTot = $MyESXHostObj.MemoryTotalGB
    $MemUsage = $MyESXHostObj.MemoryUsageGB
    $MemFreePC = [math]::round((($MemTot - $MemUsage) / $MemTot) *100, 2)
    $vm_Name = $vm.Name
  
    if (($CPUFreePC -gt 30) -and ($MemFreePC -gt 30))
        {
        Write-Host ""
        Write-Host "Destination CPU Free is $CPUFreePC."
        Write-Host "Destination Mem Free is $MemFreePC."
        Write-Host "Destination host resources are OK" -ForegroundColor Green
        Write-Host "Moving VM '$vm_Name'" -ForegroundColor Yellow

        Move-VM -VM (Get-VM -Name $vm_Name) -destination $MyESXHostObj -RunAsync
        }
        else
        {
        Write-Host ""
        Write-Host "Destination CPU Free is $CPUFreePC."
        Write-Host "Destination Mem Free is $MemFreePC."
        Write-Host "Destination host resources are not OK" -ForegroundColor Red
        }
    do
        {
        Sleep 5
        Write-Host "Waiting....." -ForegroundColor Cyan
        } while((Get-Task -Status Running | where{$_.Name -eq 'RelocateVM_Task'}).Count -ge $maxParallel)
    Sleep 10
} 

Not sure if your original script was supposed to work this way, but when $maxParallel is set to 1, I would get 2 parallel vMotions, when $maxParallel was set to 2 I would get 3 parallel vMotions, etc. I thus modified the comparitor on this line from "-gt" to "-ge":

 

} while((Get-Task -Status Running | where{$_.Name -eq 'RelocateVM_Task'}).Count -ge $maxParallel)

 

I also added the "Sleep 10" at the end to separate the vMotions, so when one ended, wait 10 seconds then start the next, not sure if this is really required- what do you think?

0 Kudos
LucD
Leadership
Leadership
Jump to solution

Nice additions to the script.

And yes, if you don't want more than $maxParallel, you have to indeed use -ge instead of -gt.

I'm not sure the sleep is needed. On the other hand, that would allow the environment to come to "rest".
Especially if this is a sensitive environment (like the timeouts seem to indicate).


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
maorzohar
Contributor
Contributor
Jump to solution

Hi LucD,

Great script.

A question - If I want to spread the VMs randomly to all the other hosts and not only to one host as the destination, what do I need to change in the script?

 

Thanks! 

0 Kudos
LucD
Leadership
Leadership
Jump to solution

You could try something like this

$vm = Get-VM -Name $vm.name
$esx = Get-VMHost | where{$_.Name -ne $vm.VMHost.Name} | Get-Random
Move-VM -VM $vm -destination $esx -RunAsync

 


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

maorzohar
Contributor
Contributor
Jump to solution

I will try that, thank you for your fast reply! 🙂

0 Kudos
maorzohar
Contributor
Contributor
Jump to solution

Works great...

 

$MaxParallel = 3

$SourceESXiServer = 'esxi01.domain.local'

$VMs =  Get-VMHost $SourceESXiServer | Get-VM

foreach ($VM in $VMs)

{

       $ESXiDest = Get-VMHost | Where {$_.Name -ne $SourceESXiServer} | Get-Random

       Move-VM -VM (Get-VM -Name $VM.Name) -Destination $ESXiDest -RunAsync

       do

       {

       Start-Sleep -Seconds 5

       } while ((Get-Task -Status Running | Where {$_.Name -eq 'RelocateVM_Task'}).Count -ge $MaxParallel)

}

0 Kudos