Created
September 14, 2012 21:12
-
-
Save chrwei/3724873 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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