|
11 | 11 | * ProxyDB_VOMSProxies -- proxy storage table with VOMS extension already added.
|
12 | 12 | * ProxyDB_Log -- table with logs.
|
13 | 13 | * ProxyDB_Tokens -- token storage table for proxy requests.
|
14 |
| - * ProxyDB_ExpNotifs -- a table for accumulating proxy expiration notifications. |
15 | 14 | """
|
16 |
| -import time |
17 |
| -import random |
18 | 15 | import hashlib
|
| 16 | +import random |
| 17 | +import textwrap |
| 18 | +import time |
19 | 19 | from urllib.request import urlopen
|
20 | 20 |
|
21 |
| -from DIRAC import gConfig, gLogger, S_OK, S_ERROR |
| 21 | +from DIRAC import S_ERROR, S_OK, gConfig, gLogger |
| 22 | +from DIRAC.ConfigurationSystem.Client.Helpers import Registry |
22 | 23 | from DIRAC.Core.Base.DB import DB
|
23 |
| -from DIRAC.Core.Utilities import DErrno |
24 |
| -from DIRAC.Core.Security import Properties |
25 |
| -from DIRAC.Core.Security.VOMS import VOMS |
26 | 24 | from DIRAC.Core.Security.MyProxy import MyProxy
|
27 |
| -from DIRAC.Core.Security.X509Request import X509Request # pylint: disable=import-error |
| 25 | +from DIRAC.Core.Security.VOMS import VOMS |
28 | 26 | from DIRAC.Core.Security.X509Chain import X509Chain, isPUSPdn # pylint: disable=import-error
|
29 |
| -from DIRAC.ConfigurationSystem.Client.Helpers import Registry |
| 27 | +from DIRAC.Core.Security.X509Request import X509Request # pylint: disable=import-error |
| 28 | +from DIRAC.Core.Utilities import DErrno |
30 | 29 | from DIRAC.FrameworkSystem.Client.NotificationClient import NotificationClient
|
31 | 30 | from DIRAC.Resources.ProxyProvider.ProxyProviderFactory import ProxyProviderFactory
|
32 | 31 |
|
@@ -157,17 +156,6 @@ def __initializeDB(self):
|
157 | 156 | "PrimaryKey": "Token",
|
158 | 157 | }
|
159 | 158 |
|
160 |
| - if "ProxyDB_ExpNotifs" not in tablesInDB: |
161 |
| - tablesD["ProxyDB_ExpNotifs"] = { |
162 |
| - "Fields": { |
163 |
| - "UserDN": "VARCHAR(255) NOT NULL", |
164 |
| - "UserGroup": "VARCHAR(255) NOT NULL", |
165 |
| - "LifeLimit": "INTEGER UNSIGNED DEFAULT 0", |
166 |
| - "ExpirationTime": "DATETIME NOT NULL", |
167 |
| - }, |
168 |
| - "PrimaryKey": ["UserDN", "UserGroup"], |
169 |
| - } |
170 |
| - |
171 | 159 | return self._createTables(tablesD)
|
172 | 160 |
|
173 | 161 | def __addUserNameToTable(self, tableName):
|
@@ -480,8 +468,7 @@ def purgeExpiredProxies(self, sendNotifications=True):
|
480 | 468 | purged += result["Value"]
|
481 | 469 | self.log.info(f"Purged {result['Value']} expired proxies from {tableName}")
|
482 | 470 | if sendNotifications:
|
483 |
| - result = self.sendExpirationNotifications() |
484 |
| - if not result["OK"]: |
| 471 | + if not (result := self.sendExpirationNotifications())["OK"]: |
485 | 472 | return result
|
486 | 473 | return S_OK(purged)
|
487 | 474 |
|
@@ -1347,134 +1334,76 @@ def useToken(self, token, requesterDN, requesterGroup):
|
1347 | 1334 | return result
|
1348 | 1335 | return S_OK(result["Value"] > 0)
|
1349 | 1336 |
|
1350 |
| - def __cleanExpNotifs(self): |
1351 |
| - """Clean expired notifications from the db |
1352 |
| -
|
1353 |
| - :return: S_OK()/S_ERROR() |
1354 |
| - """ |
1355 |
| - cmd = "DELETE FROM `ProxyDB_ExpNotifs` WHERE ExpirationTime < UTC_TIMESTAMP()" |
1356 |
| - return self._update(cmd) |
1357 |
| - |
1358 |
| - # FIXME: Add clean proxy |
1359 | 1337 | def sendExpirationNotifications(self):
|
1360 | 1338 | """Send notification about expiration
|
1361 | 1339 |
|
1362 | 1340 | :return: S_OK(list)/S_ERROR() -- tuple list of user DN, group and proxy left time
|
1363 | 1341 | """
|
1364 |
| - result = self.__cleanExpNotifs() |
1365 |
| - if not result["OK"]: |
1366 |
| - return result |
1367 |
| - cmd = "SELECT UserDN, UserGroup, LifeLimit FROM `ProxyDB_ExpNotifs`" |
1368 |
| - result = self._query(cmd) |
1369 |
| - if not result["OK"]: |
1370 |
| - return result |
1371 |
| - notifDone = {(row[0], row[1]): row[2] for row in result["Value"]} |
1372 | 1342 | notifLimits = sorted(int(x) for x in self.getCSOption("NotificationTimes", ProxyDB.NOTIFICATION_TIMES))
|
1373 |
| - sqlSel = "UserDN, UserGroup, TIMESTAMPDIFF( SECOND, UTC_TIMESTAMP(), ExpirationTime )" |
1374 |
| - sqlCond = "TIMESTAMPDIFF( SECOND, UTC_TIMESTAMP(), ExpirationTime ) < %d" % max(notifLimits) |
1375 |
| - cmd = f"SELECT {sqlSel} FROM `ProxyDB_Proxies` WHERE {sqlCond}" |
1376 |
| - result = self._query(cmd) |
1377 |
| - if not result["OK"]: |
1378 |
| - return result |
1379 |
| - pilotProps = (Properties.GENERIC_PILOT, Properties.PILOT) |
1380 |
| - data = result["Value"] |
1381 |
| - sent = [] |
1382 |
| - for row in data: |
1383 |
| - userDN, group, lTime = row |
1384 |
| - # If it's a pilot proxy, skip it |
1385 |
| - if Registry.groupHasProperties(group, pilotProps): |
1386 |
| - continue |
1387 |
| - # IF it dosn't hace the auto upload proxy, skip it |
1388 |
| - if not Registry.getGroupOption(group, "AutoUploadProxy", False): |
1389 |
| - continue |
1390 |
| - notKey = (userDN, group) |
1391 |
| - for notifLimit in notifLimits: |
1392 |
| - if notifLimit < lTime: |
1393 |
| - # Not yet in this notification limit |
1394 |
| - continue |
1395 |
| - if notKey in notifDone and notifDone[notKey] <= notifLimit: |
1396 |
| - # Already notified for this notification limit |
1397 |
| - break |
1398 |
| - if not self._notifyProxyAboutToExpire(userDN, lTime): |
1399 |
| - # Cannot send notification, retry later |
| 1343 | + |
| 1344 | + for notifLimit in notifLimits: |
| 1345 | + sqlSel = "UserName, TIMESTAMPDIFF( SECOND, UTC_TIMESTAMP(), ExpirationTime )" |
| 1346 | + sqlCond = "TIMESTAMPDIFF( SECOND, UTC_TIMESTAMP(), ExpirationTime ) < %d" % notifLimit |
| 1347 | + sqlCond += " AND TIMESTAMPDIFF( SECOND, UTC_TIMESTAMP(), ExpirationTime ) > %d" % (notifLimit - 86400) |
| 1348 | + |
| 1349 | + if not (result := self._query(f"SELECT {sqlSel} FROM `ProxyDB_CleanProxies` WHERE {sqlCond}"))["OK"]: |
| 1350 | + return result |
| 1351 | + for userName, lTime in result["Value"]: |
| 1352 | + if not self._notifyProxyAboutToExpire(userName, lTime): |
| 1353 | + self.log.warn("Cannot send notification, will retry later") |
1400 | 1354 | break
|
1401 |
| - try: |
1402 |
| - sUserDN = self._escapeString(userDN)["Value"] |
1403 |
| - sGroup = self._escapeString(group)["Value"] |
1404 |
| - except KeyError: |
1405 |
| - return S_ERROR("OOPS") |
1406 |
| - if notKey not in notifDone: |
1407 |
| - values = "( %s, %s, %d, TIMESTAMPADD( SECOND, %s, UTC_TIMESTAMP() ) )" % ( |
1408 |
| - sUserDN, |
1409 |
| - sGroup, |
1410 |
| - notifLimit, |
1411 |
| - lTime, |
1412 |
| - ) |
1413 |
| - cmd = ( |
1414 |
| - "INSERT INTO `ProxyDB_ExpNotifs` ( UserDN, UserGroup, LifeLimit, ExpirationTime ) VALUES %s" |
1415 |
| - % values |
1416 |
| - ) |
1417 |
| - result = self._update(cmd) |
1418 |
| - if not result["OK"]: |
1419 |
| - gLogger.error("Could not mark notification as sent", result["Message"]) |
1420 |
| - else: |
1421 |
| - values = "LifeLimit = %d, ExpirationTime = TIMESTAMPADD( SECOND, %s, UTC_TIMESTAMP() )" % ( |
1422 |
| - notifLimit, |
1423 |
| - lTime, |
1424 |
| - ) |
1425 |
| - cmd = "UPDATE `ProxyDB_ExpNotifs` SET {} WHERE UserDN = {} AND UserGroup = {}".format( |
1426 |
| - values, |
1427 |
| - sUserDN, |
1428 |
| - sGroup, |
1429 |
| - ) |
1430 |
| - result = self._update(cmd) |
1431 |
| - if not result["OK"]: |
1432 |
| - gLogger.error("Could not mark notification as sent", result["Message"]) |
1433 |
| - sent.append((userDN, group, lTime)) |
1434 |
| - notifDone[notKey] = notifLimit |
1435 |
| - return S_OK(sent) |
1436 |
| - |
1437 |
| - def _notifyProxyAboutToExpire(self, userDN, lTime): |
| 1355 | + |
| 1356 | + return S_OK() |
| 1357 | + |
| 1358 | + def _notifyProxyAboutToExpire(self, userName, lTime): |
1438 | 1359 | """Send notification mail about to expire
|
1439 | 1360 |
|
1440 |
| - :param str userDN: user DN |
1441 |
| - :param int lTime: left proxy live time in a seconds |
| 1361 | + :param str userName: user name |
| 1362 | + :param int lTime: left proxy live time in seconds |
1442 | 1363 |
|
1443 | 1364 | :return: boolean
|
1444 | 1365 | """
|
1445 |
| - result = Registry.getUsernameForDN(userDN) |
1446 |
| - if not result["OK"]: |
1447 |
| - return False |
1448 |
| - userName = result["Value"] |
1449 |
| - userEMail = Registry.getUserOption(userName, "Email", "") |
1450 |
| - if not userEMail: |
| 1366 | + if not (userEMail := Registry.getUserOption(userName, "Email")): |
1451 | 1367 | gLogger.error("Could not discover user email", userName)
|
1452 | 1368 | return False
|
| 1369 | + if not (userDN := Registry.getUserOption(userName, "DN")): |
| 1370 | + gLogger.error("Could not discover user DN", userName) |
| 1371 | + return False |
1453 | 1372 | daysLeft = int(lTime / 86400)
|
1454 | 1373 | if daysLeft <= 0:
|
1455 | 1374 | return True # Don't annoy users with -1 messages
|
1456 | 1375 | msgSubject = "Your proxy uploaded to DIRAC will expire in %d days" % daysLeft
|
1457 |
| - msgBody = """\ |
1458 |
| -Dear %s, |
| 1376 | + msgBody = textwrap.dedent( |
| 1377 | + """\ |
| 1378 | + Dear %s, |
| 1379 | +
|
| 1380 | + The proxy you uploaded to DIRAC will expire in aproximately %d days. The proxy |
| 1381 | + information is: |
| 1382 | +
|
| 1383 | + DN: %s |
1459 | 1384 |
|
1460 |
| - The proxy you uploaded to DIRAC will expire in aproximately %d days. The proxy |
1461 |
| - information is: |
| 1385 | + If you plan on keep using this credentials, please upload a newer proxy by executing: |
1462 | 1386 |
|
1463 |
| - DN: %s |
| 1387 | + $ dirac-proxy-init |
1464 | 1388 |
|
1465 |
| - If you have been issued different certificate, please make sure you have a |
1466 |
| - proxy uploaded with that certificate. |
| 1389 | + If you have been issued different certificate, please make sure you have a |
| 1390 | + proxy uploaded with that certificate. |
1467 | 1391 |
|
1468 |
| -Cheers, |
1469 |
| - DIRAC's Proxy Manager |
1470 |
| -""" % ( |
1471 |
| - userName, |
1472 |
| - daysLeft, |
1473 |
| - userDN, |
| 1392 | + Cheers, |
| 1393 | + DIRAC's Proxy Manager |
| 1394 | + """ |
| 1395 | + % ( |
| 1396 | + userName, |
| 1397 | + daysLeft, |
| 1398 | + userDN, |
| 1399 | + ) |
1474 | 1400 | )
|
1475 | 1401 | fromAddr = self._mailFrom
|
1476 |
| - result = self.__notifClient.sendMail(userEMail, msgSubject, msgBody, fromAddress=fromAddr) |
1477 |
| - if not result["OK"]: |
| 1402 | + if not ( |
| 1403 | + result := self.__notifClient.sendMail( |
| 1404 | + userEMail, msgSubject, msgBody, fromAddress=fromAddr, localAttempt=False |
| 1405 | + ) |
| 1406 | + )["OK"]: |
1478 | 1407 | gLogger.error("Could not send email", result["Message"])
|
1479 | 1408 | return False
|
1480 | 1409 | return True
|
0 commit comments