2 from __future__
import division
3 from __future__
import print_function
9 import samweb_client
as swc
14 from io
import BytesIO
19 X509_USER_PROXY = os.getenv(
"X509_USER_PROXY",
"/tmp/x509up_u%d" % os.getuid())
20 PNFS_DIR_PATTERN = re.compile(
r"/pnfs/(?P<area>[^/]+)")
26 ENSTORE_PATTERN = re.compile(
r"^enstore:([^(]+)(\([^)]+\))?")
32 DCACHE_REST_BASE_URL =
"https://fndca.fnal.gov:3880/api/v1/namespace" 36 def __init__(self, total, announce_threshold=50):
50 if current_decile
is None:
51 print(
" %d" % n, end=
" " )
53 curr_perc =
int(n / self.
total * 100)
54 print(
" %d%%" % curr_perc, end=
" " )
62 """Returns a pycurl object with the necessary fields set for Fermilab 65 The object can be reused for multiple requests to the 66 dcache REST API and curl will reuse the connection, which should speed 70 c.setopt(c.CAINFO, X509_USER_PROXY);
71 c.setopt(c.SSLCERT, X509_USER_PROXY);
72 c.setopt(c.SSLKEY, X509_USER_PROXY);
73 c.setopt(c.SSH_PRIVATE_KEYFILE, X509_USER_PROXY);
74 c.setopt(c.FOLLOWLOCATION,
True)
75 c.setopt(c.CAPATH,
"/etc/grid-security/certificates");
82 if filename.startswith(
"root://fndca1.fnal.gov:1094"):
83 filename_out=filename.replace(
"root://fndca1.fnal.gov:1094",
"")
84 elif filename.startswith(
"/pnfs/dune"):
85 filename_out=filename.replace(
"/pnfs/dune",
"/pnfs/fnal.gov/usr/dune")
86 elif filename.startswith(
"enstore:/pnfs/dune"):
87 filename_out=filename.replace(
"enstore:/pnfs/dune",
"/pnfs/fnal.gov/usr/dune")
93 """Using curl object `c`, find the "QoS" of `filename`. 95 QoS is "disk", "tape" or "disk+tape", with the obvious meanings 97 Returns: (currentQos, targetQos) where targetQos is non-empty if 98 there is an outstanding prestage request. currentQos will 99 be empty if there is an error (eg, file does not exist) 101 Uses the dcache REST API frontend, documented in the dcache User Guide, eg: 103 https://www.dcache.org/manuals/UserGuide-6.0/frontend.shtml 120 c.setopt(c.WRITEFUNCTION, mybuffer.write)
126 body = mybuffer.getvalue().
decode(
'iso-8859-1')
135 if "fileLocality" in j:
136 locality=j[
"fileLocality"]
138 targetQos=j[
"targetQos"]
140 return (locality, targetQos)
144 """Using curl object `c`, returns whether `filename` is online""" 149 """Using curl object `c`, request a prestage for `filename` 151 Returns whether the request succeeded (according to dcache) 153 Uses a HTTP post request in a very specific format to request a prestage of a file. Adapted from: 155 https://github.com/DmitryLitvintsev/scripts/blob/master/bash/bring-online.sh 157 Uses the dcache REST API frontend, documented in the dcache User Guide, eg: 159 https://www.dcache.org/manuals/UserGuide-6.0/frontend.shtml 161 c.setopt(c.POSTFIELDS,
"""{"action" : "qos", "target" : "disk+tape"}""")
162 c.setopt(c.HTTPHEADER, [
"Accept: application/json",
"Content-Type: application/json"])
166 c.setopt(c.WRITEFUNCTION, mybuffer.write)
172 body = mybuffer.getvalue().
decode(
'iso-8859-1')
174 return "status" in j
and j[
"status"]==
"success" 178 path, filename = os.path.split(f)
179 stat_file=
"%s/.(get)(%s)(locality)"%(path,filename)
180 theStatFile=
open(stat_file)
181 state=theStatFile.readline()
183 return 'ONLINE' in state
187 assert(METHOD
in (
"rest",
"pnfs"))
190 print(
"Checking %d files:" % len(files) )
197 progbar =
None if verbose_flag
else ProgressBar(len(files))
199 c=
make_curl()
if METHOD==
"rest" else None 204 if "ONLINE" in qos: cached += 1
205 if "disk" in targetQos: pending += 1
207 print( f, qos,
"pending" if targetQos
else "")
210 if this_cached: cached += 1
212 print( f,
"ONLINE" if this_cached
else "NEARLINE")
217 if not verbose_flag: progbar.Update(n)
219 if not verbose_flag: progbar.Update(progbar.total)
225 return (cached, pending, n)
229 announce=len(files) > 1
231 print(
"Prestaging %d files:" % len(files) )
235 n_request_succeeded = 0
238 if success: n_request_succeeded += 1
240 print( f,
"request succeeded" if success
else "request failed" )
242 return (n_request_succeeded, n)
246 """Convert a list of enstore locations as returned by 247 samweb.listFilesAndLocations() into plain pnfs paths. Sparsify by 250 for f
in samlist[::sparsification]:
251 m=ENSTORE_PATTERN.match(f[0])
255 pnfspaths.append(os.path.join(directory, filename))
257 print(
"enstore_locations_to_paths got a non-enstore location", f[0] )
263 Find the cache state of one file: 265 %(prog)s np04_raw_run004513_0008_dl5.root 267 Find the cache state of multiple files. With -v, each file's status 268 is shown; otherwise just a count is shown. Can mix-and-match full 269 paths and SAM filenames: 271 %(prog)s -v /pnfs/dune/tape_backed/myfile.root np04_raw_run004513_0008_dl5.root 273 Summarize the cache state of a SAM dataset: 275 %(prog)s -d protodune-sp_runset_4513_raw_v0 277 Show the cache state of each file matching a SAM query: 279 %(prog)s -v --dim 'run_type protodune-sp and run_number 4513 and data_tier raw' 281 Prestage an individual file, by its SAM filename: 283 %(prog)s -p np04_raw_run004513_0008_dl5.root 285 (In subsequent queries, the file will show up as "pending" until it 288 Prestage an entire dataset (like samweb prestage-dataset): 290 %(prog)s -p -d protodune-sp_runset_4513_raw_v0 294 if __name__==
"__main__":
295 parser= argparse.ArgumentParser(epilog=examples, formatter_class=argparse.RawDescriptionHelpFormatter)
297 gp = parser.add_mutually_exclusive_group()
298 gp.add_argument(
"files",
302 help=
"Files to consider. Can be specified as a full /pnfs path, or just the SAM filename",
304 gp.add_argument(
"-d",
"--dataset",
307 help=
"Name of the SAM dataset to check cache status of",
309 gp.add_argument(
"-q",
"--dim",
310 metavar=
"\"DIMENSION\"",
312 help=
"sam dimensions to check cache status of",
315 parser.add_argument(
"-s",
"--sparse", type=int, dest=
'sparse',help=
"Sparsification factor. This is used to check only a portion of a list of files",default=1)
316 parser.add_argument(
"-ss",
"--snapshot", dest=
"snapshot", help=
"[Also requires -d] Use this snapshot ID for the dataset. Specify 'latest' for the most recent one.")
317 parser.add_argument(
"-v",
"--verbose", action=
"store_true", dest=
"verbose", default=
False, help=
"Print information about individual files")
318 parser.add_argument(
"-p",
"--prestage", action=
"store_true", dest=
"prestage", default=
False, help=
"Prestage the files specified")
319 parser.add_argument(
"-m",
"--method", choices=[
"rest",
"pnfs"], default=
"rest", help=
"Use this method to look up file status.")
321 args=parser.parse_args()
325 if args.method
in (
"rest"):
327 subprocess.check_call(shlex.split(
"setup_fnal_security --check"), stdout=
open(os.devnull), stderr=subprocess.STDOUT)
328 except subprocess.CalledProcessError:
329 print(
"Your proxy is expired or missing. Please run `setup_fnal_security` and then try again." )
332 filelist =
None if args.dataset_name
else args.files
334 sam = swc.SAMWebClient(
"dune")
341 if args.dataset_name:
342 print(
"Retrieving file list for SAM dataset definition name: '%s'..." % args.dataset_name, end=
"" )
346 if args.snapshot ==
"latest":
347 dimensions =
"dataset_def_name_newest_snapshot %s" % args.dataset_name
349 dimensions =
"snapshot_id %s" % args.snapshot
351 samlist = sam.listFilesAndLocations(dimensions=dimensions, filter_path=
"enstore")
354 thislist = sam.listFiles(defname=args.dataset_name)
359 if not (a%100): print(
"Locating files: %i/%i"%(a, len(thislist)), end=
'\r')
360 locs = sam.locateFile(f)
362 if l[
'full_path'].
split(
':')[0] ==
'enstore':
363 samlist.append((l[
'full_path'], f))
371 except Exception
as e:
374 print(
'Unable to retrieve SAM information for dataset: %s' %(args.dataset_name) )
378 elif args.dimensions:
379 print(
"Retrieving file list for SAM dimensions: '%s'..." % args.dimensions, end=
"" )
382 samlist = sam.listFilesAndLocations(dimensions=args.dimensions, filter_path=
"enstore")
385 except Exception
as e:
388 print(
'Unable to retrieve SAM information for dimensions: %s' %(args.dimensions) )
394 if os.path.isfile(f):
398 if f.startswith(
"/pnfs"):
408 locs = sam.locateFile(f)
415 m=ENSTORE_PATTERN.match(l)
418 fullpath=os.path.join(directory, f)
419 filelist.append(fullpath)
420 except (swc.exceptions.FileNotFound, swc.exceptions.HTTPNotFound):
421 print(
"File is not known to SAM and is not a full path:", f, file=sys.stderr)
426 n_files = len(filelist)
427 announce = n_files > 1
431 sys.exit(0
if ngood==n
else 1)
434 miss_count = total - cache_count
436 total =
float(cache_count + miss_count)
437 cache_frac_str = (
" (%d%%)" % round(cache_count/total*100))
if total > 0
else "" 438 miss_frac_str = (
" (%d%%)" % round(miss_count/total*100))
if total > 0
else "" 444 pending_string=
"\tPending: %d (%d%%)" % (pending_count, round(pending_count/total*100))
445 print(
"Cached: %d%s\tTape only: %d%s%s" % (cache_count, cache_frac_str, miss_count, miss_frac_str, pending_string))
447 print(
"CACHED" if cache_count > 0
else "NOT CACHED", end=
"")
448 print(
" PENDING" if pending_count > 0
else "" )
def request_prestage(c, filename)
int open(const char *, int)
Opens a file descriptor.
static bool format(QChar::Decomposition tag, QString &str, int index, int len)
def enstore_locations_to_paths(samlist, sparsification=1)
def __init__(self, total, announce_threshold=50)
def is_file_online(c, filename)
def FilelistPrestageRequest(files, verbose_flag)
def is_file_online_pnfs(f)
def filename_to_namespace(filename)
void decode(std::any const &a, Hep2Vector &result)
def get_file_qos(c, filename)
void split(std::string const &s, char c, OutIter dest)
def FilelistCacheCount(files, verbose_flag, METHOD="rest")