99###############################################################
1010
1111import os
12- from pathlib import PurePath
12+ from pathlib import PurePosixPath
1313
1414import flux
1515from flux .job import JobID , job_list_id
1616from flux .uri import JobURI , URIResolverPlugin , URIResolverURI
1717
1818
19- def filter_slash (iterable ):
20- return list (filter (lambda x : "/" not in x , iterable ))
21-
22-
2319def wait_for_uri (flux_handle , jobid ):
2420 """Wait for memo event containing job uri, O/w finish event"""
2521 for event in flux .job .event_watch (flux_handle , jobid ):
@@ -30,41 +26,78 @@ def wait_for_uri(flux_handle, jobid):
3026 return None
3127
3228
29+ def resolve_parent (handle ):
30+ """Return parent-uri if instance-level > 0, else local-uri"""
31+ if int (handle .attr_get ("instance-level" )) > 0 :
32+ return handle .attr_get ("parent-uri" )
33+ return handle .attr_get ("local-uri" )
34+
35+
36+ def resolve_root (flux_handle ):
37+ """Return the URI of the top-level, or root, instance."""
38+ handle = flux_handle
39+ while int (handle .attr_get ("instance-level" )) > 0 :
40+ handle = flux .Flux (resolve_parent (handle ))
41+ return handle .attr_get ("local-uri" )
42+
43+
44+ def resolve_jobid (flux_handle , arg , wait ):
45+ try :
46+ jobid = JobID (arg )
47+ except OSError as exc :
48+ raise ValueError (f"{ arg } is not a valid jobid" )
49+
50+ try :
51+ if wait :
52+ uri = wait_for_uri (flux_handle , jobid )
53+ else :
54+ # Fetch the jobinfo object for this job
55+ job = job_list_id (
56+ flux_handle , jobid , attrs = ["state" , "annotations" ]
57+ ).get_jobinfo ()
58+ if job .state != "RUN" :
59+ raise ValueError (f"jobid { arg } is not running" )
60+ uri = job .user .uri
61+ except FileNotFoundError as exc :
62+ raise ValueError (f"jobid { arg } not found" ) from exc
63+
64+ if uri is None or str (uri ) == "" :
65+ raise ValueError (f"URI not found for job { arg } " )
66+ return uri
67+
68+
3369class URIResolver (URIResolverPlugin ):
3470 """A URI resolver that attempts to fetch the remote_uri for a job"""
3571
3672 def describe (self ):
3773 return "Get URI for a given Flux JOBID"
3874
39- def _do_resolve (self , uri , flux_handle , force_local = False , wait = False ):
75+ def _do_resolve (
76+ self , uri , flux_handle , force_local = False , wait = False , hostname = None
77+ ):
4078 #
41- # Convert a possible hierarchy of jobids to a list, dropping any
42- # extraneous '/' (e.g. //id0/id1 -> [ "id0", "id1" ]
43- jobids = filter_slash (PurePath (uri .path ).parts )
79+ # Convert a possible hierarchy of jobids to a list
80+ jobids = list (PurePosixPath (uri .path ).parts )
81+
82+ # If path is empty, return current enclosing URI
83+ if not jobids :
84+ return flux_handle .attr_get ("local-uri" )
4485
45- # Pop the first jobid off the list, this id should be local:
86+ # Pop the first jobid off the list, if a jobid it should be local,
87+ # otherwise "/" for the root URI or ".." for parent URI:
4688 arg = jobids .pop (0 )
47- try :
48- jobid = JobID (arg )
49- except OSError as exc :
50- raise ValueError (f"{ arg } is not a valid jobid" )
51-
52- try :
53- if wait :
54- uri = wait_for_uri (flux_handle , jobid )
55- else :
56- # Fetch the jobinfo object for this job
57- job = job_list_id (
58- flux_handle , jobid , attrs = ["state" , "annotations" ]
59- ).get_jobinfo ()
60- if job .state != "RUN" :
61- raise ValueError (f"jobid { arg } is not running" )
62- uri = job .user .uri
63- except FileNotFoundError as exc :
64- raise ValueError (f"jobid { arg } not found" ) from exc
65-
66- if uri is None or str (uri ) == "" :
67- raise ValueError (f"URI not found for job { arg } " )
89+ if arg == "/" :
90+ uri = resolve_root (flux_handle )
91+ elif arg == ".." :
92+ uri = resolve_parent (flux_handle )
93+ # Relative paths always use a local:// uri. But, if a jobid was
94+ # resolved earlier in the path, then use the hostname associated
95+ # with that job.
96+ if hostname :
97+ uri = JobURI (uri , remote_hostname = hostname ).remote
98+ else :
99+ uri = resolve_jobid (flux_handle , arg , wait )
100+ hostname = JobURI (uri ).netloc
68101
69102 # If there are more jobids in the hierarchy to resolve, resolve
70103 # them recursively
@@ -74,7 +107,10 @@ def _do_resolve(self, uri, flux_handle, force_local=False, wait=False):
74107 if force_local :
75108 uri = JobURI (uri ).local
76109 return self ._do_resolve (
77- resolver_uri , flux .Flux (uri ), force_local = force_local
110+ resolver_uri ,
111+ flux .Flux (uri ),
112+ force_local = force_local ,
113+ hostname = hostname ,
78114 )
79115 return uri
80116
0 commit comments