DIRAC 9.0.0a42__py3-none-any.whl → 9.0.7__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.
Files changed (236) hide show
  1. DIRAC/AccountingSystem/Client/AccountingCLI.py +0 -140
  2. DIRAC/AccountingSystem/Client/DataStoreClient.py +0 -13
  3. DIRAC/AccountingSystem/Client/Types/BaseAccountingType.py +0 -7
  4. DIRAC/AccountingSystem/ConfigTemplate.cfg +0 -5
  5. DIRAC/AccountingSystem/Service/DataStoreHandler.py +0 -72
  6. DIRAC/ConfigurationSystem/Client/Helpers/CSGlobals.py +0 -9
  7. DIRAC/ConfigurationSystem/Client/Helpers/Registry.py +38 -26
  8. DIRAC/ConfigurationSystem/Client/Helpers/Resources.py +11 -43
  9. DIRAC/ConfigurationSystem/Client/Helpers/test/Test_Helpers.py +0 -16
  10. DIRAC/ConfigurationSystem/Client/LocalConfiguration.py +14 -8
  11. DIRAC/ConfigurationSystem/Client/PathFinder.py +47 -8
  12. DIRAC/ConfigurationSystem/Client/SyncPlugins/CERNLDAPSyncPlugin.py +4 -1
  13. DIRAC/ConfigurationSystem/Client/VOMS2CSSynchronizer.py +32 -19
  14. DIRAC/ConfigurationSystem/Client/test/Test_PathFinder.py +41 -1
  15. DIRAC/ConfigurationSystem/private/RefresherBase.py +4 -2
  16. DIRAC/Core/Base/API.py +4 -7
  17. DIRAC/Core/Base/SQLAlchemyDB.py +1 -0
  18. DIRAC/Core/DISET/ServiceReactor.py +11 -3
  19. DIRAC/Core/DISET/private/BaseClient.py +1 -2
  20. DIRAC/Core/DISET/private/Transports/M2SSLTransport.py +9 -7
  21. DIRAC/Core/DISET/private/Transports/SSL/M2Utils.py +3 -1
  22. DIRAC/Core/LCG/GOCDBClient.py +5 -7
  23. DIRAC/Core/Security/DiracX.py +31 -17
  24. DIRAC/Core/Security/IAMService.py +5 -10
  25. DIRAC/Core/Security/Locations.py +27 -18
  26. DIRAC/Core/Security/ProxyInfo.py +9 -5
  27. DIRAC/Core/Security/VOMSService.py +2 -4
  28. DIRAC/Core/Security/m2crypto/X509Certificate.py +4 -6
  29. DIRAC/Core/Security/m2crypto/asn1_utils.py +17 -5
  30. DIRAC/Core/Security/test/test_diracx_token_from_pem.py +161 -0
  31. DIRAC/Core/Tornado/Client/ClientSelector.py +4 -1
  32. DIRAC/Core/Tornado/Server/TornadoService.py +1 -1
  33. DIRAC/Core/Utilities/CGroups2.py +328 -0
  34. DIRAC/Core/Utilities/ClassAd/ClassAdLight.py +4 -290
  35. DIRAC/Core/Utilities/DErrno.py +5 -309
  36. DIRAC/Core/Utilities/Extensions.py +10 -1
  37. DIRAC/Core/Utilities/File.py +1 -1
  38. DIRAC/Core/Utilities/Graphs/GraphData.py +1 -1
  39. DIRAC/Core/Utilities/Graphs/GraphUtilities.py +6 -1
  40. DIRAC/Core/Utilities/JDL.py +1 -195
  41. DIRAC/Core/Utilities/List.py +1 -124
  42. DIRAC/Core/Utilities/MySQL.py +103 -99
  43. DIRAC/Core/Utilities/Os.py +32 -1
  44. DIRAC/Core/Utilities/Platform.py +2 -107
  45. DIRAC/Core/Utilities/Proxy.py +0 -4
  46. DIRAC/Core/Utilities/ReturnValues.py +7 -252
  47. DIRAC/Core/Utilities/StateMachine.py +12 -178
  48. DIRAC/Core/Utilities/Subprocess.py +35 -14
  49. DIRAC/Core/Utilities/TimeUtilities.py +10 -253
  50. DIRAC/Core/Utilities/test/Test_JDL.py +0 -3
  51. DIRAC/Core/Utilities/test/Test_Profiler.py +20 -20
  52. DIRAC/Core/scripts/dirac_agent.py +1 -1
  53. DIRAC/Core/scripts/dirac_apptainer_exec.py +72 -46
  54. DIRAC/Core/scripts/dirac_configure.py +1 -3
  55. DIRAC/Core/scripts/dirac_install_db.py +24 -6
  56. DIRAC/Core/scripts/dirac_platform.py +1 -92
  57. DIRAC/DataManagementSystem/Agent/FTS3Agent.py +8 -7
  58. DIRAC/DataManagementSystem/Agent/RequestOperations/RemoveFile.py +7 -6
  59. DIRAC/DataManagementSystem/Client/FTS3Job.py +71 -34
  60. DIRAC/DataManagementSystem/DB/FTS3DB.py +7 -3
  61. DIRAC/DataManagementSystem/DB/FileCatalogComponents/DatasetManager/DatasetManager.py +1 -1
  62. DIRAC/DataManagementSystem/DB/FileCatalogDB.sql +9 -9
  63. DIRAC/DataManagementSystem/DB/FileCatalogWithFkAndPsDB.sql +9 -9
  64. DIRAC/DataManagementSystem/Utilities/DMSHelpers.py +6 -2
  65. DIRAC/DataManagementSystem/scripts/dirac_admin_allow_se.py +13 -8
  66. DIRAC/DataManagementSystem/scripts/dirac_admin_ban_se.py +13 -8
  67. DIRAC/DataManagementSystem/scripts/dirac_dms_create_moving_request.py +2 -0
  68. DIRAC/DataManagementSystem/scripts/dirac_dms_protocol_matrix.py +0 -1
  69. DIRAC/FrameworkSystem/Client/BundleDeliveryClient.py +2 -7
  70. DIRAC/FrameworkSystem/Client/ComponentInstaller.py +9 -4
  71. DIRAC/FrameworkSystem/Client/ProxyManagerClient.py +5 -2
  72. DIRAC/FrameworkSystem/Client/SystemAdministratorClientCLI.py +11 -6
  73. DIRAC/FrameworkSystem/ConfigTemplate.cfg +2 -0
  74. DIRAC/FrameworkSystem/DB/AuthDB.py +3 -3
  75. DIRAC/FrameworkSystem/DB/InstalledComponentsDB.py +4 -4
  76. DIRAC/FrameworkSystem/DB/ProxyDB.py +11 -3
  77. DIRAC/FrameworkSystem/DB/TokenDB.py +1 -1
  78. DIRAC/FrameworkSystem/Service/ProxyManagerHandler.py +8 -6
  79. DIRAC/FrameworkSystem/Utilities/MonitoringUtilities.py +2 -19
  80. DIRAC/FrameworkSystem/Utilities/TokenManagementUtilities.py +3 -2
  81. DIRAC/FrameworkSystem/Utilities/diracx.py +36 -14
  82. DIRAC/FrameworkSystem/private/authorization/AuthServer.py +2 -2
  83. DIRAC/FrameworkSystem/scripts/dirac_admin_update_pilot.py +18 -11
  84. DIRAC/FrameworkSystem/scripts/dirac_login.py +2 -2
  85. DIRAC/FrameworkSystem/scripts/dirac_proxy_init.py +7 -8
  86. DIRAC/Interfaces/API/Dirac.py +27 -15
  87. DIRAC/Interfaces/API/DiracAdmin.py +45 -17
  88. DIRAC/Interfaces/API/Job.py +9 -13
  89. DIRAC/Interfaces/scripts/dirac_admin_allow_site.py +12 -18
  90. DIRAC/Interfaces/scripts/dirac_admin_ban_site.py +12 -10
  91. DIRAC/Interfaces/scripts/dirac_admin_get_site_mask.py +4 -13
  92. DIRAC/Interfaces/scripts/dirac_admin_reset_job.py +3 -6
  93. DIRAC/Interfaces/scripts/dirac_wms_job_parameters.py +0 -1
  94. DIRAC/MonitoringSystem/Client/Types/WMSHistory.py +4 -0
  95. DIRAC/MonitoringSystem/Client/WebAppClient.py +26 -0
  96. DIRAC/MonitoringSystem/ConfigTemplate.cfg +9 -0
  97. DIRAC/MonitoringSystem/DB/MonitoringDB.py +6 -25
  98. DIRAC/MonitoringSystem/Service/MonitoringHandler.py +0 -33
  99. DIRAC/MonitoringSystem/Service/WebAppHandler.py +599 -0
  100. DIRAC/MonitoringSystem/private/MainReporter.py +0 -3
  101. DIRAC/ProductionSystem/DB/ProductionDB.sql +4 -4
  102. DIRAC/ProductionSystem/scripts/dirac_prod_get.py +2 -2
  103. DIRAC/ProductionSystem/scripts/dirac_prod_get_all.py +2 -2
  104. DIRAC/ProductionSystem/scripts/dirac_prod_get_trans.py +2 -3
  105. DIRAC/RequestManagementSystem/Agent/RequestExecutingAgent.py +8 -6
  106. DIRAC/RequestManagementSystem/Agent/RequestOperations/ForwardDISET.py +2 -14
  107. DIRAC/RequestManagementSystem/Client/ReqClient.py +66 -13
  108. DIRAC/RequestManagementSystem/ConfigTemplate.cfg +6 -6
  109. DIRAC/RequestManagementSystem/DB/RequestDB.py +10 -5
  110. DIRAC/RequestManagementSystem/DB/test/RMSTestScenari.py +2 -0
  111. DIRAC/RequestManagementSystem/private/RequestValidator.py +40 -46
  112. DIRAC/ResourceStatusSystem/Client/SiteStatus.py +4 -2
  113. DIRAC/ResourceStatusSystem/Command/FreeDiskSpaceCommand.py +3 -1
  114. DIRAC/ResourceStatusSystem/DB/ResourceManagementDB.py +8 -8
  115. DIRAC/ResourceStatusSystem/DB/ResourceStatusDB.py +2 -2
  116. DIRAC/ResourceStatusSystem/Utilities/CSHelpers.py +2 -31
  117. DIRAC/ResourceStatusSystem/scripts/dirac_rss_set_status.py +30 -12
  118. DIRAC/Resources/Catalog/RucioFileCatalogClient.py +195 -1
  119. DIRAC/Resources/Catalog/test/Test_RucioFileCatalogClient.py +181 -0
  120. DIRAC/Resources/Computing/AREXComputingElement.py +25 -8
  121. DIRAC/Resources/Computing/BatchSystems/Condor.py +126 -108
  122. DIRAC/Resources/Computing/BatchSystems/SLURM.py +5 -1
  123. DIRAC/Resources/Computing/BatchSystems/test/Test_SLURM.py +46 -0
  124. DIRAC/Resources/Computing/ComputingElement.py +1 -1
  125. DIRAC/Resources/Computing/HTCondorCEComputingElement.py +44 -44
  126. DIRAC/Resources/Computing/InProcessComputingElement.py +4 -2
  127. DIRAC/Resources/Computing/LocalComputingElement.py +1 -18
  128. DIRAC/Resources/Computing/SSHBatchComputingElement.py +1 -17
  129. DIRAC/Resources/Computing/SSHComputingElement.py +1 -18
  130. DIRAC/Resources/Computing/SingularityComputingElement.py +19 -5
  131. DIRAC/Resources/Computing/test/Test_HTCondorCEComputingElement.py +67 -49
  132. DIRAC/Resources/Computing/test/Test_PoolComputingElement.py +2 -1
  133. DIRAC/Resources/IdProvider/CheckInIdProvider.py +13 -0
  134. DIRAC/Resources/IdProvider/IdProviderFactory.py +11 -3
  135. DIRAC/Resources/MessageQueue/StompMQConnector.py +1 -1
  136. DIRAC/Resources/Storage/GFAL2_StorageBase.py +24 -15
  137. DIRAC/Resources/Storage/OccupancyPlugins/WLCGAccountingHTTPJson.py +1 -3
  138. DIRAC/Resources/Storage/StorageBase.py +4 -2
  139. DIRAC/Resources/Storage/StorageElement.py +6 -7
  140. DIRAC/StorageManagementSystem/DB/StorageManagementDB.sql +2 -2
  141. DIRAC/TransformationSystem/Agent/TaskManagerAgentBase.py +10 -16
  142. DIRAC/TransformationSystem/Agent/TransformationAgent.py +22 -1
  143. DIRAC/TransformationSystem/Agent/TransformationCleaningAgent.py +16 -16
  144. DIRAC/TransformationSystem/Client/TaskManager.py +2 -4
  145. DIRAC/TransformationSystem/Client/Transformation.py +6 -7
  146. DIRAC/TransformationSystem/Client/TransformationClient.py +21 -11
  147. DIRAC/TransformationSystem/Client/Utilities.py +9 -0
  148. DIRAC/TransformationSystem/DB/TransformationDB.py +11 -14
  149. DIRAC/TransformationSystem/DB/TransformationDB.sql +9 -9
  150. DIRAC/TransformationSystem/Service/TransformationManagerHandler.py +0 -333
  151. DIRAC/TransformationSystem/Utilities/ReplicationCLIParameters.py +3 -3
  152. DIRAC/TransformationSystem/Utilities/TransformationInfo.py +7 -5
  153. DIRAC/TransformationSystem/scripts/dirac_production_runjoblocal.py +2 -4
  154. DIRAC/TransformationSystem/test/Test_TransformationInfo.py +22 -15
  155. DIRAC/TransformationSystem/test/Test_replicationTransformation.py +5 -6
  156. DIRAC/Workflow/Modules/test/Test_Modules.py +5 -0
  157. DIRAC/WorkloadManagementSystem/Agent/JobAgent.py +38 -26
  158. DIRAC/WorkloadManagementSystem/Agent/JobCleaningAgent.py +12 -8
  159. DIRAC/WorkloadManagementSystem/Agent/PilotSyncAgent.py +4 -3
  160. DIRAC/WorkloadManagementSystem/Agent/PushJobAgent.py +13 -13
  161. DIRAC/WorkloadManagementSystem/Agent/SiteDirector.py +18 -14
  162. DIRAC/WorkloadManagementSystem/Agent/StalledJobAgent.py +18 -51
  163. DIRAC/WorkloadManagementSystem/Agent/StatesAccountingAgent.py +41 -1
  164. DIRAC/WorkloadManagementSystem/Agent/test/Test_Agent_JobAgent.py +45 -4
  165. DIRAC/WorkloadManagementSystem/Agent/test/Test_Agent_JobCleaningAgent.py +7 -9
  166. DIRAC/WorkloadManagementSystem/Agent/test/Test_Agent_PushJobAgent.py +1 -0
  167. DIRAC/WorkloadManagementSystem/Agent/test/Test_Agent_SiteDirector.py +9 -2
  168. DIRAC/WorkloadManagementSystem/Agent/test/Test_Agent_StalledJobAgent.py +4 -5
  169. DIRAC/WorkloadManagementSystem/Client/DownloadInputData.py +9 -9
  170. DIRAC/WorkloadManagementSystem/Client/InputDataResolution.py +6 -6
  171. DIRAC/WorkloadManagementSystem/Client/JobMonitoringClient.py +10 -11
  172. DIRAC/WorkloadManagementSystem/Client/JobReport.py +1 -1
  173. DIRAC/WorkloadManagementSystem/Client/JobState/CachedJobState.py +3 -0
  174. DIRAC/WorkloadManagementSystem/Client/JobState/JobManifest.py +32 -261
  175. DIRAC/WorkloadManagementSystem/Client/JobState/JobState.py +6 -0
  176. DIRAC/WorkloadManagementSystem/Client/JobStateUpdateClient.py +3 -0
  177. DIRAC/WorkloadManagementSystem/Client/JobStatus.py +8 -152
  178. DIRAC/WorkloadManagementSystem/Client/PoolXMLSlice.py +12 -19
  179. DIRAC/WorkloadManagementSystem/Client/SandboxStoreClient.py +25 -38
  180. DIRAC/WorkloadManagementSystem/Client/WMSClient.py +2 -3
  181. DIRAC/WorkloadManagementSystem/Client/test/Test_Client_DownloadInputData.py +29 -0
  182. DIRAC/WorkloadManagementSystem/ConfigTemplate.cfg +4 -8
  183. DIRAC/WorkloadManagementSystem/DB/JobDB.py +89 -132
  184. DIRAC/WorkloadManagementSystem/DB/JobDB.sql +8 -8
  185. DIRAC/WorkloadManagementSystem/DB/JobDBUtils.py +18 -147
  186. DIRAC/WorkloadManagementSystem/DB/JobLoggingDB.py +19 -6
  187. DIRAC/WorkloadManagementSystem/DB/JobParametersDB.py +9 -9
  188. DIRAC/WorkloadManagementSystem/DB/PilotAgentsDB.py +16 -5
  189. DIRAC/WorkloadManagementSystem/DB/PilotAgentsDB.sql +3 -3
  190. DIRAC/WorkloadManagementSystem/DB/SandboxMetadataDB.py +44 -82
  191. DIRAC/WorkloadManagementSystem/DB/StatusUtils.py +125 -0
  192. DIRAC/WorkloadManagementSystem/DB/tests/Test_JobDB.py +1 -1
  193. DIRAC/WorkloadManagementSystem/DB/tests/Test_StatusUtils.py +28 -0
  194. DIRAC/WorkloadManagementSystem/Executor/JobSanity.py +5 -4
  195. DIRAC/WorkloadManagementSystem/Executor/JobScheduling.py +4 -0
  196. DIRAC/WorkloadManagementSystem/FutureClient/JobStateUpdateClient.py +75 -33
  197. DIRAC/WorkloadManagementSystem/JobWrapper/JobWrapper.py +22 -11
  198. DIRAC/WorkloadManagementSystem/JobWrapper/JobWrapperTemplate.py +9 -10
  199. DIRAC/WorkloadManagementSystem/JobWrapper/test/Test_JobWrapper.py +60 -10
  200. DIRAC/WorkloadManagementSystem/JobWrapper/test/Test_JobWrapperTemplate.py +4 -0
  201. DIRAC/WorkloadManagementSystem/Service/JobManagerHandler.py +33 -154
  202. DIRAC/WorkloadManagementSystem/Service/JobMonitoringHandler.py +5 -323
  203. DIRAC/WorkloadManagementSystem/Service/JobStateUpdateHandler.py +0 -16
  204. DIRAC/WorkloadManagementSystem/Service/PilotManagerHandler.py +6 -103
  205. DIRAC/WorkloadManagementSystem/Service/SandboxStoreHandler.py +7 -53
  206. DIRAC/WorkloadManagementSystem/Service/WMSAdministratorHandler.py +16 -79
  207. DIRAC/WorkloadManagementSystem/Service/WMSUtilities.py +4 -18
  208. DIRAC/WorkloadManagementSystem/Utilities/JobModel.py +28 -209
  209. DIRAC/WorkloadManagementSystem/Utilities/JobParameters.py +65 -3
  210. DIRAC/WorkloadManagementSystem/Utilities/JobStatusUtility.py +2 -64
  211. DIRAC/WorkloadManagementSystem/Utilities/ParametricJob.py +7 -171
  212. DIRAC/WorkloadManagementSystem/Utilities/PilotCStoJSONSynchronizer.py +73 -7
  213. DIRAC/WorkloadManagementSystem/Utilities/PilotWrapper.py +41 -11
  214. DIRAC/WorkloadManagementSystem/Utilities/RemoteRunner.py +16 -0
  215. DIRAC/WorkloadManagementSystem/Utilities/Utils.py +36 -1
  216. DIRAC/WorkloadManagementSystem/Utilities/jobAdministration.py +15 -0
  217. DIRAC/WorkloadManagementSystem/Utilities/test/Test_JobModel.py +1 -15
  218. DIRAC/WorkloadManagementSystem/Utilities/test/Test_ParametricJob.py +45 -128
  219. DIRAC/WorkloadManagementSystem/Utilities/test/Test_PilotWrapper.py +16 -0
  220. DIRAC/WorkloadManagementSystem/scripts/dirac_jobexec.py +7 -2
  221. DIRAC/WorkloadManagementSystem/scripts/dirac_wms_pilot_job_info.py +1 -1
  222. DIRAC/__init__.py +62 -60
  223. DIRAC/tests/Utilities/testJobDefinitions.py +22 -28
  224. {DIRAC-9.0.0a42.dist-info → dirac-9.0.7.dist-info}/METADATA +8 -5
  225. {DIRAC-9.0.0a42.dist-info → dirac-9.0.7.dist-info}/RECORD +229 -228
  226. {DIRAC-9.0.0a42.dist-info → dirac-9.0.7.dist-info}/WHEEL +1 -1
  227. {DIRAC-9.0.0a42.dist-info → dirac-9.0.7.dist-info}/entry_points.txt +0 -3
  228. DIRAC/Core/Utilities/test/Test_List.py +0 -150
  229. DIRAC/Core/Utilities/test/Test_Time.py +0 -88
  230. DIRAC/Resources/Computing/PilotBundle.py +0 -70
  231. DIRAC/TransformationSystem/scripts/dirac_transformation_archive.py +0 -30
  232. DIRAC/TransformationSystem/scripts/dirac_transformation_clean.py +0 -30
  233. DIRAC/TransformationSystem/scripts/dirac_transformation_remove_output.py +0 -30
  234. DIRAC/WorkloadManagementSystem/Utilities/test/Test_JobManager.py +0 -58
  235. {DIRAC-9.0.0a42.dist-info → dirac-9.0.7.dist-info/licenses}/LICENSE +0 -0
  236. {DIRAC-9.0.0a42.dist-info → dirac-9.0.7.dist-info}/top_level.txt +0 -0
