source: fedkit/splitter.pl @ 838fb6a

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

getting hostnames from the current directory - should be from tmpdir

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