source: fedkit/splitter.pl @ f70f9c8

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

One more filehandle to IO::File and add fed-tun.pl to the scripts list.

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