@@ -57,99 +57,6 @@ class AccountingCLI(CLI):
57
57
  traceback.print_tb(sys.exc_info()[2])
58
58
  print("________________________\n")
59
59
 
60
- def do_registerType(self, args):
61
- """
62
- Registers a new accounting type
63
- Usage : registerType <typeName>
64
- <DIRACRoot>/DIRAC/AccountingSystem/Client/Types/<typeName>
65
- should exist and inherit the base type
66
- """
67
- try:
68
- argList = args.split()
69
- if argList:
70
- typeName = argList[0].strip()
71
- else:
72
- gLogger.error("No type name specified")
73
- return
74
- # Try to import the type
75
- result = self.objectLoader.loadObject(f"DIRAC.AccountingSystem.Client.Types.{typeName}")
76
- if not result["OK"]:
77
- return result
78
- typeClass = result["Value"]
79
-
80
- gLogger.info(f"Loaded type {typeClass.__name__}")
81
- typeDef = typeClass().getDefinition()
82
- acClient = DataStoreClient()
83
- retVal = acClient.registerType(*typeDef)
84
- if retVal["OK"]:
85
- gLogger.info("Type registered successfully")
86
- else:
87
- gLogger.error(f"Error: {retVal['Message']}")
88
- except Exception:
89
- self.showTraceback()
90
-
91
- def do_resetBucketLength(self, args):
92
- """
93
- Set the bucket Length. Will trigger a recalculation of buckets. Can take a while.
94
- Usage : resetBucketLength <typeName>
95
- <DIRACRoot>/DIRAC/AccountingSystem/Client/Types/<typeName>
96
- should exist and inherit the base type
97
- """
98
- try:
99
- argList = args.split()
100
- if argList:
101
- typeName = argList[0].strip()
102
- else:
103
- gLogger.error("No type name specified")
104
- return
105
-
106
- # Try to import the type
107
- result = self.objectLoader.loadObject(f"DIRAC.AccountingSystem.Client.Types.{typeName}")
108
- if not result["OK"]:
109
- return result
110
- typeClass = result["Value"]
111
- gLogger.info(f"Loaded type {typeClass.__name__}")
112
- typeDef = typeClass().getDefinition()
113
- acClient = DataStoreClient()
114
- retVal = acClient.setBucketsLength(typeDef[0], typeDef[3])
115
- if retVal["OK"]:
116
- gLogger.info("Type registered successfully")
117
- else:
118
- gLogger.error(f"Error: {retVal['Message']}")
119
- except Exception:
120
- self.showTraceback()
121
-
122
- def do_regenerateBuckets(self, args):
123
- """
124
- Regenerate buckets for type. Can take a while.
125
- Usage : regenerateBuckets <typeName>
126
- <DIRACRoot>/DIRAC/AccountingSystem/Client/Types/<typeName>
127
- should exist and inherit the base type
128
- """
129
- try:
130
- argList = args.split()
131
- if argList:
132
- typeName = argList[0].strip()
133
- else:
134
- gLogger.error("No type name specified")
135
- return
136
-
137
- # Try to import the type
138
- result = self.objectLoader.loadObject(f"DIRAC.AccountingSystem.Client.Types.{typeName}")
139
- if not result["OK"]:
140
- return result
141
- typeClass = result["Value"]
142
- gLogger.info(f"Loaded type {typeClass.__name__}")
143
- typeDef = typeClass().getDefinition()
144
- acClient = DataStoreClient()
145
- retVal = acClient.regenerateBuckets(typeDef[0])
146
- if retVal["OK"]:
147
- gLogger.info("Buckets recalculated!")
148
- else:
149
- gLogger.error(f"Error: {retVal['Message']}")
150
- except Exception:
151
- self.showTraceback()
152
-
153
60
  def do_showRegisteredTypes(self, args):
