When a user executes the file upload procedure, the trace file from the compute nodes are copied to a server at SDSC. The user executes make -C /opt/app-trace/collect/Makefile sdsc and the Makefile has the contents:
TRACEID = $(shell date +%s.%N) local: cluster-fork '/opt/app-trace/bin/collect.sh $(TRACEID) local' sdsc: cluster-fork '/opt/app-trace/bin/collect.sh $(TRACEID) sdsc' |
The TRACEID is the unique value that will be used to create a directory on SDSC's server to hold all the trace files. It is important to note that this value is just the date (to the nanosecond) and doesn't contain any information about the cluster (e.g., there is no IP or MAC address information in TRACEID). |
In the Makefile above, file upload is carried out by a script on the compute node called /opt/app-trace/bin/collect.sh. Note that the TRACEID is passed to the next stage in the --id parameter.
1 #!/bin/bash 2 # 3 # $Id: internals.sgml,v 1.2 2005/11/30 21:48:40 bruno Exp $ 4 # 5 # @Copyright@ 6 # 7 # Rocks 8 # www.rocksclusters.org 9 # version 4.1 (fuji) 10 # 11 # Copyright (c) 2005 The Regents of the University of California. All 12 # rights reserved. 13 # 14 # Redistribution and use in source and binary forms, with or without 15 # modification, are permitted provided that the following conditions are 16 # met: 17 # 18 # 1. Redistributions of source code must retain the above copyright 19 # notice, this list of conditions and the following disclaimer. 20 # 21 # 2. Redistributions in binary form must reproduce the above copyright 22 # notice, this list of conditions and the following disclaimer in the 23 # documentation and/or other materials provided with the distribution. 24 # 25 # 3. All advertising materials mentioning features or use of this 26 # software must display the following acknowledgement: 27 # 28 # "This product includes software developed by the Rocks 29 # Cluster Group at the San Diego Supercomputer Center and 30 # its contributors." 31 # 32 # 4. Neither the name or logo of this software nor the names of its 33 # authors may be used to endorse or promote products derived from this 34 # software without specific prior written permission. The name of the 35 # software includes the following terms, and any derivatives thereof: 36 # "Rocks", "Rocks Clusters", and "Avalanche Installer". 37 # 38 # THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' 39 # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 40 # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 41 # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS 42 # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 43 # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 44 # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 45 # BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 46 # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 47 # OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 48 # IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 49 # 50 # @Copyright@ 51 # 52 # $Log: internals.sgml,v $ 52 # Revision 1.2 2005/11/30 21:48:40 bruno 52 # touch ups 52 # 53 # Revision 1.3 2005/11/30 01:41:35 bruno 54 # a bit more 55 # 56 # Revision 1.2 2005/11/18 00:54:54 bruno 57 # only upload app trace files 58 # 59 # Revision 1.1 2005/11/17 16:55:56 bruno 60 # first rev 61 # 62 # 63 # 64 65 . /opt/app-trace/conf/variables 66 67 echo "" > /proc/sys/debug/traced-apps 68 69 for i in `find $TRACEDIR -type f -name "*app-trace.out*"` 70 do 71 file $i | grep 'bzip2 compressed' > /dev/null 2>&1 72 notcompressed=$? 73 74 if [ $notcompressed == 1 ] 75 then 76 bzip2 --force $i 77 filename=$i.bz2 78 else 79 filename=$i 80 fi 81 82 if [ $2 == 'local' ] 83 then 84 CHOST=$COLLECTHOSTLOCAL 85 else 86 CHOST=$COLLECTHOSTSDSC 87 fi 88 89 /opt/app-trace/bin/upload.py \ 90 --upload-server=$CHOST --filename=$filename --id=$1 91 done 92 |
For each file in TRACEDIR (line 69), it compresses the file (if not already compressed), then calls /opt/app-trace/bin/upload.py which uses HTTPS POST to copy the compressed file to your frontend (when executing make -f /opt/app-trace/collect/Makefile local) or to the the SDSC server (when executing make -f /opt/app-trace/collect/Makefile sdsc).
Here is the contents of /opt/app-trace/bin/upload.py:
1 #!/opt/rocks/usr/bin/python 2 # 3 # $Id: internals.sgml,v 1.2 2005/11/30 21:48:40 bruno Exp $ 4 # 5 # @Copyright@ 6 # 7 # Rocks 8 # www.rocksclusters.org 9 # version 4.1 (fuji) 10 # 11 # Copyright (c) 2005 The Regents of the University of California. All 12 # rights reserved. 13 # 14 # Redistribution and use in source and binary forms, with or without 15 # modification, are permitted provided that the following conditions are 16 # met: 17 # 18 # 1. Redistributions of source code must retain the above copyright 19 # notice, this list of conditions and the following disclaimer. 20 # 21 # 2. Redistributions in binary form must reproduce the above copyright 22 # notice, this list of conditions and the following disclaimer in the 23 # documentation and/or other materials provided with the distribution. 24 # 25 # 3. All advertising materials mentioning features or use of this 26 # software must display the following acknowledgement: 27 # 28 # "This product includes software developed by the Rocks 29 # Cluster Group at the San Diego Supercomputer Center and 30 # its contributors." 31 # 32 # 4. Neither the name or logo of this software nor the names of its 33 # authors may be used to endorse or promote products derived from this 34 # software without specific prior written permission. The name of the 35 # software includes the following terms, and any derivatives thereof: 36 # "Rocks", "Rocks Clusters", and "Avalanche Installer". 37 # 38 # THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' 39 # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 40 # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 41 # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS 42 # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 43 # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 44 # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 45 # BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 46 # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 47 # OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 48 # IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 49 # 50 # @Copyright@ 51 # 52 # $Log: internals.sgml,v $ 52 # Revision 1.2 2005/11/30 21:48:40 bruno 52 # touch ups 52 # 53 # Revision 1.1 2005/11/17 16:55:56 bruno 54 # first rev 55 # 56 # 57 58 import getopt 59 import sys 60 import httplib 61 import os 62 import os.path 63 64 boundary = '------------Rocks-Trace-File-Upload------------' 65 66 67 def file_header(filename): 68 str = '--' + boundary + '\n' 69 str += 'Content-Disposition: form-data; ' 70 str += 'name="filename"; ' 71 str += 'filename="%s"\n\n' % (os.path.basename(filename)) 72 return str 73 74 75 def file_trailer(): 76 str = '\n--' + boundary + '\n\n\r\n' 77 return str 78 79 80 def encode_fields(fields): 81 str = '' 82 83 for (key, value) in fields: 84 str += '--' + boundary + '\n' 85 str += 'Content-Disposition: form-data; ' + \ 86 'name="%s"\n\n' % (key) 87 str += value + '\n' 88 89 return str 90 91 92 93 def send_file(host, req, fields, filename): 94 str_fields = encode_fields(fields) 95 header = file_header(filename) 96 trailer = file_trailer() 97 filesize = os.path.getsize(filename) 98 99 h = httplib.HTTPSConnection(host) 100 101 h.putrequest('POST', req) 102 103 h.putheader('content-type', 104 'multipart/form-data; boundary=%s' % (boundary)) 105 106 bodysize = len(str_fields) + len(header) + len(trailer) + filesize 107 h.putheader('content-length', '%d' % (bodysize)) 108 109 h.endheaders() 110 111 # 112 # send the body of the message 113 # 114 h.send(str_fields) 115 h.send(header) 116 117 file = open(filename, 'r') 118 line = file.readline() 119 while line: 120 h.send(line) 121 line = file.readline() 122 file.close() 123 124 h.send(trailer) 125 126 response = h.getresponse() 127 128 return response 129 130 # 131 # main 132 # 133 134 # 135 # get the command line arguments 136 # 137 opts, args = getopt.getopt(sys.argv[1:], '', ['upload-server=', 138 'filename=', 'id=' ]) 139 140 # 141 # IP address of the node we care about 142 # 143 upload_server = '' 144 filename = '' 145 id = '' 146 147 for c in opts: 148 if c[0] == '--upload-server': 149 upload_server = c[1] 150 if c[0] == '--filename': 151 filename = c[1] 152 if c[0] == '--id': 153 id = c[1] 154 155 156 req = '/traces/sbin/store-trace.cgi' 157 fields = [ ('username', 'rocks'), ('id', id) ] 158 159 send_file(upload_server, req, fields, filename) |
Line 99 shows the HTTPS connection and line 101 shows the POST command.
It's important to note that all trace files are transferred using a secure link. That is, if an outside program is eavesdropping on the connection, they will only see ciphertext and not cleartext. |
The program /opt/app-trace/bin/upload.py calls the CGI program /traces/sbin/store-trace.cgi on SDSC's server. The contents of the CGI is:
1 #!/opt/rocks/usr/bin/python 2 3 import cgi 4 import os 5 6 tracedir = '/state/partition1/traces/' 7 8 9 def savefile(infile, outfilename): 10 outfile = open('%s' % (outfilename), 'w+') 11 12 if infile: 13 line = infile.readline() 14 while line: 15 outfile.write(line) 16 line = infile.readline() 17 else: 18 outfile.write(f.value) 19 20 outfile.close() 21 return 22 23 # 24 # main 25 # 26 form = cgi.FieldStorage() 27 28 username = '' 29 filename = '' 30 id = '' 31 32 file = open('/tmp/store-file.cgi', 'w+') 33 for key in form.keys(): 34 35 if key == 'username': 36 username = form.getvalue(key) 37 file.write('username (%s)\n' % (username)) 38 file.write('\n') 39 elif key == 'id': 40 id = form.getvalue(key) 41 file.write('id (%s)\n' % (id)) 42 file.write('\n') 43 elif key == 'filename' and form[key].filename: 44 filename = form[key].filename 45 46 file.close() 47 48 if username == 'rocks' and id != '' and filename != '': 49 dirname = os.path.join('/state/partition1/traces/', id) 50 if not os.path.exists(dirname): 51 os.system('mkdir -p %s' % (dirname)) 52 53 outfilename = os.path.join(dirname, filename) 54 55 savefile(form['filename'].file, outfilename) 56 57 print 'Content-type: application/octet-stream' 58 print 'Content-length: %d' % (len('')) 59 print '' 60 print '' |
The CGI above creates a new directory based on the id passed to it by upload.py.
Again, no cluster-specific information is stored on the SDSC server. |