source: fedkit/splitter.pl @ c8c45ee

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

add script dir

  • 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 "RemoteScriptDir: /proj/$project{$dtb}/exp/$eid/tmp\n";
456        print $gwconfig "Peer: $desthost$ddomain\n";
457        print $gwconfig "Pubkeys: " . 
458            "/proj/$sproject/exp/$eid/tmp/$gw_pubkey_base\n";
459        print $gwconfig "Privkeys: " .
460            "/proj/$sproject/exp/$eid/tmp/$gw_secretkey_base\n";
461        $gwconfig->close();
462
463        # This testbed has a gateway (most will) so make a copy of the keys it
464        # needs in this testbed's subdirectory.  start_segment will transfer
465        # them.
466        unless (-r "$tmpdir/$gateways/$gw_pubkey_base" ) {
467            copy($gw_pubkey, "$tmpdir/$gateways/$gw_pubkey_base") ||
468                die "Can't copy pubkeys ($gw_pubkey to " . 
469                    "$tmpdir/$gateways/$gw_pubkey_base): $!\n";
470        }
471        if ($active eq "true" ) {
472            unless (-r "$tmpdir/$gateways/$gw_secretkey_base" ) {
473                copy($gw_secretkey, "$tmpdir/$gateways/$gw_secretkey_base") ||
474                    die "Can't copy secret keys ($gw_secretkey to " . 
475                        "$tmpdir/$gateways/$gw_secretkey_base): $!\n";
476            }
477        }
478
479        #done processing gateway entry, ready for next line
480        next; 
481    };
482    (/^#\s+Begin\s+tarfiles/../^#\s+End\s+tarfiles/) && do {
483        next if /^#/;
484        chomp;
485        push(@tarfiles, $_);
486        next;
487    };
488
489    next unless $destfile;  # Unidentified testbed, ignore config
490
491    # Substitute variables
492    s/GWTYPE/$gwtype{$ctb}/g;
493    s/GWIMAGE/$gwimage{$ctb}/g;
494    if ($ctb eq $master ) {
495        s/GWSTART/$mgwstart{$ctb}/g;
496        s/EXPSTART/$mexpstart{$ctb}/g;
497    }
498    else {
499        s/GWSTART/$gwstart{$ctb}/g;
500        s/EXPSTART/$expstart{$ctb}/g;
501    }
502    # XXX: oh is this bad
503    s#GWCONF#FEDDIR\`hostname\`.gw.conf#g;
504    s#FEDDIR#/proj/$project{$ctb}/exp/$eid/tmp/#g;
505    print FILE;
506}
507$pipe->close();
508die "No nodes in master testbed ($master)\n" unless $allocated{$master};
509
510for $t (@tarfiles) {
511    die "tarfile '$t' unreadable: $!\n" unless -r $t;
512    for $tb (keys %allocated) {
513        unless (-d "$tmpdir/$tb/tarfiles") {
514            mkdir("$tmpdir/$tb/tarfiles") || 
515                die "Can't create $tmpdir/$tb/tarfiles:$!\n";
516        }
517        copy($t, "$tmpdir/$tb/tarfiles") || 
518                die "Can't copy $t to  $tmpdir/$tb/tarfiles:$!\n";
519    }
520}
521
522exit(0) unless $startem;
523
524# Start up the slave sub-experiments first
525TESTBED:
526for $tb (keys %allocated) {
527    if ($tb ne $master) {
528        if (&start_segment($tb, $eid)) { $started{$tb}++; }
529        else { last TESTBED; }
530    }
531}
532
533# Now the master
534if (&start_segment($master, $eid)) { 
535    $started{$master}++;
536}
537
538# If any testbed failed, swap the rest out.
539if ( scalar(keys %started) != scalar(keys %allocated)) {
540    for $tb (keys %started) { &stop_segment($tb, $eid); }
541    print "Error starting experiment\n";
542    exit(1);
543}
544print "Experiment started\n";
545print "Deleting $tmpdir (-d to leave them in place)\n" if $verbose && !$debug;
546system("rm -rf $tmpdir") unless $debug;
547exit(0);    # set the exit value
548
549=pod
550
551=head1 NAME
552
553B<splitter.pl>
554
555=head1 SYNOPSIS
556
557B<splitter.pl> [B<-nd>] [B<-c> F<config_file>] [B<-f> F<experiment_tcl>]
558    [F<experiment_tcl>]
559
560=head1 DESCRIPTION
561
562B<splitter.pl> invokes the DETER experiment parser to split an annotated
563experiment into multiple sub-experments and instantiates the sub-experiments on
564their intended testbeds.  Annotation is accomplished using the
565tb-set-node-testbed command, added to the parser.
566
567The testbed labels are meaningful based on their presence in the testbeds file.
568that file can be specified in the configuration file using the B<Testbeds>
569directive, and defaults to F<./testbeds>.  The syntax is described below.
570
571Most of the intermediate files are staged in a sub-directory of a temporary
572files directory and deleted at the end of the script.  Specifying the B<-d>
573flag on the command line avoids the deletion for debbugging.  By default the
574temporary files directory is directory is F</tmp> and can be reset in the
575configuration file using the B<Tmpdir> directive.  Intermediate files are
576stored under a subdirectory formed by adding the process ID of the splitter
577process.  For example, if the temporary files directory is F</tmp> and the
578B<splitter.pl> process ID is 2323, the temporary files will be stored in
579F</tmp/split2323/>.
580
581The expreriment is split out into one experiment description per testbed in the
582temporary directory named as F<experiment.testbed.tcl> where the experiment is
583the experiment ID given in the configuration file, and the testbed is the
584tb-set-node-testbed parameter for the nodes in the file.
585
586If the B<-n> option is absent the sub-experiments are then instantiated on
587their testbeds.  (Here B<-n> is analogous to its use in L<make(1)>).
588Per-testbed parameters are set in the testbeds file.  Sub-experiments on
589slave testbeds are instantiated in a random order, but the master testbed is
590currently instantiated last.
591
592Scripts to start federation (the federation kit) are copied into the local
593experiment's tmp file - e.g., F</proj/DETER/exp/simple-split/tmp>.  These are
594taken from the directory given by the B<ScriptDir> directive in the
595configuration file.
596
597If any sub-experiment fails to instantiate, the other sub-exeriments are
598swapped out.
599
600=head2 Configuration File
601
602The configuration file is a simple attribute-value pair set of colon-separated
603parameters and values.  A configuration file must be present, either specified
604in the B<-c> flag or the default F<./splitter.conf>.  All the parameter names
605are case insensitive, but should not include any whitespace.  Parameter values
606may include whitespace, but no newlines.
607
608Possible parameters are:
609
610=over 5
611
612=item Experiment
613
614The name of the experiment on the various testbeds
615
616=item Master
617
618The master testbed label from the testbeds file, described below.
619
620=item Testbeds
621
622The testbeds file described below, giving per-testbed parameters.  If this
623directive is absent the testbeds file defaults to F<./testbeds>
624
625=item ScriptDir
626
627Location of the default federation scripts, i.e. the federation kit.
628
629=item GatewayPubkey
630
631=item GatewaySecretKey
632
633The names of the files containing secret and public keys to use in setting up
634tunnels between testbeds.  These will eventually be automatically generated.
635
636=item TmpDir
637
638=item TempDir
639
640The directory where temporary files are created.  These are synonyms, but
641should both be specified, B<TmpDir> has priority.  If neither is specified,
642F</tmp> is used.
643
644=item SMBShare
645
646The SMB share on the master testbed that will be exported to remote clients.
647
648=item SMBUser
649
650The experiment user to mount project directories as.  This user needs to be a
651member of the exported experiment - that is one of the users in the project
652containing this experiment on the master testbed.
653
654=item Tclparse
655
656The pathname to the experiment parsing program.  Only developers should set
657this.
658
659=item Tclsh
660
661The pathname to the local oTcl shell.  Only developers should set
662this.
663
664=back
665
666=head2 Testbeds file
667
668The configuration file (F<./testbeds> unless overridden by B<-c>) is a
669colon-separated set of parameters keyed by testbed name.  The fields, in order,
670are:
671
672=over 5
673
674=item name
675
676The testbed to which this line of parameters applies.
677
678=item user
679
680The user under which to make requests to this testbed.  The user running
681B<splitter.pl> must be able to authenicate as this user under L<ssh(1)> to this
682testbed.
683
684=item host
685
686The host name of the testbed's ops node.  The user calling B<splitter.pl> must
687be able to execute commands on this host via L<ssh(1)>.
688
689=item domain
690
691The domain of nodes in this testbed (including the ops host).
692
693=item project
694
695The project under which to instantiate sub-experiments on this testbed.
696
697=item gateway type
698
699The node type for inter-testbed gateway nodes on this testbed.
700
701=item experiment start (slave)
702
703The start command to run on experimental nodes when this testbed is used as a
704slave.  In all the start commands the string FEDDIR will be replaced by the
705local experiment's federation scripts directory and the string GWCONF replaced
706by the gatway configuration file.
707
708=item gateway start (slave)
709
710The start command to run on gateway nodes when this testbed is used as a slave.
711The same string substitutions are made in this command as in experiment start.
712
713=item experiment start (master)
714
715The start command to run on experimental nodes when this testbed is used as a
716master.  The same string substitutions are made in this command as in
717experiment start.
718
719=item gateway start (master)
720
721The start command to run on gateway nodes when this testbed is used as a
722master.  The same string substitutions are made in this command as in
723experiment start.
724
725=item gateway image
726
727The disk image to be loaded on a gateway node on this testbed.
728
729=back
730
731The parsing of the testbeds is extremely simple.  Colons separate each
732field and there is n provision for escaping them at this time.
733
734=head1 ENVIRONMENT
735
736B<splitter.pl> does not directly make use of environment variables, but calls
737out to L<ssh(1)> and (indirectly) to L<sh(1)>, which may be influenced by the
738environment.
739
740=head1 SEE ALSO
741
742L<sh(1)>, L<ssh(1)>
743
744=cut
Note: See TracBrowser for help on using the repository browser.