154
61
  """
155
62
  Get a list of registered types
@@ -170,50 +77,3 @@ class AccountingCLI(CLI):
170
77
  print(" Value fields:\n %s" % "\n ".join(typeList[2]))
171
78
  except Exception:
172
79
  self.showTraceback()
173
-
174
- def do_deleteType(self, args):
175
- """
176
- Delete a registered accounting type.
177
- Usage : deleteType <typeName>
178
- WARN! It will delete all data associated to that type! VERY DANGEROUS!
179
- If you screw it, you'll discover a new dimension of pain and doom! :)
180
- """
181
- try:
182
- argList = args.split()
183
- if argList:
184
- typeName = argList[0].strip()
185
- else:
186
- gLogger.error("No type name specified")
187
- return
188
-
189
- choice = input(
190
- f"Are you completely sure you want to delete type {typeName} and all it's data? yes/no [no]: "
191
- )
192
- choice = choice.lower()
193
- if choice not in ("yes", "y"):
194
- print("Delete aborted")
195
- return
196
-
197
- acClient = DataStoreClient()
198
- retVal = acClient.deleteType(typeName)
199
- if not retVal["OK"]:
200
- gLogger.error(f"Error: {retVal['Message']}")
201
- return
202
- print("Hope you meant it, because it's done")
203
- except Exception:
204
- self.showTraceback()
205
-
206
- def do_compactBuckets(self, args):
207
- """
208
- Compact buckets table
209
- Usage : compactBuckets
210
- """
211
- try:
212
- acClient = DataStoreClient()
213
- retVal = acClient.compactDB()
214
- if not retVal["OK"]:
215
- gLogger.error(f"Error: {retVal['Message']}")
216
- return
217
- gLogger.info("Done")
218
- except Exception:
219
- self.showTraceback()
@@ -122,19 +122,6 @@ class DataStoreClient(Client):
122
122
 
123
123
  return S_OK()
124
124
 
125
- def remove(self, register):
126
- """
127
- Remove a Register from the Accounting DataStore
128
- """
129
- if not self.__checkBaseType(register.__class__):
130
- return S_ERROR("register is not a valid type (has to inherit from BaseAccountingType")
131
- retVal = register.checkValues()
132
- if not retVal["OK"]:
133
- return retVal
134
- if gConfig.getValue("/LocalSite/DisableAccounting", False):
135
- return S_OK()
136
- return self._getRPC().remove(*register.getValues())
137
-
138
125
 
139
126
  def _sendToFailover(rpcStub):
140
127
  """Create a ForwardDISET operation for failover"""
@@ -161,13 +161,6 @@ class BaseAccountingType:
161
161
  cD[self.fieldsList[iPos]] = self.valuesList[iPos]
162
162
  return cD
163
163
 
164
- def registerToServer(self):
165
- """
166
- Register type in server
167
- """
168
- rpcClient = Client(url="Accounting/DataStore")
169
- return rpcClient.registerType(*self.getDefinition())
170
-
171
164
  def commit(self):
172
165
  """
