Table of Contents
Slides from the morning session are online.
These notes have been written to lead you through the exercises on your own and provide commands to type, expected output and notes highlighting the key aspects of a particular step. Feel free to ask the TAs for help if you have any problems or have any questions.
These notes have transcripts from a machine called
iwr-gks-globus01.fzk.de. You might be
using a different machine, in which case you should be careful to replace
iwr-gks-globus01.fzk.de with the name of the machine
you are logged in to.
The exercise notes was prepared by running as user
train99.
Replace that with your actual username in all command line parameters.
You will see various styles of text in the tutorial notes.
Text like this represents output from your computer.
Text like this is input that you should type.
Text like this is a listing of the content of a file, such as a program will will need to type in.
We assume you're using the default "bash" shell set up on your logins on the laptops and lab servers. We recommend you don't change your shell.
You will be doing all the lab exercises on a set of Linux computers
("hosts") named iwr-gks-globus01 and
iwr-gks-globus02 (its "fully qualified
host name" looks like "iwr-gks-globus01.fzk.de"). From these machines, we will
run Grid jobs and explore various Grid sites.
To access iwr-gks-globus01
from your computer, use secure shell.
On a Windows machine, use the PuTTY program. Open PuTTY and enter the hostname of the computer that you will use.
On a Mac, use the Terminal and ssh command-line tool. Open Terminal and type:
$ssh train99@iwr-gks-globus01.fzk.deThe authenticity of host 'iwr-gks-globus01.fzk.de (141.52.174.160)' can't be established. RSA key fingerprint is 36:74:78:a8:ed:6b:38:96:63:20:01:df:46:9b:59:3b. Are you sure you want to continue connecting (yes/no)?Note
Make sure to replace the login name with your login name, as assigned by the instructors.yesWarning: Permanently added 'iwr-gks-globus01.fzk.de,141.52.174.160' (RSA) to the list of known hosts. train99@iwr-gks-globus01.fzk.de's password:PASSWORD# not echoed iwr-gks-globus01$Note
Now you're talking to a shell on the iwr-gks-globus01 server
After the first time you do this, you won't get the "Are you sure..." prompt.
$ssh train99@iwr-gks-globus01.fzk.dePassword:PASSWORDiwr-gks-globus01$
You should be able to reach the other lab host
iwr-gks-globus02.fzk.de in this way too.
To start, practice cutting text from this page in your web browser to run a command or set of commands: cut the pwd command from the box below and paste it into your terminal window to execute it. This is a good way to avoid making typos while entering commands from the examples.
$ pwd
/home/train99
In order to do things (like submit jobs or transfer data) on the grid, you need a grid proxy. A grid proxy contains everything necessary to authenticate you to grid resources. You will do more with grid security in the security lab, later on.
We have given each training account a proxy that will work on many grid systems. You can check this with the grid-proxy-info command.
iwr-gks-globus01.fzk.de$ grid-proxy-info
subject : /DC=org/DC=doegrids/OU=People/CN=OSG Education student 37 789564/CN=1558914057
issuer : /DC=org/DC=doegrids/OU=People/CN=OSG Education student 37 789564
identity : /DC=org/DC=doegrids/OU=People/CN=OSG Education student 37 789564
type : Proxy draft (pre-RFC) compliant impersonation proxy
strength : 512 bits
path : /tmp/x509up_u1048
timeleft : 98:42:47 (4.1 days)
Look at the timeleft field. This tells you how much time this proxy will be valid for. Check that there is some time left on your proxy. (When this proxy has expired, you will no longer be able to use the grid, and you will have to get a new proxy)
Now, if everything is set correctly, you should be able to run "Grid jobs" on the hosts in the lab Grid. Run a 'hello world' test like this:
iwr-gks-globus01$ globusrun-ws -submit -s -job-command /bin/echo Hello World
Delegating user credentials...Done.
Submitting job...Done.
Job ID: uuid:c9eae254-1111-11dc-b480-001558a1e39c
Termination time: 06/03/2007 14:01 GMT
Current job state: Active
Current job state: CleanUp-Hold
Hello World
Current job state: CleanUp
Current job state: Done
Destroying job...Done.
Cleaning up any delegated credentials...Done.You've just submitted a job (the Linux command echo) to run on iwr-gks-globus01.fzk.de. This is a simple building block that will lead to more powerful things.
The globusrun-ws utility runs commands on remote sites, but it expects them to be fully qualified path names (i.e., they must start with a "/"). Lets say we want to run the Linux command hostname on the remote site to verify that we're talking to the resource we think we are.
Run it locally to make sure you are invoking it correctly.
Use the command which to discover the location of the version of hostname that you are using. It will return a fully-qualified path name.
iwr-gks-globus01$hostnameiwr-gks-globus01.fzk.de iwr-gks-globus01$which hostname/bin/hostname
This tells you that to run hostname via
globusrun-ws, use /bin/hostname.
Use which to discover the location of the following commands on the system:
Now run hostname remotely, on iwr-gks-globus02.fzk.de, to verify that you really are reaching a remote system:
iwr-gks-globus01$ globusrun-ws -submit -F iwr-gks-globus02.fzk.de -s -job-command /bin/hostname Next, see what else can you learn about the remote system with this approach.
Discover what user ID your job ran under using id.
Discover what environment variables are set using env.
Discover the load on the remote Grid server using uptime.
Discover the default working directory in which your remote job will run using pwd.
Do an ls of this working directory.
Use df to discover how much storage space exists in this working directory.
Use df to discover how much storage space
exists in the remote /tmp
directory.
Can you create a file on the remote system?
Can you remove it?
GRAM, the Globus component for running remote jobs, supports the concept of a job manager as an adapter to local job management environments. Each Grid site - or collection of resources - can support one or more such job managers. The fork job manager runs a job immediately through the UNIX fork() interface. Another job manager we have installed on the lab hosts acts as an interface to the Condor batch scheduling system.
Which do you think will be faster? Lets find out: use the command time to test which jobmanager is faster.
To time a command, enter time :
commandname
iwr-gks-globus01$ time sleep 3
real 0m3.007s <------ this line is the interesting output
user 0m0.004s
sys 0m0.000s
time told us that the command sleep 3 took 3.007 seconds to execute. That sounds about right - 3 seconds of sleep plus a little bit of overhead.
Now time a few trivial Grid jobs to compare Fork and Condor, like this:
iwr-gks-globus01$time globusrun-ws -submit -factory-type Fork -s -job-command /bin/hostname[...] iwr-gks-globus01$time globusrun-ws -submit -factory-type Condor -s -job-command /bin/hostname
You should have seen that the fork job manager ran faster than the condor job manager. It has low scheduling latency, so it runs trivial commands very quickly. But it also has no compute power - fork jobs run on the head node of the resource that you are submitting to.
A batch job manager like condor, on the other hand, has a higher scheduling overhead, but usually gives you access to all computers in a cluster, and the opportunity to do real parallel computing. You may have to wait longer to get access to a resource but when you do, you will often have more computing power available.
While our lab hosts use the Condor scheduler, other systems use other schedulers. For example, systems using Portable Batch System(PBS) require that you specify -factory-type PBS.
Now try running a few jobs through condor on a different machine:
iwr-gks-globus01$ globusrun-ws -submit -F iwr-gks-globus02.fzk.de -factory-type Condor -s -job-command /bin/hostname
Next try starting five such jobs on iwr-gks-globus02 at once: put an "&" at the end of the line, and either use cut-and-past, or shell command history, or a simple shell script to run five of these commands at once.
Now we'll create a simple application and send the application to run on remote Grid sites.
Our application will be called genr and will be a script to generate fixed-width pseudo-random numbers.
#! /bin/sh
NLINES=$1
NDIGITS=$2
awk "BEGIN {
for (i = 0 ; i < $NLINES; i++ ) {
print int(rand() * 10^$NDIGITS )
}
}"Using copy/paste, copy the script above into a new file named
genr.
Save the file in your home directory on iwr-gks-globus01.
Make the genr script executable:
iwr-gks-globus01$ chmod +x genrTest the script by running it locally. Your genr script should behave like this:
iwr-gks-globus01$ ./genr 5 8 # 5 lines of 8 digits
23778751
29106573
84581385
15220829
58553734
$Test genr under globusrun-ws to make sure it runs locally through GRAM:
iwr-gks-globus01$ globusrun-ws -submit -s -job-command /home/train99/genr 5 5
23773
29102
84589
15225
58553
$We ran genr on iwr-gks-globus01 but using the fork jobmanager of GRAM.
Try to execute genr on iwr-gks-globus02.fzk.de from iwr-gks-globus01.fzk.de:
iwr-gks-globus01$ globusrun-ws -submit -F iwr-gks-globus02.fzk.de -s \
-job-command /home/train99/genr 5 4It doesn't work!
What happens? Why doesn't this work?
The command will fail because the genr program is not installed on iwr-gks-globus02. We have only installed it on iwr-gks-globus01. In the next steps, we'll use Globus to copy the script to iwr-gks-globus02 so that it can be used there too.
Now we introduce a new command, globus-url-copy, that can be used to copy files between grid nodes:
iwr-gks-globus01$globus-url-copy file:///home/train99/genr \ gsiftp://iwr-gks-globus02.fzk.de/home/train99/iwr-gks-globus01$globusrun-ws -submit -F iwr-gks-globus02.fzk.de -s \ -job-command /bin/chmod +x /home/train99/genr
Now try running the genr submission again. Does it work now? (It should)
Can you run the same application on tg-grid.uc.teragrid.org? Which steps above do you need to do? What do you need to change from the above to make them work with tg-grid.uc.teragrid.org?
Create some files of different sizes, to use for exercises:
$dd if=/dev/zero of=smallfile-train99 bs=1M count=10$dd if=/dev/zero of=mediumfile-train99 bs=1M count=50$ls -shtotal 62M 51M mediumfile-train99 11M smallfile-train99
Use globus-url-copy to move your small file from your home directory on iwr-gks-globus01.fzk.de to your home directory on iwr-gks-globus02.fzk.de.
iwr-gks-globus01$globus-url-copy file:///home/train99/smallfile-train99 gsiftp://iwr-gks-globus02.fzk.de/home/train99/ex1iwr-gks-globus01$echo $?0
The echo $? checks to see what the return value was for the previous command. If you see a 0 (zero), then globus-url-copy succeeded. A different number indicates a problem. In that case you should also see an error message.
See how fast the file transfer is happening by using the -vb flag when copying the medium file. Since this is a transfer over a local network that should not be too busy it should be fairly quick:
iwr-gks-globus01$ globus-url-copy -vb file:///home/train99/mediumfile-train99 gsiftp://iwr-gks-globus02.fzk.de/home/train99/ex1
Source: file:///home/train99/
Dest: gsiftp://iwr-gks-globus02.fzk.de/home/train99/
mediumfile-train99 -> ex1
207618048 bytes 8.81 MB/sec avg 9.09 MB/sec instThere are two numbers given - the average transfer speed (over the whole transfer so far) and the instantaneous speed.
If the transfer is very fast, then no statistics will be printed. This is because the statistics are measured using performance markers which are transmitted periodically during a long transfer. If the transfer is very short, then there is not enough time for any performance markers to be sent.
Now try transferring a file to a remote site. This example uses tg-grid.uc.teragrid.org as the remote site. However, there are various other sites that you could use - the instructors can tell you.
First you will need some scratch space on the remote system. You can create a working directory in your remote home directory.
iwr-gks-globus01$ globus-job-run tg-grid.uc.teragrid.org /bin/mkdir /home/etrain99/dataNow copy the file over to this directory:
iwr-gks-globus01$ globus-url-copy -vb file:///home/train99/smallfile-train99 gsiftp://tg-grid.uc.teragrid.org/home/etrain99/ex1
Source: file:///home/train99/smallfile
Dest: gsiftp://tg-grid.uc.teragrid.org/home/etrain99/
mediumfile-train99 -> ex1
208666624 bytes 1.41 MB/sec avg 1.43 MB/sec instYou will probably find that the transfer rate is much lower than when copying to local machines.
You can try copying to other sites in addition to tg-grid.uc.teragrid.org. Remember that you might need to make a scratch directory on each one, and that the place for this will be different for each site.
A quick reminder on URL formats: We've seen two kind of URLs so far.
file:///home/train99/mediumfile - a file called mediumfile on the local file system, in directory /home/train99/.
gsiftp://tg-grid.uc.teragrid.org/scratch/train99/ - a directory accessible via gsiftp on the host called tg-grid.uc.teragrid.org in directory /scratch/train99.
Trying using 4 parallel data streams by adding the -p flag with an argument of 4.
Use the following globus-url-copy command to transfer the file from iwr-gks-globus01.fzk.de to the tg-grid.uc.teragrid.org:
iwr-gks-globus01$ globus-url-copy -p 4 -vb file:///home/train99/smallfile-train99 gsiftp://tg-grid.uc.teragrid.org/home/etrain99/data/ex1Experiment with transferring different file sizes and numbers of parallel streams, to both local and remote sites and see how the speed varies.
Next try a third-party transfer. You do this by specifying two gsiftp URLs, instead of one gsiftp URL and one file URL.
globus-url-copy will control the transfers but data will not pass through the local machine. Instead, it will go directly between the source and destination machines.
Transfer a file between two remote sites, and see if it is faster than if you had transferred it to iwr-gks-globus01.fzk.de and then back out again.
Try to make up a command line for this yourself - you should use two gsiftp URLs, instead of a file url and a gsiftp URL.
Next use RFT, the Reliable File Transfer service, to transfer a block of files between two sites.
First, create a transfer job file, which lists some RFT parameters and all of the files to transfer. You can get an example from iwr-gks-globus01.fzk.de:/sw/misc/example.rft. Read through this and change the URLs at the end to refer to your files.
You can list as many source and destination URLs as you want in a transfer file.
The RFT command and transfer job file reference is available here.
This example lists three transfers: mediumfile will be transfered three times, once each to iwr-gks-globus02.fzk.de, once to tg-grid.uc.teragrid.org, and once to another host on the grid.
When you have prepared your transfer file, you can start the transfers using the rft command. This client will periodically output transfer status, with a count of files in each of five states - Finished, Active, Failed, Retrying, Pending. You can watch jobs move from the Pending state, to the Active state and then to the Finished state. If there is a problem, some jobs will end up in the Failed state instead.
$cp /sw/misc/example.rft rft.xfr$vi rft.xfr... make your changes ... $rft -h iwr-gks-globus01.fzk.de -f ./rft.xfrNumber of transfers in this request: 3 Subscribed for overall status Termination time to set: 60 minutes Overall status of transfer: Finished/Active/Failed/Retrying/Pending 0/1/0/0/2 Overall status of transfer: Finished/Active/Failed/Retrying/Pending 1/0/0/0/2 Overall status of transfer: Finished/Active/Failed/Retrying/Pending 1/1/0/0/1 Overall status of transfer: Finished/Active/Failed/Retrying/Pending 2/0/0/0/1 Overall status of transfer: Finished/Active/Failed/Retrying/Pending 2/1/0/0/0 Overall status of transfer: Finished/Active/Failed/Retrying/Pending 3/0/0/0/0 All Transfers are completed
Initally all jobs start in the pending state, move to active state and then hopefully to finished state (but maybe fail, in which case they go to the failed state).
The transfer file has a number of options. You can experiment changing them. Interesting ones to try:
Add more URLs to transfer
Transfer between two remote sites
Use parallel streams
Increase the transfer concurrency
In particular you should check that you understand the difference between parallel streams (the number of streams used when transferring one file) and concurrency (the number of files that can be transferred at once).
The above sections have dealt with moving data around, and always made the assumption that you knew where the files you wanted were located.
Next we will deal with the Replica Location Service (RLS), which helps finding the location of files on the Grid.
$ globus-rls-admin -p rls://iwr-gks-globus01.fzk.de
ping rls://iwr-gks-globus01.fzk.de: 0 secondsFirst perform a simple query for an example logical filename that has been placed in the RLS by the instructors:
$globus-rls-cli rls://iwr-gks-globus01.fzk.derls>query lrc lfn exampleexample: gsiftp://iwr-gks-globus01.fzk.de/scratch/example example: gsiftp://iwr-gks-globus02.fzk.de/scratch/example
This queries for a logical filename example. The results show that this file can be retrieved via either of two URLs (one in scratch space on iwr-gks-globus01.fzk.de, and one in scratch space on iwr-gks-globus02.fzk.de).
Now try querying for logical filename another-example.
You can also publish your own logical filename into the RLS, with mappings to physical files, using the create command:
rls> create train99-first-lfn gsiftp://iwr-gks-globus01.fzk.de/home/train99/largefile-train99This creates an LFN called train99-first-lfn and then adds a mapping to gsiftp://iwr-gks-globus01.fzk.de/home/train99/largefile-train99.
rls> query lrc lfn train99-first-lfn
train99-first-lfn: gsiftp://iwr-gks-globus01.fzk.de/home/train99/largefile-train99Now copy largefile to another place (on another gridlab machine or on one of the remote sites), and register it into the RLS, with the same LFN. You will need to use the add command instead of the create command, because the LFN already exists and you just need to add a new mapping.
Get a neighbour to query the RLS for your logical filename, and see that the mappings you have made are public for everyone to see.
So far, you have only been using the RLS server on iwr-gks-globus01.fzk.de. There are servers running on other machines.
Use globus-rls-admin to ping the RLS server on iwr-gks-globus02.fzk.de and check that it is online.
Then, connect to one of the other servers using globus-rls-cli and query for the example LFN that we used above. You should see that there are some other locations from which you can get the example file.
Try adding your own LFN into one of the other servers, using globus-rls-cli.
So far, you have interacted with the Local Replica Catalog on each installation. This is where LFNs and mappings are created.
RLS has another component, called a Replica Location Index. This gathers information from several LRCs, so that you can find LFN mappings from all of those LRCs in one place.
There is an RLI on iwr-gks-globus01.fzk.de that gathers information from all of the tutorial LRCs.
You can query it like this:
rls>query rli lfn examplerls>query rli lfn exampleexample: rls://iwr-gks-globus01.fzk.de:39281
What comes back from the RLI is not a list of physical files. Instead, it is a list of LRCs that have some information about the requested LFN.
To find all the replicas, you need to query all of the listed LRCs in turn. In the above paste, only iwr-gks-globus01.fzk.de is listed. During the tutorial, you will hopefully find that other LRCs also know some information about example LFN.
Although it may not happen immediately, the RLIs will also learn about the logical filenames that you have created for yourself.
Query the RLI to see if the logical names that you added above have appeared in the RLI. If they haven't yet, wait a while and try again.
Next use the -S option to check the status/statistics of each of the two servers. You should see output similar to that below:
$ globus-rls-admin -S rls://iwr-gks-globus01.fzk.de
Version: 2.1.5
Uptime: 00:28:15
LRC stats
update method: lfnlist
update method: bloomfilter
updates bloomfilter: rls://iwr-gks-globus02.fzk.de:39281 last 06/21/04 22:44:45
lfnlist update interval: 86400
bloomfilter update interval: 900
numlfn: 1
numpfn: 1
nummap: 1
RLI stats
updated by: rls://iwr-gks-globus02.fzk.de:39281 last 06/21/04 22:44:35
updated via bloomfilters
globus-rls-admin -S rls://gk2
Version: 2.1.5
Uptime: 00:32:33
LRC stats
update method: lfnlist
update method: bloomfilter
updates bloomfilter: rls://iwr-gks-globus02.fzk.de:39281 last 06/21/04 22:44:40
lfnlist update interval: 86400
bloomfilter update interval: 900
numlfn: 2
numpfn: 2
nummap: 2
RLI stats
updated by: rls://iwr-gks-globus02.fzk.de:39281 last 06/21/04 22:44:49
updated via bloomfiltersA valid certificate was already installed for you and configuration was set up to use it. In this step we will attempt to get a new certificate from Globus Certificate Service. Globus Certificate Service(GCS) is a web-based CA service that issues certificates.
These are not secure certificates since anyone can obtain certificates from this CA and are generally used for testing. But since an infrastructure needs to trust a CA for anyone to use the certificate issued by the CA, issuing such certificates doesn't pose any security threat. For instance the certificates you obtain from this CA can be used to submit jobs or transfer files on the server running on your local machine, but will fail if you submit jobs on the remote cluster, since the cluster does not trust GCS CA.
First create a certificate request using grid-cert-request.
iwr-gks-globus01$ grid-cert-request
Enter your name, e.g., John Smith: Trainee 31
A certificate request and private key is being created.
You will be asked to enter a PEM pass phrase.
This pass phrase is akin to your account password,
and is used to protect your key file.
If you forget your pass phrase, you will need to
obtain a new certificate.
Generating a 1024 bit RSA private key
..........++++++
...............++++++
writing new private key to '/home/train31/userkey.pem'
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
...
A private key and a certificate request has been generated with the subject:
/C=US/O=Globus Alliance/OU=User/CN=Trainee 31
If the CN=Trainee 31 is not appropriate, rerun this
script with the -force -cn "Common Name" options.
Your private key is stored in /home/train31/userkey.pem
Your request is stored in /home/train31/usercert_request.pem
The command will ask for a pass phrase and this is used to encrypt the private key. The -dir option stores the created certificates in the specified directory. This is so that we don't overwrite the certificates in the default directory.
$ ls -lt ~/.globus/
total 8
-rw-r--r-- 1 train31 train31 1322 Jun 23 10:10 usercert_request.pem
-r-------- 1 train31 train31 963 Jun 23 10:10 userkey.pem
-rw-r--r-- 1 train31 train31 0 Jun 23 10:10 usercert.pem
$
The .globus directory has three files:
usercert_request.pem: the request that the CA needs to sign.
userkey.pem: the file with encrypted private key. Note the permissions on the file.
usercert.pem: a place holder for the signed certificate obtained from the CA. It currently has a zero file size.
Now submit the request for GCS to sign, using a web browser.
In your browser, go to the Globus Certificate Service.
Click Acquiring User Certificate under Available Services. The first two steps have already been completed: the CA certificate has been installed on your machine
Choose the second option, Paste the certificate request text in the box below.
Open usercert_request.pem, copy its complete contents and paste them into the text box:
iwr-gks-globus01$ cat ~/.globus/usercert_request.pem
[...]
-----BEGIN CERTIFICATE REQUEST-----
MIIBpjCCAQ8CAQAwNDENMAsGA1UEChMER3JpZDEMMAoGA1UECxMDT1NHMRUwEwYD
[...]
/ve+Ws+XSLITorDHmnAM+QDOFOkiQV5UKU63Cw+bXQnNIRembVFj2ek8
-----END CERTIFICATE REQUEST-----
iwr-gks-globus01$
The service will return the signed certificate.
Copy the contents from ----BEGIN CERTIFICATE---- to ----END CERTIFICATE---- into usercert.pem
Use the grid-proxy-init command to create proxies.
$grid-proxy-init -verifyYour identity: /O=Grid/OU=OSG/CN=Training User 99 Enter GRID pass phrase for this identity:PASSWORDCreating proxy .......................................... Done Your proxy is valid until: Fri Jun 23 22:00:10 2006 [train99 ~]$
The proxy is created using the user certificate and key.
The passphrase is used to decrypt the private key file.
The -verify option is not required, but is
useful for debugging. -verify will warn you if an
expected Certificate Authority (CA) certificate
is missing.
Use grid-proxy-info to show information about your proxy.
Use the -all parameter to display information your proxy:
[train99 ~]$ grid-proxy-info -all
subject : /O=Grid/OU=OSG/CN=Training User 99/CN=203360020
issuer : /O=Grid/OU=OSG/CN=Training User 99
identity : /O=Grid/OU=OSG/CN=Training User 99
type : Proxy draft (pre-RFC) compliant impersonation proxy
strength : 512 bits
path : /tmp/x509up_u539
timeleft : 11:58:58Grid Proxy Variables
subjectThe distingushed name (DN) from the certificate, appended with a uniqe string of numbers.
issuer The distinguished name of the user certificate itself.
pathThe file system location where the your proxy is stored.
timeleftHow much longer the proxy will be valid, in hours, minutes and seconds.
As you can see, the issuer of the grid certificate is the user certificate. This shows the chain of trust: CA -> user certificate -> proxy certificate.
The proxy certificate contains the private key generated for proxy, correspnding public key and is signed like a certificate by the user certificate.
Now list the contents of the proxy using grid-cert-info, specifying the full path to your proxy.
$ grid-cert-info -file /path/to/proxy/proxyFileName
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 203360020 (0xc1f0714)
Signature Algorithm: md5WithRSAEncryption
Issuer: C=US, O=SDSC, OU=SDSC, CN=Account Train31/UID=train31
Validity
Not Before: Jun 23 14:55:10 2006 GMT
Not After : Jun 24 03:00:10 2006 GMT
Subject: C=US, O=SDSC, OU=SDSC, CN=Account Train31/UID=train31, CN=203360020
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public Key: (512 bit)
Modulus (512 bit):
00:b8:75:e3:a4:3c:31:9e:b9:71:e8:b0:4e:fc:18:
69:e6:79:15:90:f4:0f:49:20:f0:e3:62:9f:e2:92:
d0:96:4c:9b:b5:97:12:b3:bd:87:c7:8c:2f:bb:b0:
fe:79:8c:3d:61:5e:49:f6:c1:46:e1:1e:08:d1:d7:
89:a0:e3:8a:f3
Exponent: 65537 (0x10001)
X509v3 extensions:
1.3.6.1.4.1.3536.1.222: critical
0.0
..+.......
Signature Algorithm: md5WithRSAEncryption
45:05:52:c7:9f:a7:35:32:d9:a8:be:58:92:a7:b0:61:e4:7a:
2a:a2:36:0f:eb:65:0e:0f:ca:40:3d:0e:27:8b:38:14:a6:af:
51:7d:28:2f:ac:3e:3e:05:7b:ea:d6:0e:fc:78:7d:eb:60:80:
6a:74:43:64:ef:ca:e8:25:fe:d3:07:a9:4d:e0:54:4a:75:9f:
c9:8e:9a:1e:82:19:a4:fc:72:a3:6f:0d:de:33:57:d8:f8:cd:
da:d2:bc:8a:ee:48:34:4b:00:3e:7e:b7:5e:66:fa:2e:5c:22:
4a:50:98:02:32:c6:e3:a9:07:b7:bb:e6:4d:02:e8:6c:d4:48:
5e:55:ec:ed:a9:38:ee:b8:33:60:88:c1:ab:38:ce:d8:53:a3:
ac:c3:a2:c1:d8:1e:95:5b:e5:3a:3f:d1:e0:51:c2:5e:82:e0:
a4:48:d3:e6:82:66:56:d9:6b:e0:a5:1e:85:4d:3d:d7:e0:4e:
03:ce:f7:5a:63:cd:5c:9a:38:96:59:0f:92:11:6b:eb:ed:34:
1a:55:73:e1:c0:b0:91:ea:b4:1e:3b:8d:0f:2d:53:83:10:98:
44:19:ac:39:6d:1a:6b:37:90:60:6a:35:9b:c6:41:2e:5a:ef:
ae:54:6c:9e:51:b8:68:c2:97:83:2f:72:25:df:90:b9:bc:31:
92:23:45:77
[train99 ~]$ The contents are similar to your user certificate, but there are some differences; for example, the issuer is the DN of the user certificate, rather than of the certificate authority.
grid-cert-info is useful to see how long your proxy certificate will last (the Not Before and Not After lines under Validity).
By default your user certificate and corresponding user key
are installed in ~/.globus and
called usercert.pem and userkey.pem. Unless
overriden explicitly, the clients use these credentials.
iwr-gks-globus01$ ls -lt ~/.globus/
total 12
-rw------- 1 train99 train99 1743 Jun 22 16:45 userkey.pem
-rw------- 1 train99 train99 5011 Jun 22 16:37 usercert.pem
iwr-gks-globus01$
The userkey.pem is the file containing encrypted private key. The permissions on that file are very restrictive - only the owner can read or write to that file.
The usercert.pem is the certificate, containing the public key. This file is not encrypted and can be distributed freely.
This shows the an example of a certificate's contents. You can show the contents of your certificate using the grid-cert-info command:
$ grid-cert-info -f ~/.globus/usercert.pem
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 923 (0x39b)
Signature Algorithm: md5WithRSAEncryption
Issuer: C=US, O=SDSC, OU=SDSC-CA, CN=Certificate Authority/UID=certman
Validity
Not Before: Jun 22 00:46:02 2006 GMT
Not After : Jul 2 00:46:02 2006 GMT
Subject: C=US, O=SDSC, OU=SDSC, CN=Account Train99/UID=train99
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public Key: (2048 bit)
Modulus (2048 bit):
00:af:93:40:80:ce:14:68:d6:6c:67:89:45:0c:3e:
30:98:38:35:c9:bd:b5:08:00:17:4c:e1:fb:38:50:
bd:97:f5:41:92:e7:6e:c4:6f:dc:ad:52:2c:e0:2a:
54:83:79:45:fb:5d:e2:f5:a5:cf:42:94:45:98:22:
d9:5b:81:93:e2:46:5f:e0:7f:71:5f:2d:b0:4a:82:
21:7d:f2:41:f7:b6:33:eb:59:93:f1:71:e3:79:ea:
c0:1b:5e:07:c6:d5:c2:67:41:56:73:d8:1f:a3:fb:
32:4b:f5:96:9f:65:f5:0a:f0:28:d5:90:d6:b0:dc:
4b:29:85:aa:8b:b7:d5:c0:f3:45:28:f9:af:80:7a:
88:40:40:21:60:ea:14:cd:8a:8e:53:40:67:c5:47:
51:bc:95:76:1e:90:b0:ee:ee:41:5a:ec:d4:4c:3c:
ea:eb:2f:f1:55:82:d8:b2:36:d9:92:88:bd:b6:93:
eb:46:69:3b:3a:e2:15:54:82:c0:30:4b:a9:54:3c:
af:52:4e:a5:71:40:a1:58:21:2e:ab:6d:c4:7c:59:
5d:68:b6:95:80:0e:12:91:51:90:0e:38:84:3f:de:
07:99:43:86:a1:0f:70:01:2f:3c:bf:e3:47:b2:16:
67:eb:00:6b:c4:7d:d8:e5:39:77:ac:29:cc:76:94:
2b:d3
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Basic Constraints:
CA:FALSE
Netscape Cert Type:
SSL Client, S/MIME, Object Signing
Netscape Comment:
OpenSSL Generated Certificate
Netscape CA Revocation Url:
http://www.sdsc.edu/CA/SDSC_CRL.pem
X509v3 Subject Key Identifier:
E1:E3:C9:6E:A6:CF:2C:FC:D3:B7:51:F6:03:66:98:C5:18:71:60:F8
X509v3 Authority Key Identifier:
keyid:BF:A3:87:2C:F6:0D:74:BD:48:6C:0E:27:BF:01:E4:F2:4F:46:BA:27
DirName:/C=US/O=SDSC/OU=SDSC-CA/CN=Certificate Authority/UID=certman
serial:00
Signature Algorithm: md5WithRSAEncryption
93:b2:78:07:d9:72:e2:71:d7:66:83:0c:d3:97:0c:9e:24:33:
4e:e3:48:28:9c:44:7e:31:13:70:cc:f8:4a:5d:bc:64:84:3e:
aa:fa:da:86:3f:5e:f8:4a:72:a1:59:57:5a:89:49:5a:2d:c9:
09:5c:a5:69:6e:65:f7:85:8b:07:57:f1:6a:cb:6e:e5:00:17:
5d:02:0a:b5:52:6f:92:93:5b:94:c3:84:59:66:f4:29:f1:6a:
a2:ff:eb:5d:6a:89:43:1a:82:cf:d7:66:d3:f6:f6:b6:ba:45:
02:ec:60:86:88:00:4d:09:53:fc:7e:a7:cd:71:d8:ff:72:4f:
36:1f:15:b1:af:ca:d3:8c:ac:4c:1b:99:5a:de:98:7a:81:22:
c3:c3:3f:65:04:06:b7:5b:de:1a:65:f1:69:74:51:67:bc:0d:
d2:00:cd:f0:c1:b2:c1:12:ba:6a:30:01:4c:98:fe:7a:bb:a8:
d8:1e:61:39:9f:c4:c3:f4:f5:ba:be:43:13:75:84:fe:82:93:
a9:00:3e:35:75:60:f7:8c:68:58:74:ed:27:c6:99:49:a8:e4:
c0:27:32:1f:5c:b0:06:ed:63:d7:f7:79:89:11:d2:4e:5d:31:
33:6e:d4:fd:90:51:4b:65:29:c6:6c:68:55:e6:2d:41:6a:c1:
58:2b:f4:d3
You specified a specific credential. Try the same command
with -help to look at other options. We will use some
later in the exercise.
The Issuer DN is the distinguished name (DN) of the Certificate Authority who issues the certificate.
The certificate has validity times that indicate over which time period the certificate is valid. This is usually around a year for regular certificates.
Subject is the distinguished name that this certificate is bound to.
Key information is the public key.
The CA generates a digest of the key and other binding information (validity, DN and so on) and signs it. The signature is included at the end of the cerificate.
The algorithm used to generate digest and sign is important information, since the same algorithms should be applied at verification.
The client globus-url-copy can be used to transfer files on the grid. It uses the GridFTP server to transfer the files. This requires that the client who is requesting transfer have valid credentials and be authorized to the transfer. We will go into authorization step later, for now you are already authorized, so lets try the client.
Destroy your proxy with the grid-proxy-destroy. Ignore any errors.
Run the following commands to set the environment variables. This will ensure that the certificate and key are used, since by default _globus-url-copy_ uses proxy certificates.
$export X509_USER_CERT=.globus/usercert.pem$export X509_USER_KEY=.globus/userkey.pem
Create a temporary file containing some text. You can use some text editor (e.g., vi) to create it and add some contents. For example:
$ cat tempFile
Temporary file for testing globus-url-copy
$
Try to use globus-url-copy to move the file.
[train99@gridlab1 ~]$ globus-url-copy gsiftp://localhost:2811/home/train99/tempFile
gsiftp://localhost:2811/home/train99/destFile
error: globus_ftp_control: gss_init_sec_context failed
globus_gsi_gssapi: Error with gss credential handle
globus_credential: Valid credentials could not be found in any of the possible locations
specified by the credential search order.
Valid credentials could not be found in any of the possible locations specified by the
credential search order.
Attempt 1
globus_credential: Error reading host credential
globus_sysconfig: Error with certificate filename
globus_sysconfig: Error with certificate filename
globus_sysconfig: File is not owned by current user: /etc/grid-security/hostcert.pem is not
owned by current user
Attempt 2
globus_credential: Error reading proxy credential
globus_sysconfig: Could not find a valid proxy certificate file location
globus_sysconfig: Error with key filename
globus_sysconfig: File does not exist: /tmp/x509up_u502 is not a valid file
Attempt 3
globus_credential: Error reading user credential
globus_credential: Key is password protected: GSI does not currently support password
protected private keys.
OpenSSL Error: pem_lib.c:401: in library: PEM routines, function PEM_do_header: bad
password read
[train99 ~]$
The client first attempts to authenticate with the server, to prove its identity. To do that it needs valid credentials. The command attempts to use host credentials. Second, it attempts to use a proxy, which does not exist. Last, it attempts to use your user credentials. The command failed since the private key is encrypted.
A real, live person will be required each time to enter the passphrase. To alleviate the problems associated with this, that is to sign on once and run numerous time, we use proxies.
Unset variables to use default locations.
[train99 ~]$unset X509_USER_CERT[train99 ~]$unset X509_USER_KEY[train99 ~]$
Globus services (for example, GRAM and GridFTP) use a
grid mapfile located in /etc/grid-security/grid-mapfile on
each server.
This file is write protected so only administrators can change it to give access. But the file can be read by anyone.
You can look at the gridmap file on iwr-gks-globus01 like this:
[train99@iwr-gks-globus01.fzk.de ~]$ cat /etc/grid-security/grid-mapfile
#
# Automatically generated by gx-gen-mapfile (gx-map 0.5.1)
# at Fri 2006-06-23 15:26:02 UTC on iwr-gks-globus01.fzk.de.
# DO NOT EDIT THIS FILE. ANY CHANGES YOU MAKE WILL BE LOST ON THE NEXT UPDATE.
#
"/C=US/O=Globus Alliance/OU=User/CN=101497d3dcd.3dcd5aef" ranantha
"/C=US/O=Globus Alliance/OU=User/CN=10bd8f410f6.5f0086b4" benc
"/C=US/O=Globus Alliance/OU=User/CN=10bf234e01a.ac286cfa" ranantha
"/C=US/O=SDSC/OU=SDSC/CN=Account Train10/UID=train10" train10
"/C=US/O=SDSC/OU=SDSC/CN=Account Train11/UID=train11" train11
"/C=US/O=SDSC/OU=SDSC/CN=Account Train12/UID=train12" train12
...
"/C=US/O=SDSC/OU=SDSC/CN=Account Train58/UID=train58" train58
"/C=US/O=SDSC/OU=SDSC/CN=Account Train59/UID=train59" train59
"/C=US/O=SDSC/OU=SDSC/CN=Account Train60/UID=train60" train60
"/DC=org/DC=doegrids/OU=People/CN=Gaurang Mehta 998137" gmehta
Grid mapfiles can be created by system administrators by hand or using a number of tools. In this workshop, the grid mapfile is maintained by a tool called gx-map.
Only the listed DNs are allowed to access Globus services running on iwr-gks-globus01.
Each entry is a mapping from DN to username. For example, DN /O=Grid/OU=OSG/CN=Training User 99 is mapped to usename train99.
Typically an administrator is required to add users to the gridmap file and is an out of band activity. The tool gx-request, if set up by the admnistator, can be used by anyone who has access to a machine to add an identity to the gridmap file. The actual addition is not instant and will take a few minutes to appear in the gridmap file.
[train99@iwr-gks-globus01.fzk.de ~]$gx-request -quick-addAbout to map distinguished name "/C=US/O=SDSC/OU=SDSC/CN=Account Train55/UID=train99" to user train99 Proceed? [yn]yMapping request submitted. The grid-mapfile should be updated in a few minutes [train99@iwr-gks-globus01.fzk.de ~]$
This update will take a few minutes. You can look for the update by searching the gridmap file for your DN.
[train99@iwr-gks-globus01.fzk.de ~]$grep "/O=Grid/OU=OSG/CN=Training User 99" /etc/grid-security/grid-mapfile[train99@iwr-gks-globus01.fzk.de ~]$grep "/O=Grid/OU=OSG/CN=Training User 99" /etc/grid-security/grid-mapfile"/O=Grid/OU=OSG/CN=Training User 99" train99 [train99@iwr-gks-globus01.fzk.de ~]$
To get grid access to iwr-gks-globus02 with your new credential, you have to do something similar there.
First, let us get the DN we want mapped on the remote machine.
[train99@iwr-gks-globus01.fzk.de ~]$ grid-proxy-info -identity
/O=Grid/OU=OSG/CN=Training User 99
The output needs to be pasted in the command you run on remote machine.
Open an ssh connection to iwr-gks-globus02.fzk.de and run gx-request there.
iwr-gks-globus02$gx-request -interactiveThe gx-request command lets you submit a request to modify the Globus grid-mapfile(s) on one or more machines. Once the request is submitted, the updates should occur within a few minutes. A grid-mapfile entry maps a DN (Distinguished Name) to a Unix user name. For example, an entry like "/O=Big University/OU=Small Department/CN=John Doe" jdoe allows a user holding a Globus certificate with the specified DN to run Globus jobs under the Unix account "jdoe". gx-request can be run interactively or with command-line arguments. In this interactive mode, you will be asked a series of questions. Enter your responses followed by >return>. Single-letter menu responses are case-insensitive; other responses must be entered exactly. enter it by just typing >return>. (a) Add a grid-mapfile entry (r) Remove a grid-mapfile entry (u) Request an update of the grid-mapfiles (x) Exit (The "set" operation is not currently available in interactive mode.) What do you want to do? [arux]aYou can specify the DN in one of the following ways: (c) Certificate, extract from /home/train99/.globus/usercert.pem (f) File, extract from a specified certificate file (i) Input the DN directly (x) Exit How do you want to specify the DN? [cfix]iEnter distinguished name:/O=Grid/OU=OSG/CN=Training User 99You may provide your e-mail address if you wish. It will be recorded in the request log, and may be used to contact you if there is a problem with your certificate. E-mail address (>return> for none): You may provide an optional comment. If you do, it will be recorded in the request log. Press return if you don't wish to provide a comment. Comment: About to map distinguished name "/O=Grid/OU=OSG/CN=Training User 99" to user train99 Proceed? [yn]yMapping request submitted. The grid-mapfile should be updated in a few minutes
The update takes a few minutes.
[train99 ~]$globus-url-copy gsiftp://localhost:2811/home/train99/tempFile gsiftp://localhost:2811/home/train99/destFile[train99 ~]$ls -lt destFilerw-r--r-- 1 train99 train99 43 Jun 23 10:04 destFile [train99 ~]$more destFileTemporary file for testing globus-url-copy [train99 ~]$
globus-url-copy picks up the proxy from the default location and uses that to authenticate with the GridFTP server. Authentication establishes your identity. Note that the identity in proxy certificate is still your certificate's identity.
Upon successful authentication, the server knows the client is who it claims to be. It then checks to see if the identity to authorized to transfer files and uses grid map authorization to determine this. We have already set up the gridmap to allow your identity. You will learn more about this later in the exercise.
By default, grid-proxy-init creates a proxy valid for 12 hours. However, the duration of a proxy can be specified on the command line.
[train99 ~]$dateFri Jun 23 10:06:01 CDT 2006 [train99 ~]$grid-proxy-init -valid 0:1Your identity: /O=Grid/OU=OSG/CN=Training User 99 Enter GRID pass phrase for this identity: Creating proxy ........................................ Done Your proxy is valid until: Fri Jun 23 10:07:10 2006 [train99 ~]$grid-proxy-infosubject : /O=Grid/OU=OSG/CN=Training User 99/CN=24915772 issuer : /O=Grid/OU=OSG/CN=Training User 99 identity : /O=Grid/OU=OSG/CN=Training User 99 type : Proxy draft (pre-RFC) compliant impersonation proxy strength : 512 bits path : /tmp/x509up_u539 timeleft : 0:00:52 [train99 ~]$
The proxy requested was for 1 minute. grid-proxy-info shows the valid time left. You should see it is just less than a minute. If you run grid-proxy-info again, you should see it is even shorter. Eventually it will reach 0.
Wait for your proxy to expire. You can check this by watching the timeleft field in the output of grid-proxy-info and waiting for it to reach zero.
Now you have a proxy, but the proxy is invalid because it has expired.
$dateFri Jun 23 10:07:35 CDT 2006 $grid-proxy-infosubject : /O=Grid/OU=OSG/CN=Training User 99/CN=24915772 issuer : /O=Grid/OU=OSG/CN=Training User 99 identity : /O=Grid/OU=OSG/CN=Training User 99 type : Proxy draft (pre-RFC) compliant impersonation proxy strength : 512 bits path : /tmp/x509up_u539 timeleft : 0:00:00 $globus-url-copy gsiftp://localhost:2811/home/train99/tempFile gsiftp://localhost:2811/home/train99/expiredTesterror: globus_ftp_control: gss_init_sec_context failed globus_gsi_gssapi: Error with GSI credential globus_gsi_gssapi: Error with gss credential handle globus_credential: Error with credential: The proxy credential: /tmp/x509up_u539 with subject: /O=Grid/OU=OSG/CN=Training User 99/CN=24915772 expired 1 minutes ago. $ls -lt expiredTestls: expiredTest: No such file or directory
The error indicates that the proxy file has expired. So the client was not able to successfully authenticate with server and the file was not transfered.
[train99@iwr-gks-globus01.fzk.de ~]$ globus-url-copy gsiftp://localhost:2811/home/train99/tempFile gsiftp://iwr-gks-globus01.fzk.de:2811/tmp/train99TestFile
error: globus_ftp_client: the server responded with an error
535 535-FTPD GSSAPI error: GSS Major Status: Authentication Failed
535-FTPD GSSAPI error: GSS Minor Status Error Chain:
[...]
[train99@iwr-gks-globus01.fzk.de ~]$ The above error indicates that the authentication failed because the credential that you have just acquired is not trusted on iwr-gks-globus01.fzk.de. The proxy is valid, but it is not trusted on that specific machine.
Now lets try running the same command using the DOEGrids proxy to transfer file with in local cluster. This cluster has been set up to trust the DOEGrids CA. In this example iwr-gks-globus01.fzk.de is local machine and iwr-gks-globus01.fzk.de is remote machine.
[train99@iwr-gks-globus01.fzk.de ~]$ globus-url-copy gsiftp://localhost:2811/home/train99/tempFile gsiftp://iwr-gks-globus01.fzk.de:2811/tmp/train99Test
error: globus_ftp_client: the server responded with an error
530 530-Login incorrect. :
globus_gss_assist: Gridmap lookup failure:
Could not map /C=US/O=Globus Alliance/OU=User/CN=10c00791bfb.54294d53
530-
530 End.
[train99@iwr-gks-globus01.fzk.de ~]$
The transfer fails here with authorization exceptions.
The client authenticated with the server and the server established your identity as the DN specified in the error message. In this case:
/C=US/O=Globus Alliance/OU=User/CN=10c00791bfb.54294d53
But the identity established in authentication is not authorized to use the service. The service uses GridMap authorization, where a mapping of of authorized identities (DNs) is mapped to local user names.
Now that the gridmap file has been updated such that your identity is authorized to submit jobs, lets try the command again.
[train99@iwr-gks-globus01 ~]$ globus-url-copy gsiftp://localhost:2811/home/train99/tempFile gsiftp://iwr-gks-globus01.fzk.de.:2811/tmp/train99Test
[train99@iwr-gks-globus01 ~]$ The client authenticated succesfully with the server. So the server knows the identity of the client. A handshake occured between the client and server to establish a "context", which is a secret key used to secure the message.
The request and response was then signed using that context, so that it cannot be tampered with.
We can explicitly request for this message to be encrypted, so that no one else can read it. Then the same context is used to encrypt the message.
To ensure the transfer occured, lets ssh to remote machine and look for file:
[train99@iwr-gks-globus01 ~]$ssh iwr-gks-globus01.fzk.de[train99@iwr-gks-globus02 ~]$ls -lt /tmp/train99Test-rw-r--r-- 1 train99 train99 43 Jun 23 12:07 /tmp/train99Test [train99@iwr-gks-globus02 ~]$
Now we will look at implementing a grid application. This application is often used as an example for workflow systems, but we will try to do it with globus tools.
In the application, we will take a number of fMRI brain scans which have resulted in 3-d volume data, combine them to produce an average brain (also a 3-d volume) and then take 2-d slices through that brain volume to give some different viws of that brain.
There are five applications: align_warp reslice softmean slicer and convert.
There are ten input files, in pairs:
anatomy1.img anatomy1.hdr anatomy2.img anatomy2.hdr anatomy3.img anatomy3.hdr anatomy4.img anatomy4.hdr reference.img reference.hdr
The workflow is this:
1. Align each anatomy pair with the reference pair, using align_warp.
2. Slice the results using reslice, giving two output files per pair.
3. Average the files into a single data file pair (atlas) using softmean
4. Slice the atlas in three different ways, along the X, Y and Z axes.
5. Convert the slices into JPEG format.
The data files and applications are installed on a machine called workshop4.ci.uchicago.edu. You can access this machine using grid protocols but you cannot log in directly.
The data files are in /sw/workflow/data/ on workshop4.ci.uchicago.edu:
root@workshop4:~# ls /sw/workflow/data/ anatomy1.hdr anatomy2.hdr anatomy3.hdr anatomy4.hdr reference.hdr anatomy1.img anatomy2.img anatomy3.img anatomy4.img reference.img
This is where the application executables live on workshop4:
align_warp /sw/workflow/app/AIR/bin/align_warp reslice /sw/workflow/app/AIR/bin/reslice softmean /sw/workflow/app/softmean-swift slicer /sw/workflow/app/slicer-swift convert /usr/bin/convert
Here are some example command-lines that you will need to execute through globus:
align_warp reference.img anatomy1.img warp1.warp -m 12 -q # 4 times, once for each anatomy image reslice warp1.warp resliced1.img # 4 times softmean atlas.img y null resliced1.img resliced2.img resliced3.img resliced4.img # once slicer atlas.img -x .5 atlas-x.pgm # 3 times, for x, y and z convert atlas-x.pgm atlas-x.jpeg # 3 times, once for each sliced image
You must implement the workflow in the picture above - use globusrun-ws to run the necessary commands on workshop4 and then copy the final jpeg files back to gridka to view them.
You will need to copy all of the data files into your home directory on workshop4.ci.uchicago.edu first.
Then run the above workflow steps.
You can view files in your home directory on iwr-gks-globus01 by pointing your web browser at http://iwr-gks-globus01.fzk.de/~train99/
These notes were produced from the Open Science Grid Education, Outreach and Training group SVN repository, at this location and revision:
Path: . URL: https://svn.ci.uchicago.edu/svn/osgedu/schools/2007/gridka Repository UUID: b4a0e4a1-be33-0410-93ba-8605a86001b8 Revision: 116 Node Kind: directory Schedule: normal Last Changed Author: benc@CI.UCHICAGO.EDU Last Changed Rev: 116 Last Changed Date: 2007-09-12 06:44:17 -0500 (Wed, 12 Sep 2007)