225 lines
6.5 KiB
PowerShell
225 lines
6.5 KiB
PowerShell
<#
|
|
DISKSPD - VM Fleet
|
|
|
|
Copyright(c) Microsoft Corporation
|
|
All rights reserved.
|
|
|
|
MIT License
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
of this software and associated documentation files (the "Software"), to deal
|
|
in the Software without restriction, including without limitation the rights
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
furnished to do so, subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in all
|
|
copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
SOFTWARE.
|
|
#>
|
|
|
|
#
|
|
# VM Master Script
|
|
#
|
|
# This script must be executed on autologon by the VM. It establishes a mapping a location containing the Run Script
|
|
# and then repeatedly polls/executes the latest one it finds. This allows the runner to inject new run scripts on the
|
|
# fly and/or touch pre-existing ones to bump them to the top of the list.
|
|
#
|
|
# In the initial form, it assumes the VM is connected by an internal switch and it just polls all the node names to
|
|
# find the one which will work. This could be improved by using specialization to inject the specific path to a
|
|
# configuration file.
|
|
#
|
|
|
|
param(
|
|
[string] $connectuser,
|
|
[string] $connectpass
|
|
)
|
|
|
|
$null = net use l: /d
|
|
|
|
if ($(Get-SmbMapping) -eq $null) {
|
|
New-SmbMapping -LocalPath l: -RemotePath \\169.254.1.1\c$\clusterstorage\collect\control -UserName $connectuser -Password $connectpass -ErrorAction SilentlyContinue
|
|
}
|
|
|
|
# update tooling
|
|
cp l:\tools\* c:\run -Force
|
|
|
|
$run = 'c:\run\run.ps1'
|
|
$master = 'c:\run\master.ps1'
|
|
|
|
$mypause = "l:\flag\pause-$(gc c:\vmspec.txt)"
|
|
$mydone = "l:\flag\done-$(gc c:\vmspec.txt)"
|
|
|
|
$done = $false
|
|
$donetouched = $false
|
|
$pause = $false
|
|
|
|
$tick = 0
|
|
|
|
function get-newfile(
|
|
$sourcepat,
|
|
$dest,
|
|
$clean = $false,
|
|
$silent = $false
|
|
)
|
|
{
|
|
$sf = dir $sourcepat | sort -Property LastWriteTime -Descending | select -first 1
|
|
$df = gi $dest -ErrorAction SilentlyContinue
|
|
|
|
# no source?
|
|
if ($sf -eq $null) {
|
|
write-host -fore green NO source present
|
|
# clean if needed
|
|
if ($clean) {
|
|
rm $dest
|
|
}
|
|
# no new file is an update condition
|
|
$true
|
|
} elseif ($df -eq $null -or $sf.lastwritetime -gt $df.lastwritetime) {
|
|
write-host -fore green NEWER source $sf.fullname '=>' $dest
|
|
# update with newer source file and indicate update condition
|
|
cp $sf.fullname $dest -Force
|
|
$true
|
|
} else {
|
|
if (-not $silent) {
|
|
write-host -fore green NO newer source $sf.lastwritetime $sf.fullname '**' $df.LastWriteTime $df.fullname
|
|
}
|
|
# already have latest, indicate no new
|
|
$false
|
|
}
|
|
}
|
|
|
|
function get-flagfile(
|
|
[string] $flag,
|
|
[switch] $gc = $false
|
|
)
|
|
{
|
|
if ($gc) {
|
|
gc "l:\flag\$flag" -ErrorAction SilentlyContinue
|
|
} else {
|
|
gi "l:\flag\$flag" -ErrorAction SilentlyContinue
|
|
}
|
|
}
|
|
|
|
while ($true) {
|
|
|
|
# update master control?
|
|
# assume runners have a simple loop to re-execute on exit
|
|
if (get-newfile l:\master*.ps1 $master -silent:$true) {
|
|
break
|
|
}
|
|
|
|
# check and acknowledge pause - only drop flag once
|
|
$pauseepoch = get-flagfile pause -gc:$true
|
|
if ($pauseepoch -ne $null) {
|
|
|
|
# pause clears done
|
|
$done = $false
|
|
|
|
# drop into pause flagfile if needed
|
|
if ($pause -eq $false) {
|
|
write-host -fore red PAUSE IN FORCE
|
|
$pause = $true
|
|
echo $pauseepoch > $mypause
|
|
} else {
|
|
if ($tick % 10 -eq 0) {
|
|
write-host -fore red -NoNewline '.'
|
|
}
|
|
}
|
|
|
|
} elseif ($done) {
|
|
|
|
# drop epoch into done flagfile if needed
|
|
if (-not $donetouched) {
|
|
echo $goepoch > $mydone
|
|
$donetouched = $true
|
|
}
|
|
|
|
# if go flag is now different, release for the next go around
|
|
if ($goepoch -ne (get-flagfile go -gc:$true)) {
|
|
$done = $false
|
|
write-host -fore cyan `nReleasing from Done
|
|
} else {
|
|
if ($tick % 10 -eq 0) {
|
|
write-host -fore yellow -NoNewline '.'
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
# clear pause & donetouched flags
|
|
$pause = $false
|
|
$donetouched = $false
|
|
|
|
# update run script?
|
|
$null = get-newfile l:\run*.ps1 $run -clean:$true
|
|
$runf = gi $run -ErrorAction SilentlyContinue
|
|
|
|
if ($runf -eq $null) {
|
|
write-host -fore yellow no control file found
|
|
sleep 30
|
|
continue
|
|
}
|
|
|
|
# update go epoch - a change to this (if present) will be what
|
|
# allows us to proceed past a done flag
|
|
$goepoch = get-flagfile go -gc:$true
|
|
if ($goepoch -ne $null) {
|
|
write-host -fore cyan Go Epoch acknowledged at: $goepoch
|
|
}
|
|
|
|
# acknowledge script
|
|
write-host -fore cyan Run Script $runf.lastwritetime "`n$("*"*20)"
|
|
gc $runf
|
|
write-host -fore cyan ("*"*20)
|
|
|
|
# launch and monitor pause and new run file
|
|
$j = start-job -arg $run { param($run) & $run }
|
|
while (($jf = wait-job $j -Timeout 1) -eq $null) {
|
|
|
|
$halt = $null
|
|
|
|
# check pause or new run file: if so, stop and loop
|
|
if (get-flagfile pause) {
|
|
$halt = "pause set"
|
|
}
|
|
|
|
if (get-newfile l:\run*.ps1 $run -clean:$true -silent:$true) {
|
|
$halt = "new run file"
|
|
}
|
|
|
|
if ($halt -ne $null) {
|
|
write-host -fore yellow STOPPING CURRENT "(reason: $halt)"
|
|
$j | stop-job
|
|
$j | remove-job
|
|
break
|
|
}
|
|
}
|
|
|
|
# job finished?
|
|
if ($jf -ne $null) {
|
|
$result = $jf | receive-job
|
|
|
|
if ($result -eq "done") {
|
|
write-host -fore yellow DONE CURRENT
|
|
$done = $true
|
|
}
|
|
|
|
$jf | remove-job
|
|
}
|
|
|
|
write-host -fore cyan ("*"*20)
|
|
}
|
|
|
|
# force gc to teardown potentially conflicting handles and enforce min pause
|
|
[system.gc]::Collect()
|
|
sleep 1
|
|
$tick += 1
|
|
} |