173
166
  Commit register to server
@@ -9,11 +9,6 @@ Services
9
9
  Authorization
10
10
  {
11
11
  Default = authenticated
12
- compactDB = ServiceAdministrator
13
- deleteType = ServiceAdministrator
14
- registerType = ServiceAdministrator
15
- setBucketsLength = ServiceAdministrator
16
- regenerateBuckets = ServiceAdministrator
17
12
  }
18
13
  }
19
14
  ##END
@@ -14,7 +14,6 @@ import datetime
14
14
  from DIRAC import S_ERROR, S_OK
15
15
  from DIRAC.AccountingSystem.DB.MultiAccountingDB import MultiAccountingDB
16
16
  from DIRAC.ConfigurationSystem.Client import PathFinder
17
- from DIRAC.Core.Base.Client import Client
18
17
  from DIRAC.Core.DISET.RequestHandler import RequestHandler, getServiceOption
19
18
  from DIRAC.Core.Utilities import TimeUtilities
20
19
  from DIRAC.Core.Utilities.ThreadScheduler import gThreadScheduler
@@ -39,30 +38,6 @@ class DataStoreHandler(RequestHandler):
39
38
  gThreadScheduler.addPeriodicTask(60, cls.__acDB.loadPendingRecords)
40
39
  return S_OK()
