1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90 """Module defining class for creating, querying and renewing Grid proxy"""
91
92 __author__ = "K.Harrison <Harrison@hep.phy.cam.ac.uk>"
93 __date__ = "12 November 2009"
94 __version__ = "1.21"
95
96 import os
97 import re
98 import time
99
100 from ICredential import ICommandSet
101 from ICredential import ICredential
102 from ICredential import registerCommandSet
103 from Ganga.GPIDev.Schema import SimpleItem
104 from Ganga.Utility.logging import getLogger
105 from Ganga.Utility.GridShell import getShell
106
107 logger = getLogger()
108
110 """
111 Class used to define shell commands and options for working with Grid proxy
112 """
113
114 _schema = ICommandSet._schema.inherit_copy()
115 _schema['init']._meta['defvalue'] = "grid-proxy-init"
116 _schema['info']._meta['defvalue'] = "grid-proxy-info"
117 _schema['destroy']._meta['defvalue'] = "grid-proxy-destroy"
118 _schema['init_parameters']._meta['defvalue'] = { "pipe" : "-pwstdin", "valid" : "-valid" }
119 _schema['destroy_parameters']._meta['defvalue'] = {}
120 _schema['info_parameters']._meta['defvalue'] = {}
121
122 _name = "GridCommand"
123 _hidden = 1
124 _enable_config = 1
125
127 super( GridCommand, self ).__init__()
128
129 self.currentOpts = {}
130 self.infoOpts = {}
131 self.destroyOpts = {}
132
134 """
135 Class used to define shell commands and options for working with Grid proxy,
136 using VOMS extensions
137 """
138
139 _schema = ICommandSet._schema.inherit_copy()
140
141 _schema['init']._meta['defvalue'] = "voms-proxy-init"
142 _schema['info']._meta['defvalue'] = "voms-proxy-info"
143 _schema['destroy']._meta['defvalue'] = "voms-proxy-destroy"
144 _schema['init_parameters']._meta['defvalue'] = { "pipe" : "-pwstdin", "valid" : "-valid", \
145 "voms" : "-voms" }
146 _schema['destroy_parameters']._meta['defvalue'] = {}
147 _schema['info_parameters']._meta['defvalue'] = { "vo" : "-vo" }
148
149 _name = "VomsCommand"
150 _hidden = 1
151 _enable_config = 1
152
154 super( VomsCommand, self ).__init__()
155
156 self.currentOpts = {}
157 self.infoOpts = {}
158 self.destroyOpts = {}
159
160 for commandSet in [ GridCommand, VomsCommand ]:
161 registerCommandSet( commandSet )
162
163
164 _infoCache = {}
165
167 """
168 Class for working with Grid proxy
169 """
170
171 _schema = ICredential._schema.inherit_copy()
172 _schema.datadict[ "voms" ] = SimpleItem( defvalue = "", doc = \
173 "Virtual organisation managment system information" )
174 _schema.datadict[ "init_opts" ] = SimpleItem( defvalue = "", doc = \
175 "String of options to be passed to command for proxy creation" )
176 _schema.datadict[ "info_refresh_time" ] = SimpleItem( defvalue = "00:15", \
177 doc = "Refresh time of proxy info cache" )
178 _name = "GridProxy"
179 _hidden = 1
180 _enable_config = 1
181 _exportmethods = [ "create", "destroy", "identity", "info", "isAvailable", \
182 "isValid", "location", "renew", "timeleft", "voname", "fullIdentity" ]
183
184 - def __init__( self, middleware = "EDG" ):
193
195 """
196 Choose command set to be used for proxy-related commands
197
198 No arguments other than self
199
200 If self.voms has a null value then the GridCommand set of commands
201 is used. Otherwise the VomsCommand set of commands is used.
202
203 Return value: None
204 """
205 if ( "ICommandSet" == self.command._name ):
206 if self.voms:
207 self.command = self.vomsCommand
208 else:
209 self.command = self.gridCommand
210 return None
211
212
213
214 - def buildOpts( self, command, clear = True ):
235
236 - def create\
237 ( self, validity = "", maxTry = 0, minValidity = "", check = False ):
242
243 - def destroy( self, allowed_exit = [ 0, 1 ] ):
247
249 if self.shell:
250 return True
251 else:
252 return False
253
254 - def isValid( self, validity = "", log = False, force_check = False ):
255
256
257 if not ICredential.isValid( self, validity, log, force_check ):
258 return False
259
260
261 if self.voname() != self.voms:
262 if log:
263 logger.warning("Grid Proxy not valid. Certificate VO '%s' does not match requested '%s'"
264 % (self.voname(), self.voms))
265 return False
266
267 return True
268
270
271 proxyPath = self.info( "-path" ).strip()
272
273 if not os.path.exists( proxyPath ):
274 proxyPath = ""
275
276 return proxyPath
277
279 """
280 Return the users full identity as a dictionary
281
282 Argument:
283 safe - logical flag
284 => False : return identity exactly as obtained from proxy
285 => True : return identity after stripping out
286 non-alphanumeric characters
287
288 Return value: Dictionary of the various labels in the users DN
289 """
290
291 ele_dict = {}
292
293 subjectList = self.info( opt = "-identity" ).split( "/" )
294
295 for subjectElement in subjectList:
296 element = subjectElement.strip()
297 if element.find("=") == -1:
298 continue
299
300 field, val = element.split("=")
301 if safe:
302 val = re.sub( "[^a-zA-Z0-9]", "" ,val )
303 ele_dict[field] = val
304
305 return ele_dict
306
307
309 """
310 Return user's identify
311
312 Argument:
313 safe - logical flag
314 => False : return identity exactly as obtained from proxy
315 => True : return identity after stripping out
316 non-alphanumeric characters
317
318 => The identity is determined from the user proxy if possible,
319 or otherwise from the user's top-level directory
320
321 Return value: String specifying user identity
322 """
323
324 cn = os.path.basename( os.path.expanduser( "~" ) )
325 try:
326 subjectList = self.info( opt = "-identity" ).split( "/" )
327 subjectList.reverse()
328 for subjectElement in subjectList:
329 element = subjectElement.strip()
330 try:
331 cn = element.split( "CN=" )[ 1 ].strip()
332 if cn != "proxy":
333 break
334 except IndexError:
335 pass
336 except:
337 pass
338
339 id = "".join( cn.split() )
340 if safe:
341 id = re.sub( "[^a-zA-Z0-9]", "" ,id )
342
343 return id
344
345 - def info( self, opt = "", force_check = False ):
346 """
347 Obtain proxy information
348
349 Arguments other than self:
350 opt - String of options to be used when querying
351 proxy information
352 => Help on valid options can be obtained using:
353 info( opt = "-help" )
354 force_check - Force credential check, rather than relying on cache
355
356 Return value: Output from result of querying proxy
357 """
358
359
360 output = self.getProxyCacheValue( opt )
361
362 if ( force_check ) or ( output == "" ):
363 self.chooseCommandSet()
364 infoCommand = " ".join( [ self.command.info, opt ] )
365 status, output, message = self.shell.cmd1\
366 ( cmd = infoCommand, allowed_exit = range( 1000 ) )
367
368 self.addToProxyCache( status, output, opt )
369
370 if not output:
371 output = ""
372
373 return output
374
375 - def renew( self, validity = "", maxTry = 0, minValidity = "", check = True ):
381
382 - def timeleft( self, units = "hh:mm:ss", force_check = False ):
384
386 global _infoCache
387
388 output = self.getProxyCacheValue( "timeleftInHMS" )
389 status = 0
390
391 if ( force_check ) or ( output == "" ):
392
393 self.chooseCommandSet()
394 infoList = [ self.command.info ]
395
396 for optName, optVal in self.command.infoOpts.iteritems():
397 infoList.append( "%s %s" % ( optName, optVal ) )
398 status, output, message = self.shell.cmd1\
399 ( cmd = " ".join( infoList ), allowed_exit = range( 1000 ) )
400
401 self.addToProxyCache( status, output, "timeleftInHMS" )
402
403 timeRemaining = "00:00:00"
404
405 if status:
406 if ( 1 + output.lower().find( "command not found" ) ):
407 logger.warning( "Command '" + self.command.info + "' not found" )
408 logger.warning( "Unable to obtain information on Grid proxy" )
409 timeRemaining = ""
410 if _infoCache.has_key( "timeleftInHMS" ):
411 del _infoCache[ "timeleftInHMS" ]
412
413 if timeRemaining:
414 lineList = output.split( "\n" )
415 for line in lineList:
416 if ( 1 + line.find( "Couldn't find a valid proxy" ) ):
417 timeRemaining = "-1"
418 if _infoCache.has_key('timeleftInHMS'):
419 del _infoCache['timeleftInHMS']
420 break
421 elif ( 1 + line.find( "timeleft" ) ):
422 elementList = line.split()
423 timeRemaining = elementList[ 2 ]
424 break
425
426 return timeRemaining
427
428 - def voname( self, force_check = False ):
429 """
430 Obtain name of virtual organisation from proxy
431
432 Argument other than self:
433 force_check - Force credential check, rather than relying on cache
434
435 Return value: Name of virtual organisation where this can be determined
436 (voms proxy), or empty string otherwise (globus proxy)
437 """
438 global _infoCache
439 output = self.getProxyCacheValue( "voname" )
440
441 if ( force_check ) or ( output == "" ):
442 self.chooseCommandSet()
443 infoCommand = ""
444
445 if self.command.info_parameters.has_key( "vo" ):
446 if self.command.info:
447 infoCommand = " ".join\
448 ( [ self.command.info, self.command.info_parameters[ "vo" ] ] )
449 else:
450 infoCommand = self.command.info
451
452 if infoCommand:
453 status, output, message = self.shell.cmd1( cmd = infoCommand, \
454 allowed_exit = range( 1000 ), capture_stderr = True )
455
456 self.addToProxyCache( status, output, "voname" )
457
458 else:
459 output = ""
460
461 if not output:
462 output = ""
463 if _infoCache.has_key( "voname" ):
464 del _infoCache[ "voname" ]
465
466 output = output.strip()
467
468 for error in [ "VOMS extension not found", "unrecognized option" ]:
469 if output.find( error ) != -1:
470 output = ""
471 if _infoCache.has_key('voname'):
472 del _infoCache['voname']
473 break
474
475
476 if len( output.split() ) != 1:
477 output = self.voms
478
479 return output
480
482 """
483 Check the proxy cache for the required key. Make sure the proxy
484 file is older than the last check.
485
486 opt - the key to check for
487 """
488
489 global _infoCache
490
491 info_refresh = self.timeInSeconds( self.info_refresh_time )
492 output = ''
493 path = ''
494
495
496 if not _infoCache.has_key( '-path' ) or ( _infoCache[ '-path' ][ 1 ] < ( time.time() - info_refresh ) ):
497 self.chooseCommandSet()
498 infoCommand = " ".join( [ self.command.info, '-path' ] )
499 status, output, message = self.shell.cmd1\
500 ( cmd = infoCommand, allowed_exit = range( 1000 ) )
501
502 if not status:
503 path = output
504 self.addToProxyCache( status, output, '-path')
505
506 else:
507 path = _infoCache[ '-path' ][0]
508
509 path = path.strip()
510 if not os.path.exists(path):
511
512 _infoCache = {}
513 return ''
514
515
516 if _infoCache.has_key( opt ) and ( _infoCache[ opt ][ 1 ] > ( time.time() - info_refresh ) ) and ( _infoCache[ opt ][ 1 ] > os.path.getmtime(path) ):
517 output = _infoCache[ opt ][ 0 ]
518 else:
519 output = ""
520
521 return output
522
524 """
525 Test the result of grid proxy call
526 and add to the cache if all OK
527
528 status - the status output
529 output - the output text
530 opt - opt to add
531 """
532
533 if ( not status ) and ( output ):
534 error = False
535 for line in output.split('\n'):
536 if ( 1 + line.find( "Couldn't find a valid proxy" ) ):
537 error = True
538
539 if not error:
540 _infoCache[ opt ] = [ output, time.time() ]
541
542 return None
543
544
545 for method in [ create, destroy, isAvailable, isValid, location, \
546 renew, timeleft, timeleftInHMS ]:
547 if hasattr( ICredential, method.__name__ ):
548 baseMethod = getattr( ICredential, method.__name__ )
549 setattr( method, "__doc__",\
550 baseMethod.__doc__.replace( "credential", "Grid Proxy" ) )
551