File indexing completed on 2026-04-11 08:41:05
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 import os
0014 import logging
0015
0016 from pilot.user.atlas.setup import get_file_system_root_path
0017 from pilot.util.container import execute
0018 from pilot.common.errorcodes import ErrorCodes
0019 from time import time
0020
0021 logger = logging.getLogger(__name__)
0022 errors = ErrorCodes()
0023
0024
0025 def verify_proxy(limit=None, x509=None, proxy_id="pilot", test=False):
0026 """
0027 Check for a valid voms/grid proxy longer than N hours.
0028 Use `limit` to set required time limit.
0029
0030 :param limit: time limit in hours (int).
0031 :param x509: points to the proxy file. If not set (=None) - get proxy file from X509_USER_PROXY environment
0032 :return: exit code (NOPROXY or NOVOMSPROXY), diagnostics (error diagnostics string).
0033 """
0034
0035 if limit is None:
0036 limit = 48
0037
0038
0039
0040 if x509 is None:
0041 x509 = os.environ.get('X509_USER_PROXY', '')
0042 if x509 != '':
0043 envsetup = 'export X509_USER_PROXY=%s;' % x509
0044 else:
0045 envsetup = ''
0046
0047 envsetup += ". %s/atlas.cern.ch/repo/ATLASLocalRootBase/user/atlasLocalSetup.sh --quiet;" % get_file_system_root_path()
0048 if os.environ.get('ALRB_noGridMW', '').lower() != "yes":
0049 envsetup += "lsetup emi;"
0050 else:
0051 logger.warning('Skipping "lsetup emi" as ALRB_noGridMW=YES')
0052
0053
0054
0055
0056 exit_code, diagnostics = verify_arcproxy(envsetup, limit, proxy_id, test=test)
0057 if exit_code != 0 and exit_code != -1:
0058 return exit_code, diagnostics
0059 elif exit_code == -1:
0060 pass
0061 else:
0062 return 0, diagnostics
0063
0064 exit_code, diagnostics = verify_vomsproxy(envsetup, limit)
0065 if exit_code != 0:
0066 return exit_code, diagnostics
0067 else:
0068 return 0, diagnostics
0069
0070 return 0, diagnostics
0071
0072
0073 def verify_arcproxy(envsetup, limit, proxy_id="pilot", test=False):
0074 """
0075 Verify the proxy using arcproxy.
0076
0077 :param envsetup: general setup string for proxy commands (string).
0078 :param limit: time limit in hours (int).
0079 :param proxy_id: proxy unique id name. The verification result will be cached for this id. If None the result will not be cached (string)
0080 :return: exit code (int), error diagnostics (string).
0081 """
0082 exit_code = 0
0083 diagnostics = ""
0084
0085 if test:
0086 return errors.NOVOMSPROXY, 'dummy test'
0087
0088 if proxy_id is not None:
0089 if not hasattr(verify_arcproxy, "cache"):
0090 verify_arcproxy.cache = {}
0091
0092 if proxy_id in verify_arcproxy.cache:
0093 validity_end = verify_arcproxy.cache[proxy_id]
0094 if validity_end < 0:
0095 exit_code = -1
0096 diagnostics = "arcproxy verification failed (cached result)"
0097 else:
0098 tnow = int(time() + 0.5)
0099 seconds_left = validity_end - tnow
0100 logger.info("cache: check %s proxy validity: wanted=%dh left=%.2fh (now=%d validity_end=%d left=%d)",
0101 proxy_id, limit, float(seconds_left) / 3600, tnow, validity_end, seconds_left)
0102 if seconds_left < limit * 3600:
0103 diagnostics = "%s proxy validity time is too short: %.2fh" % (proxy_id, float(seconds_left) / 3600)
0104 logger.warning(diagnostics)
0105 exit_code = errors.NOVOMSPROXY
0106 else:
0107 logger.info("%s proxy validity time is verified", proxy_id)
0108 return exit_code, diagnostics
0109
0110
0111 cmd = "%sarcproxy -i vomsACvalidityEnd -i vomsACvalidityLeft" % envsetup
0112
0113 _exit_code, stdout, stderr = execute(cmd, shell=True)
0114 if stdout is not None:
0115 if 'command not found' in stdout:
0116 logger.warning("arcproxy is not available on this queue,"
0117 "this can lead to memory issues with voms-proxy-info on SL6: %s", stdout)
0118 exit_code = -1
0119 else:
0120 exit_code, diagnostics, validity_end = interpret_proxy_info(_exit_code, stdout, stderr, limit)
0121 if proxy_id and validity_end:
0122 if exit_code == 0:
0123 logger.info("cache the validity_end: cache['%s'] = %d", proxy_id, validity_end)
0124 verify_arcproxy.cache[proxy_id] = validity_end
0125 else:
0126 verify_arcproxy.cache[proxy_id] = -1
0127 if exit_code == 0:
0128 logger.info("voms proxy verified using arcproxy")
0129 return 0, diagnostics
0130 elif exit_code == -1:
0131 return exit_code, diagnostics
0132 elif exit_code == errors.NOVOMSPROXY:
0133 return exit_code, diagnostics
0134 else:
0135 logger.info("will try voms-proxy-info instead")
0136 exit_code = -1
0137 else:
0138 logger.warning('command execution failed')
0139
0140 return exit_code, diagnostics
0141
0142
0143 def verify_vomsproxy(envsetup, limit):
0144 """
0145 Verify proxy using voms-proxy-info command.
0146
0147 :param envsetup: general setup string for proxy commands (string).
0148 :param limit: time limit in hours (int).
0149 :return: exit code (int), error diagnostics (string).
0150 """
0151
0152 exit_code = 0
0153 diagnostics = ""
0154
0155 if os.environ.get('X509_USER_PROXY', '') != '':
0156 cmd = "%svoms-proxy-info -actimeleft --file $X509_USER_PROXY" % envsetup
0157 logger.info('executing command: %s', cmd)
0158 _exit_code, stdout, stderr = execute(cmd, shell=True)
0159 if stdout is not None:
0160 if "command not found" in stdout:
0161 logger.info("skipping voms proxy check since command is not available")
0162 else:
0163 exit_code, diagnostics, validity_end = interpret_proxy_info(_exit_code, stdout, stderr, limit)
0164 if exit_code == 0:
0165 logger.info("voms proxy verified using voms-proxy-info")
0166 return 0, diagnostics
0167 else:
0168 logger.warning('command execution failed')
0169 else:
0170 logger.warning('X509_USER_PROXY is not set')
0171
0172 return exit_code, diagnostics
0173
0174
0175 def verify_gridproxy(envsetup, limit):
0176 """
0177 Verify proxy using grid-proxy-info command.
0178
0179 :param envsetup: general setup string for proxy commands (string).
0180 :param limit: time limit in hours (int).
0181 :return: exit code (int), error diagnostics (string).
0182 """
0183
0184 ec = 0
0185 diagnostics = ""
0186
0187 if limit:
0188
0189
0190
0191 limit_hours = int(limit * 60) / 60
0192 limit_minutes = int(limit * 60 + .999) - limit_hours * 60
0193 cmd = "%sgrid-proxy-info -exists -valid %d:%02d" % (envsetup, limit_hours, limit_minutes)
0194 else:
0195 cmd = "%sgrid-proxy-info -exists -valid 24:00" % (envsetup)
0196
0197 logger.info('executing command: %s', cmd)
0198 exit_code, stdout, stderr = execute(cmd, shell=True)
0199 if stdout is not None:
0200 if exit_code != 0:
0201 if stdout.find("command not found") > 0:
0202 logger.info("skipping grid proxy check since command is not available")
0203 else:
0204
0205 diagnostics = "grid proxy certificate does not exist or is too short: %d, %s" % (exit_code, stdout)
0206 logger.warning(diagnostics)
0207 return errors.NOPROXY, diagnostics
0208 else:
0209 logger.info("grid proxy verified")
0210 else:
0211 logger.warning('command execution failed')
0212
0213 return ec, diagnostics
0214
0215
0216 def interpret_proxy_info(ec, stdout, stderr, limit):
0217 """
0218 Interpret the output from arcproxy or voms-proxy-info.
0219
0220 :param ec: exit code from proxy command (int).
0221 :param stdout: stdout from proxy command (string).
0222 :param stderr: stderr from proxy command (string).
0223 :param limit: time limit in hours (int).
0224 :return: exit code (int), diagnostics (string). validity end in seconds if detected, None if not detected(int)
0225 """
0226
0227 exitcode = 0
0228 diagnostics = ""
0229 validity_end = None
0230
0231 logger.debug('stdout = %s', stdout)
0232 logger.debug('stderr = %s', stderr)
0233
0234 if ec != 0:
0235 if "Unable to verify signature! Server certificate possibly not installed" in stdout:
0236 logger.warning("skipping voms proxy check: %s", stdout)
0237
0238 elif "arcproxy: error while loading shared libraries" in stderr:
0239 exitcode = -1
0240 logger.warning('skipping arcproxy test')
0241 elif "arcproxy:" in stdout:
0242 diagnostics = "arcproxy failed: %s" % (stdout)
0243 logger.warning(diagnostics)
0244 exitcode = errors.GENERALERROR
0245 else:
0246
0247 diagnostics = "voms proxy certificate check failure: %d, %s" % (ec, stdout)
0248 logger.warning(diagnostics)
0249 exitcode = errors.NOVOMSPROXY
0250 else:
0251 if "\n" in stdout:
0252
0253 validity_end, stdout = extract_time_left(stdout)
0254 if validity_end:
0255 return exitcode, diagnostics, validity_end
0256
0257
0258 if "arcproxy:" in stdout:
0259 diagnostics = "arcproxy failed: %s" % stdout
0260 logger.warning(diagnostics)
0261 exitcode = errors.GENERALERROR
0262 else:
0263
0264 if ":" in stdout:
0265 ftr = [3600, 60, 1]
0266 stdout = sum([a * b for a, b in zip(ftr, list(map(int, stdout.split(':'))))])
0267 try:
0268 validity = int(stdout)
0269 if validity >= limit * 3600:
0270 logger.info("voms proxy verified (%d s)", validity)
0271 else:
0272 diagnostics = "voms proxy certificate does not exist or is too short (lifetime %d s)" % validity
0273 logger.warning(diagnostics)
0274 exitcode = errors.NOVOMSPROXY
0275 except ValueError as exc:
0276 diagnostics = "failed to evaluate command stdout: %s, stderr: %s, exc=%s" % (stdout, stderr, exc)
0277 logger.warning(diagnostics)
0278 exitcode = errors.GENERALERROR
0279
0280 return exitcode, diagnostics, validity_end
0281
0282
0283 def extract_time_left(stdout):
0284 """
0285 Extract the time left from the proxy command.
0286 Some processing on the stdout is done.
0287
0288 :param stdout: stdout (string).
0289 :return: validity_end, stdout (int, string))
0290 """
0291
0292
0293 if stdout[-1] == '\n':
0294 stdout = stdout[:-1]
0295 stdout_split = stdout.split('\n')
0296 logger.debug("splitted stdout = %s", stdout_split)
0297
0298 try:
0299 validity_end = int(stdout_split[-2])
0300 except (ValueError, TypeError):
0301
0302 try:
0303 validity_end_str = stdout_split[-1]
0304 logger.debug("try to get validity_end from the line: \"%s\"", validity_end_str)
0305 validity_end = int(validity_end_str)
0306 except (IndexError, ValueError) as exc:
0307 logger.info("validity_end not found in stdout (%s)", exc)
0308
0309
0310 if validity_end:
0311 logger.info("validity_end = %d", validity_end)
0312
0313 return validity_end, stdout