41
40
 
42
- types_registerType = [str, list, list, list]
43
-
44
- def export_registerType(self, typeName, definitionKeyFields, definitionAccountingFields, bucketsLength):
45
- """
46
- Register a new type. (Only for all powerful admins)
47
- """
48
- return self.__acDB.registerType(typeName, definitionKeyFields, definitionAccountingFields, bucketsLength)
49
-
50
- types_setBucketsLength = [str, list]
51
-
52
- def export_setBucketsLength(self, typeName, bucketsLength):
53
- """
54
- Change the buckets Length. (Only for all powerful admins)
55
- """
56
- return self.__acDB.changeBucketsLength(typeName, bucketsLength)
57
-
58
- types_regenerateBuckets = [str]
59
-
60
- def export_regenerateBuckets(self, typeName):
61
- """
62
- Recalculate buckets. (Only for all powerful admins)
63
- """
64
- return self.__acDB.regenerateBuckets(typeName)
65
-
66
41
  types_getRegisteredTypes = []
67
42
 
68
43
  def export_getRegisteredTypes(self):
@@ -106,51 +81,4 @@ class DataStoreHandler(RequestHandler):
106
81
  records.append((entry[0], startTime, endTime, entry[3]))
107
82
  return self.__acDB.insertRecordBundleThroughQueue(records)
