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.
- DIRAC/AccountingSystem/Client/AccountingCLI.py +0 -140
- DIRAC/AccountingSystem/Client/DataStoreClient.py +0 -13
- DIRAC/AccountingSystem/Client/Types/BaseAccountingType.py +0 -7
- DIRAC/AccountingSystem/ConfigTemplate.cfg +0 -5
- DIRAC/AccountingSystem/Service/DataStoreHandler.py +0 -72
- DIRAC/ConfigurationSystem/Client/Helpers/CSGlobals.py +0 -9
- DIRAC/ConfigurationSystem/Client/Helpers/Registry.py +38 -26
- DIRAC/ConfigurationSystem/Client/Helpers/Resources.py +11 -43
- DIRAC/ConfigurationSystem/Client/Helpers/test/Test_Helpers.py +0 -16
- DIRAC/ConfigurationSystem/Client/LocalConfiguration.py +14 -8
- DIRAC/ConfigurationSystem/Client/PathFinder.py +47 -8
- DIRAC/ConfigurationSystem/Client/SyncPlugins/CERNLDAPSyncPlugin.py +4 -1
- DIRAC/ConfigurationSystem/Client/VOMS2CSSynchronizer.py +32 -19
- DIRAC/ConfigurationSystem/Client/test/Test_PathFinder.py +41 -1
- DIRAC/ConfigurationSystem/private/RefresherBase.py +4 -2
- DIRAC/Core/Base/API.py +4 -7
- DIRAC/Core/Base/SQLAlchemyDB.py +1 -0
- DIRAC/Core/DISET/ServiceReactor.py +11 -3
- DIRAC/Core/DISET/private/BaseClient.py +1 -2
- DIRAC/Core/DISET/private/Transports/M2SSLTransport.py +9 -7
- DIRAC/Core/DISET/private/Transports/SSL/M2Utils.py +3 -1
- DIRAC/Core/LCG/GOCDBClient.py +5 -7
- DIRAC/Core/Security/DiracX.py +31 -17
- DIRAC/Core/Security/IAMService.py +5 -10
- DIRAC/Core/Security/Locations.py +27 -18
- DIRAC/Core/Security/ProxyInfo.py +9 -5
- DIRAC/Core/Security/VOMSService.py +2 -4
- DIRAC/Core/Security/m2crypto/X509Certificate.py +4 -6
- DIRAC/Core/Security/m2crypto/asn1_utils.py +17 -5
- DIRAC/Core/Security/test/test_diracx_token_from_pem.py +161 -0
- DIRAC/Core/Tornado/Client/ClientSelector.py +4 -1
- DIRAC/Core/Tornado/Server/TornadoService.py +1 -1
- DIRAC/Core/Utilities/CGroups2.py +328 -0
- DIRAC/Core/Utilities/ClassAd/ClassAdLight.py +4 -290
- DIRAC/Core/Utilities/DErrno.py +5 -309
- DIRAC/Core/Utilities/Extensions.py +10 -1
- DIRAC/Core/Utilities/File.py +1 -1
- DIRAC/Core/Utilities/Graphs/GraphData.py +1 -1
- DIRAC/Core/Utilities/Graphs/GraphUtilities.py +6 -1
- DIRAC/Core/Utilities/JDL.py +1 -195
- DIRAC/Core/Utilities/List.py +1 -124
- DIRAC/Core/Utilities/MySQL.py +103 -99
- DIRAC/Core/Utilities/Os.py +32 -1
- DIRAC/Core/Utilities/Platform.py +2 -107
- DIRAC/Core/Utilities/Proxy.py +0 -4
- DIRAC/Core/Utilities/ReturnValues.py +7 -252
- DIRAC/Core/Utilities/StateMachine.py +12 -178
- DIRAC/Core/Utilities/Subprocess.py +35 -14
- DIRAC/Core/Utilities/TimeUtilities.py +10 -253
- DIRAC/Core/Utilities/test/Test_JDL.py +0 -3
- DIRAC/Core/Utilities/test/Test_Profiler.py +20 -20
- DIRAC/Core/scripts/dirac_agent.py +1 -1
- DIRAC/Core/scripts/dirac_apptainer_exec.py +72 -46
- DIRAC/Core/scripts/dirac_configure.py +1 -3
- DIRAC/Core/scripts/dirac_install_db.py +24 -6
- DIRAC/Core/scripts/dirac_platform.py +1 -92
- DIRAC/DataManagementSystem/Agent/FTS3Agent.py +8 -7
- DIRAC/DataManagementSystem/Agent/RequestOperations/RemoveFile.py +7 -6
- DIRAC/DataManagementSystem/Client/FTS3Job.py +71 -34
- DIRAC/DataManagementSystem/DB/FTS3DB.py +7 -3
- DIRAC/DataManagementSystem/DB/FileCatalogComponents/DatasetManager/DatasetManager.py +1 -1
- DIRAC/DataManagementSystem/DB/FileCatalogDB.sql +9 -9
- DIRAC/DataManagementSystem/DB/FileCatalogWithFkAndPsDB.sql +9 -9
- DIRAC/DataManagementSystem/Utilities/DMSHelpers.py +6 -2
- DIRAC/DataManagementSystem/scripts/dirac_admin_allow_se.py +13 -8
- DIRAC/DataManagementSystem/scripts/dirac_admin_ban_se.py +13 -8
- DIRAC/DataManagementSystem/scripts/dirac_dms_create_moving_request.py +2 -0
- DIRAC/DataManagementSystem/scripts/dirac_dms_protocol_matrix.py +0 -1
- DIRAC/FrameworkSystem/Client/BundleDeliveryClient.py +2 -7
- DIRAC/FrameworkSystem/Client/ComponentInstaller.py +9 -4
- DIRAC/FrameworkSystem/Client/ProxyManagerClient.py +5 -2
- DIRAC/FrameworkSystem/Client/SystemAdministratorClientCLI.py +11 -6
- DIRAC/FrameworkSystem/ConfigTemplate.cfg +2 -0
- DIRAC/FrameworkSystem/DB/AuthDB.py +3 -3
- DIRAC/FrameworkSystem/DB/InstalledComponentsDB.py +4 -4
- DIRAC/FrameworkSystem/DB/ProxyDB.py +11 -3
- DIRAC/FrameworkSystem/DB/TokenDB.py +1 -1
- DIRAC/FrameworkSystem/Service/ProxyManagerHandler.py +8 -6
- DIRAC/FrameworkSystem/Utilities/MonitoringUtilities.py +2 -19
- DIRAC/FrameworkSystem/Utilities/TokenManagementUtilities.py +3 -2
- DIRAC/FrameworkSystem/Utilities/diracx.py +36 -14
- DIRAC/FrameworkSystem/private/authorization/AuthServer.py +2 -2
- DIRAC/FrameworkSystem/scripts/dirac_admin_update_pilot.py +18 -11
- DIRAC/FrameworkSystem/scripts/dirac_login.py +2 -2
- DIRAC/FrameworkSystem/scripts/dirac_proxy_init.py +7 -8
- DIRAC/Interfaces/API/Dirac.py +27 -15
- DIRAC/Interfaces/API/DiracAdmin.py +45 -17
- DIRAC/Interfaces/API/Job.py +9 -13
- DIRAC/Interfaces/scripts/dirac_admin_allow_site.py +12 -18
- DIRAC/Interfaces/scripts/dirac_admin_ban_site.py +12 -10
- DIRAC/Interfaces/scripts/dirac_admin_get_site_mask.py +4 -13
- DIRAC/Interfaces/scripts/dirac_admin_reset_job.py +3 -6
- DIRAC/Interfaces/scripts/dirac_wms_job_parameters.py +0 -1
- DIRAC/MonitoringSystem/Client/Types/WMSHistory.py +4 -0
- DIRAC/MonitoringSystem/Client/WebAppClient.py +26 -0
- DIRAC/MonitoringSystem/ConfigTemplate.cfg +9 -0
- DIRAC/MonitoringSystem/DB/MonitoringDB.py +6 -25
- DIRAC/MonitoringSystem/Service/MonitoringHandler.py +0 -33
- DIRAC/MonitoringSystem/Service/WebAppHandler.py +599 -0
- DIRAC/MonitoringSystem/private/MainReporter.py +0 -3
- DIRAC/ProductionSystem/DB/ProductionDB.sql +4 -4
- DIRAC/ProductionSystem/scripts/dirac_prod_get.py +2 -2
- DIRAC/ProductionSystem/scripts/dirac_prod_get_all.py +2 -2
- DIRAC/ProductionSystem/scripts/dirac_prod_get_trans.py +2 -3
- DIRAC/RequestManagementSystem/Agent/RequestExecutingAgent.py +8 -6
- DIRAC/RequestManagementSystem/Agent/RequestOperations/ForwardDISET.py +2 -14
- DIRAC/RequestManagementSystem/Client/ReqClient.py +66 -13
- DIRAC/RequestManagementSystem/ConfigTemplate.cfg +6 -6
- DIRAC/RequestManagementSystem/DB/RequestDB.py +10 -5
- DIRAC/RequestManagementSystem/DB/test/RMSTestScenari.py +2 -0
- DIRAC/RequestManagementSystem/private/RequestValidator.py +40 -46
- DIRAC/ResourceStatusSystem/Client/SiteStatus.py +4 -2
- DIRAC/ResourceStatusSystem/Command/FreeDiskSpaceCommand.py +3 -1
- DIRAC/ResourceStatusSystem/DB/ResourceManagementDB.py +8 -8
- DIRAC/ResourceStatusSystem/DB/ResourceStatusDB.py +2 -2
- DIRAC/ResourceStatusSystem/Utilities/CSHelpers.py +2 -31
- DIRAC/ResourceStatusSystem/scripts/dirac_rss_set_status.py +30 -12
- DIRAC/Resources/Catalog/RucioFileCatalogClient.py +195 -1
- DIRAC/Resources/Catalog/test/Test_RucioFileCatalogClient.py +181 -0
- DIRAC/Resources/Computing/AREXComputingElement.py +25 -8
- DIRAC/Resources/Computing/BatchSystems/Condor.py +126 -108
- DIRAC/Resources/Computing/BatchSystems/SLURM.py +5 -1
- DIRAC/Resources/Computing/BatchSystems/test/Test_SLURM.py +46 -0
- DIRAC/Resources/Computing/ComputingElement.py +1 -1
- DIRAC/Resources/Computing/HTCondorCEComputingElement.py +44 -44
- DIRAC/Resources/Computing/InProcessComputingElement.py +4 -2
- DIRAC/Resources/Computing/LocalComputingElement.py +1 -18
- DIRAC/Resources/Computing/SSHBatchComputingElement.py +1 -17
- DIRAC/Resources/Computing/SSHComputingElement.py +1 -18
- DIRAC/Resources/Computing/SingularityComputingElement.py +19 -5
- DIRAC/Resources/Computing/test/Test_HTCondorCEComputingElement.py +67 -49
- DIRAC/Resources/Computing/test/Test_PoolComputingElement.py +2 -1
- DIRAC/Resources/IdProvider/CheckInIdProvider.py +13 -0
- DIRAC/Resources/IdProvider/IdProviderFactory.py +11 -3
- DIRAC/Resources/MessageQueue/StompMQConnector.py +1 -1
- DIRAC/Resources/Storage/GFAL2_StorageBase.py +24 -15
- DIRAC/Resources/Storage/OccupancyPlugins/WLCGAccountingHTTPJson.py +1 -3
- DIRAC/Resources/Storage/StorageBase.py +4 -2
- DIRAC/Resources/Storage/StorageElement.py +6 -7
- DIRAC/StorageManagementSystem/DB/StorageManagementDB.sql +2 -2
- DIRAC/TransformationSystem/Agent/TaskManagerAgentBase.py +10 -16
- DIRAC/TransformationSystem/Agent/TransformationAgent.py +22 -1
- DIRAC/TransformationSystem/Agent/TransformationCleaningAgent.py +16 -16
- DIRAC/TransformationSystem/Client/TaskManager.py +2 -4
- DIRAC/TransformationSystem/Client/Transformation.py +6 -7
- DIRAC/TransformationSystem/Client/TransformationClient.py +21 -11
- DIRAC/TransformationSystem/Client/Utilities.py +9 -0
- DIRAC/TransformationSystem/DB/TransformationDB.py +11 -14
- DIRAC/TransformationSystem/DB/TransformationDB.sql +9 -9
- DIRAC/TransformationSystem/Service/TransformationManagerHandler.py +0 -333
- DIRAC/TransformationSystem/Utilities/ReplicationCLIParameters.py +3 -3
- DIRAC/TransformationSystem/Utilities/TransformationInfo.py +7 -5
- DIRAC/TransformationSystem/scripts/dirac_production_runjoblocal.py +2 -4
- DIRAC/TransformationSystem/test/Test_TransformationInfo.py +22 -15
- DIRAC/TransformationSystem/test/Test_replicationTransformation.py +5 -6
- DIRAC/Workflow/Modules/test/Test_Modules.py +5 -0
- DIRAC/WorkloadManagementSystem/Agent/JobAgent.py +38 -26
- DIRAC/WorkloadManagementSystem/Agent/JobCleaningAgent.py +12 -8
- DIRAC/WorkloadManagementSystem/Agent/PilotSyncAgent.py +4 -3
- DIRAC/WorkloadManagementSystem/Agent/PushJobAgent.py +13 -13
- DIRAC/WorkloadManagementSystem/Agent/SiteDirector.py +18 -14
- DIRAC/WorkloadManagementSystem/Agent/StalledJobAgent.py +18 -51
- DIRAC/WorkloadManagementSystem/Agent/StatesAccountingAgent.py +41 -1
- DIRAC/WorkloadManagementSystem/Agent/test/Test_Agent_JobAgent.py +45 -4
- DIRAC/WorkloadManagementSystem/Agent/test/Test_Agent_JobCleaningAgent.py +7 -9
- DIRAC/WorkloadManagementSystem/Agent/test/Test_Agent_PushJobAgent.py +1 -0
- DIRAC/WorkloadManagementSystem/Agent/test/Test_Agent_SiteDirector.py +9 -2
- DIRAC/WorkloadManagementSystem/Agent/test/Test_Agent_StalledJobAgent.py +4 -5
- DIRAC/WorkloadManagementSystem/Client/DownloadInputData.py +9 -9
- DIRAC/WorkloadManagementSystem/Client/InputDataResolution.py +6 -6
- DIRAC/WorkloadManagementSystem/Client/JobMonitoringClient.py +10 -11
- DIRAC/WorkloadManagementSystem/Client/JobReport.py +1 -1
- DIRAC/WorkloadManagementSystem/Client/JobState/CachedJobState.py +3 -0
- DIRAC/WorkloadManagementSystem/Client/JobState/JobManifest.py +32 -261
- DIRAC/WorkloadManagementSystem/Client/JobState/JobState.py +6 -0
- DIRAC/WorkloadManagementSystem/Client/JobStateUpdateClient.py +3 -0
- DIRAC/WorkloadManagementSystem/Client/JobStatus.py +8 -152
- DIRAC/WorkloadManagementSystem/Client/PoolXMLSlice.py +12 -19
- DIRAC/WorkloadManagementSystem/Client/SandboxStoreClient.py +25 -38
- DIRAC/WorkloadManagementSystem/Client/WMSClient.py +2 -3
- DIRAC/WorkloadManagementSystem/Client/test/Test_Client_DownloadInputData.py +29 -0
- DIRAC/WorkloadManagementSystem/ConfigTemplate.cfg +4 -8
- DIRAC/WorkloadManagementSystem/DB/JobDB.py +89 -132
- DIRAC/WorkloadManagementSystem/DB/JobDB.sql +8 -8
- DIRAC/WorkloadManagementSystem/DB/JobDBUtils.py +18 -147
- DIRAC/WorkloadManagementSystem/DB/JobLoggingDB.py +19 -6
- DIRAC/WorkloadManagementSystem/DB/JobParametersDB.py +9 -9
- DIRAC/WorkloadManagementSystem/DB/PilotAgentsDB.py +16 -5
- DIRAC/WorkloadManagementSystem/DB/PilotAgentsDB.sql +3 -3
- DIRAC/WorkloadManagementSystem/DB/SandboxMetadataDB.py +44 -82
- DIRAC/WorkloadManagementSystem/DB/StatusUtils.py +125 -0
- DIRAC/WorkloadManagementSystem/DB/tests/Test_JobDB.py +1 -1
- DIRAC/WorkloadManagementSystem/DB/tests/Test_StatusUtils.py +28 -0
- DIRAC/WorkloadManagementSystem/Executor/JobSanity.py +5 -4
- DIRAC/WorkloadManagementSystem/Executor/JobScheduling.py +4 -0
- DIRAC/WorkloadManagementSystem/FutureClient/JobStateUpdateClient.py +75 -33
- DIRAC/WorkloadManagementSystem/JobWrapper/JobWrapper.py +22 -11
- DIRAC/WorkloadManagementSystem/JobWrapper/JobWrapperTemplate.py +9 -10
- DIRAC/WorkloadManagementSystem/JobWrapper/test/Test_JobWrapper.py +60 -10
- DIRAC/WorkloadManagementSystem/JobWrapper/test/Test_JobWrapperTemplate.py +4 -0
- DIRAC/WorkloadManagementSystem/Service/JobManagerHandler.py +33 -154
- DIRAC/WorkloadManagementSystem/Service/JobMonitoringHandler.py +5 -323
- DIRAC/WorkloadManagementSystem/Service/JobStateUpdateHandler.py +0 -16
- DIRAC/WorkloadManagementSystem/Service/PilotManagerHandler.py +6 -103
- DIRAC/WorkloadManagementSystem/Service/SandboxStoreHandler.py +7 -53
- DIRAC/WorkloadManagementSystem/Service/WMSAdministratorHandler.py +16 -79
- DIRAC/WorkloadManagementSystem/Service/WMSUtilities.py +4 -18
- DIRAC/WorkloadManagementSystem/Utilities/JobModel.py +28 -209
- DIRAC/WorkloadManagementSystem/Utilities/JobParameters.py +65 -3
- DIRAC/WorkloadManagementSystem/Utilities/JobStatusUtility.py +2 -64
- DIRAC/WorkloadManagementSystem/Utilities/ParametricJob.py +7 -171
- DIRAC/WorkloadManagementSystem/Utilities/PilotCStoJSONSynchronizer.py +73 -7
- DIRAC/WorkloadManagementSystem/Utilities/PilotWrapper.py +41 -11
- DIRAC/WorkloadManagementSystem/Utilities/RemoteRunner.py +16 -0
- DIRAC/WorkloadManagementSystem/Utilities/Utils.py +36 -1
- DIRAC/WorkloadManagementSystem/Utilities/jobAdministration.py +15 -0
- DIRAC/WorkloadManagementSystem/Utilities/test/Test_JobModel.py +1 -15
- DIRAC/WorkloadManagementSystem/Utilities/test/Test_ParametricJob.py +45 -128
- DIRAC/WorkloadManagementSystem/Utilities/test/Test_PilotWrapper.py +16 -0
- DIRAC/WorkloadManagementSystem/scripts/dirac_jobexec.py +7 -2
- DIRAC/WorkloadManagementSystem/scripts/dirac_wms_pilot_job_info.py +1 -1
- DIRAC/__init__.py +62 -60
- DIRAC/tests/Utilities/testJobDefinitions.py +22 -28
- {DIRAC-9.0.0a42.dist-info → dirac-9.0.7.dist-info}/METADATA +8 -5
- {DIRAC-9.0.0a42.dist-info → dirac-9.0.7.dist-info}/RECORD +229 -228
- {DIRAC-9.0.0a42.dist-info → dirac-9.0.7.dist-info}/WHEEL +1 -1
- {DIRAC-9.0.0a42.dist-info → dirac-9.0.7.dist-info}/entry_points.txt +0 -3
- DIRAC/Core/Utilities/test/Test_List.py +0 -150
- DIRAC/Core/Utilities/test/Test_Time.py +0 -88
- DIRAC/Resources/Computing/PilotBundle.py +0 -70
- DIRAC/TransformationSystem/scripts/dirac_transformation_archive.py +0 -30
- DIRAC/TransformationSystem/scripts/dirac_transformation_clean.py +0 -30
- DIRAC/TransformationSystem/scripts/dirac_transformation_remove_output.py +0 -30
- DIRAC/WorkloadManagementSystem/Utilities/test/Test_JobManager.py +0 -58
- {DIRAC-9.0.0a42.dist-info → dirac-9.0.7.dist-info/licenses}/LICENSE +0 -0
- {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
|
-
"""
|
|
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
|
|
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
|
|
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()}
|
|
332
|
-
for k, v in platformsDict.items():
|
|
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()}
|
|
369
|
-
for k, v in platformsDict.items():
|
|
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.
|
|
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
|
-
|
|
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():
|
|
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
|
-
"""
|
|
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):
|