Home > event, PowerShell, vMotion, vSphere > Events – Part 8 – vMotion history

Events – Part 8 – vMotion history

Another idea triggered by a post in the PowerCLI Community. Lars wanted to know where his VMs had been running in the past.

Since vSphere doesn’t maintain any historical data with the guests themselves, we have to fall back on the Tasks and Events to create such a report. The basic algorithm to query the tasks, and their related events, is already published in Events – Part 3 : Auditing VM device changes. But to get a historical record of the servers where your guests have been hosted requires a bit more logic in the script.

The script

There are 2 distinct parts in the script.

  1. Get all the vMotion tasks. A vMotion can be user- or DRS-initiated. These produce different tasks.
  2. Compile the final report by only looking at the selected guests
$hours = 24 # Number of hours back
$start = (Get-Date).AddHours(-$hours)
$tasknumber = 999 # Windowsize for task collector
$eventnumber = 100 # Windowsize for event collector
$tgtTaskDescriptions = "VirtualMachine.migrate","Drm.ExecuteVMotionLRO"
$migrations = @()
$report = @()

# Get the guest for which we want the report
$vmHash = @{}
Get-Datacenter -Name "MyDC" | Get-VM | %{
	$vmHash[$_.Name] = $_.Host
}

# Retrieve the vMotion tasks and the corresponding events
$taskMgr = Get-View TaskManager
$eventMgr = Get-View eventManager

$tFilter = New-Object VMware.Vim.TaskFilterSpec
$tFilter.Time = New-Object VMware.Vim.TaskFilterSpecByTime
$tFilter.Time.beginTime = $start
$tFilter.Time.timeType = "startedTime"

$tCollector = Get-View ($taskMgr.CreateCollectorForTasks($tFilter))

$dummy = $tCollector.RewindCollector
$tasks = $tCollector.ReadNextTasks($tasknumber)

while($tasks){
	$tasks | where {$tgtTaskDescriptions -contains $_.DescriptionId} | % {
		$task = $_
		$eFilter = New-Object VMware.Vim.EventFilterSpec
		$eFilter.eventChainId = $task.EventChainId

		$eCollector = Get-View ($eventMgr.CreateCollectorForEvents($eFilter))
		$events = $eCollector.ReadNextEvents($eventnumber)
		while($events){
			$events | % {
				$event = $_
				switch($event.GetType().Name){
					"VmBeingHotMigratedEvent" {
						$migrations += New-Object PSObject -Property @{
							VMname = $task.EntityName
							Source = $event.Host.Name
							Destination = $event.DestHost.Name
							Start = $task.StartTime
							Finish = $task.CompleteTime
							Result = $task.State
							User = $task.Reason.UserName
							DRS = &{if($task.DescriptionId -like "Drm.*"){$true}else{$false}}
						}
					}
					Default {}
				}
			}
			$events = $eCollector.ReadNextEvents($eventnumber)
		}
		$ecollection = $eCollector.ReadNextEvents($eventnumber)
# By default 32 event collectors are allowed. Destroy this event collector.
		$eCollector.DestroyCollector()
	}
	$tasks = $tCollector.ReadNextTasks($tasknumber)
}

# By default 32 task collectors are allowed. Destroy this task collector.
$tCollector.DestroyCollector()

# Handle the guests that have been vMotioned
$grouped = $migrations | Group-Object -Property VMname
$grouped | Sort-Object -Property Count -Descending | where{$vmHash.ContainsKey($_.Name)} | %{
	$i = 1
	$row = New-Object PSObject
	Add-Member -InputObject $row -Name VM -Value $_.Name -MemberType NoteProperty
	$_.Group | Sort-Object -Property Finish | %{
# The original location of the guest
		if($i -eq 1){
			Add-Member -InputObject $row -Name ("Time" + $i) -Value $start -MemberType NoteProperty
			Add-Member -InputObject $row -Name ("Host" + $i) -Value $_.Source -MemberType NoteProperty
			$i++
		}
# All the vMotion destinations
		Add-Member -InputObject $row -Name ("Time" + $i) -Value $_.Finish -MemberType NoteProperty
		Add-Member -InputObject $row -Name ("Host" + $i) -Value $_.Destination -MemberType NoteProperty
		Add-Member -InputObject $row -Name ("DRS" + $i) -Value $_.DRS -MemberType NoteProperty
		Add-Member -InputObject $row -Name ("User" + $i) -Value $_.User -MemberType NoteProperty
		$i++
	}
	$report += $row
	$vmHash.Remove($_.Name)
}

# Add remaining guests to report
$vmHash.GetEnumerator() | %{
	$row = New-Object PSObject
	Add-Member -InputObject $row -Name VM -Value $_.Name -MemberType NoteProperty
	Add-Member -InputObject $row -Name Time1 -Value $start -MemberType NoteProperty
	Add-Member -InputObject $row -Name Host1 -Value $_.Value -MemberType NoteProperty
	Add-Member -InputObject $row -Name DRS1 -Value $false -MemberType NoteProperty
	$report += $row
}

$report | Export-Csv "C:\vMotion-history.csv" -NoTypeInformation -UseCulture

Annotations

Line 1-2: Specify how far back you want to report on through the $start variable

Line 5: The vMotion tasks can be triggered by a user or by DRS.

Line 10-13: We collect all the guests on which we want to report. This can be changed at will, just make sure the hash table $vmHash is populated.

Line 15-66: This is the same logic as was used in Events – Part 3 : Auditing VM device changes

Line 69-70: We group the discovered vMotions per guest and then we sort the groups descending on the Count property. This is required because we will later use the Export-Csv cmdlet and if the array holds rows of varying length, the longest row should be first.

Line 76-80: For the vMotioned guest we first make an entry with the original location at time $start.

Line 82-86: For each vMotion we add the same properties Time, Host, DRS and User, but each time with an incremented suffix number.

Line 89: A guest that was vMotioned is removed from hash table to avoid duplicate entries later one.

Line 93-100: The guest that were not vMotioned during the reporting interval are added to the report.

Sample output

The script produces a CSV file that contains quite a bit of information.

A guest that was not vMotioned during the reporting interval will only have a Time1 and Host1 column.

Guests that were vMotioned will have additional Timen and Hostn columns. Notice the DRSn column which indicates if a vMotion was triggered by DRS or by a user.  The Usern column will display the username if it was a user-invoked vMotion.

  1. Kayser Soze
    July 6th, 2011 at 03:26 | #1

    There is a DRS history tab on the VI Client – is it possible to create a script to export that info?

    thanks.

  1. June 23rd, 2010 at 00:37 | #1