108
83
 
109
- types_compactDB = []
110
-
111
- def export_compactDB(self):
112
- """
113
- Compact the db by grouping buckets
114
- """
115
- # if we are running workers (not only one service) we can redirect the request to the master
116
- # For more information please read the Administrative guide Accounting part!
117
- # ADVICE: If you want to trigger the bucketing, please make sure the bucketing is not running!!!!
118
- if self.runBucketing:
119
- return self.__acDB.compactBuckets()
120
-
121
- return Client(url="Accounting/DataStoreMaster").compactDB()
122
-
123
84
  types_remove = [str, datetime.datetime, datetime.datetime, list]
124
-
125
- def export_remove(self, typeName, startTime, endTime, valuesList):
126
- """
127
- Remove a record for a type
128
- """
129
- startTime = int(TimeUtilities.toEpoch(startTime))
130
- endTime = int(TimeUtilities.toEpoch(endTime))
131
- return self.__acDB.deleteRecord(typeName, startTime, endTime, valuesList)
132
-
133
- types_removeRegisters = [list]
134
-
135
- def export_removeRegisters(self, entriesList):
136
- """
137
- Remove a record for a type
138
- """
139
- expectedTypes = [str, datetime.datetime, datetime.datetime, list]
140
- for entry in entriesList:
141
- if len(entry) != 4:
142
- return S_ERROR("Invalid records")
143
- for i, en in enumerate(entry):
144
- if not isinstance(en, expectedTypes[i]):
145
- return S_ERROR(f"{i} field in the records should be {expectedTypes[i]}")
146
- ok = 0
147
- for entry in entriesList:
148
- startTime = int(TimeUtilities.toEpoch(entry[1]))
149
- endTime = int(TimeUtilities.toEpoch(entry[2]))
150
- record = entry[3]
151
- result = self.__acDB.deleteRecord(entry[0], startTime, endTime, record)
152
- if not result["OK"]:
153
- return S_OK(ok)
154
- ok += 1
155
-
156
- return S_OK(ok)
@@ -4,15 +4,6 @@ Some Helper functions to retrieve common location from the CS
4
4
  from DIRAC.Core.Utilities.Extensions import extensionsByPriority
5
5
 
6
6
 
7
- def getSetup() -> str:
8
- """
9
- Return setup name
10
- """
11
- from DIRAC import gConfig
12
-
13
- return gConfig.getValue("/DIRAC/Setup", "")
14
-
15
-
16
7
  def getVO(defaultVO: str = "") -> str:
17
8
  """
18
9
  Return VO from configuration
@@ -1,18 +1,49 @@
1
- """ Helper for /Registry section
2
- """
1
+ """Helper for /Registry section"""
2
+
3
3
  import errno
4
+ import inspect
5
+ import sys
6
+ from collections.abc import Iterable
7
+ from threading import Lock
8
+ from typing import Optional
9
+
10
+ from cachetools import TTLCache, cached
11
+ from cachetools.keys import hashkey
4
12
 
5
- from DIRAC import S_OK, S_ERROR
13
+ from DIRAC import S_ERROR, S_OK
6
14
  from DIRAC.ConfigurationSystem.Client.Config import gConfig
7
15
  from DIRAC.ConfigurationSystem.Client.Helpers.CSGlobals import getVO
8
16
 
9
17
  ID_DN_PREFIX = "/O=DIRAC/CN="
10
18
 
19
+ # 300 is the default CS refresh time
20
+
21
+ CACHE_REFRESH_TIME = 300
11
22
  # pylint: disable=missing-docstring
12
23
 
13
24
  gBaseRegistrySection = "/Registry"
14
25
 
15
26
 
27
+ def reset_all_caches():
28
+ """This method is called to clear all caches.
29
+ It is necessary to reinitialize them after the central CS
30
+ has been loaded
31
+ """
32
+ for cache in [
33
+ obj
34
+ for name, obj in inspect.getmembers(sys.modules[__name__])
35
+ if (inspect.isfunction(obj) and hasattr(obj, "cache_clear"))
36
+ ]:
37
+ cache.cache_clear()
38
+
39
+
40
+ def get_username_for_dn_key(dn: str, userList: Optional[Iterable[str]] = None):
41
+ if userList:
42
+ return hashkey(dn, *sorted(userList))
43
+ return hashkey(dn)
44
+
45
+
46
+ @cached(TTLCache(maxsize=1000, ttl=CACHE_REFRESH_TIME), lock=Lock(), key=get_username_for_dn_key)
16
47
  def getUsernameForDN(dn, usersList=None):
17
48
  """Find DIRAC user for DN
18
49
 
@@ -33,6 +64,7 @@ def getUsernameForDN(dn, usersList=None):
33
64
  return S_ERROR(f"No username found for dn {dn}")
34
65
 
35
66
 
67
+ @cached(TTLCache(maxsize=1000, ttl=CACHE_REFRESH_TIME), lock=Lock())
36
68
  def getDNForUsername(username):
