]>
Commit | Line | Data |
---|---|---|
50881e44 | 1 | #!/bin/bash |
2 | ||
3 | # | |
4 | # launch-relval.sh -- by Dario Berzano <dario.berzano@cern.ch> | |
5 | # | |
6 | # Controls the release validation submission by managing the validation virtual | |
7 | # cluster. | |
8 | # | |
9 | ||
10 | # | |
11 | # Variables | |
12 | # | |
13 | ||
14 | # error codes | |
15 | errCfg=1 | |
16 | errMissingCmd=2 | |
17 | errEc2Auth=3 | |
18 | errInvalidOpt=4 | |
19 | errSessionDir=5 | |
20 | errCreateKey=6 | |
21 | errRunVm=7 | |
22 | errLaunchValidation=8 | |
23 | errSshNotReady=9 | |
24 | errStatusUnavailable=10 | |
25 | errPickSession=11 | |
26 | errCopyKey=12 | |
27 | errAttachScreen=13 | |
28 | ||
29 | # error codes not treated as errors (100 to 140) | |
30 | errStatusRunning=100 | |
31 | errStatusNotRunning=101 | |
32 | errStatusDoneOk=102 | |
33 | errStatusDoneFail=103 | |
34 | ||
35 | # thresholds | |
36 | maxVmLaunchAttempts=10 | |
37 | maxSshConnectAttempts=400 | |
38 | maxVmAddressWait=120 | |
39 | ||
40 | # working directory prefix | |
1211d5b0 | 41 | sessionPrefix="$HOME/.alice-release-validation" |
50881e44 | 42 | |
43 | # screen name for the validation | |
44 | screenName='AliceReleaseValidation' | |
45 | ||
46 | # program name | |
47 | Prog=$(basename "$0") | |
48 | ||
49 | # | |
50 | # Functions | |
51 | # | |
52 | ||
53 | # Pretty print | |
54 | function pr() { | |
55 | local nl | |
56 | if [ "$1" == '-n' ] ; then | |
57 | nl="-n" | |
58 | shift | |
59 | fi | |
60 | echo $nl -e "\033[1m$@\033[m" >&2 | |
61 | } | |
62 | ||
63 | # Nice date in UTC | |
64 | function ndate() { | |
65 | date -u +%Y%m%d-%H%M%S-utc | |
66 | } | |
67 | ||
68 | # Temporary file | |
69 | function tmpf() { | |
70 | mktemp /tmp/alirelval-XXXX | |
71 | } | |
72 | ||
73 | # Swallow output. Show only if something goes wrong | |
74 | function swallow() { | |
75 | local tout ret | |
76 | tout=$(tmpf) | |
77 | "$@" > "$tout" 2>&1 | |
78 | ret=$? | |
79 | if [ $ret != 0 ] ; then | |
80 | pr "Command failed (exit status: $ret): $@" | |
81 | cat "$tout" >&2 | |
82 | fi | |
83 | rm -f "$tout" | |
84 | return $ret | |
85 | } | |
86 | ||
87 | # Launch a VM. Create the keypair if the given keyfile does not exist. Syntax: | |
88 | # | |
89 | # RunVM <image_id> <profile> <user_data> <key_name> <key_file> | |
90 | # | |
91 | # Returns 0 on success, nonzero on failure. IP address is returned on stdout. | |
92 | function RunVM() { | |
93 | local imageId profile userData keyName | |
94 | imageId="$1" | |
95 | profile="$2" | |
96 | userData="$3" | |
97 | keyName="$4" | |
98 | keyFile="$5" | |
8ca5b365 | 99 | local raw iip iid ret attempt createdKeypair error |
50881e44 | 100 | |
101 | # keypair part: if file does not exist, create keypair | |
102 | if [ ! -e "$keyFile" ] ; then | |
103 | pr "Creating a new keypair: $keyName (private key: $keyFile)" | |
104 | swallow euca-create-keypair -f "$keyFile" "$keyName" | |
105 | if [ $? != 0 ] ; then | |
106 | pr 'Problems creating the keypair' | |
107 | return $errCreateKey | |
108 | fi | |
109 | createdKeypair=1 | |
110 | fi | |
111 | ||
112 | attempt=0 | |
113 | pr 'Attempting to run virtual machine' | |
114 | ||
115 | # resubmit loop | |
116 | while true ; do | |
117 | ||
118 | if [ $((++attempt)) -gt $maxVmLaunchAttempts ] ; then | |
119 | pr " * Reached maximum number of attempts, giving up" | |
120 | if [ "$createdKeypair" == 1 ] ; then | |
121 | ( euca-delete-keypair "$keyName" ; rm -f "$keyFile" ) > /dev/null 2>&1 | |
122 | fi | |
123 | return $errRunVm | |
124 | fi | |
125 | ||
126 | pr -n " * Launching VM (attempt #$attempt/$maxVmLaunchAttempts)..." | |
8ca5b365 | 127 | error=0 |
50881e44 | 128 | |
129 | raw=$( euca-run-instances "$imageId" -t "$profile" -d "$userData" -k "$keyName" 2>&1 ) | |
130 | ret=$? | |
131 | iid=$( echo "$raw" | egrep '^INSTANCE' | head -n1 | awk '{ print $2 }' ) | |
132 | if [ $ret != 0 ] || [ "$iid" == '' ] ; then | |
133 | # 'hard' error, but can be temporary | |
134 | pr 'error: message follows' | |
135 | echo "$raw" >&2 | |
136 | sleep 1 | |
137 | continue | |
138 | else | |
139 | pr 'ok' | |
140 | fi | |
141 | ||
142 | pr " * VM has instance ID $iid" | |
143 | pr -n " * Waiting for IP address..." | |
144 | ||
145 | # wait for address loop | |
146 | iip='' | |
147 | for ((i=0; i<$maxVmAddressWait; i++)) ; do | |
148 | sleep 1 | |
149 | raw=$( euca-describe-instances 2>&1 | grep -E '^INSTANCE' | grep "$iid" | head -n1 ) | |
150 | ||
151 | # error state? | |
152 | echo "$raw" | grep -i error -q | |
153 | if [ $? == 0 ] ; then | |
8ca5b365 | 154 | pr ; pr " * VM went to error state" |
155 | error=1 | |
50881e44 | 156 | break |
157 | fi | |
158 | ||
159 | # no error: try to parse address (NOTE: only IPv4 for the moment) | |
160 | iip=$( echo "$raw" | grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' ) | |
161 | if [ "$iip" != '' ] ; then | |
162 | pr | |
163 | break | |
164 | fi | |
165 | ||
166 | # no address | |
167 | pr -n '.' | |
168 | ||
169 | done | |
170 | ||
171 | # do we have address? | |
172 | if [ "$iip" != '' ] ; then | |
173 | pr " * VM has address $iip" | |
174 | break | |
175 | fi | |
176 | ||
177 | # we don't: terminate (timeout) | |
8ca5b365 | 178 | [ "$error" != 1 ] && pr 'timeout' |
179 | pr " * Terminating instance $iid" | |
50881e44 | 180 | euca-terminate-instances "$iid" > /dev/null 2>&1 |
181 | ||
182 | done | |
183 | ||
184 | # success | |
185 | [ "$createdKeypair" == 1 ] && euca-delete-keypair "$keyName" > /dev/null 2>&1 | |
186 | echo "$iid $iip" # must be parsed | |
187 | return 0 | |
188 | ||
189 | } | |
190 | ||
191 | # Prepare the validation session directory. Syntax: | |
192 | # | |
193 | # PrepareSession <aliroot_tag> | |
194 | # | |
195 | # Returns 0 on success, nonzero on failure. Session tag returned on stdout. | |
196 | function PrepareSession() { | |
197 | local aliRootTag sessionTag sessionDir | |
198 | aliRootTag="$1" | |
4a94e8bb | 199 | shift |
50881e44 | 200 | sessionTag="${aliRootTag}_$(ndate)" |
201 | sessionDir="$sessionPrefix/$sessionTag" | |
202 | ||
203 | # session directory already exists? abort | |
204 | if [ -d "$sessionDir" ] ; then | |
205 | pr "Session directory already exists, aborting" | |
206 | return $errSessionDir | |
207 | fi | |
208 | ||
209 | # create working directory | |
210 | mkdir -p "$sessionDir" | |
211 | if [ $? != 0 ] ; then | |
212 | pr "Fatal: cannot create session directory $sessionDir" | |
213 | return $errSessionDir | |
214 | fi | |
215 | ||
216 | # aliroot version written to a file | |
217 | echo "$aliRootTag" > "$sessionDir/aliroot-version.txt" | |
218 | ||
219 | # benchmark script, configuration and file list | |
220 | cp benchmark.sh benchmark.config files.list "$sessionDir/" | |
221 | if [ $? != 0 ] ; then | |
222 | pr "Cannot copy benchmark configuration and script to $sessionDir" | |
223 | return $errSessionDir | |
224 | fi | |
225 | ||
226 | # append local files to the configuration | |
227 | for f in benchmark.config.d/*.config ; do | |
228 | [ ! -e "$f" ] && continue | |
229 | ( echo '' | |
230 | echo "### from $f ###" | |
231 | cat $f | |
232 | echo '' | |
233 | ) >> "$sessionDir/benchmark.config" | |
234 | done | |
235 | ||
4a94e8bb | 236 | # command-line options override the configuration |
237 | if [ $# != 0 ] ; then | |
238 | pr "Note: the following command-line options will override the corresponding ones in the config files:" | |
239 | ( echo '' | |
240 | echo "### from the command line ###" | |
241 | while [ $# -gt 0 ] ; do | |
242 | extraName="${1%%=*}" | |
243 | extraVal="${1#*=}" | |
244 | if [ "$extraName" != "$1" ] ; then | |
245 | pr " * $extraName = $extraVal" | |
246 | echo "$1" | |
247 | fi | |
248 | shift | |
249 | done | |
250 | echo '' | |
251 | ) >> "$sessionDir/benchmark.config" | |
252 | fi | |
253 | ||
50881e44 | 254 | # success: return the session tag and move to the session directory |
255 | pr "*** Creating new working session: $sessionTag ***" | |
256 | pr "*** Use this name for future session operations ***" | |
257 | echo "$sessionTag" | |
258 | return 0 | |
259 | } | |
260 | ||
261 | # Undo the previous action | |
262 | function PrepareSession_Undo() { | |
263 | rm -rf "$sessionPrefix/$1" | |
264 | } | |
265 | ||
266 | # Move into the session tag directory. Usage: | |
267 | # | |
268 | # MoveToSessionDir <session_tag> | |
269 | # | |
270 | # Returns 0 on success, nonzero on error. | |
271 | function MoveToSessionDir() { | |
272 | originalWorkDir="$PWD" | |
273 | cd "$sessionPrefix/$sessionTag" || return $errSessionDir | |
274 | return 0 | |
275 | } | |
276 | ||
277 | # Undo the previous action | |
278 | function MoveToSessionDir_Undo() { | |
279 | cd "$originalWorkDir" | |
280 | } | |
281 | ||
282 | # Load the benchmark configuration | |
283 | function LoadConfig() { | |
284 | source benchmark.config > /dev/null 2>&1 | |
285 | if [ $? != 0 ] ; then | |
286 | pr "Cannot load benchmark configuration" | |
287 | return $errCfg | |
288 | fi | |
289 | return 0 | |
290 | } | |
291 | ||
292 | # Instantiate the validation VM | |
293 | function InstantiateValidationVM() { | |
294 | local sessionTag instanceId instanceIp ret raw | |
295 | sessionTag="$1" | |
296 | ||
297 | # check if we already have a vm | |
298 | instanceId="$(cat instance-id.txt 2> /dev/null)" | |
299 | if [ "$instanceId" != '' ] ; then | |
300 | pr "Virtual machine $instanceId is already running" | |
301 | return 0 # consider it a success | |
302 | else | |
303 | rm -f instance-id.txt instance-address.txt | |
304 | fi | |
305 | ||
306 | # do we need to create a keypair? | |
307 | if [ "$cloudKeyName" == '' ] ; then | |
308 | pr "Note: temporary SSH keys will be created for this VM" | |
309 | cloudKeyName="$sessionTag" | |
310 | cloudKeyFile="$PWD/key.pem" | |
311 | rm -f "$cloudKeyFile" | |
312 | elif [ -e "$cloudKeyFile" ] ; then | |
313 | # copy key to session dir | |
314 | pr -n "Copying private key $cloudKeyFile to session directory..." | |
315 | cp "$cloudKeyFile" 'key.pem' 2> /dev/null | |
316 | if [ $? != 0 ] ; then | |
317 | pr 'error' | |
318 | return $errCopyKey | |
319 | else | |
320 | pr 'ok' | |
321 | fi | |
322 | cloudKeyFile="$PWD/key.pem" | |
323 | else | |
324 | pr "Cannot find private key to access virtual machines: $cloudKeyFile" | |
325 | return $errCopyKey | |
326 | fi | |
327 | ||
328 | # launch virtual machine and get its address | |
329 | raw=$( RunVM "$cloudImageId" "$cloudProfile" "$cloudUserData" "$cloudKeyName" "$cloudKeyFile" ) | |
330 | ret=$? | |
331 | ||
332 | if [ $ret == 0 ] ; then | |
333 | instanceId=$( echo $raw | cut -d' ' -f1 ) | |
334 | instanceIp=$( echo $raw | cut -d' ' -f2 ) | |
335 | ||
336 | # write both parameters to files | |
337 | echo $instanceId > 'instance-id.txt' | |
338 | echo $instanceIp > 'instance-address.txt' | |
339 | fi | |
340 | ||
341 | return $ret | |
342 | } | |
343 | ||
344 | # Undo the previous action | |
345 | function InstantiateValidationVM_Undo() { | |
346 | local sessionTag | |
347 | sessionTag="$1" | |
348 | if [ -e 'instance-id.txt' ] ; then | |
349 | swallow euca-terminate-instances $(cat instance-id.txt) | |
350 | if [ $? == 0 ] ; then | |
351 | rm -f instance-id.txt instance-address.txt key.pem | |
352 | fi | |
353 | fi | |
354 | } | |
355 | ||
356 | # Generic SSH function to the VM | |
357 | function VMSSH() { | |
358 | local instanceIp sshParams ret | |
359 | instanceIp=$(cat instance-address.txt 2> /dev/null) | |
360 | sshParams="-oUserKnownHostsFile=/dev/null -oStrictHostKeyChecking=no -oPasswordAuthentication=no -i $PWD/key.pem" | |
361 | ||
362 | if [ "$1" == '--rsync-cmd' ] ; then | |
363 | shift | |
364 | echo ssh $sshParams "$@" | |
365 | ret=0 | |
366 | else | |
367 | ssh $sshParams "$cloudUserName"@"$instanceIp" "$@" | |
368 | ret=$? | |
369 | fi | |
370 | return $ret | |
371 | } | |
372 | ||
373 | # Opens a shell to the remote VM | |
374 | function Shell() { | |
375 | local sessionTag | |
376 | sessionTag="$1" | |
377 | VMSSH | |
378 | } | |
379 | ||
380 | # Checks status of the validation | |
381 | function Status() { | |
382 | local raw ret screen exitcode | |
8c3e0568 | 383 | raw=$( VMSSH -t "screen -ls 2> /dev/null | grep -q .$screenName && echo -n 'screen_yes ' || echo -n 'screen_no ' ; cat $sessionTag/validation.done 2> /dev/null || echo 'not_done' ; true" 2> /dev/null ) |
50881e44 | 384 | raw=$( echo "$raw" | tr -cd '[:alnum:]_ ' ) # garbage removal |
385 | ret=$? | |
386 | ||
387 | if [ "$ret" != 0 ] ; then | |
388 | pr "Cannot get status" | |
389 | return $errStatusUnavailable | |
390 | fi | |
391 | ||
392 | screen="${raw%% *}" | |
393 | exitcode="${raw#* }" | |
394 | ||
395 | if [ "$screen" == 'screen_yes' ] ; then | |
396 | pr 'Status: validation still running' | |
397 | return $errStatusRunning | |
398 | else | |
399 | if [ "$exitcode" == 'not_done' ] ; then | |
400 | pr 'Status: validation not running' | |
401 | return $errStatusNotRunning | |
402 | elif [ "$exitcode" == 0 ] ; then | |
403 | pr 'Status: validation completed successfully' | |
404 | return $errStatusDoneOk | |
405 | else | |
406 | pr "Status: validation finished with errors (exitcode: $exitcode)" | |
407 | return $errStatusDoneFail | |
408 | fi | |
409 | fi | |
410 | ||
411 | } | |
412 | ||
413 | # Wait for host to be ready | |
414 | function WaitSsh() { | |
415 | local attempt error | |
416 | attempt=0 | |
417 | pr -n 'Waiting for the VM to accept SSH connections...' | |
418 | ||
419 | while ! VMSSH -Tq true > /dev/null 2>&1 ; do | |
420 | if [ $((++attempt)) -gt $maxSshConnectAttempts ] ; then | |
421 | pr 'timeout' | |
422 | error=1 | |
423 | break | |
424 | fi | |
425 | pr -n '.' | |
426 | sleep 3 | |
427 | done | |
428 | ||
429 | [ "$error" == 1 ] && return $errSshNotReady | |
430 | pr 'ok' | |
431 | return 0 | |
432 | } | |
433 | ||
434 | # Run the validation | |
435 | function Validate() { | |
436 | local instanceIp sshParams sessionTag | |
437 | sessionTag="$1" | |
438 | instanceIp=$(cat instance-address.txt 2> /dev/null) | |
439 | sshParams="-oUserKnownHostsFile=/dev/null -oStrictHostKeyChecking=no -oPasswordAuthentication=no -i $PWD/key.pem" | |
440 | ||
441 | # create helper script to launch benchmark | |
442 | cat > run-benchmark.sh <<_EoF_ | |
443 | #!/bin/bash | |
444 | cd \$(dirname "\$0") | |
445 | v=validation.done | |
446 | rm -f \$v | |
447 | env ALIROOT_VERSION=$(cat aliroot-version.txt) ./benchmark.sh run $sessionTag files.list benchmark.config | |
448 | #sleep 1000 | |
449 | ret=\$? | |
450 | echo \$ret > \$v | |
451 | echo ; echo ; echo | |
452 | echo "*** Validation finished with exitcode \$ret ***" | |
453 | echo ; echo ; echo | |
454 | read -p 'Press ENTER to dismiss: automatic dismiss in 60 seconds...' -t 60 | |
455 | _EoF_ | |
456 | chmod +x run-benchmark.sh | |
457 | ||
458 | # transfer files | |
459 | pr 'Transferring files to the VM' | |
8c3e0568 | 460 | rsync -av -e "$(VMSSH --rsync-cmd)" $PWD/ $cloudUserName@$instanceIp:$sessionTag/ || return $errLaunchValidation |
50881e44 | 461 | |
462 | # open a screen that does something; note that the command is not executed if | |
463 | # the screen already exists, which is what we want | |
464 | # note: sleep necessary to avoid "dead" screens | |
8c3e0568 | 465 | VMSSH -t "screen -wipe > /dev/null 2>&1 ; if screen -ls | grep -q $screenName ; then ret=42 ; else screen -dmS AliceReleaseValidation $sessionTag/run-benchmark.sh ; ret=0 ; sleep 3 ; fi ; exit \$ret" |
50881e44 | 466 | ret=$? |
467 | ||
468 | # message | |
469 | if [ $ret == 42 ] ; then | |
470 | pr 'Validation already running inside a screen.' | |
471 | else | |
472 | pr 'Validation launched inside a screen.' | |
473 | fi | |
474 | ||
475 | pr | |
476 | pr 'Check the progress status with:' | |
477 | pr " $Prog --session $sessionTag --status" | |
478 | pr 'Attach to the screen for debug:' | |
479 | pr " $Prog --session $sessionTag --attach" | |
480 | pr 'Open a shell to the virtual machine:' | |
481 | pr " $Prog --session $sessionTag --shell" | |
482 | pr | |
483 | ||
484 | # ignore ssh errors | |
485 | return 0 | |
486 | } | |
487 | ||
488 | # Attach current validation screen, if possible | |
489 | function Attach() { | |
490 | local sessionTag | |
491 | sessionTag="$1" | |
492 | ||
493 | VMSSH -t "( screen -wipe ; screen -rx $screenName ) > /dev/null 2>&1" | |
494 | ||
495 | if [ $? != 0 ] ; then | |
496 | pr "Cannot attach screen: check if validation is running with:" | |
497 | pr " $Prog --session $sessionTag --status" | |
498 | pr "or connect manually to the VM for debug:" | |
499 | pr " $Prog --session $sessionTag --attach" | |
500 | return $errAttachScreen | |
501 | fi | |
502 | ||
503 | return 0 | |
504 | } | |
505 | ||
506 | # Pick session interactively | |
507 | function PickSession() { | |
508 | local sessionTag sess listSessions | |
509 | listSessions=() | |
510 | mkdir -p "$sessionPrefix" | |
511 | ||
512 | while read sess ; do | |
513 | [ ! -d "$sessionPrefix/$sess" ] && continue | |
514 | listSessions+=( $sess ) | |
515 | done < <( cd $sessionPrefix ; ls -1t ) | |
516 | ||
517 | if [ ${#listSessions[@]} == 0 ] ; then | |
518 | pr "No session available in session directory $sessionPrefix" | |
519 | return $errPickSession | |
520 | fi | |
521 | ||
522 | pr 'Available sessions (most recent first):' | |
523 | for ((i=0; i<${#listSessions[@]}; i++)) ; do | |
524 | pr "$( printf " % 2d. ${listSessions[$i]}" $((i+1)) )" | |
525 | done | |
526 | pr -n 'Pick one: ' | |
527 | read i | |
528 | ||
529 | let i-- | |
530 | if [ "$i" -lt 0 ] || [ "${listSessions[$i]}" == '' ] ; then | |
531 | pr 'Invalid session' | |
532 | return $errPickSession | |
533 | fi | |
534 | ||
535 | sess="${listSessions[$i]}" | |
536 | pr "You chose session $sess" | |
537 | echo $sess | |
538 | return 0 | |
539 | } | |
540 | ||
541 | # Run an action | |
542 | function RunAction() { | |
543 | local ret | |
544 | type "$1" > /dev/null 2>&1 | |
545 | if [ $? == 0 ] ; then | |
546 | #pr "--> $1 (wd: $PWD)" | |
547 | eval "$@" | |
548 | ret=$? | |
549 | #pr "<-- $1 (ret: $ret, wd: $PWD)" | |
550 | return $ret | |
551 | fi | |
552 | return 0 | |
553 | } | |
554 | ||
555 | # Print help screen | |
556 | function Help() { | |
557 | pr "$Prog -- by Dario Berzano <dario.berzano@cern.ch>" | |
558 | pr 'Controls the Release Validation workflow on the cloud for AliRoot.' | |
559 | pr | |
4a94e8bb | 560 | pr "Usage 1: $Prog [--prepare|--launch] --aliroot <aliroot_tag> [-- arbitraryOpt1=value [arbitraryOpt2=value2...]]" |
50881e44 | 561 | pr |
562 | pr 'A new session is created to validate the specified AliRoot tag.' | |
563 | pr | |
564 | pr ' --prepare : prepares the session directory containing the files needed' | |
565 | pr ' for the validation' | |
566 | pr ' --launch : launches the full validation process: prepares session,' | |
567 | pr ' runs the virtual machine, launches the validation program' | |
568 | pr ' --aliroot : the AliRoot tag to validate, in the form "vAN-20140610"' | |
4a94e8bb | 569 | pr |
570 | pr 'Arbitrary options (in the form variable=value) can be specified after the' | |
571 | pr 'double dash and will override the corresponding options in any of the' | |
572 | pr 'configuration files.' | |
50881e44 | 573 | pr ; pr |
574 | pr "Usage 2: $Prog [--runvm|--validate|--shell|--status] --session <session_tag>" | |
575 | pr | |
576 | pr 'Runs the validation step by step after a session is created with' | |
577 | pr '--prepare, and runs other actions on a certain session.' | |
578 | pr | |
579 | pr ' --session : session identifier, e.g. vAN-20140610_20140612-123047-utc:' | |
580 | pr ' if no session is specified an interactive prompt is' | |
581 | pr ' presented' | |
582 | pr ' --runvm : instantiates the head node of the validation cluster on' | |
583 | pr ' the cloud' | |
584 | pr ' --validate : runs the validation script on the head node for the' | |
585 | pr ' current session. Head node must be already up, or it' | |
586 | pr ' should be created with --runvm. If validation is running' | |
587 | pr ' already, connects to the existing validation shell' | |
588 | pr ' --attach : attach a currently running validation screen; remember to' | |
589 | pr ' detach with Ctrl+A+D (and *not* Ctrl-C)' | |
590 | pr ' --shell : does SSH on the head node' | |
591 | pr ' --status : returns the status of the validation' | |
592 | pr ; pr | |
593 | pr 'Example 1: run the validation of AliRoot tag vAN-20140610:' | |
594 | pr | |
595 | pr " $Prog --aliroot vAN-20140610 --launch" | |
596 | pr | |
597 | pr 'Example 2: do the same thing step-by-step:' | |
598 | pr | |
599 | pr " $Prog --aliroot vAN-20140610 --prepare" | |
600 | pr " $Prog --runvm" | |
601 | pr " $Prog --validate" | |
602 | pr | |
603 | } | |
604 | ||
605 | # The main function | |
606 | function Main() { | |
607 | ||
608 | # local variables | |
609 | local Args aliRootTag EnterShell Actions sessionTag | |
610 | Actions=() | |
611 | ||
612 | # parse command line options | |
613 | while [ $# -gt 0 ] ; do | |
614 | case "$1" in | |
615 | ||
616 | # options | |
617 | --aliroot|-a) | |
618 | aliRootTag="$2" | |
619 | shift 2 | |
620 | ;; | |
621 | --session) | |
622 | sessionTag="$2" | |
623 | shift 2 | |
624 | ;; | |
625 | ||
626 | # actions | |
627 | --launch) | |
628 | # all actions | |
629 | Actions=( PrepareSession MoveToSessionDir LoadConfig InstantiateValidationVM WaitSsh Validate ) | |
630 | shift | |
631 | ;; | |
632 | --prepare) | |
633 | Actions=( PrepareSession MoveToSessionDir ) | |
634 | shift | |
635 | ;; | |
636 | --runvm) | |
637 | Actions=( MoveToSessionDir LoadConfig InstantiateValidationVM ) | |
638 | shift | |
639 | ;; | |
640 | --validate) | |
641 | Actions=( MoveToSessionDir LoadConfig WaitSsh Validate ) | |
642 | shift | |
643 | ;; | |
644 | --attach) | |
645 | Actions=( MoveToSessionDir LoadConfig WaitSsh Attach ) | |
646 | shift | |
647 | ;; | |
648 | ||
649 | # extra actions | |
650 | --shell) | |
651 | Actions=( MoveToSessionDir LoadConfig WaitSsh Shell ) | |
652 | shift | |
653 | ;; | |
654 | --status) | |
655 | Actions=( MoveToSessionDir LoadConfig WaitSsh Status ) | |
656 | shift | |
657 | ;; | |
658 | --help) | |
659 | Help | |
660 | exit 0 | |
661 | ;; | |
662 | ||
4a94e8bb | 663 | # end of options |
664 | --) | |
665 | shift | |
666 | break | |
667 | ;; | |
668 | ||
50881e44 | 669 | *) |
670 | pr "Invalid option: $1. Use --help for assistance." | |
671 | return $errInvalidOpt | |
672 | ;; | |
673 | esac | |
674 | done | |
50881e44 | 675 | |
676 | # check for the presence of the required tools in the $PATH | |
677 | for T in euca-describe-instances euca-describe-regions euca-run-instances euca-create-keypair euca-delete-keypair rsync ; do | |
678 | which "$T" > /dev/null 2>&1 | |
679 | if [ $? != 0 ] ; then | |
680 | pr "Cannot find one of the required commands: $T" | |
681 | return $errMissingCmd | |
682 | fi | |
683 | done | |
684 | ||
685 | # test EC2 credentials | |
686 | # euca-describe-regions > /dev/null 2>&1 | |
687 | # if [ $? != 0 ] ; then | |
688 | # pr 'Cannot authenticate to EC2.' | |
689 | # pr 'Note: you must have at least the following variables properly set in your environment:' | |
690 | # pr " * EC2_URL (current value: ${EC2_URL-<not set>})" | |
691 | # pr " * EC2_ACCESS_KEY (current value: ${EC2_ACCESS_KEY-<not set>})" | |
692 | # pr " * EC2_SECRET_KEY (current value: ${EC2_SECRET_KEY-<not set>})" | |
693 | # return $errEc2Auth | |
694 | # fi | |
695 | ||
696 | # what to do? | |
697 | if [ ${#Actions[@]} == 0 ] ; then | |
698 | pr 'Nothing to do. Use --help for assistance.' | |
699 | return $errInvalidOpt | |
700 | fi | |
701 | ||
702 | # run actions | |
703 | for ((i=0; i<${#Actions[@]}; i++)) ; do | |
704 | ||
705 | A=${Actions[$i]} | |
706 | ||
707 | if [ "$A" == 'PrepareSession' ] ; then | |
708 | # special action returning the session tag | |
709 | if [ "$aliRootTag" == '' ] ; then | |
710 | pr 'Specify an AliRoot version with --aliroot <tag>' | |
711 | return $errInvalidOpt | |
712 | fi | |
713 | if [ "$sessionTag" != '' ] ; then | |
714 | pr 'Cannot use --session with --prepare. Use --help for assistance.' | |
715 | return $errInvalidOpt | |
716 | fi | |
4a94e8bb | 717 | sessionTag=$( RunAction "$A" "$aliRootTag" "$@" ) |
50881e44 | 718 | ret=$? |
719 | else | |
720 | if [ "$sessionTag" == '' ] ; then | |
721 | sessionTag=$( PickSession ) | |
722 | ret=$? | |
723 | [ $ret != 0 ] && return $ret | |
724 | fi | |
725 | RunAction "$A" "$sessionTag" | |
726 | ret=$? | |
727 | fi | |
728 | ||
729 | # 100 to 140 --> not errors | |
730 | ( [ $ret != 0 ] && ( [ $ret -ge 100 ] || [ $ret -le 140 ] ) ) && break | |
731 | ||
732 | done | |
733 | ||
734 | # undo actions | |
735 | let i-- | |
736 | if [ $ret != 0 ] && ( [ $ret -ge 100 ] || [ $ret -le 140 ] ) ; then | |
737 | for ((; i>=0; i--)) ; do | |
738 | RunAction "${Actions[$i]}_Undo" "$sessionTag" | |
739 | done | |
740 | fi | |
741 | ||
742 | # return last value | |
743 | return $ret | |
744 | ||
745 | } | |
746 | ||
747 | # | |
748 | # Entry point | |
749 | # | |
750 | ||
751 | Main "$@" || exit $? |