Changeset 9c00d41


Ignore:
Timestamp:
Sep 12, 2007 5:47:56 PM (17 years ago)
Author:
Ted Faber <faber@…>
Branches:
axis_example, compt_changes, info-ops, master, version-1.30, version-2.00, version-3.01, version-3.02
Children:
c9f5490
Parents:
4addf9d
Message:

Mods to generate gateway parameter file and place them in the local project's
/proj hierarchy as well as shipping around the keys required for setup.

Moved to configuration file to avoid remembering all the command line opts.

Moved over to IO:: file handling to stop polluting the global filehandle space.

Updated the docs.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • fedkit/splitter.pl

    r4addf9d r9c00d41  
    22
    33use Getopt::Std;
     4use IO::File;
     5use IO::Dir;
     6use IO::Pipe;
     7use File::Copy;
    48
    59@scripts = ("federate.sh", "smbmount.pl");
    610$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
    742
    843# use scp to transfer a file, reporting true if successful and false otherwise.
     
    5489    return 1;
    5590}
     91
     92# Ship per-testbed configuration generated by this script to the remote /proj
     93# directories on the remote testbeds
     94sub ship_configs {
     95    my($host, $user, $src_dir, $dest_dir) = @_;     # Where, who, where remotely
     96    my($d, $f);
     97
     98    $d = IO::Dir->new($src_dir) || return 0;
     99
     100    while ( $f = $d->read()) {
     101        next if $f =~ /^\./;
     102        &scp_file("$src_dir/$f", "$user\@$host", $dest_dir) || return 0;
     103    }
     104    return 1;
     105}
     106
    56107
    57108
     
    75126    my($proj_dir) = "/proj/$pid/exp/$eid/tmp";  # Where to stash federation stuff
    76127    my($to_hostname) = "$proj_dir/hosts";   # remote hostnames file
     128    my($status) = new IO::Pipe;             # The pipe to get status
    77129
    78130    # Determine the status of the remote experiment
    79     open(STATUS, "ssh $user\@$host /usr/testbed/bin/expinfo $pid $eid|") ||
     131    $status->reader("ssh $user\@$host /usr/testbed/bin/expinfo $pid $eid") ||
    80132        die "Can't ssh to $user\@$host:$!\n";
     133
    81134    # XXX: this is simple now.  Parsing may become more complex
    82     while (<STATUS>) {
     135    while (<$status>) {
    83136        /State: (\w+)/ && ($state = $1);
    84137        /No\s+such\s+experiment/ && ($state = "none");
    85138    }
    86     close(STATUS);
     139    $status->close();
    87140    print "$tb: $state\n";
    88141
     
    95148            return 0;
    96149        &ship_scripts($host, $user, $proj_dir) || return 0;
     150        &ship_configs($host, $user, "$tmpdir/$tb", $proj_dir) || return 0;
    97151        &ssh_cmd($user, $host, "/usr/testbed/bin/modexp -r -s -w $pid " .
    98152            "$eid $tclfile", "modexp") || return 0;
     
    107161        &scp_file("./hostnames", "$user\@$host", $to_hostname) || return 0;
    108162        &ship_scripts($host, $user, $proj_dir) || return 0;
     163        &ship_configs($host, $user, "$tmpdir/$tb", $proj_dir) || return 0;
    109164        # Now start up
    110165        &ssh_cmd($user, $host, "/usr/testbed/bin/swapexp -w $pid $eid in",
     
    121176        &scp_file("./hostnames", "$user\@$host", $to_hostname) || return 0;
    122177        &ship_scripts($host, $user, $proj_dir) || return 0;
     178        &ship_configs($host, $user, "$tmpdir/$tb", $proj_dir) || return 0;
    123179        # Now start up
    124180        &ssh_cmd($user, $host, "/usr/testbed/bin/swapexp -w $pid $eid in",
     
    147203}
    148204
    149 # tcl program to split experiments
    150 # $tcl_splitter = "/usr/testbed/lib/ns2ir/parse.tcl";
    151 $tcl_splitter = "/users/faber/testbed/tbsetup/ns2ir/parse.tcl";
    152 $tclsh = "/usr/local/bin/otclsh";   # tclsh to call directly
    153205
    154206$pid = $gid = "dummy";              # Default project and group to pass to
     
    157209                                    # use them at all, but we supply them to
    158210                                    # keep our changes to the parser minimal.
    159 
    160211# Argument processing.
    161 getopts('d:c:m:e:f:nt:', \%opts);
    162 
    163 $eid = $opts{'e'};                  # Experiment ID
    164 $tcl = $opts{'f'} || shift;         # The experiment description
    165 $master = $opts{'m'};               # Master testbed
    166 $startem = $opts{'n'} ? 0 : 1;      # If true, start the sub-experiments
    167 $tmpdir = $opts{'t'} || "/tmp";             # where to collect tmp files
    168 $config = $opts{'c'} || "./testbeds";
    169 $local_script_dir = $opts{'d'};     # Local scripts
    170 
     212getopts('c:f:nd', \%opts);
     213$splitter_config = $opts{'c'} || "./splitter.conf";
     214$debug = $opts{'d'};
     215&parse_config("$splitter_config", \%opts) ||
     216    die "Cannot read config file $splitter_conf: $!\n";
     217
     218
     219$startem = $opts{'n'} ? 0 : 1;          # If true, start the sub-experiments
     220$eid = $opts{'experiment'};             # Experiment ID
     221$tcl = $opts{'f'} || shift;             # The experiment description
     222$master = $opts{'master'};              # Master testbed
     223$tmpdir = $opts{'tmpdir'} || $opts{'tempdir'}|| "/tmp"; # tmp files
     224$tb_config = $opts{'testbeds'} || "./testbeds"; # testbed configurations
     225$local_script_dir = $opts{'scriptdir'}; # Local scripts
     226# For now specify these.  We may want to generate them later.
     227$gw_pubkey = $opts{'gatewaypubkey'};
     228($gw_pubkey_base = $gw_pubkey) =~ s#.*/##;
     229$gw_secretkey = $opts{'gatewaysecretkey'};
     230($gw_secretkey_base = $gw_secretkey) =~ s#.*/##;
     231
     232# tcl program to split experiments (changed during devel)
     233$tcl_splitter = $opts{'tclparse'} || "/usr/testbed/lib/ns2ir/parse.tcl";
     234# tclsh to call directly (changed during devel)
     235$tclsh = $opts{'tclsh'} || "/usr/local/bin/otclsh";
     236
     237# Prefix to avoid collisions
    171238$tmpdir .= "/split$$";
    172239
     240# Create a workspace
    173241unless (-d "$tmpdir") {
    174242    mkdir("$tmpdir") || die "Can't create $tmpdir: $!";
    175243}
    176244
    177 
     245# Validate scripts directory
    178246for $s (@scripts) {
    179247    die "$local_script_dir/$s not in local script directory. Try -d\n"
     
    184252
    185253# Read a hash of per-testbed parameters from the local configurations.
    186 open(CONF, $config) || die "can't read testbed configutions from $config: $!\n";
    187 while (<CONF>) {
     254$conf = new IO::File($tb_config) ||
     255    die "can't read testbed configutions from $tb_config: $!\n";
     256while (<$conf>) {
    188257    next if /^#/;
    189258    chomp;
     
    203272    $domain{$tb} = ".$domain{$tb}" unless $domain{$tb} =~ /^\./;
    204273}
    205 close(CONF);
     274$conf->close();
    206275
    207276# Open a pipe to the splitter program and start it parsing the experiments
    208 open(PIPE, "$tclsh $tcl_splitter -s -m $master -p $pid $gid $eid $tcl|") ||
     277$pipe = new IO::Pipe;
     278$pipe->reader("$tclsh $tcl_splitter -s -m $master -p $pid $gid $eid $tcl") ||
    209279    die "Cannot execute $tclsh $tcl_splitter -s -p $pid $gid $eid $tcl:$!\n";
    210280
    211 # Parse the splitter output.
    212 while (<PIPE>) {
     281# Parse the splitter output.  This loop creates the sub experiments, gateway
     282# configurations and hostnames file
     283while (<$pipe>) {
    213284    # Start of a sub-experiment
    214285    /^#\s+Begin\s+Testbed\s+\((\w+)\)/ && do {
     
    290361        my($sdomain) = $domain{$gateways};      # domain for the source
    291362        my($ddomain) = $domain{$dtb};           # domain for the destination
     363        my($sproject) = $project{$gateways};    # Project of the destination
    292364
    293365        $sdomain = ".$eid.$project{$gateways}$sdomain";
     
    305377        # Write out the file
    306378        open(GWCONFIG, ">$tmpdir/$gateways/$myname$sdomain.gw.conf") ||
    307             die "can't open $tmpdir/%gateways/$myname$sdomain.gw.conf: $!\n";
     379            die "can't open $tmpdir/$gateways/$myname$sdomain.gw.conf: $!\n";
    308380        print GWCONFIG "Active: $active\n";
    309381        print GWCONFIG "Type: $type\n";
    310382        print GWCONFIG "Peer: $desthost$ddomain\n";
    311         print GWCONFIG "Pubkeys: /placeholder\n";
    312         print GWCONFIG "Privkeys: /placeholder\n";
     383        print GWCONFIG "Pubkeys: " .
     384            "/proj/$sproject/exp/$eid/tmp/$gw_pubkey_base\n";
     385        print GWCONFIG "Privkeys: " .
     386            "/proj/$sproject/exp/$eid/tmp/$gw_secretkey_base\n";
    313387        close(GWCONFIG);
     388
     389        # This testbed has a gateway (most will) so make a copy of the keys it
     390        # needs in this testbed's subdirectory.  start_segment will transfer
     391        # them.
     392        unless (-r "$tmpdir/$gateways/$gw_pubkey_base" ) {
     393            copy($gw_pubkey, "$tmpdir/$gateways/$gw_pubkey_base") ||
     394                die "Can't copy pubkeys ($gw_pubkey to " .
     395                    "$tmpdir/$gateways/$gw_pubkey_base): $!\n";
     396        }
     397        if ($active eq "true" ) {
     398            unless (-r "$tmpdir/$gateways/$gw_secretkey_base" ) {
     399                copy($gw_secretkey, "$tmpdir/$gateways/$gw_secretkey_base") ||
     400                    die "Can't copy secret keys ($gw_secretkey to " .
     401                        "$tmpdir/$gateways/$gw_secretkey_base): $!\n";
     402            }
     403        }
    314404
    315405        #done processing gateway entry, ready for next line
     
    336426    print FILE;
    337427}
    338 close(PIPE);
     428$pipe->close();
    339429die "No nodes in master testbed ($master)\n" unless $allocated{$master};
    340430
     
    362452}
    363453print "Experiment started\n";
     454system("rm -rf $tmpdir") unless $debug;
    364455exit(0);    # set the exit value
    365456
     
    372463=head1 SYNOPSIS
    373464
    374 B<splitter.pl> B<-e> I<experiment> B<-m> I<master_testbed> [B<-n>]
    375     [B<-d> F<script_dir>] [B<-c> F<config_file>] [B<-f> F<experiment_tcl>]
     465B<splitter.pl> [B<-nd>] [B<-c> F<config_file>] [B<-f> F<experiment_tcl>]
    376466    [F<experiment_tcl>]
    377467
     
    384474
    385475The testbed labels are meaningful based on their presence in the testbeds file.
    386 that file can be specified with the B<-c> option, and defaults to
    387 F<./testbeds>.  The syntax is described below.
     476that file can be specified in the configuration file using the B<Testbeds>
     477directive, and defaults to F<./testbeds>.  The syntax is described below.
     478
     479Most of the intermediate files are staged in a sub-directory of a temporary
     480files directory and deleted at the end of the script.  Specifying the B<-d>
     481flag on the command line avoids the deletion for debbugging.  By default the
     482temporary files directory is directory is F</tmp> and can be reset in the
     483configuration file using the B<Tmpdir> directive.  Intermediate files are
     484stored under a subdirectory formed by adding the process ID of the splitter
     485process.  For example, if the temporary files directory is F</tmp> and the
     486B<splitter.pl> process ID is 2323, the temporary files will be stored in
     487F</tmp/split2323/>.
    388488
    389489The expreriment is split out into one experiment description per testbed in the
    390 current directory named as F<experiment.testbed.tcl> where the experiment is
    391 the argument to B<-e> and the testbed is the tb-set-node-testbed parameter for
    392 the nodes in the file.
     490temporary directory named as F<experiment.testbed.tcl> where the experiment is
     491the experiment ID given in the configuration file, and the testbed is the
     492tb-set-node-testbed parameter for the nodes in the file.
    393493
    394494If the B<-n> option is absent the sub-experiments are then instantiated on
    395495their testbeds.  (Here B<-n> is analogous to its use in L<make(1)>).
    396 Per-testbed parameters are set in the configuration file.  Sub-experiments on
     496Per-testbed parameters are set in the testbeds file.  Sub-experiments on
    397497slave testbeds are instantiated in a random order, but the master testbed is
    398498currently instantiated last.
    399499
    400 Scripts to start federation are copied into the local experiment's tmp file -
    401 e.g., F</proj/DETER/exp/simple-split/tmp>.  These are taken from the directory
    402 given by the B<-d> option.
     500Scripts to start federation (the federation kit) are copied into the local
     501experiment's tmp file - e.g., F</proj/DETER/exp/simple-split/tmp>.  These are
     502taken from the directory given by the B<ScriptDir> directive in the
     503configuration file.
    403504
    404505If any sub-experiment fails to instantiate, the other sub-exeriments are
    405506swapped out.
    406507
    407 =head2 Configuration file
     508=head2 Configuration File
     509
     510The configuration file is a simple attribute-value pair set of colon-separated
     511parameters and values.  A configuration file must be present, either specified
     512in the B<-c> flag or the default F<./splitter.conf>.  All the parameter names
     513are case insensitive, but should not include any whitespace.  Parameter values
     514may include whitespace, but no newlines.
     515
     516Possible parameters are:
     517
     518=over 5
     519
     520=item Experiment
     521
     522The name of the experiment on the various testbeds
     523
     524=item Master
     525
     526The master testbed label from the testbeds file, described below.
     527
     528=item Testbeds
     529
     530The testbeds file described below, giving per-testbed parameters.  If this
     531directive is absent the testbeds file defaults to F<./testbeds>
     532
     533=item ScriptDir
     534
     535Location of the default federation scripts, i.e. the federation kit.
     536
     537=item GatewayPubkey
     538
     539=item GatewaySecretKey
     540
     541The names of the files containing secret and public keys to use in setting up
     542tunnels between testbeds.  These will eventually be automatically generated.
     543
     544=item TmpDir
     545
     546=item TempDir
     547
     548The directory where temporary files are created.  These are synonyms, but
     549should both be specified, B<TmpDir> has priority.  If neither is specified,
     550F</tmp> is used.
     551
     552=item Tclparse
     553
     554The pathname to the experiment parsing program.  Only developers should set
     555this.
     556
     557=item Tclsh
     558
     559The pathname to the local oTcl shell.  Only developers should set
     560this.
     561
     562=back
     563
     564=head2 Testbeds file
    408565
    409566The configuration file (F<./testbeds> unless overridden by B<-c>) is a
     
    443600
    444601The start command to run on experimental nodes when this testbed is used as a
    445 slave.
     602slave.  In all the start commands the string FEDDIR will be replaced by the
     603local experiment's federation scripts directory and the string GWCONF replaced
     604by the gatway configuration file.
    446605
    447606=item gateway start (slave)
    448607
     608The start command to run on gateway nodes when this testbed is used as a slave.
     609The same string substitutions are made in this command as in experiment start.
     610
     611=item experiment start (master)
     612
     613The start command to run on experimental nodes when this testbed is used as a
     614master.  The same string substitutions are made in this command as in
     615experiment start.
     616
     617=item gateway start (master)
     618
    449619The start command to run on gateway nodes when this testbed is used as a
    450 slave.
    451 
    452 =item experiment start (master)
    453 
    454 The start command to run on experimental nodes when this testbed is used as a
    455 master.
    456 
    457 =item gateway start (master)
    458 
    459 The start command to run on gateway nodes when this testbed is used as a
    460 master.
     620master.  The same string substitutions are made in this command as in
     621experiment start.
    461622
    462623=item gateway image
     
    466627=back
    467628
    468 The parsing of the configuration is extremely simple.  Colons separate each
     629The parsing of the testbeds is extremely simple.  Colons separate each
    469630field and there is n provision for escaping them at this time.
    470631
Note: See TracChangeset for help on using the changeset viewer.