37
69
  """Get user DN for user
38
70
 
@@ -413,6 +445,7 @@ def getBannedIPs():
413
445
  return gConfig.getValue(f"{gBaseRegistrySection}/BannedIPs", [])
414
446
 
415
447
 
448
+ @cached(TTLCache(maxsize=1000, ttl=CACHE_REFRESH_TIME), lock=Lock())
416
449
  def getVOForGroup(group):
417
450
  """Search VO name for group
418
451
 
@@ -420,7 +453,7 @@ def getVOForGroup(group):
420
453
 
421
454
  :return: str
422
455
  """
423
- return getVO() or gConfig.getValue(f"{gBaseRegistrySection}/Groups/{group}/VO", "")
456
+ return gConfig.getValue(f"{gBaseRegistrySection}/Groups/{group}/VO", "") or getVO()
424
457
 
425
458
 
426
459
  def getIdPForGroup(group):
@@ -451,28 +484,6 @@ def getVOMSAttributeForGroup(group):
451
484
  return gConfig.getValue(f"{gBaseRegistrySection}/Groups/{group}/VOMSRole", getDefaultVOMSAttribute())
452
485
 
453
486
 
454
- def getDefaultVOMSVO():
455
- """Get default VOMS VO
456
-
457
- :return: str
458
- """
459
- return gConfig.getValue(f"{gBaseRegistrySection}/DefaultVOMSVO", "") or getVO()
460
-
461
-
462
- def getVOMSVOForGroup(group):
463
- """Search VOMS VO for group
464
-
465
- :param str group: group name
466
-
467
- :return: str
468
- """
469
- vomsVO = gConfig.getValue(f"{gBaseRegistrySection}/Groups/{group}/VOMSVO", getDefaultVOMSVO())
470
- if not vomsVO:
471
- vo = getVOForGroup(group)
472
- vomsVO = getVOOption(vo, "VOMSName", "")
473
- return vomsVO
474
-
475
-
476
487
  def getGroupsWithVOMSAttribute(vomsAttr):
477
488
  """Search groups with VOMS attribute
478
489
 
@@ -628,6 +639,7 @@ def getDNProperty(userDN, value, defaultValue=None):
628
639
  return S_OK(defaultValue)
629
640
 
630
641
 
642
+ @cached(TTLCache(maxsize=1000, ttl=CACHE_REFRESH_TIME), lock=Lock())
631
643
  def getProxyProvidersForDN(userDN):
632
644
  """Get proxy providers by user DN
633
645
 
@@ -1,11 +1,14 @@
1
1
  """ Helper for the CS Resources section
2
2
  """
3
- import re
4
3
  from urllib import parse
5
4
 
6
5
  from DIRAC import S_ERROR, S_OK, gConfig, gLogger
7
6
  from DIRAC.ConfigurationSystem.Client.Helpers.Path import cfgPath
8
7
  from DIRAC.Core.Utilities.List import fromChar, uniqueElements
8
+ from DIRACCommon.ConfigurationSystem.Client.Helpers.Resources import (
9
+ getDIRACPlatform as _getDIRACPlatform,
10
+ _platformSortKey,
11
+ )
9
12
 
10
13
  gBaseResourcesSection = "/Resources"
11
14
 
@@ -328,8 +331,8 @@ def getCompatiblePlatforms(originalPlatforms):
328
331
  if not (result["OK"] and result["Value"]):
329
332
  return S_ERROR("OS compatibility info not found")
330
333
 
331
- platformsDict = {k: v.replace(" ", "").split(",") for k, v in result["Value"].items()} # can be an iterator
332
- for k, v in platformsDict.items(): # can be an iterator
334
+ platformsDict = {k: v.replace(" ", "").split(",") for k, v in result["Value"].items()}
335
+ for k, v in platformsDict.items():
333
336
  if k not in v:
334
337
  v.append(k)
335
338
 
@@ -355,7 +358,6 @@ def getDIRACPlatform(OSList):
355
358
  :param list OSList: list of platforms defined by resource providers
356
359
  :return: a list of DIRAC platforms that can be specified in job descriptions
357
360
  """
358
-
359
361
  # For backward compatibility allow a single string argument
360
362
  osList = OSList
361
363
  if isinstance(OSList, str):
@@ -365,31 +367,12 @@ def getDIRACPlatform(OSList):
365
367
  if not (result["OK"] and result["Value"]):
366
368
  return S_ERROR("OS compatibility info not found")
367
369
 
368
- platformsDict = {k: v.replace(" ", "").split(",") for k, v in result["Value"].items()} # can be an iterator
369
- for k, v in platformsDict.items(): # can be an iterator
370
+ platformsDict = {k: set(v.replace(" ", "").split(",")) for k, v in result["Value"].items()}
371
+ for k, v in platformsDict.items():
370
372
  if k not in v:
371
- v.append(k)
372
-
373
- # making an OS -> platforms dict
374
- os2PlatformDict = dict()
375
- for platform, osItems in platformsDict.items(): # can be an iterator
376
- for osItem in osItems:
377
- if os2PlatformDict.get(osItem):
378
- os2PlatformDict[osItem].append(platform)
379
- else:
380
- os2PlatformDict[osItem] = [platform]
381
-
382
- platforms = []
383
- for os in osList:
384
- if os in os2PlatformDict:
385
- platforms += os2PlatformDict[os]
386
-
387
- if not platforms:
388
- return S_ERROR(f"No compatible DIRAC platform found for {','.join(OSList)}")
373
+ v.add(k)
389
374
 
390
- platforms.sort(key=_platformSortKey, reverse=True)
391
-
392
- return S_OK(platforms)
375
+ return _getDIRACPlatform(osList, platformsDict)
393
376
 
394
377
 
395
378
  def getDIRACPlatforms():
@@ -451,7 +434,7 @@ def getInfoAboutProviders(of=None, providerName=None, option="", section=""):
451
434
  result = gConfig.getConfigurationTree(relPath)
452
435
  if not result["OK"]:
453
436
  return result
454
- for key, value in result["Value"].items(): # can be an iterator
437
+ for key, value in result["Value"].items():
455
438
  if value:
456
439
  resDict[key.replace(relPath, "")] = value
457
440
  return S_OK(resDict)
@@ -459,18 +442,3 @@ def getInfoAboutProviders(of=None, providerName=None, option="", section=""):
459
442
  return gConfig.getSections(f"{gBaseResourcesSection}/{of}Providers/{providerName}/{section}/")
460
443
  else:
461
444
  return S_OK(gConfig.getValue(f"{gBaseResourcesSection}/{of}Providers/{providerName}/{section}/{option}"))
462
-
463
-
464
- def _platformSortKey(version: str) -> list[str]:
465
- # Loosely based on distutils.version.LooseVersion
466
- parts = []
467
- for part in re.split(r"(\d+|[a-z]+|\.| -)", version.lower()):
468
- if not part or part == ".":
469
- continue
470
- if part[:1] in "0123456789":
471
- part = part.zfill(8)
472
- else:
473
- while parts and parts[-1] == "00000000":
474
- parts.pop()
475
- parts.append(part)
476
- return parts
@@ -9,7 +9,6 @@ from DIRAC.ConfigurationSystem.Client import ConfigurationData
9
9
  from DIRAC.ConfigurationSystem.Client.Helpers.Resources import (
10
10
  getDIRACPlatform,
11
11
  getCompatiblePlatforms,
12
- _platformSortKey,
13
12
  getQueue,
14
13
  )
15
14
 
@@ -77,21 +76,6 @@ def test_getDIRACPlatform(mocker, mockGCReplyInput, requested, expectedRes, expe
77
76
  assert set(res["Value"]) == set(expectedValue), res["Value"]
78
77
 
79
78
 
80
- @pytest.mark.parametrize(
81
- "string,expected",
82
- [
83
- ("Darwin_arm64_12.4", ["darwin", "_", "arm", "64", "_", "12", "4"]),
84
- ("Linux_x86_64_glibc-2.17", ["linux", "_", "x", "86", "_", "64", "_", "glibc", "-", "2", "17"]),
85
- ("Linux_aarch64_glibc-2.28", ["linux", "_", "aarch", "64", "_", "glibc", "-", "2", "28"]),
86
- ],
87
- )
88
- def test_platformSortKey(string, expected):
89
- actual = _platformSortKey(string)
90
- for a, e in zip_longest(actual, expected):
91
- # Numbers are padded with zeros so string comparison works
92
- assert a.lstrip("0") == e
93
-
94
-
95
79
  @pytest.mark.parametrize(
96
80
  "mockGCReplyInput, requested, expectedRes, expectedValue",
97
81
  [
@@ -1,5 +1,5 @@
1
- """ This is the guy that parses and interprets the local configuration options.
2
- """
1
+ """This is the guy that parses and interprets the local configuration options."""
2
+
3
3
  import re
4
4
  import os
5
5
  import sys
@@ -286,16 +286,18 @@ class LocalConfiguration:
286
286
  gLogger.exception()
287
287
  return S_ERROR(str(e))
288
288
 
289
- def initialize(self, *, returnErrors=False):
289
+ def initialize(self, *, returnErrors=False, requireSuccessfulSync=False):
290
290
  """Entrypoint used by :py:class:`DIRAC.initialize`
291
291
 
292
+ :param requireSuccessfulSync: fails if syncing with the remote did not work
293
+
292
294
  TODO: This is currently a hack that returns a list of errors for so it
293
295
  can be used by ``__addUserDataToConfiguration``. This entire module
294
296
  should be refactored and simplified with ``Script.parseCommandLine``.
295
297
  """
296
298
  errorsList = self.__loadCFGFiles()
297
299
  if gConfigurationData.getServers():
298
- retVal = self.syncRemoteConfiguration()
300
+ retVal = self.syncRemoteConfiguration(strict=requireSuccessfulSync)
299
301
  if not retVal["OK"]:
300
302
  return retVal
301
303
  else:
@@ -321,7 +323,7 @@ class LocalConfiguration:
321
323
  gLogger.showHeaders(True)
322
324
  gLogger.enableLogsFromExternalLibs()
323
325
 
324
- def loadUserData(self):
326
+ def loadUserData(self, requireSuccessfulSync=False):
325
327
  """
326
328
  This is the magic method that reads the command line and processes it
327
329
  It is used by the Script Base class and the dirac-service and dirac-agent scripts
@@ -329,6 +331,7 @@ class LocalConfiguration:
329
331
  - any additional switches to be processed
330
332
  - mandatory and default configuration configuration options must be defined.
331
333
 
334
+ :param requireSuccessfulSync: if True, will fail if the sync with remote server failed
332
335
  """
333
336
  if self.initialized:
334
337
  return S_OK()
@@ -336,7 +339,7 @@ class LocalConfiguration:
336
339
  try:
337
340
  if not self.isParsed:
338
341
  self.__parseCommandLine() # Parse command line
339
- retVal = self.__addUserDataToConfiguration()
342
+ retVal = self.__addUserDataToConfiguration(requireSuccessfulSync=requireSuccessfulSync)
340
343
 
341
344
  for optionTuple in self.optionalEntryList:
342
345
  optionPath = self.__getAbsolutePath(optionTuple[0])
@@ -496,8 +499,8 @@ class LocalConfiguration:
496
499
 
497
500
  return errorsList
498
501
 
499
- def __addUserDataToConfiguration(self):
500
- retVal = self.initialize(returnErrors=True)
502
+ def __addUserDataToConfiguration(self, requireSuccessfulSync=False):
503
+ retVal = self.initialize(returnErrors=True, requireSuccessfulSync=requireSuccessfulSync)
501
504
  if not retVal["OK"]:
502
505
  return retVal
503
506
  errorsList = retVal["Value"]
@@ -568,6 +571,9 @@ class LocalConfiguration:
568
571
  objLoader = ObjectLoader()
569
572
  objLoader.reloadRootModules()
570
573
  self.__initLogger(self.componentName, self.loggingSection, forceInit=True)
574
+ from DIRAC.ConfigurationSystem.Client.Helpers.Registry import reset_all_caches
575
+
576
+ reset_all_caches()
571
577
  return res
572
578
 
573
579
  def isCSEnabled(self):