def guess_version(appname): """Guess the default Gaudi application version""" s = Shell() tmp = tempfile.NamedTemporaryFile(suffix='.log') command = 'SetupProject.sh --ask %s' % appname rc,output,m=s.cmd1("echo 'q\n' | %s >& %s; echo" % (command,tmp.name)) output = tmp.read() tmp.close() version = output[output.rfind('[')+1:output.rfind(']')] return version
def available_versions(appname): """Provide a list of the available Gaudi application versions""" s = Shell() tmp = tempfile.NamedTemporaryFile(suffix='.log') command = 'SetupProject.sh --ask %s' % appname rc,output,m=s.cmd1("echo 'q\n' | %s >& %s; echo" % (command,tmp.name)) output = tmp.read() tmp.close() versions = output[output.rfind('(')+1:output.rfind('q[uit]')].split() return versions
class ICredential( GangaObject ): """ Interface class for working with credentials """ _schema = Schema( Version( 1, 0 ), { "maxTry" : SimpleItem( defvalue = 1, doc = "Number of password attempts allowed when creating credential" ), "minValidity" : SimpleItem( defvalue = "00:15", doc = "Default minimum validity" ), "validityAtCreation" : SimpleItem( defvalue = "24:00", doc = "Default credential validity at creation" ), "command" : ComponentItem( category = "credential_commands", defvalue = "ICommandSet", doc = "Set of commands to be used for credential-related operations" ) } ) _category = "credentials" _name = "ICredential" _hidden = 1 _exportmethods = [ "create", "destroy", "isAvailable", "isValid",\ "location", "renew", "timeleft" ] def __init__( self ): super( ICredential, self ).__init__() self.shell = Shell() self.inputPW_Widget = None return def create( self, validity = "", maxTry = 0, minValidity = "", \ check = False ): """ Create credential. Arguments other than self: validity - Validity with which credential should be created, specified as string of format "hh:mm" [ Defaults to value of self.validityAtCreation ] maxTry - Number of password attempts allowed [ Defaults to value of self.maxTry ] minValidity - Minimum validity in case checking of pre-existing credential is performed, specified as strong of format "hh:mm" [ Defaults to value of self.minValidity ] check - Flag to request checking of pre-existing credential; if flag is set to true, then new credential is created only if the validity of any pre-existing credential is less than the value of minValidity [ Default: False ] Note: create is the same as renew, except for the default value of check Return value: True if credential is created successfully, and False otherwise. """ global logTimeStamp dummy = False if not self.command.init: dummy = True if self.command.init_parameters.has_key( "valid" ): if not self.command.init_parameters[ "valid" ]: dummy = True if dummy: logger.warning( "Dummy CommandSet used - no credential created" ) return False if not maxTry: maxTry = self.maxTry if not minValidity: minValidity = self.minValidity if not validity: validity = self.validityAtCreation validityInSeconds = self.timeInSeconds( validity ) if not validityInSeconds: logger.warning( "Problems with requested validity: %s" \ % str( validity ) ) return False if check and self.isValid( minValidity ): return True ntry = 0 while ntry < maxTry: ntry = ntry + 1 # Test if GUI widget is to be used. if self.inputPW_Widget: # Since self.inputPW_Widget is called, current arguments are # ignored since renew() and create() in GUI mode will not be # called with any arguments. if self.inputPW_Widget.ask( self._proxyObject ): logger.debug( "Proceeding to retrieve password from inputPW_Widget." ) __pw = self.inputPW_Widget.getPassword( self._proxyObject ) if not __pw: logger.warning( "Password/passphrase expected!" ) return False try: tFile = tempfile.NamedTemporaryFile() tFile.write( __pw ) tFile.flush() except: del __pw logger.warning( "Could not create secure temporary file for password!" ) return False del __pw else: # Current credential modification denied for various reasons. # see GangaGUI.customDialogs.ask() method for more details. return False # self.inputPW_Widget.ask() may have modified parameters. # Calling buildOpts() to take them into account. self.buildOpts( self.command.init, False ) # Create initialisation list with the 'pipe' parameter initList = [ self.command.init, self.command.init_parameters[ "pipe" ] ] # Append option value pairs for optName, optVal in self.command.currentOpts.iteritems(): initList.append( "%s %s" % ( optName, optVal ) ) status = self.shell.system( "cat %s|%s" % ( tFile.name, " ".join( initList ) ) ) tFile.close() # self.inputPW_Widget dialog postprocessing. # E.g. disable autorenew mechanism if status != 0. self.inputPW_Widget.renewalStatus( self._proxyObject, status ) if status == 0: logger.info( "%s creation/renewal successful." % self._name ) return True else: logger.warning( "%s creation/renewal failed [%s]." % ( self._name, status ) ) return False else: # Non-GUI credential renewal/creation # Check if renewal is from main process (i.e. by bootstrap or user) if threading.currentThread().getName() == 'MainThread': if self.command.init_parameters.has_key( "valid" ): self.command.currentOpts\ [ self.command.init_parameters[ 'valid' ] ] = validity initList = [ self.command.init ] # Append option value pairs for optName, optVal in self.command.currentOpts.iteritems(): initList.append( "%s %s" % ( optName, optVal ) ) status = self.shell.system( " ".join( initList ) ) if status == 0: logger.info( "%s creation/renewal successful." % self._name ) return True else: logger.warning( "%s creation/renewal failed [%s]." % ( self._name, status ) ) else: # create initiated from worker thread from monitoring component. currTime = time.time() if currTime - logTimeStamp >= logRepeatDuration: logTimeStamp = currTime # Check validity but print logging messages this time self.isValid( "", True ) _credentialObject = self._name[ 0 ].lower() + self._name[ 1: ] logger.warning( \ "Renew by typing '%s.renew()' at the prompt." % \ ( _credentialObject ) ) #notify the Core that the credential is not valid _validity = self.timeInSeconds(self.timeleft()) _minValidity = self.timeInSeconds(minValidity)/2 if _validity <= max(120,_minValidity): Coordinator.notifyInvalidCredential(self) return True logger.warning( "%s creation/renewal attempts exceeded %s tries!" % ( self._name, maxTry ) ) return False def destroy( self, allowed_exit = [ 0 ] ): """ Destroy credential Argument other than self: allowed_exit - List of exit codes accepted without error when issuing system command for destroying credential Return value: False if command for destroying credential is undefined, or True otherwise """ if not self.command.destroy: logger.warning( "Dummy CommandSet used - no credential created" ) return False destroyList = [ self.command.destroy ] for optName, optVal in self.command.destroyOpts.iteritems(): destroyList.append( "%s %s" % ( optName, optVal ) ) Coordinator.notifyInvalidCredential(self) status, output, message = \ self.shell.cmd1( " ".join( destroyList ), allowed_exit ) proxyPath = self.location() if proxyPath: os.remove( proxyPath ) return True def isAvailable( self ): """ Check whether credential is available with system/configuration used No arguments other than self Return value: True if credential is available, false otherwise """ logger.warning( "Dummy method used - this always returns True" ) return True def isValid( self, validity = "", log = False, force_check = False ): """ Check validity Arguments other than self: validity - Minimum time for which credential should be valid, specified as string of format "hh:mm" [ Defaults to valud of self.minValidity ] log - Print logger messages if credential not valid force_check - Force credential check, rather than relying on cache Return value: True if credential is valid for required time, False otherwise. """ valid = True if not validity: validity = self.minValidity validityInSeconds = self.timeInSeconds( validity ) timeleft = self.timeleft( force_check = force_check ) if not timeleft: valid = False else: timeleftInSeconds = self.timeInSeconds( timeleft ) if timeleftInSeconds <= validityInSeconds: valid = False if not valid and log: _tl = self.timeleft( force_check = force_check ) if _tl == "-1" or _tl == "0:00:00": _expiryStatement = "has expired!" else: _expiryStatement = "will expire in %s!" % _tl itemList = [] text = self._name[ 0 ] for i in range( len( self._name ) - 1 ): character = self._name[ i + 1 ] if character.isupper(): itemList.append( text ) text = character.lower() else: text = "".join( [ text, character ] ) itemList.append( text ) _credentialName = " ".join( itemList ) logger.warning( "%s %s" % \ ( _credentialName, _expiryStatement ) ) return valid def location( self ): """ Determine credential location No arguments other than self Return value: Path to credential if found, or empty string otherwise """ return "" def renew( self, validity = "", maxTry = 0, minValidity = "", \ check = True ): """ Renew credential. Arguments other than self: validity - Validity with which credential should be created, specified as string of format "hh:mm" [ Defaults to value of self.validityAtCreation ] maxTry - Number of password attempts allowed [ Defaults to value of self.maxTry ] minValidity - Minimum validity in case checking of pre-existing credential is performed, specified as strong of format "hh:mm" [ Defaults to value of self.minValidity ] check - Flag to request checking of pre-existing credential; if flag is set to true, then new credential is created only if the validity of any pre-existing credential is less than the value of minValidity [ Default: True ] Note: renew is the same as create, except for the default value of check Return value: True if new credential is created successfully, and False otherwise. """ status = self.create( validity, maxTry, minValidity, check ) return status def timeInSeconds( self, timeString = "" ): """ Convert time string to time in seconds Arguments other than self: timeString - Time specified as string of format "hh:mm:ss" Return value: Time in seconds (integer) """ totalTime = 0 timeList = timeString.split( ":" ) if len( timeList ) >= 1: totalTime = totalTime + int( timeList[ 0 ] ) * 60 * 60 if len( timeList ) >= 2: totalTime = totalTime + int( timeList[ 1 ] ) * 60 if len( timeList ) >= 3: totalTime = totalTime + int (timeList[ 2 ] ) return totalTime def timeleft( self, units = "hh:mm:ss", force_check = False ): """ Check time for which credential is valid. Arguments other than self: units - String specifying units in which time is returned force_check - Force credential check, rather than relying on cache Allowed values for units are: "hours" - time returned as in hours "minutes" - time returned in minutes "seconds" - time returned in seconds "hh:mm:ss" [default] - time returned as hours, minutes seconds Return value: Credential validity as string giving time in requested units, or empty string if command for querying credential validity is unavailable """ timeRemaining = self.timeleftInHMS( force_check = force_check ) if timeRemaining not in [ "", "-1" ]: if units in [ "hours", "minutes", "seconds" ]: timeleftInSeconds = self.timeInSeconds( timeRemaining ) if "seconds" == units: timeRemaining = "%.2f" % ( timeleftInSeconds ) elif "minutes" == units: timeRemaining = "%.2f" % ( timeleftInSeconds / 60. ) elif "hours" == units: timeRemaining = "%.2f" % ( timeleftInSeconds / ( 60. * 60. ) ) return timeRemaining def timeleftInHMS( self, force_check = False ): """ Determine remaining validity of credential in hours, minutes and seconds Argument other than self: force_check - Force credential check, rather than relying on cache Return value: String giving credential validity, or empty string if command for querying credential validity is unavailable """ logger.warning( "Dummy method used - no information returned" ) return ""
class AfsTokenInfo(ICredentialInfo): """ A wrapper around an AFS token For now it is very CERN-specific (or at least only follows the CERN use-case) """ should_warn = False info_pattern = re.compile( r"^User's \(AFS ID \d*\) tokens for (?P<id>\w*@\S*) \[Expires (?P<expires>.*)\]$", re.MULTILINE) __slots__ = ('shell', 'cache', 'initial_requirements') def __init__(self, requirements, check_file=False, create=False): """ Args: requirements (ICredentialRequirement): An object specifying the requirements check_file (bool): Raise an exception if the file does not exist create (bool): Create the credential file """ self.shell = Shell() super(AfsTokenInfo, self).__init__(requirements, check_file, create) @retry_command def create(self): """ Creates a new AFS token Raises: CredentialRenewalError: If the renewal process returns a non-zero value """ command = 'kinit' process = subprocess.Popen(command, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdoutdata, stderrdata = process.communicate( getpass('Kerberos password: '******'AFS token %s created. Valid for %s', self.location, self.time_left()) else: raise CredentialRenewalError(stderrdata) def renew(self): """ Renews the AFS token Raises: CredentialRenewalError: If the renewal process returns a non-zero value """ status, output, message = self.shell.cmd1('kinit -R') if status != 0: logger.debug('kinit -R failed, creating as new') self.create() def destroy(self): """ This removes the kerberos token from disk """ self.shell.cmd1('unlog') if self.location: os.remove(self.location) @property @cache def info(self): """ This returns a summary of the token infor on disk """ status, output, message = self.shell.cmd1('tokens') return output @cache def expiry_time(self): """ This calculates the number of seconds left for the kerberos token on disk """ info = self.info matches = re.finditer(AfsTokenInfo.info_pattern, info) if not matches: return datetime.timedelta() all_tokens = [match.group('expires') for match in matches] if len(all_tokens) > 1: if AfsTokenInfo.should_warn: logger.warning( "Found multiple AFS tokens, taking soonest expiring one for safety" ) logger.warning("Tokens found for: %s".format(" ".join( [match.group('id') for match in matches]))) AfsTokenInfo.should_warn = False soonest = None for expires in all_tokens: expires = datetime.datetime.strptime(expires, '%b %d %H:%M') now = datetime.datetime.now() expires = expires.replace(year=now.year) # If the expiration date is in the past then assume it should be in the future if expires < now: expires = expires.replace(year=now.year + 1) if not soonest or expires < soonest: soonest = expires return soonest def default_location(self): """ This returns the default location of a kerberos token on disk as determined from the uid """ krb_env_var = os.getenv('KRB5CCNAME', '') if krb_env_var.startswith('FILE:'): krb_env_var = krb_env_var[5:] # If file already exists if os.path.exists(krb_env_var): return krb_env_var # Lets try to find it if we can't get it from the env default_name_prefix = '/tmp/krb5cc_{uid}'.format(uid=os.getuid()) matches = glob(default_name_prefix + '*') # Check for partial matches on disk if len(matches) == 1: # If one then use it filename_guess = matches[0] else: # Otherwise use the default filename_guess = default_name_prefix return filename_guess
class AfsTokenInfo(ICredentialInfo): """ A wrapper around an AFS token For now it is very CERN-specific (or at least only follows the CERN use-case) """ should_warn = False info_pattern = re.compile(r"^User's \(AFS ID \d*\) tokens for (?P<id>\w*@\S*) \[Expires (?P<expires>.*)\]$", re.MULTILINE) __slots__=('shell', 'cache', 'initial_requirements') def __init__(self, requirements, check_file=False, create=False): """ Args: requirements (ICredentialRequirement): An object specifying the requirements check_file (bool): Raise an exception if the file does not exist create (bool): Create the credential file """ self.shell = Shell() super(AfsTokenInfo, self).__init__(requirements, check_file, create) @retry_command def create(self): """ Creates a new AFS token Raises: CredentialRenewalError: If the renewal process returns a non-zero value """ command = 'kinit' process = subprocess.Popen(command, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdoutdata, stderrdata = process.communicate(getpass('Kerberos password: '******'AFS token %s created. Valid for %s', self.location, self.time_left()) else: raise CredentialRenewalError(stderrdata) def renew(self): """ Renews the AFS token Raises: CredentialRenewalError: If the renewal process returns a non-zero value """ status, output, message = self.shell.cmd1('kinit -R') if status != 0: logger.debug('kinit -R failed, creating as new') self.create() def destroy(self): """ This removes the kerberos token from disk """ self.shell.cmd1('unlog') if self.location: os.remove(self.location) @property @cache def info(self): """ This returns a summary of the token infor on disk """ status, output, message = self.shell.cmd1('tokens') return output @cache def expiry_time(self): """ This calculates the number of seconds left for the kerberos token on disk """ info = self.info matches = re.finditer(AfsTokenInfo.info_pattern, info) if not matches: return datetime.timedelta() all_tokens = [match.group('expires') for match in matches] if len(all_tokens) > 1: if AfsTokenInfo.should_warn: logger.warning("Found multiple AFS tokens, taking soonest expiring one for safety") logger.warning("Tokens found for: %s".format(" ".join([match.group('id') for match in matches]))) AfsTokenInfo.should_warn = False soonest = None for expires in all_tokens: expires = datetime.datetime.strptime(expires, '%b %d %H:%M') now = datetime.datetime.now() expires = expires.replace(year=now.year) # If the expiration date is in the past then assume it should be in the future if expires < now: expires = expires.replace(year=now.year+1) if not soonest or expires < soonest: soonest = expires return soonest def default_location(self): """ This returns the default location of a kerberos token on disk as determined from the uid """ krb_env_var = os.getenv('KRB5CCNAME', '') if krb_env_var.startswith('FILE:'): krb_env_var = krb_env_var[5:] # If file already exists if os.path.exists(krb_env_var): return krb_env_var # Lets try to find it if we can't get it from the env default_name_prefix = '/tmp/krb5cc_{uid}'.format(uid=os.getuid()) matches = glob(default_name_prefix+'*') # Check for partial matches on disk if len(matches) == 1: # If one then use it filename_guess = matches[0] else: # Otherwise use the default filename_guess = default_name_prefix return filename_guess
class ICredential(GangaObject): """ Interface class for working with credentials """ _schema = Schema( Version(1, 0), { "maxTry": SimpleItem( defvalue=1, typelist=[int], doc= "Number of password attempts allowed when creating credential" ), "minValidity": SimpleItem(defvalue="00:15", typelist=[str], doc="Default minimum validity"), "validityAtCreation": SimpleItem(defvalue="24:00", typelist=[str], doc="Default credential validity at creation"), "command": ComponentItem( category="credential_commands", defvalue="ICommandSet", doc= "Set of commands to be used for credential-related operations") }) _category = "credentials" _name = "ICredential" _hidden = 1 _exportmethods = [ "create", "destroy", "isAvailable", "isValid", "location", "renew", "timeleft" ] def __init__(self): super(ICredential, self).__init__() self.shell = Shell() self.inputPW_Widget = None return def create(self, validity="", maxTry=0, minValidity="", check=False): """ Create credential. Arguments other than self: validity - Validity with which credential should be created, specified as string of format "hh:mm" [ Defaults to value of self.validityAtCreation ] maxTry - Number of password attempts allowed [ Defaults to value of self.maxTry ] minValidity - Minimum validity in case checking of pre-existing credential is performed, specified as strong of format "hh:mm" [ Defaults to value of self.minValidity ] check - Flag to request checking of pre-existing credential; if flag is set to true, then new credential is created only if the validity of any pre-existing credential is less than the value of minValidity [ Default: False ] Note: create is the same as renew, except for the default value of check Return value: True if credential is created successfully, and False otherwise. """ global logTimeStamp dummy = False if not self.command.init: dummy = True if "valid" in self.command.init_parameters: if not self.command.init_parameters["valid"]: dummy = True if dummy: logger.warning("Dummy CommandSet used - no credential created") return False if not maxTry: maxTry = self.maxTry if not minValidity: minValidity = self.minValidity if not validity: validity = self.validityAtCreation validityInSeconds = self.timeInSeconds(validity) if not validityInSeconds: logger.warning("Problems with requested validity: %s" % str(validity)) return False if check and self.isValid(minValidity): return True ntry = 0 while ntry < maxTry: ntry = ntry + 1 # Test if GUI widget is to be used. if self.inputPW_Widget: # Since self.inputPW_Widget is called, current arguments are # ignored since renew() and create() in GUI mode will not be # called with any arguments. #proxy_obj = self._proxyObject ## This is removed to get rid of ref to _proxyObject proxy_obj = self if self.inputPW_Widget.ask(proxy_obj): logger.dg( "Proceeding to retrieve password from inputPW_Widget.") __pw = self.inputPW_Widget.getPassword(proxy_obj) if not __pw: logger.warning("Password/passphrase expected!") return False try: tFile = tempfile.NamedTemporaryFile() tFile.write(__pw) tFile.flush() except: del __pw logger.warning( "Could not create secure temporary file for password!" ) return False del __pw else: # Current credential modification denied for various reasons. # see GangaGUI.customDialogs.ask() method for more details. return False # self.inputPW_Widget.ask() may have modified parameters. # Calling buildOpts() to take them into account. self.buildOpts(self.command.init, False) # Create initialisation list with the 'pipe' parameter initList = [ self.command.init, self.command.init_parameters["pipe"] ] # Append option value pairs for optName, optVal in self.command.currentOpts.iteritems(): initList.append("%s %s" % (optName, optVal)) status = self.shell.system("cat %s|%s" % (tFile.name, " ".join(initList))) tFile.close() # self.inputPW_Widget dialog postprocessing. # E.g. disable autorenew mechanism if status != 0. self.inputPW_Widget.renewalStatus(proxy_obj, status) if status == 0: logger.info("%s creation/renewal successful." % self._name) return True else: logger.warning("%s creation/renewal failed [%s]." % (self._name, status)) return False else: # Non-GUI credential renewal/creation # Check if renewal is from main process (i.e. by bootstrap or # user) if threading.currentThread().getName() == 'MainThread' or\ threading.currentThread().getName().startswith('GANGA_Update_Thread_Ganga_Worker_'): if "valid" in self.command.init_parameters: self.command.currentOpts[ self.command.init_parameters['valid']] = validity initList = [self.command.init] # Append option value pairs for optName, optVal in self.command.currentOpts.iteritems( ): initList.append("%s %s" % (optName, optVal)) status = self.shell.system(" ".join(initList)) if status == 0: logger.info("%s creation/renewal successful." % self._name) return True else: logger.warning("%s creation/renewal failed [%s]." % (self._name, status)) # create initiated from worker thread from monitoring # component. else: currTime = time.time() if currTime - logTimeStamp >= logRepeatDuration: logTimeStamp = currTime # Check validity but print logging messages this time self.isValid("", True) _credentialObject = self._name[0].lower( ) + self._name[1:] logger.warning( "Renew by typing '%s.renew()' at the prompt." % (_credentialObject)) # notify the Core that the credential is not valid _validity = self.timeInSeconds(self.timeleft()) _minValidity = self.timeInSeconds(minValidity) / 2. if _validity <= max(120, _minValidity): Coordinator.notifyInvalidCredential(self) return True logger.warning("%s creation/renewal attempts exceeded %s tries!" % (self._name, maxTry)) return False def destroy(self, allowed_exit=[0]): """ Destroy credential Argument other than self: allowed_exit - List of exit codes accepted without error when issuing system command for destroying credential Return value: False if command for destroying credential is undefined, or True otherwise """ if not self.command.destroy: logger.warning("Dummy CommandSet used - no credential created") return False destroyList = [self.command.destroy] for optName, optVal in self.command.destroyOpts.iteritems(): destroyList.append("%s %s" % (optName, optVal)) Coordinator.notifyInvalidCredential(self) status, output, message = \ self.shell.cmd1(" ".join(destroyList), allowed_exit) proxyPath = self.location() if proxyPath: os.remove(proxyPath) return True def isAvailable(self): """ Check whether credential is available with system/configuration used No arguments other than self Return value: True if credential is available, false otherwise """ logger.warning("Dummy method used - this always returns True") return True def isValid(self, validity="", log=False, force_check=False): """ Check validity Arguments other than self: validity - Minimum time for which credential should be valid, specified as string of format "hh:mm" [ Defaults to valud of self.minValidity ] log - Print logger messages if credential not valid force_check - Force credential check, rather than relying on cache Return value: True if credential is valid for required time, False otherwise. """ valid = True if not validity or validity is None: validity = self.minValidity validityInSeconds = self.timeInSeconds(validity) timeleft = self.timeleft(force_check=force_check) if not timeleft: valid = False else: timeleftInSeconds = self.timeInSeconds(timeleft) if timeleftInSeconds <= validityInSeconds: valid = False if not valid and log: _tl = self.timeleft(force_check=force_check) if _tl == "-1" or _tl == "0:00:00": _expiryStatement = "has expired!" else: _expiryStatement = "will expire in %s!" % _tl itemList = [] text = self._name[0] for i in range(len(self._name) - 1): character = self._name[i + 1] if character.isupper(): itemList.append(text) text = character.lower() else: text = "".join([text, character]) itemList.append(text) _credentialName = " ".join(itemList) logger.warning("%s %s" % (_credentialName, _expiryStatement)) return valid def location(self): """ Determine credential location No arguments other than self Return value: Path to credential if found, or empty string otherwise """ return "" def renew(self, validity="", maxTry=0, minValidity="", check=True): """ Renew credential. Arguments other than self: validity - Validity with which credential should be created, specified as string of format "hh:mm" [ Defaults to value of self.validityAtCreation ] maxTry - Number of password attempts allowed [ Defaults to value of self.maxTry ] minValidity - Minimum validity in case checking of pre-existing credential is performed, specified as strong of format "hh:mm" [ Defaults to value of self.minValidity ] check - Flag to request checking of pre-existing credential; if flag is set to true, then new credential is created only if the validity of any pre-existing credential is less than the value of minValidity [ Default: True ] Note: renew is the same as create, except for the default value of check Return value: True if new credential is created successfully, and False otherwise. """ status = self.create(validity, maxTry, minValidity, check) return status def timeInSeconds(self, timeString=""): """ Convert time string to time in seconds Arguments other than self: timeString - Time specified as string of format "hh:mm:ss" Return value: Time in seconds (integer) """ totalTime = 0 timeList = timeString.split(":") if len(timeList) >= 1: totalTime = totalTime + int(timeList[0]) * 60 * 60 if len(timeList) >= 2: totalTime = totalTime + int(timeList[1]) * 60 if len(timeList) >= 3: totalTime = totalTime + int(timeList[2]) return totalTime def timeleft(self, units="hh:mm:ss", force_check=False): """ Check time for which credential is valid. Arguments other than self: units - String specifying units in which time is returned force_check - Force credential check, rather than relying on cache Allowed values for units are: "hours" - time returned as in hours "minutes" - time returned in minutes "seconds" - time returned in seconds "hh:mm:ss" [default] - time returned as hours, minutes seconds Return value: Credential validity as string giving time in requested units, or empty string if command for querying credential validity is unavailable """ timeRemaining = self.timeleftInHMS(force_check=force_check) if timeRemaining not in ["", "-1"]: if units in ["hours", "minutes", "seconds"]: timeleftInSeconds = self.timeInSeconds(timeRemaining) if "seconds" == units: timeRemaining = "%.2f" % (timeleftInSeconds) elif "minutes" == units: timeRemaining = "%.2f" % (timeleftInSeconds / 60.) elif "hours" == units: timeRemaining = "%.2f" % (timeleftInSeconds / (60. * 60.)) return timeRemaining def timeleftInHMS(self, force_check=False): """ Determine remaining validity of credential in hours, minutes and seconds Argument other than self: force_check - Force credential check, rather than relying on cache Return value: String giving credential validity, or empty string if command for querying credential validity is unavailable """ logger.warning("Dummy method used - no information returned") return ""