Skip to content

Instantly share code, notes, and snippets.

@chrwei
Created September 14, 2012 21:12
Show Gist options
  • Save chrwei/3724873 to your computer and use it in GitHub Desktop.
Save chrwei/3724873 to your computer and use it in GitHub Desktop.
if ((Get-PSSnapin "VMware.VimAutomation.Core" -ErrorAction SilentlyContinue) -eq $null) {
Add-PSSnapin "VMware.VimAutomation.Core"
}
Connect-VIServer 'vcenter'
$vmlist = @()
$vmlist += "vncproxy"
$vmlist += "vma"
$valignervm = "valigner"
$valignerip = "10.212.0.17"
$method = "align" #check_alignemnt, align, space_reclaim
$targetalign=2048.0 #in 512B blocks, 2048 is 1MB
$hashType = @{}
$hashType."align" = 1
$hashType."check_alignment" = 4
$hashType."space_reclaim" = 5
function uberaligner_rest {
param ($method,$type,$send,$valignerip,$d=$false)
if($d) { Write-Host "J1" }
# since using system.net.webclient, this will stop malformed header errors
$netAssembly = [Reflection.Assembly]::GetAssembly([System.Net.Configuration.SettingsSection])
IF($netAssembly) {
$bindingFlags = [Reflection.BindingFlags] "Static,GetProperty,NonPublic"
$settingsType = $netAssembly.GetType("System.Net.Configuration.SettingsSectionInternal")
$instance = $settingsType.InvokeMember("Section", $bindingFlags, $null, $null, @())
if($instance) {
$bindingFlags = "NonPublic","Instance"
$useUnsafeHeaderParsingField = $settingsType.GetField("useUnsafeHeaderParsing", $bindingFlags)
if($useUnsafeHeaderParsingField) {
$useUnsafeHeaderParsingField.SetValue($instance, $true) | out-null
}
}
}
$URL="http://$valignerip/uberalign"+$method
if($d) { Write-Host "J2 sending $URL" }
$webclient = New-Object System.Net.WebClient
$webclient.Headers.Add("Content-Type","application/json")
if($d) { Write-Host "J3" }
if($type -eq "POST") {
if($d) { Write-Host "J4" }
if(!$webclient.UploadString([string]$URL,"POST",$send)) {
if($d) { Write-Host "J4f" }
return $false
} else {
if($d) { Write-Host "J4t" }
return $webclient }
} else{
if($d) { Write-Host "J5" }
return $webclient.DownloadString([string]$URL)
}
}
function hashToJSON {
param ($hash)
[string]("{"+((
$hash.keys | %{
if($hash.$_.gettype().toString() -eq "System.String") {
'"'+$_+'":"'+$hash.$_+'"'
} elseif($hash.$_.gettype().toString() -eq "System.Double") {
if($hash.$_ -eq [math]::round($hash.$_,0)) {
'"'+$_+'":'+$hash.$_+".0"
} else {
'"'+$_+'":'+$hash.$_
}
}
else {
'"'+$_+'":'+$hash.$_
}
}
) -join ",")+"}")
}
function serverGuid {
get-wmiobject win32_computersystemproduct | %{ $_.uuid }
}
function serverHostname {
get-wmiobject win32_computersystemproduct | %{ $_.__SERVER }
}
function formatOut {
param($tmpText,$state)
if($tmpText.length -ge 65) { $tmpText = $tmpText.substring(0,65) }
if($state -eq $true) { $state = "OK" } else { $state = "FAILED" }
$len = 70 - $tmpText.length
"{0,0} {1,$len}" -f $tmpText,"[ $state ]"
}
function initOut {
param($tmpText)
($tmpText | %{ $_ -split "(\[)|(\])" } | %{
if($_ -eq " OK ") { write-host -f "green" -nonewline $_ }
elseif ($_ -eq " FAILED "){ write-host -f "red" -nonewline $_}
else { write-host -nonewline $_ }}) -join ""
}
function docleanup {
param($vm)
initOut(formatOut("Start Cleanup") $true)
initOut(formatOut(" Removing hard disk from aligner") $true)
get-vm $vm | Get-HardDisk | where {$_.Persistence -eq "Persistent"} | %{$_.Filename} | %{ $df=$_;get-vm $valignervm | get-harddisk | where {$_.filename -eq $df } | remove-harddisk -confirm:$false} | out-null
# initOut(formatOut(" Remove snap on $vm") $true)
# Get-Snapshot -VM $vm | Remove-Snapshot -Confirm:$false | out-null
initOut(formatOut(" Powering on $vm") $true)
Get-VM $vm | Start-VM -Confirm:$false | out-null
}
# set up timer to keep the Lock on the aligner
$timer = new-object timers.timer
$timer.Interval = 15000 #15 seconds
[string]$SessLockSend = hashToJSON @{"guid"=$serverGuid;"ip"=serverHostname;"timestamp"=0;"locked"="false";"secondsleft"=0}
$sessionlockaction = {
$tmpResp = uberaligner_rest -type "POST" -method "/api/session/lock" -send $SessLockSend -valignerip $valignerip
if(!$tmpResp) {
initOut(formatOut("submit lock request") $false)
$timer.stop()
Unregister-Event sesslocktimer
}
# if($tmpResp.responseheaders.get("/session/LockStatus") -eq 400) {
# Write-Host -ForegroundColor Blue "JOB::Lock granted"
# } else {
# Write-Host -ForegroundColor Blue "JOB::Possible problem with lock"
# }
}
Register-ObjectEvent -InputObject $timer -EventName elapsed –SourceIdentifier sesslocktimer -Action $sessionlockaction
$assembly = [Reflection.Assembly]::LoadWithPartialName("System.Web.Extensions")
$transmogrifer = New-Object System.Web.Script.Serialization.JavaScriptSerializer
$serverGuid = serverGuid
# Check to see if valigner is responsive
$tmpHttp = uberaligner_rest -type "GET" -method "/api/job/current" -valignerip $valignerip
if($tmpHttp -eq "null") {
initOut(formatOut("Checked to see if aligner is responsive") $false)
exit
}
initOut(formatOut("Checked to see if aligner is responsive") $true)
# Check the valigner and see if it is locked, and if not start job to keep it locked
initOut(formatOut("Check to see if aligner $valignervm is locked") $true)
$tmpHttp = uberaligner_rest -type "GET" -method "/api/session" -valignerip $valignerip
[psobject]$tmpState = $transmogrifer.DeserializeObject($tmpHttp)
if($tmpState.locked -eq "true" -and $tmpState.guid -ne (serverGuid)) {
initOut(formatOut(" Aligner is locked by "+$tmpState.ip+" with "+$tmpState.secondsleft+" seconds remaining on lock") $false)
exit
} elseif ($tmpState.locked -match "true|false") {
if($tmpState.guid -eq ($serverGuid)) {
initOut(formatOut(" I own the current lock, issuing new lock request") $true)
}
$timer.start() #start lock timer
}
#setup reconfig spec
$vmview = Get-View (Get-VM $valignervm).ID
$Cntrlkey = get-vm $valignervm | get-view | %{$_.config.hardware.device} | where{$_.deviceInfo.label -eq "SCSI controller 0"} | %{ $_.key }
$spec = New-Object VMware.Vim.VirtualMachineConfigSpec
$spec.deviceChange = @()
$spec.deviceChange += New-Object VMware.Vim.VirtualDeviceConfigSpec
$spec.deviceChange[0].operation = "add"
:loop1 foreach($targetvm in $vmlist) {
try {
initOut(formatOut("Checking for specified VM $targetvm existence") $true)
get-vm -name $targetvm -erroraction stop | out-null
initOut(formatOut(" VM $targetvm found") $true)
} catch {
initOut(formatOut(" VM $targetvm notfound") $false);continue loop1
}
# Check the valigner and see if it is in ready state (0,9)
initOut(formatOut("Checking to see if aligner is busy") $true)
$time = 0 #timeout in 60 seconds
Write-Host "Waiting: " -NoNewline
do {
sleep 1
$time = $time + 1
Write-Host $time " " -NoNewline
$tmpHttp = uberaligner_rest -type "GET" -method "/api/state" -valignerip $valignerip
} until ((@(0,9) -contains $transmogrifer.DeserializeObject($tmpHttp).state) -or ($time -gt 59))
Write-Host "" #clear the -NoNewline above
if ($time -gt 59) { #bail
initOut(formatOut(" Aligner is not busy") $fasle)
initOut(formatOut("Removing background job to lock aligner") $true)
$timer.stop()
Unregister-Event sesslocktimer
exit
}
initOut(formatOut(" Aligner is not busy") $true)
initOut(formatOut("Checking to see if VM $targetvm is powered off") $true)
if (get-vm -name $targetvm | where {$_.PowerState -ne "PoweredOff"}) {
initOut(formatOut(" VM $targetvm powered off") $false)
Get-VM $targetvm | Shutdown-VMGuest -Confirm:$false | out-null
initOut(formatOut(" Waiting for power off") $true)
do {
Start-Sleep -s 1
#update objects and Check the power status
$objvm = Get-VM -Name $targetvm
$status = $objvm.PowerState
}until($status -eq "PoweredOff")
}
initOut(formatOut(" VM $targetvm powered off") $true)
#expand disks
Get-VM $targetvm | get-harddisk | %{ Set-HardDisk -CapacityKB ($_.CapacityKB + 1024) -Confirm:$false }
# Take a VMware snapshot of VM
try {
get-vm $targetvm | new-snapshot -name psuberaligner -description "Failback snapshot by PSUberAligner" -erroraction stop -Quiesce:$true -Memory:$false | out-null
initOut(formatOut("Took snapshot") $true)
} catch {
initOut(formatOut("Took snapshot") $false)
write-host -f "red" $error[0]
docleanup($targetvm)
continue loop1
}
$hddlist = get-vm $targetvm | get-view | %{ $_.config.hardware.device } | where {$_.deviceInfo.label -like "Hard disk*" -and $_.Backing.DiskMode -eq "persistent" }
foreach($device in $hddlist) {
initOut(formatOut("Starting hard disk "+$device.Backing.FileName+" to aligner") $true)
$spec.deviceChange[0].device = $device
$spec.deviceChange[0].device.key = 2001
$spec.deviceChange[0].device.UnitNumber = 1
$spec.deviceChange[0].device.controllerKey = $CntrlKey
$taskMoRef = $vmview.ReconfigVM_Task($spec)
do {
$task = Get-View $taskMoRef
if($task.info.state -eq "error") {
initOut(formatOut(" Adding hard disk "+$device.Backing.FileName+" to aligner") $false)
docleanup($targetvm)
continue loop1
}
} until ($task.info.state -eq "success" -or $task.info.state -eq "error")
# Send job to aligner
$jobGuid = [System.Guid]::NewGuid().toString()
[string]$tmpSend = hashToJSON @{"type"=$hashType."$method";"offset"=$targetalign;"id"=$jobGuid;"name"=$targetvm+' / '+$device.DeviceInfo.Label ;"guid"=$serverGuid}
#$tmpSend
if($tmpHttp = uberaligner_rest -type "POST" -method "/api/job/new" -send $tmpSend -valignerip $valignerip) {
initOut(formatOut("Sending job to aligner") $true)
} else {
initOut(formatOut("Sending job to aligner") $false)
docleanup($targetvm)
continue loop1
}
initOut(formatOut("Waiting for job to begin") $true)
#timeout in 60 seconds
$time = 0
Write-Host "Waiting: " -NoNewline
do {
sleep 5
$time = $time + 5
Write-Host $time " " -NoNewline
$tmpHttp = uberaligner_rest -type "GET" -method "/api/job/current" -valignerip $valignerip
} until (($transmogrifer.DeserializeObject($tmpHttp).id -eq $jobGuid) -or ($time -gt 59))
Write-Host "" #clear the -NoNewline above
if ($time -gt 59) { #bail
initOut(formatOut(" job responded") $false)
docleanup($targetvm)
initOut(formatOut("Removing background job to lock aligner") $true)
$timer.stop()
Unregister-Event sesslocktimer
exit
}
initOut(formatOut(" Job has started, waiting for job to finish") $true)
do {
if($method -eq "align") {
$tmpHttp = uberaligner_rest -type "GET" -method "/api/job/current" -valignerip $valignerip
$jobDetails = $transmogrifer.DeserializeObject($tmpHttp)
[array]$tmpDesc = ($jobDetails.currentstep -split "(\d{1,3})\%")[0] -split "\s{1,4}","" -replace ":",""
if($tmpPerc = ($jobDetails.currentstep -split "(\d{1,3})\%")[1]) {
$tmpStatus = ($tmpDesc[1]+" "+[math]::round(([double]($tmpPerc/100)*([double]$jobDetails.diskdetails._totalsectors * 512 / 1GB)),1)+"/"+[math]::round(([double]$jobDetails.diskdetails._totalsectors * 512 / 1GB),1)+" GB")
write-progress -activity $tmpDesc[0] -percentcomplete $tmpPerc -status $tmpStatus
}
}
sleep 5
$tmpHttp = uberaligner_rest -type "GET" -method "/api/state" -valignerip $valignerip
} until (@(0,9) -contains $transmogrifer.DeserializeObject($tmpHttp).state)
if($transmogrifer.DeserializeObject($tmpHttp).state -eq 0) {
initOut(formatOut(" Job has finished") $true)
} else {
initOut(formatOut(" Job has finished") $false)
#no need to clean up here since it's the last step
}
$tmpHttp = uberaligner_rest -type "GET" -method "/api/state" -valignerip $valignerip
#$transmogrifer.DeserializeObject($tmpHttp)
$tmpHttp = uberaligner_rest -type "GET" -method "/api/job/current" -valignerip $valignerip
$transmogrifer.DeserializeObject($tmpHttp)
#$transmogrifer.DeserializeObject($tmpHttp).diskdetails
#$transmogrifer.DeserializeObject($tmpHttp).partitions
initOut(formatOut(" Removing hard disk from aligner") $true)
get-vm $targetvm | Get-HardDisk | where {$_.Persistence -eq "Persistent"} | %{$_.Filename} | %{ $df=$_;get-vm $valignervm | get-harddisk | where {$_.filename -eq $df } | remove-harddisk -confirm:$false} | out-null
}
#done with this vm
docleanup($targetvm)
}
initOut(formatOut("Removing background job to lock aligner") $true)
$timer.stop()
Unregister-Event sesslocktimer
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment