source: fedkit/splitter.pl @ a835df7

axis_examplecompt_changesinfo-opsversion-1.30version-2.00version-3.01version-3.02
Last change on this file since a835df7 was a835df7, checked in by Ted Faber <faber@…>, 17 years ago

Add more progress printouts via -d or -v
flatten the config filenames to lower case so the hacky hostname trick to find config files works.

  • Property mode set to 100644
File size: 24.2 KB
Line 
1#!/usr/bin/perl
2
3use Getopt::Std;
4use IO::File;
5use IO::Dir;
6use IO::Pipe;
7use File::Copy;
8
9@scripts = ("federate.sh", "smbmount.pl", "make_hosts", "fed-tun.pl");
10$local_script_dir = ".";
11
12# Parse the config file.  The format is a colon-separated parameter name
13# followed by the value of that parameter to the end of the line.  This parses
14# that format and puts the parameters into the referenced hash.  Parameter
15# names are mapped to lower case, parameter values are unchanged.  Returns 0 on
16# failure (e.g. file open) and 1 on success.
17sub parse_config {
18    my($file, $href) = @_;
19    my($fh) = new IO::File($file);
20       
21    unless ($fh) {
22        warn "Can't open $file: $!\n";
23        return 0;
24    }
25
26    while (<$fh>) {
27        next if /^\s*#/ || /^\s*$/;     # Skip comments & blanks
28        chomp;
29        /^([^:]+):\s*(.*)/ && do {
30            my($key) = $1; 
31
32            $key =~ tr/A-Z/a-z/;
33            $href->{$key} = $2;
34            next;
35        };
36        warn "Unparasble line in $file: $_\n";
37    }
38    $fh->close();   # It will close when it goes out of scope, but...
39    return 1;
40}
41
42
43# use scp to transfer a file, reporting true if successful and false otherwise.
44# Parameters are the local file name, the ssh host destination (either hostname
45# oe user@host), and an optional destination file name or directory.  If no
46# destination is given, the file is transferred to the given user's home
47# directory.  If only a machine is given in the ssh host destination, the
48# current user is used.
49sub scp_file {
50    my($file, $where, $dest) = @_;
51
52    # XXX system with a relative pathname is sort of gross
53    system("scp $file $where:$dest");
54    if ($?) {
55        warn "scp failed $?\n";
56        return 0;
57    }
58    else { return 1; }
59}
60
61# use ssh to execute the given command on the machine (and as the user) in
62# $where.  Parameters are the ssh destination directive ($where) and the
63# command to execute, and a prefix to be placed on a message generated if the
64# command fails.   On failure print a warning if a warning prefix was given and
65# return false.
66sub ssh_cmd {
67    my($user, $host, $cmd, $wname) = @_;
68
69    # XXX system with a relative pathname is sort of gross
70    system ("ssh $user\@$host $cmd");
71    if ($?) {
72        warn "$wname failed $?\n" if $wname;
73        return 0;
74    }
75    else { return 1; }
76}
77
78# Ship local copies of the federation scripts out to the given host.  If any of
79# the script transfers fails, return 0.  The scripts to transfer are from the
80# global @scripts and are found locally in $local_script_dir (another global).
81sub ship_scripts {
82    my($host, $user, $dest_dir) = @_;       # Where, who, where remotely
83    my($s);
84
85    &ssh_cmd($user, $host, "mkdir -p $dest_dir");
86    for $s (@scripts) {
87        &scp_file("$local_script_dir/$s", "$user\@$host", $dest_dir) || 
88            return 0;
89    }
90    return 1;
91}
92
93# Ship per-testbed configuration generated by this script to the remote /proj
94# directories on the remote testbeds
95sub ship_configs {
96    my($host, $user, $src_dir, $dest_dir) = @_;     # Where, who, where remotely
97    my($d, $f);
98
99
100    $d = IO::Dir->new($src_dir) || return 0;
101
102    # All directories under $tmpdir are 770 so we can delete them later.
103    &ssh_cmd($user, $host, "mkdir -p $dest_dir") || return 0;
104    &ssh_cmd($user, $host, "chmod 770 $dest_dir") || return 0;
105    while ( $f = $d->read()) {
106        next if $f =~ /^\./;
107        if ( -d "$src_dir/$f" ) {
108            &ship_configs($host, $user, "$src_dir/$f", "$dest_dir/$f") || 
109                return 0;
110        }
111        else {
112            &scp_file("$src_dir/$f", "$user\@$host", $dest_dir) || return 0;
113        }
114    }
115    return 1;
116}
117
118
119
120
121# Start a sub section of the experiment on a given testbed.  The testbed and
122# the user to start the experiment as are pulled from the global per-testbed
123# hash, as is the project name on the remote testbed.  Parameters are the
124# testbed and the experiment id.  Configuration files are scp-ed over to the
125# target testbed from the global $tmpdir/$tb directory.  Then the current state
126# of the experiment determined using expinfo.  From that state, the experiment
127# is either created, modified or spapped in.  If everything succeeds, true is
128# returned.  If the global verbose is set progress messages are printed.
129sub start_segment {
130    my($tb, $eid) = @_;                     # testbed and experiment ID
131    my($host) = "$host{$tb}$domain{$tb}";   # Host name of remote ops (FQDN)
132    my($user) = $user{$tb};                 # user to pass to ssh
133    my($pid) = $project{$tb};               # remote project to start the
134                                            # experiment under
135    my($tclfile) = "./$eid.$tb.tcl";        # Local tcl file with the
136                                            # sub-experiment
137    my($proj_dir) = "/proj/$pid/exp/$eid/tmp";  # Where to stash federation stuff
138    my($to_hostname) = "$proj_dir/hosts";   # remote hostnames file
139    my($status) = new IO::Pipe;             # The pipe to get status
140
141    # Determine the status of the remote experiment
142    $status->reader("ssh $user\@$host /usr/testbed/bin/expinfo $pid $eid") || 
143        die "Can't ssh to $user\@$host:$!\n";
144
145    # XXX: this is simple now.  Parsing may become more complex
146    while (<$status>) {
147        /State: (\w+)/ && ($state = $1);
148        /No\s+such\s+experiment/ && ($state = "none");
149    }
150    $status->close();
151    print "$tb: $state\n";
152
153    # Copy the experiment definition data over
154    print "transferring subexperiment to $tb\n" if $verbose;
155    &scp_file("$tmpdir/$tb/$tclfile", "$user\@$host") || return 0;
156    # Clear out any old experiment data; if not deleted, copies over it by
157    # different users will fail.
158    # (O /bin/csh, how evil thou art.  The -c and the escaped single quotes
159    # force the /bin/sh interpretation of the trailing * (which we need to keep
160    # tmp around))  Again, this needs to be done more properly once we have a
161    # non-ssh interface here.)
162    print "clearing experiment subdirs on $tb\n" if $verbose;
163    &ssh_cmd($user, $host, "/bin/sh -c \\'/bin/rm -rf $proj_dir/*\\'") || 
164        return 0;
165    # Remote experiment is active.  Modify it.
166    if ($state eq "active") {
167        print "Transferring federation support files to $tb\n" if $verbose;
168        # First copy new scripts and hostinfo into the remote /proj
169        &scp_file("$tmpdir/hostnames", "$user\@$host", $to_hostname) ||
170            return 0;
171        &ship_scripts($host, $user, $proj_dir) || return 0;
172        &ship_configs($host, $user, "$tmpdir/$tb", $proj_dir) || return 0;
173
174        print "Modifying $eid in place on $tb\n" if $verbose;
175        &ssh_cmd($user, $host, "/usr/testbed/bin/modexp -r -s -w $pid " . 
176            "$eid $tclfile", "modexp") || return 0;
177        return 1;
178    }
179
180    # Remote experiment is swapped out, modify it and swap it in.
181    if ($state eq "swapped") {
182        print "Transferring federation support files to $tb\n" if $verbose;
183        # First copy new scripts and hostinfo into the remote /proj (because
184        # the experiment exists, the directory tree should be there.
185        &scp_file("$tmpdir/hostnames", "$user\@$host", $to_hostname) ||
186            return 0;
187        &ship_scripts($host, $user, $proj_dir) || return 0;
188        &ship_configs($host, $user, "$tmpdir/$tb", $proj_dir) || return 0;
189
190        print "Modifying $eid on $tb\n" if $verbose;
191        &ssh_cmd($user, $host, "/usr/testbed/bin/modexp -w $pid $eid $tclfile", 
192            "modexp") || return 0;
193        print "Swapping $eid in on $tb\n" if $verbose;
194        # Now start up
195        &ssh_cmd($user, $host, "/usr/testbed/bin/swapexp -w $pid $eid in", 
196            "swapexp") || return 0;
197        return 1;
198    }
199
200    # No remote experiment.  Create one.  We do this in 2 steps so we can put
201    # the configuration files and scripts into the new experiment directories.
202    if ($state eq "none") {
203        print "Creating $exp on $tb\n" if $verbose;
204        &ssh_cmd($user, $host, "/usr/testbed/bin/startexp -f -w -p " . 
205            "$pid -e $eid $tclfile", "startexp") || return 0;
206        print "Transferring federation support files to $tb\n" if $verbose;
207        # First copy new scripts and hostinfo into the remote /proj
208        &scp_file("$tmpdir/hostnames", "$user\@$host", $to_hostname) ||
209            return 0;
210        &ship_scripts($host, $user, $proj_dir) || return 0;
211        &ship_configs($host, $user, "$tmpdir/$tb", $proj_dir) || return 0;
212        # Now start up
213        print "Swapping $eid in on $tb\n" if $verbose;
214        &ssh_cmd($user, $host, "/usr/testbed/bin/swapexp -w $pid $eid in", 
215            "swapexp") || return 0;
216        return 1;
217    }
218
219    # Every branch for a known state returns.  If execution gets here, the
220    # state is unknown.
221    warn "unknown state: $state\n";
222    return 0;
223}
224
225# Swap out a sub-experiment - probably because another has failed.  Arguments
226# are testbed and experiment.  Most of the control flow is similar to
227# start_segment, though much simpler.
228sub stop_segment {
229    my($tb, $eid) = @_;
230    my($user) = "$user{$tb}";
231    my($host) = "$host{$tb}$domain{$tb}";
232    my($pid) = $project{$tb};
233
234    print "Stopping $eid on $tb\n" if $verbose;
235    &ssh_cmd($user, $host, "/usr/testbed/bin/swapexp -w $pid $eid out", 
236        "swapexp (out)") || return 0;
237    return 1;
238}
239
240
241$pid = $gid = "dummy";              # Default project and group to pass to
242                                    # $tcl_splitter above.  These are total
243                                    # dummy arguments;  the splitter doesn't
244                                    # use them at all, but we supply them to
245                                    # keep our changes to the parser minimal.
246# Argument processing.
247getopts('c:f:ndv', \%opts);
248$splitter_config = $opts{'c'} || "./splitter.conf";
249$debug = $opts{'d'};
250$verbose = $opts{'v'} || $opts{'d'};
251
252&parse_config("$splitter_config", \%opts) || 
253    die "Cannot read config file $splitter_conf: $!\n";
254
255
256$startem = $opts{'n'} ? 0 : 1;          # If true, start the sub-experiments
257$eid = $opts{'experiment'};             # Experiment ID
258$tcl = $opts{'f'} || shift;             # The experiment description
259$master = $opts{'master'};              # Master testbed
260$tmpdir = $opts{'tmpdir'} || $opts{'tempdir'}|| "/tmp"; # tmp files
261$tb_config = $opts{'testbeds'} || "./testbeds"; # testbed configurations
262$local_script_dir = $opts{'scriptdir'}; # Local scripts
263
264$smb_share = $opts{'smbshare'} ||       # Share to mount from the master
265    die "Must give an SMB share\n";
266$project_user = $opts{'smbuser'} ||     # User to mount project dirs as
267    die "Must give an SMB user\n";
268
269# For now specify these.  We may want to generate them later.
270$gw_pubkey = $opts{'gatewaypubkey'};
271($gw_pubkey_base = $gw_pubkey) =~ s#.*/##;
272$gw_secretkey = $opts{'gatewaysecretkey'};
273($gw_secretkey_base = $gw_secretkey) =~ s#.*/##;
274
275# tcl program to split experiments (changed during devel)
276$tcl_splitter = $opts{'tclparse'} || "/usr/testbed/lib/ns2ir/parse.tcl";
277# tclsh to call directly (changed during devel)
278$tclsh = $opts{'tclsh'} || "/usr/local/bin/otclsh";
279
280# Prefix to avoid collisions
281$tmpdir .= "/split$$";
282
283print "Temp files are in $tmpdir\n" if $verbose;
284# Create a workspace
285unless (-d "$tmpdir") {
286    mkdir("$tmpdir") || die "Can't create $tmpdir: $!";
287}
288
289# Validate scripts directory
290for $s (@scripts) {
291    die "$local_script_dir/$s not in local script directory. Try -d\n"
292        unless -r "$local_script_dir/$s";
293}
294
295die "Must supply file, master and experiment" unless $master && $tcl && $eid;
296
297# Read a hash of per-testbed parameters from the local configurations.
298$conf = new IO::File($tb_config) || 
299    die "can't read testbed configutions from $tb_config: $!\n";
300while (<$conf>) {
301    next if /^#/;
302    chomp;
303    ($tb, $h, $d, $u, $p, $es, $gs, $mes, $mgs, $t, $i, $fs, $boss, $tun) = 
304        split(":", $_);
305    $host{$tb} = $h;
306    $user{$tb} = $u;
307    $domain{$tb} = $d;
308    $project{$tb} = $p;
309    $gwtype{$tb} = $t;
310    $expstart{$tb} = $es;
311    $gwstart{$tb} = $gs;
312    $mexpstart{$tb} = $mes;
313    $mgwstart{$tb} = $mgs;
314    $gwimage{$tb} = $i;
315    $fs{$tb} = $fs;
316    $boss{$tb} = $boss;
317    $tun{$tb} = $tun;
318
319    # Make sure the domain starts with a period
320    $domain{$tb} = ".$domain{$tb}" unless $domain{$tb} =~ /^\./;
321}
322$conf->close();
323
324# Open a pipe to the splitter program and start it parsing the experiments
325$pipe = new IO::Pipe;
326# NB no more -p call on parse call.
327$pipe->reader("$tclsh $tcl_splitter -s -m $master  $pid $gid $eid $tcl") || 
328    die "Cannot execute $tclsh $tcl_splitter -s -m $master $pid $gid $eid $tcl:$!\n";
329
330# Parse the splitter output.  This loop creates the sub experiments, gateway
331# configurations and hostnames file
332while (<$pipe>) {
333    # Start of a sub-experiment
334    /^#\s+Begin\s+Testbed\s+\((\w+)\)/ && do {
335        $ctb = $1;
336
337        # If we know the testbed, start collecting its sub experiment tcl
338        # description.  If not, warn the caller and ignore the configuration of
339        # this testbed.
340        if ($host{$ctb}) {
341            $allocated{$ctb}++; # Keep track of the testbeds allocated
342
343            unless (-d "$tmpdir/$ctb") {
344                mkdir("$tmpdir/$ctb") || die "Can't create $tmpdir/$ctb: $!";
345            }
346            $destfile = "$tmpdir/$ctb/$eid.$ctb.tcl";
347
348            open(FILE, ">$destfile") || die "Cannot open $destfile:$!\n";
349        }
350        else { 
351            warn "No such testbed $ctb\n";
352            $destfile = "";
353        }
354        next;
355    };
356
357    # End of that experiment
358    /^#\s+End\s+Testbed\s+\((\w+)\)/ && do {
359        # Simple syntax check and close out this experiment's tcl description
360        die "Mismatched testbed markers ($1, $ctb)\n" unless ($1 eq $ctb);
361        close(FILE);
362        $destfile = $ctb = "";
363        next;
364    };
365
366    # Beginning of a gateway set
367    /^#\s+Begin\s+gateways\s+\((\w+)\)/ && do {
368        $gateways = $1;
369        # If we've heard of this tb, create the config lines for it one at a
370        # time.
371        if ($allocated{$gateways}) {
372            # Just in case.  This directory should already have been created
373            # above.
374            unless (-d "$tmpdir/$gateways") {
375                mkdir("$tmpdir/$gateways") || 
376                    die "Can't create $tmpdir/$gateways: $!";
377            }
378        }
379        else {
380            warn "Gateways given (and ignored) for testbed not in use: " .
381                "$gateways\n";
382            $gateways = 0;
383        }
384        next;
385    };
386    # End of the gateways section.  Output the client config for this testbed
387    /^#\s+End\s+gateways\s+\((\w+)\)/ && do {
388        die "Mismatched gateway markers ($1, $gateways)\n" 
389            unless !$gateways || $gateways == $1;
390
391        die "No control gateway for $gateways?" unless $control_gateway;
392        # Client config
393        $cc = new IO::File(">$tmpdir/$gateways/client.conf");
394        die "Can't open $tmpdir/$gateways/client.conf: $!\n" unless $cc;
395        print $cc "ControlGateway: $control_gateway\n";
396        print $cc "SMBShare: $smb_share\n";
397        print $cc "ProjectUser: $project_user\n";
398        $cc->close();
399       
400        $gateways = 0;
401        next;
402    };
403    # Beginning of the hostnames list.  Collection is always in the hostnames
404    # file.
405    /^#\s+Begin\s+hostnames/ && do {
406        $destfile = "$tmpdir/hostnames";
407        open(FILE, ">$destfile") || die "Can't open $destfile:$!\n";
408        next;
409    };
410    # end of the hostnames list.
411    /^#\s+End\s+hostnames/ && do {
412        close(FILE);
413        $destfile = "";
414        next;
415    };
416
417    # Generate gateway configuration info, one file per line
418    $gateways && do {
419        chomp;
420        my($dtb, $myname, $desthost, $type) = split(" ", $_);
421        my($sdomain) = $domain{$gateways};      # domain for the source
422        my($ddomain) = $domain{$dtb};           # domain for the destination
423        my($sproject) = $project{$gateways};    # Project of the destination
424
425        $sdomain = ".$eid.$project{$gateways}$sdomain";
426        $ddomain = ".$eid.$project{$dtb}$ddomain";
427
428        my($conf_file) = "$myname$sdomain.gw.conf";
429        # translate to lower case so the `hostname` hack for specifying
430        # configuration files works.
431        $conf_file =~ tr/A-Z/a-z/;
432
433        # If either end of this link is in the master side of the testbed, that
434        # side is the active end. Otherwise the first testbed encountered in
435        # the file will be the active end.  The $active_end variable keeps
436        # track of those decisions
437        if ( $dtb eq $master ) { $active = "false"; }
438        elsif ($gateways eq $master ) { $active = "true"; }
439        elsif ( $active_end{"$dtb-$gateways"} ) { $active="false"; }
440        else { $active_end{"$gateways-$dtb"}++; $active = "true"; }
441
442        # This is used to create the client configuration.
443        $control_gateway = "$myname$sdomain"
444            if $type =~ /(control|both)/;
445
446        # Write out the file
447        $gwconfig= new IO::File(">$tmpdir/$gateways/$conf_file")|| 
448            die "can't open $tmpdir/$gateways/$conf_file: $!\n";
449
450        print $gwconfig "Active: $active\n";
451        print $gwconfig "TunnelCfg: $tun{$gateways}\n";
452        print $gwconfig "BossName: $boss{$master}$domain{$master}\n";
453        print $gwconfig "FsName: $fs{$master}$domain{$master}\n";
454        print $gwconfig "Type: $type\n";
455        print $gwconfig "Peer: $desthost$ddomain\n";
456        print $gwconfig "Pubkeys: " . 
457            "/proj/$sproject/exp/$eid/tmp/$gw_pubkey_base\n";
458        print $gwconfig "Privkeys: " .
459            "/proj/$sproject/exp/$eid/tmp/$gw_secretkey_base\n";
460        $gwconfig->close();
461
462        # This testbed has a gateway (most will) so make a copy of the keys it
463        # needs in this testbed's subdirectory.  start_segment will transfer
464        # them.
465        unless (-r "$tmpdir/$gateways/$gw_pubkey_base" ) {
466            copy($gw_pubkey, "$tmpdir/$gateways/$gw_pubkey_base") ||
467                die "Can't copy pubkeys ($gw_pubkey to " . 
468                    "$tmpdir/$gateways/$gw_pubkey_base): $!\n";
469        }
470        if ($active eq "true" ) {
471            unless (-r "$tmpdir/$gateways/$gw_secretkey_base" ) {
472                copy($gw_secretkey, "$tmpdir/$gateways/$gw_secretkey_base") ||
473                    die "Can't copy secret keys ($gw_secretkey to " . 
474                        "$tmpdir/$gateways/$gw_secretkey_base): $!\n";
475            }
476        }
477
478        #done processing gateway entry, ready for next line
479        next; 
480    };
481    (/^#\s+Begin\s+tarfiles/../^#\s+End\s+tarfiles/) && do {
482        next if /^#/;
483        chomp;
484        push(@tarfiles, $_);
485        next;
486    };
487
488    next unless $destfile;  # Unidentified testbed, ignore config
489
490    # Substitute variables
491    s/GWTYPE/$gwtype{$ctb}/g;
492    s/GWIMAGE/$gwimage{$ctb}/g;
493    if ($ctb eq $master ) {
494        s/GWSTART/$mgwstart{$ctb}/g;
495        s/EXPSTART/$mexpstart{$ctb}/g;
496    }
497    else {
498        s/GWSTART/$gwstart{$ctb}/g;
499        s/EXPSTART/$expstart{$ctb}/g;
500    }
501    # XXX: oh is this bad
502    s#GWCONF#FEDDIR\`hostname\`.gw.conf#g;
503    s#FEDDIR#/proj/$project{$ctb}/exp/$eid/tmp/#g;
504    print FILE;
505}
506$pipe->close();
507die "No nodes in master testbed ($master)\n" unless $allocated{$master};
508
509for $t (@tarfiles) {
510    die "tarfile '$t' unreadable: $!\n" unless -r $t;
511    for $tb (keys %allocated) {
512        unless (-d "$tmpdir/$tb/tarfiles") {
513            mkdir("$tmpdir/$tb/tarfiles") || 
514                die "Can't create $tmpdir/$tb/tarfiles:$!\n";
515        }
516        copy($t, "$tmpdir/$tb/tarfiles") || 
517                die "Can't copy $t to  $tmpdir/$tb/tarfiles:$!\n";
518    }
519}
520
521exit(0) unless $startem;
522
523# Start up the slave sub-experiments first
524TESTBED:
525for $tb (keys %allocated) {
526    if ($tb ne $master) {
527        if (&start_segment($tb, $eid)) { $started{$tb}++; }
528        else { last TESTBED; }
529    }
530}
531
532# Now the master
533if (&start_segment($master, $eid)) { 
534    $started{$master}++;
535}
536
537# If any testbed failed, swap the rest out.
538if ( scalar(keys %started) != scalar(keys %allocated)) {
539    for $tb (keys %started) { &stop_segment($tb, $eid); }
540    print "Error starting experiment\n";
541    exit(1);
542}
543print "Experiment started\n";
544print "Deleting $tmpdir (-d to leave them in place)\n" if $verbose && !$debug;
545system("rm -rf $tmpdir") unless $debug;
546exit(0);    # set the exit value
547
548=pod
549
550=head1 NAME
551
552B<splitter.pl>
553
554=head1 SYNOPSIS
555
556B<splitter.pl> [B<-nd>] [B<-c> F<config_file>] [B<-f> F<experiment_tcl>]
557    [F<experiment_tcl>]
558
559=head1 DESCRIPTION
560
561B<splitter.pl> invokes the DETER experiment parser to split an annotated
562experiment into multiple sub-experments and instantiates the sub-experiments on
563their intended testbeds.  Annotation is accomplished using the
564tb-set-node-testbed command, added to the parser.
565
566The testbed labels are meaningful based on their presence in the testbeds file.
567that file can be specified in the configuration file using the B<Testbeds>
568directive, and defaults to F<./testbeds>.  The syntax is described below.
569
570Most of the intermediate files are staged in a sub-directory of a temporary
571files directory and deleted at the end of the script.  Specifying the B<-d>
572flag on the command line avoids the deletion for debbugging.  By default the
573temporary files directory is directory is F</tmp> and can be reset in the
574configuration file using the B<Tmpdir> directive.  Intermediate files are
575stored under a subdirectory formed by adding the process ID of the splitter
576process.  For example, if the temporary files directory is F</tmp> and the
577B<splitter.pl> process ID is 2323, the temporary files will be stored in
578F</tmp/split2323/>.
579
580The expreriment is split out into one experiment description per testbed in the
581temporary directory named as F<experiment.testbed.tcl> where the experiment is
582the experiment ID given in the configuration file, and the testbed is the
583tb-set-node-testbed parameter for the nodes in the file.
584
585If the B<-n> option is absent the sub-experiments are then instantiated on
586their testbeds.  (Here B<-n> is analogous to its use in L<make(1)>).
587Per-testbed parameters are set in the testbeds file.  Sub-experiments on
588slave testbeds are instantiated in a random order, but the master testbed is
589currently instantiated last.
590
591Scripts to start federation (the federation kit) are copied into the local
592experiment's tmp file - e.g., F</proj/DETER/exp/simple-split/tmp>.  These are
593taken from the directory given by the B<ScriptDir> directive in the
594configuration file.
595
596If any sub-experiment fails to instantiate, the other sub-exeriments are
597swapped out.
598
599=head2 Configuration File
600
601The configuration file is a simple attribute-value pair set of colon-separated
602parameters and values.  A configuration file must be present, either specified
603in the B<-c> flag or the default F<./splitter.conf>.  All the parameter names
604are case insensitive, but should not include any whitespace.  Parameter values
605may include whitespace, but no newlines.
606
607Possible parameters are:
608
609=over 5
610
611=item Experiment
612
613The name of the experiment on the various testbeds
614
615=item Master
616
617The master testbed label from the testbeds file, described below.
618
619=item Testbeds
620
621The testbeds file described below, giving per-testbed parameters.  If this
622directive is absent the testbeds file defaults to F<./testbeds>
623
624=item ScriptDir
625
626Location of the default federation scripts, i.e. the federation kit.
627
628=item GatewayPubkey
629
630=item GatewaySecretKey
631
632The names of the files containing secret and public keys to use in setting up
633tunnels between testbeds.  These will eventually be automatically generated.
634
635=item TmpDir
636
637=item TempDir
638
639The directory where temporary files are created.  These are synonyms, but
640should both be specified, B<TmpDir> has priority.  If neither is specified,
641F</tmp> is used.
642
643=item SMBShare
644
645The SMB share on the master testbed that will be exported to remote clients.
646
647=item SMBUser
648
649The experiment user to mount project directories as.  This user needs to be a
650member of the exported experiment - that is one of the users in the project
651containing this experiment on the master testbed.
652
653=item Tclparse
654
655The pathname to the experiment parsing program.  Only developers should set
656this.
657
658=item Tclsh
659
660The pathname to the local oTcl shell.  Only developers should set
661this.
662
663=back
664
665=head2 Testbeds file
666
667The configuration file (F<./testbeds> unless overridden by B<-c>) is a
668colon-separated set of parameters keyed by testbed name.  The fields, in order,
669are:
670
671=over 5
672
673=item name
674
675The testbed to which this line of parameters applies.
676
677=item user
678
679The user under which to make requests to this testbed.  The user running
680B<splitter.pl> must be able to authenicate as this user under L<ssh(1)> to this
681testbed.
682
683=item host
684
685The host name of the testbed's ops node.  The user calling B<splitter.pl> must
686be able to execute commands on this host via L<ssh(1)>.
687
688=item domain
689
690The domain of nodes in this testbed (including the ops host).
691
692=item project
693
694The project under which to instantiate sub-experiments on this testbed.
695
696=item gateway type
697
698The node type for inter-testbed gateway nodes on this testbed.
699
700=item experiment start (slave)
701
702The start command to run on experimental nodes when this testbed is used as a
703slave.  In all the start commands the string FEDDIR will be replaced by the
704local experiment's federation scripts directory and the string GWCONF replaced
705by the gatway configuration file.
706
707=item gateway start (slave)
708
709The start command to run on gateway nodes when this testbed is used as a slave.
710The same string substitutions are made in this command as in experiment start.
711
712=item experiment start (master)
713
714The start command to run on experimental nodes when this testbed is used as a
715master.  The same string substitutions are made in this command as in
716experiment start.
717
718=item gateway start (master)
719
720The start command to run on gateway nodes when this testbed is used as a
721master.  The same string substitutions are made in this command as in
722experiment start.
723
724=item gateway image
725
726The disk image to be loaded on a gateway node on this testbed.
727
728=back
729
730The parsing of the testbeds is extremely simple.  Colons separate each
731field and there is n provision for escaping them at this time.
732
733=head1 ENVIRONMENT
734
735B<splitter.pl> does not directly make use of environment variables, but calls
736out to L<ssh(1)> and (indirectly) to L<sh(1)>, which may be influenced by the
737environment.
738
739=head1 SEE ALSO
740
741L<sh(1)>, L<ssh(1)>
742
743=cut
Note: See TracBrowser for help on using the repository browser.