DIRAC 9.0.5__py3-none-any.whl → 9.0.6__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,9 +1,11 @@
1
- """ FTS3Job module containing only the FTS3Job class """
1
+ """FTS3Job module containing only the FTS3Job class"""
2
2
 
3
3
  import datetime
4
4
  import errno
5
+ import os
5
6
  from packaging.version import Version
6
7
 
8
+ from cachetools import cachedmethod, LRUCache
7
9
 
8
10
  # Requires at least version 3.3.3
9
11
  from fts3 import __version__ as fts3_version
@@ -26,8 +28,9 @@ from DIRAC.Resources.Storage.StorageElement import StorageElement
26
28
 
27
29
  from DIRAC.FrameworkSystem.Client.Logger import gLogger
28
30
  from DIRAC.FrameworkSystem.Client.TokenManagerClient import gTokenManager
31
+ from DIRAC.FrameworkSystem.Utilities.TokenManagementUtilities import getIdProviderClient
29
32
 
30
- from DIRAC.Core.Utilities.ReturnValues import S_OK, S_ERROR
33
+ from DIRAC.Core.Utilities.ReturnValues import S_OK, S_ERROR, returnValueOrRaise
31
34
  from DIRAC.Core.Utilities.DErrno import cmpError
32
35
 
33
36
  from DIRAC.Core.Utilities.JEncode import JSerializable
@@ -36,6 +39,10 @@ from DIRAC.DataManagementSystem.Client.FTS3File import FTS3File
36
39
  # 3 days in seconds
37
40
  BRING_ONLINE_TIMEOUT = 259200
38
41
 
42
+ # Number of IdP to keep in cache. Should correspond roughly
43
+ # to the number of groups performing transfers
44
+ IDP_CACHE_SIZE = 8
45
+
39
46
 
40
47
  class FTS3Job(JSerializable):
41
48
  """Abstract class to represent a job to be executed by FTS. It belongs
@@ -78,6 +85,8 @@ class FTS3Job(JSerializable):
78
85
  "userGroup",
79
86
  ]
80
87
 
88
+ _idp_cache = LRUCache(maxsize=IDP_CACHE_SIZE)
89
+
81
90
  def __init__(self):
82
91
  self.submitTime = None
83
92
  self.lastUpdate = None
@@ -113,6 +122,11 @@ class FTS3Job(JSerializable):
113
122
  # when a job is in a final state
114
123
  self.accountingDict = None
115
124
 
125
+ @classmethod
126
+ @cachedmethod(lambda cls: cls._idp_cache)
127
+ def _getIdpClient(cls, group_name: str):
128
+ return returnValueOrRaise(getIdProviderClient(group_name, None, client_name_prefix="fts"))
129
+
116
130
  def monitor(self, context=None, ftsServer=None, ucert=None):
117
131
  """Queries the fts server to monitor the job.
118
132
  The internal state of the object is updated depending on the
@@ -509,11 +523,10 @@ class FTS3Job(JSerializable):
509
523
  if not res["OK"]:
510
524
  return res
511
525
  srcTokenPath = res["Value"]
