17
17
from DIRAC .ConfigurationSystem .Client .Helpers .Operations import Operations
18
18
from DIRAC .ConfigurationSystem .Client .Helpers .Registry import getVOs
19
19
from DIRAC .Core .Base .AgentModule import AgentModule
20
+ from DIRAC .Core .Security .ProxyInfo import getProxyInfo
20
21
from DIRAC .Core .Utilities .Proxy import executeWithoutServerCertificate
21
22
from DIRAC .Core .Utilities .Proxy import getProxy
22
23
from DIRAC .DataManagementSystem .Client .DataManager import DataManager
@@ -34,7 +35,8 @@ class PilotLoggingAgent(AgentModule):
34
35
def __init__ (self , * args , ** kwargs ):
35
36
"""c'tor"""
36
37
super ().__init__ (* args , ** kwargs )
37
- self .clearPilotsDelay = 30
38
+ self .clearPilotsDelay = 30 # in days
39
+ self .proxyTimeleftLimit = 600 # in seconds
38
40
39
41
def initialize (self ):
40
42
"""
@@ -46,6 +48,8 @@ def initialize(self):
46
48
"""
47
49
# pilot logs lifetime in days
48
50
self .clearPilotsDelay = self .am_getOption ("ClearPilotsDelay" , self .clearPilotsDelay )
51
+ # proxy timeleft limit before we get a new one.
52
+ self .proxyTimeleftLimit = self .am_getOption ("ProxyTimeleftLimit" , self .proxyTimeleftLimit )
49
53
# configured VOs
50
54
res = getVOs ()
51
55
if not res ["OK" ]:
@@ -76,24 +80,20 @@ def initialize(self):
76
80
continue
77
81
78
82
self .log .info (f"Proxy used for pilot logging: VO: { vo } , User: { proxyUser } , Group: { proxyGroup } " )
79
- # download a proxy and save a filename for future use:
83
+ # download a proxy and save a file name, userDN and proxyGroup for future use:
80
84
result = getDNForUsername (proxyUser )
81
85
if not result ["OK" ]:
82
86
self .log .error (f"Could not obtain a DN of user { proxyUser } for VO { vo } , skipped" )
83
87
continue
84
- userDNs = result ["Value" ] # a same user may have more than one DN
85
- fd , filename = tempfile .mkstemp (prefix = vo + "__" )
86
- print ("filename" , filename )
87
- os .close (fd )
88
- vomsAttr = getVOMSAttributeForGroup (proxyGroup )
89
- result = getProxy (userDNs , proxyGroup , vomsAttr = vomsAttr , proxyFilePath = filename )
88
+ userDNs = result ["Value" ] # the same user may have more than one DN
89
+
90
+ with tempfile .NamedTemporaryFile (prefix = "gridpp" + "__" , delete = False ) as ntf :
91
+ result = self ._downloadProxy (vo , userDNs , proxyGroup , ntf .name )
90
92
91
93
if not result ["OK" ]:
92
- self .log .error (
93
- f"Could not download a proxy for DN { userDNs } , group { proxyGroup } for VO { vo } , skipped"
94
- )
94
+ # no proxy, we have no other option than to skip the VO
95
95
continue
96
- self .proxyDict [vo ] = result ["Value" ]
96
+ self .proxyDict [vo ] = { "proxy" : result ["Value" ], "DN" : userDNs , "group" : proxyGroup }
97
97
98
98
return S_OK ()
99
99
@@ -107,8 +107,13 @@ def execute(self):
107
107
voRes = {}
108
108
self .log .verbose (f"VOs configured for remote logging: { list (self .proxyDict .keys ())} " )
109
109
originalUserProxy = os .environ .get ("X509_USER_PROXY" )
110
- for vo , proxy in self .proxyDict .items ():
111
- os .environ ["X509_USER_PROXY" ] = proxy
110
+ for vo , elem in self .proxyDict .items ():
111
+ if self ._isProxyExpired (elem ["proxy" ], self .proxyTimeleftLimit ):
112
+ result = self ._downloadProxy (vo , elem ["DN" ], elem ["group" ], elem ["proxy" ])
113
+ if not result ["OK" ]:
114
+ voRes [vo ] = result ["Message" ]
115
+ continue
116
+ os .environ ["X509_USER_PROXY" ] = elem ["proxy" ]
112
117
res = self .executeForVO (vo )
113
118
if not res ["OK" ]:
114
119
voRes [vo ] = res ["Message" ]
@@ -215,3 +220,41 @@ def clearOldPilotLogs(self, pilotLogPath):
215
220
os .remove (fullpath )
216
221
except Exception as excp :
217
222
self .log .exception (f"Cannot remove an old log file after { fullpath } " , lException = excp )
223
+
224
+ def _downloadProxy (self , vo , userDNs , proxyGroup , filename ):
225
+ """
226
+ Fetch a new proxy and store it in a file filename.
227
+
228
+ :param str vo: VO to get a proxy for
229
+ :param list userDNs: user DN list
230
+ :param str proxyGroup: user group
231
+ :param str filename: file name to store a proxy
232
+ :return: Dirac S_OK or S_ERROR object
233
+ :rtype: dict
234
+ """
235
+ vomsAttr = getVOMSAttributeForGroup (proxyGroup )
236
+ result = getProxy (userDNs , proxyGroup , vomsAttr = vomsAttr , proxyFilePath = filename )
237
+ if not result ["OK" ]:
238
+ self .log .error (f"Could not download a proxy for DN { userDNs } , group { proxyGroup } for VO { vo } , skipped" )
239
+ return S_ERROR (f"Could not download a proxy, { vo } skipped" )
240
+ return result
241
+
242
+ def _isProxyExpired (self , proxyfile , limit ):
243
+ """
244
+ Check proxy timeleft. If less than a limit, return True.
245
+
246
+ :param str proxyfile:
247
+ :param int limit: timeleft threshold below which a proxy is considered expired.
248
+ :return: True or False
249
+ :rtype: bool
250
+ """
251
+ result = getProxyInfo (proxyfile )
252
+ if not result ["OK" ]:
253
+ self .log .error (f"Could not get proxy info { result ['Message' ]} " )
254
+ return True
255
+ timeleft = result ["Value" ]["secondsLeft" ]
256
+ self .log .debug (f"Proxy { proxyfile } time left: { timeleft } " )
257
+ if timeleft < limit :
258
+ self .log .info (f"proxy { proxyfile } expired/is about to expire. Will fetch a new one" )
259
+ return True
260
+ return False
0 commit comments