send.py revision 1816
1#!/usr/bin/env python 2# Copyright (c) 2005 The Regents of The University of Michigan 3# All rights reserved. 4# 5# Redistribution and use in source and binary forms, with or without 6# modification, are permitted provided that the following conditions are 7# met: redistributions of source code must retain the above copyright 8# notice, this list of conditions and the following disclaimer; 9# redistributions in binary form must reproduce the above copyright 10# notice, this list of conditions and the following disclaimer in the 11# documentation and/or other materials provided with the distribution; 12# neither the name of the copyright holders nor the names of its 13# contributors may be used to endorse or promote products derived from 14# this software without specific prior written permission. 15# 16# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27# 28# Authors: Ali Saidi 29# Nathan Binkert 30 31import os, os.path, re, socket, sys 32from os import environ as env, listdir 33from os.path import basename, isdir, isfile, islink, join as joinpath, normpath 34from filecmp import cmp as filecmp 35from shutil import copy 36 37def nfspath(dir): 38 if dir.startswith('/.automount/'): 39 dir = '/n/%s' % dir[12:] 40 elif not dir.startswith('/n/'): 41 dir = '/n/%s%s' % (socket.gethostname().split('.')[0], dir) 42 return dir 43 44def syncdir(srcdir, destdir): 45 srcdir = normpath(srcdir) 46 destdir = normpath(destdir) 47 if not isdir(destdir): 48 sys.exit('destination directory "%s" does not exist' % destdir) 49 50 for root, dirs, files in os.walk(srcdir): 51 root = normpath(root) 52 prefix = os.path.commonprefix([root, srcdir]) 53 root = root[len(prefix):] 54 if root.startswith('/'): 55 root = root[1:] 56 for rem in [ d for d in dirs if d.startswith('.') or d == 'SCCS']: 57 dirs.remove(rem) 58 59 for entry in dirs: 60 newdir = joinpath(destdir, root, entry) 61 if not isdir(newdir): 62 os.mkdir(newdir) 63 print 'mkdir', newdir 64 65 for i,d in enumerate(dirs): 66 if islink(joinpath(srcdir, root, d)): 67 dirs[i] = joinpath(d, '.') 68 69 for entry in files: 70 dest = normpath(joinpath(destdir, root, entry)) 71 src = normpath(joinpath(srcdir, root, entry)) 72 if not isfile(dest) or not filecmp(src, dest): 73 print 'copy %s %s' % (dest, src) 74 copy(src, dest) 75 76progpath = nfspath(sys.path[0]) 77progname = basename(sys.argv[0]) 78usage = """\ 79Usage: 80 %(progname)s [-c] [-e] [-f] [-j <jobfile>] [-q queue] [-v] <regexp> 81 -c clean directory if job can be run 82 -e only echo pbs command info, don't actually send the job 83 -f force the job to run regardless of state 84 -q <queue> submit job to the named queue 85 -j <jobfile> specify the jobfile (default is <basedir>/test.py) 86 -v be verbose 87 88 %(progname)s [-j <jobfile>] -l [-v] <regexp> 89 -j <jobfile> specify the jobfile (default is <basedir>/test.py) 90 -l list job names, don't submit 91 -v be verbose (list job parameters) 92 93 %(progname)s -h 94 -h display this help 95""" % locals() 96 97try: 98 import getopt 99 opts, args = getopt.getopt(sys.argv[1:], '-cd:efhj:lq:v') 100except getopt.GetoptError: 101 sys.exit(usage) 102 103clean = False 104onlyecho = False 105exprs = [] 106force = False 107listonly = False 108queue = '' 109verbose = False 110rootdir = nfspath(os.getcwd()) 111jfile = 'test.py' 112for opt,arg in opts: 113 if opt == '-c': 114 clean = True 115 if opt == '-d': 116 rootdir = arg 117 if opt == '-e': 118 onlyecho = True 119 if opt == '-f': 120 force = True 121 if opt == '-h': 122 print usage 123 sys.exit(0) 124 if opt == '-j': 125 jfile = arg 126 if opt == '-l': 127 listonly = True 128 if opt == '-q': 129 queue = arg 130 if opt == '-v': 131 verbose = True 132 133basedir = joinpath(rootdir, 'Base') 134linkdir = joinpath(rootdir, 'Link') 135 136for arg in args: 137 exprs.append(re.compile(arg)) 138 139if not listonly and not onlyecho and isdir(linkdir): 140 if verbose: 141 print 'Checking for outdated files in Link directory' 142 syncdir(linkdir, basedir) 143 144import job, jobfile, pbs 145 146test = jobfile.JobFile(joinpath(basedir, jfile)) 147 148joblist = [] 149for jobname in test.jobs: 150 if not exprs: 151 joblist.append(jobname) 152 continue 153 154 for expr in exprs: 155 if expr.match(jobname): 156 joblist.append(jobname) 157 break 158 159if listonly: 160 if verbose: 161 for jobname in joblist: 162 test.printinfo(jobname) 163 else: 164 for jobname in joblist: 165 print jobname 166 sys.exit(0) 167 168if not onlyecho: 169 jl = [] 170 for jobname in joblist: 171 jobdir = joinpath(rootdir, jobname) 172 if os.path.exists(jobname): 173 if not force: 174 if os.path.isfile(joinpath(jobdir, '.success')): 175 continue 176 177 if os.path.isfile(joinpath(jobdir, '.start')) and \ 178 not os.path.isfile(joinpath(jobdir, '.stop')): 179 continue 180 181 if not clean: 182 sys.exit('job directory not clean!') 183 184 job.cleandir(jobdir) 185 else: 186 os.mkdir(jobdir) 187 jl.append(jobname) 188 joblist = jl 189 190def setname(jobid, jobname): 191 # since pbs can handle jobnames of 15 characters or less, don't 192 # use the raj hack. 193 if len(jobname) <= 15: 194 return 195 196 import socket 197 s = socket.socket() 198 # Connect to pbs.pool and send the jobid/jobname pair to port 199 # 24465 (Raj didn't realize that there are only 64k ports and 200 # setup inetd to point to port 90001) 201 s.connect(("pbs.pool", 24465)) 202 s.send("%s %s\n" % (jobid, jobname)) 203 s.close() 204 205for jobname in joblist: 206 jobdir = joinpath(rootdir, jobname) 207 208 if not onlyecho and not os.path.isdir(jobdir): 209 sys.exit('%s is not a directory. Cannot build job' % jobdir) 210 211 print 'Job name: %s' % jobname 212 print 'Job directory: %s' % jobdir 213 214 qsub = pbs.qsub() 215 qsub.pbshost = 'simpool.eecs.umich.edu' 216 qsub.stdout = joinpath(jobdir, 'jobout') 217 qsub.name = jobname[:15] 218 qsub.join = True 219 qsub.node_type = 'FAST' 220 qsub.env['ROOTDIR'] = rootdir 221 qsub.env['JOBNAME'] = jobname 222 if len(queue): 223 qsub.queue = queue 224 qsub.build(joinpath(progpath, 'job.py')) 225 226 if verbose: 227 print 'PBS Command: %s' % qsub.command 228 229 if not onlyecho: 230 ec = qsub.do() 231 if ec == 0: 232 jobid = qsub.result 233 print 'PBS Jobid: %s' % jobid 234 setname(jobid, jobname) 235 else: 236 print 'PBS Failed' 237