512
- res = gTokenManager.getToken(
513
- userGroup=self.userGroup,
514
- requiredTimeLeft=3600,
526
+ res = self._getIdpClient(self.userGroup).fetchToken(
527
+ grant_type="client_credentials",
515
528
  scope=[f"storage.read:/{srcTokenPath}", "offline_access"],
516
- useCache=False,
529
+ # TODO: add a specific audience
517
530
  )
518
531
  if not res["OK"]:
519
532
  return res
@@ -528,11 +541,17 @@ class FTS3Job(JSerializable):
528
541
  if not res["OK"]:
529
542
  return res
530
543
  dstTokenPath = res["Value"]
531
- res = gTokenManager.getToken(
532
- userGroup=self.userGroup,
533
- requiredTimeLeft=3600,
534
- scope=[f"storage.modify:/{dstTokenPath}", f"storage.read:/{dstTokenPath}", "offline_access"],
535
- useCache=False,
544
+ res = self._getIdpClient(self.userGroup).fetchToken(
545
+ grant_type="client_credentials",
546
+ scope=[
547
+ f"storage.modify:/{dstTokenPath}",
548
+ f"storage.read:/{dstTokenPath}",
549
+ # Needed because CNAF
550
+ # https://ggus.eu/index.php?mode=ticket_info&ticket_id=165048
551
+ f"storage.read:/{os.path.dirname(dstTokenPath)}",
552
+ "offline_access",
553
+ ],
554
+ # TODO: add a specific audience
536
555
  )
537
556
  if not res["OK"]:
538
557
  return res
@@ -728,6 +747,7 @@ class FTS3Job(JSerializable):
728
747
  retry=3,
729
748
  metadata=job_metadata,
730
749
  priority=self.priority,
750
+ unmanaged_tokens=True,
731
751
  **dest_spacetoken,
732
752
  )
733
753
 
@@ -10,11 +10,12 @@ DEFAULT_RT_EXPIRATION_TIME = 24 * 3600
10
10
  DEFAULT_AT_EXPIRATION_TIME = 1200
11
11
 
12
12
 
13
- def getIdProviderClient(userGroup: str, idProviderClientName: str = None):
13
+ def getIdProviderClient(userGroup: str, idProviderClientName: str = None, client_name_prefix: str = ""):
14
14
  """Get an IdProvider client
15
15
 
16
16
  :param userGroup: group name
17
17
  :param idProviderClientName: name of an identity provider in the DIRAC CS
18
+ :param client_name_prefix: prefix of the client in the CS options
18
19
  """
19
20
  # Get IdProvider credentials from CS
20
21
  if not idProviderClientName and userGroup:
@@ -23,7 +24,7 @@ def getIdProviderClient(userGroup: str, idProviderClientName: str = None):
23
24
  return S_ERROR(f"The {userGroup} group belongs to the VO that is not tied to any Identity Provider.")
24
25
 
25
26
  # Prepare the client instance of the appropriate IdP
26
- return IdProviderFactory().getIdProvider(idProviderClientName)
27
+ return IdProviderFactory().getIdProvider(idProviderClientName, client_name_prefix=client_name_prefix)
27
28
 
28
29
 
29
30
  def getCachedKey(
@@ -1,6 +1,7 @@
1
- """ The Identity Provider Factory instantiates IdProvider objects
2
- according to their configuration
1
+ """The Identity Provider Factory instantiates IdProvider objects
2
+ according to their configuration
3
3
  """
4
+
4
5
  import jwt
5
6
 
6
7
  from DIRAC import S_OK, S_ERROR, gLogger, gConfig
@@ -40,11 +41,12 @@ class IdProviderFactory:
40
41
  return result
41
42
  return self.getIdProvider(result["Value"])
42
43
 
43
- def getIdProvider(self, name, **kwargs):
44
+ def getIdProvider(self, name, client_name_prefix="", **kwargs):
44
45
  """This method returns a IdProvider instance corresponding to the supplied
45
46
  name.
46
47
 
47
48
  :param str name: the name of the Identity Provider client
49
+ :param str client_name_prefix: name of the client of the IdP
48
50
 
49
51
  :return: S_OK(IdProvider)/S_ERROR()
50
52
  """
@@ -68,8 +70,14 @@ class IdProviderFactory:
68
70
  if not result["OK"]:
69
71
  self.log.error("Failed to read configuration", f"{name}: {result['Message']}")
70
72
  return result
73
+
71
74
  pDict = result["Value"]
72
75
 
76
+ if client_name_prefix:
77
+ client_name_prefix = client_name_prefix + "_"
78
+ pDict["client_id"] = pDict[f"{client_name_prefix}client_id"]
79
+ pDict["client_secret"] = pDict[f"{client_name_prefix}client_secret"]
80
+
73
81
  pDict.update(kwargs)
74
82
  pDict["ProviderName"] = name
75
83
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: DIRAC
3
- Version: 9.0.5
3
+ Version: 9.0.6
4
4
  Summary: DIRAC is an interware, meaning a software framework for distributed computing.
5
5
  Home-page: https://github.com/DIRACGrid/DIRAC/
6
6
  License: GPL-3.0-only
@@ -19,7 +19,7 @@ Requires-Dist: cachetools
19
19
  Requires-Dist: certifi
20
20
  Requires-Dist: cwltool
21
21
  Requires-Dist: diraccfg
22
- Requires-Dist: DIRACCommon==v9.0.5
22
+ Requires-Dist: DIRACCommon==v9.0.6
23
23
  Requires-Dist: diracx-client>=v0.0.1
24
24
  Requires-Dist: diracx-core>=v0.0.1
25
25
  Requires-Dist: diracx-cli>=v0.0.1
@@ -365,7 +365,7 @@ DIRAC/DataManagementSystem/Client/DataManager.py,sha256=edLmRUHJtZEYAMyen3y9qwdG
365
365
  DIRAC/DataManagementSystem/Client/DirectoryListing.py,sha256=CvQZ5Da5WhgwdDL8iLk0xVBjKZrBHTdwMKWwSJwzwEI,7582
366
366
  DIRAC/DataManagementSystem/Client/FTS3Client.py,sha256=Kk1wy4YnkYuOI6IltyDYZqkzxV7Zsf7ZuoKT12_VbTw,3531
367
367
  DIRAC/DataManagementSystem/Client/FTS3File.py,sha256=gZFN_Uxc2tblUCETb4qWPJ2M1tSmKUvTMiZUL-yJ6M0,3122
368
- DIRAC/DataManagementSystem/Client/FTS3Job.py,sha256=X0BCd35SSGjGBr3tL0TmQiPDxMT8H5gHugBK86x0I04,38482
368
+ DIRAC/DataManagementSystem/Client/FTS3Job.py,sha256=uiiTDowNrv91OeFHWPCrygZR--JqIdBOgZOv0AS5tEg,39393
369
369
  DIRAC/DataManagementSystem/Client/FTS3Operation.py,sha256=L3yqc0X0ziluMPegoQU6o3aYDnTYwLtujShgbGFJjsw,24455
370
370
  DIRAC/DataManagementSystem/Client/FailoverTransfer.py,sha256=2V-dKtgAndMuw9iZHYV019V0hLwlezUNP33wvClpsaA,13373
371
371
  DIRAC/DataManagementSystem/Client/FileCatalogClientCLI.py,sha256=sc_6mT0BCbXgj5wOEFtCxNc0AvyQ186A_yLi2lnduvw,80094
@@ -531,7 +531,7 @@ DIRAC/FrameworkSystem/Service/TornadoUserProfileManagerHandler.py,sha256=9z8Vky8
531
531
  DIRAC/FrameworkSystem/Service/UserProfileManagerHandler.py,sha256=DyZFvqFeKjxVYNXqGYLkTlYgj3raUsfsb68GE4FX5x4,5707
532
532
  DIRAC/FrameworkSystem/Service/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
533
533
  DIRAC/FrameworkSystem/Utilities/MonitoringUtilities.py,sha256=wt6QhJ6A_ifRP8kAgRWo-vtS_jJa8e5Xi9GdrRuA-i8,2556
534
- DIRAC/FrameworkSystem/Utilities/TokenManagementUtilities.py,sha256=qbh6WQMvbczBjiP8Dig3PCQWODXSgPXeYpgXLTOaIiU,2895
534
+ DIRAC/FrameworkSystem/Utilities/TokenManagementUtilities.py,sha256=eEeKs9JMJOiokjDtDcRlyQiRWIM1TNYwcVy1C4oozuY,3034
535
535
  DIRAC/FrameworkSystem/Utilities/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
536
536
  DIRAC/FrameworkSystem/Utilities/diracx.py,sha256=cyHtKuRY-maOUmY96uhj5sEKzb6nTEhNvOd2LlDhp18,3647
537
537
  DIRAC/FrameworkSystem/Utilities/test/Test_TokenManagementUtilities.py,sha256=XIaNe18QjuBUmPvDFBmKO0UNSEiYJCzQP-XuH-JMY3s,6551
@@ -948,7 +948,7 @@ DIRAC/Resources/Computing/test/Test_SSHComputingElement.py,sha256=ahYUZ9hySaEXik
948
948
  DIRAC/Resources/Computing/test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
949
949
  DIRAC/Resources/IdProvider/CheckInIdProvider.py,sha256=Tq8ENK6yhC7Tl6JkTF1q8mCOrFRfsN3ediF251iU4oM,1163
950
950
  DIRAC/Resources/IdProvider/IAMIdProvider.py,sha256=kk2ty2mLevxGmJRBpLYlQXce_vy4cxp-dO2w7b1rCz0,822
951
- DIRAC/Resources/IdProvider/IdProviderFactory.py,sha256=-MbDuQ7bIGcBhaHDAlA9NUzgC6VwMlujfHUOwf8uzEE,3899
951
+ DIRAC/Resources/IdProvider/IdProviderFactory.py,sha256=bAUYnGQQUhCCXTq1o68lRlOPG--77oR9JoOAX6t0TNs,4238
952
952
  DIRAC/Resources/IdProvider/OAuth2IdProvider.py,sha256=smoGhSD1JsyjJDot9XmMUmT7fw8kcfS3w392s2Lg9P8,23650
953
953
  DIRAC/Resources/IdProvider/Utilities.py,sha256=bHF-aNtOapEN7Z18XKOFfAcXCHceLbEWU9dOrKeHxDo,1785
954
954
  DIRAC/Resources/IdProvider/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -1295,9 +1295,9 @@ DIRAC/tests/Workflow/Integration/exe-script.py,sha256=B_slYdTocEzqfQLRhwuPiLyYUn
1295
1295
  DIRAC/tests/Workflow/Integration/helloWorld.py,sha256=tBgEHH3ZF7ZiTS57gtmm3DW-Qxgm_57HWHpM-Y8XSws,205
1296
1296
  DIRAC/tests/Workflow/Regression/helloWorld.py,sha256=69eCgFuVSYo-mK3Dj2dw1c6g86sF5FksKCf8V2aGVoM,509
1297
1297
  DIRAC/tests/Workflow/Regression/helloWorld.xml,sha256=xwydIcFTAHIX-YPfQfyxuQ7hzvIO3IhR3UAF7ORgkGg,5310
1298
- dirac-9.0.5.dist-info/licenses/LICENSE,sha256=uyr4oV6jmjUeepXZPPjkJRwa5q5MrI7jqJz5sVXNblQ,32452
1299
- dirac-9.0.5.dist-info/METADATA,sha256=WgBoEsoG3B1PTa2YPy4NsEzaG4q01d5BOVhMYEIZbTs,10016
1300
- dirac-9.0.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
1301
- dirac-9.0.5.dist-info/entry_points.txt,sha256=hupzIL8aVmjK3nn7RLKdhcaiPmLOiD3Kulh3CSDHKmw,16492
1302
- dirac-9.0.5.dist-info/top_level.txt,sha256=RISrnN9kb_mPqmVu8_o4jF-DSX8-h6AcgfkO9cgfkHA,6
1303
- dirac-9.0.5.dist-info/RECORD,,
1298
+ dirac-9.0.6.dist-info/licenses/LICENSE,sha256=uyr4oV6jmjUeepXZPPjkJRwa5q5MrI7jqJz5sVXNblQ,32452
1299
+ dirac-9.0.6.dist-info/METADATA,sha256=tbETxonTh5kgVSZJNZeZgQNue961cdGH4IXCZEgmWN8,10016
1300
+ dirac-9.0.6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
1301
+ dirac-9.0.6.dist-info/entry_points.txt,sha256=hupzIL8aVmjK3nn7RLKdhcaiPmLOiD3Kulh3CSDHKmw,16492
1302
+ dirac-9.0.6.dist-info/top_level.txt,sha256=RISrnN9kb_mPqmVu8_o4jF-DSX8-h6AcgfkO9cgfkHA,6
1303
+ dirac-9.0.6.dist-info/RECORD,,
File without changes