DIRAC 9.0.0a54__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 +34 -32
- 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 +9 -2
- DIRAC/ConfigurationSystem/Client/test/Test_PathFinder.py +41 -1
- DIRAC/ConfigurationSystem/private/RefresherBase.py +4 -2
- 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/Security/DiracX.py +12 -7
- DIRAC/Core/Security/IAMService.py +4 -3
- DIRAC/Core/Security/ProxyInfo.py +9 -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/ClassAd/ClassAdLight.py +4 -290
- DIRAC/Core/Utilities/DErrno.py +5 -309
- DIRAC/Core/Utilities/Extensions.py +10 -1
- DIRAC/Core/Utilities/Graphs/GraphData.py +1 -1
- DIRAC/Core/Utilities/JDL.py +1 -195
- DIRAC/Core/Utilities/List.py +1 -124
- DIRAC/Core/Utilities/MySQL.py +101 -97
- DIRAC/Core/Utilities/Os.py +32 -1
- DIRAC/Core/Utilities/Platform.py +2 -107
- DIRAC/Core/Utilities/ReturnValues.py +7 -252
- DIRAC/Core/Utilities/StateMachine.py +12 -178
- 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 +16 -7
- 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 +3 -0
- DIRAC/DataManagementSystem/DB/FileCatalogComponents/DatasetManager/DatasetManager.py +1 -1
- DIRAC/DataManagementSystem/Utilities/DMSHelpers.py +6 -2
- DIRAC/DataManagementSystem/scripts/dirac_dms_create_moving_request.py +2 -0
- DIRAC/DataManagementSystem/scripts/dirac_dms_protocol_matrix.py +0 -1
- DIRAC/FrameworkSystem/Client/ComponentInstaller.py +4 -2
- DIRAC/FrameworkSystem/DB/ProxyDB.py +9 -5
- DIRAC/FrameworkSystem/Utilities/TokenManagementUtilities.py +3 -2
- DIRAC/FrameworkSystem/Utilities/diracx.py +2 -74
- DIRAC/FrameworkSystem/private/authorization/AuthServer.py +2 -2
- DIRAC/FrameworkSystem/scripts/dirac_login.py +2 -2
- DIRAC/FrameworkSystem/scripts/dirac_proxy_init.py +1 -1
- DIRAC/Interfaces/API/Dirac.py +27 -13
- DIRAC/Interfaces/API/DiracAdmin.py +42 -7
- DIRAC/Interfaces/API/Job.py +1 -0
- DIRAC/Interfaces/scripts/dirac_admin_allow_site.py +7 -1
- DIRAC/Interfaces/scripts/dirac_admin_ban_site.py +7 -1
- 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/scripts/dirac_prod_get_trans.py +2 -3
- DIRAC/RequestManagementSystem/Agent/RequestExecutingAgent.py +8 -6
- DIRAC/RequestManagementSystem/ConfigTemplate.cfg +6 -6
- DIRAC/RequestManagementSystem/DB/test/RMSTestScenari.py +2 -0
- DIRAC/ResourceStatusSystem/Client/SiteStatus.py +4 -2
- DIRAC/ResourceStatusSystem/Command/FreeDiskSpaceCommand.py +3 -1
- DIRAC/ResourceStatusSystem/Utilities/CSHelpers.py +2 -31
- DIRAC/ResourceStatusSystem/scripts/dirac_rss_set_status.py +18 -4
- DIRAC/Resources/Catalog/RucioFileCatalogClient.py +1 -1
- DIRAC/Resources/Computing/AREXComputingElement.py +19 -3
- 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/HTCondorCEComputingElement.py +37 -43
- DIRAC/Resources/Computing/SingularityComputingElement.py +6 -1
- 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/Storage/StorageBase.py +4 -2
- DIRAC/Resources/Storage/StorageElement.py +4 -4
- DIRAC/TransformationSystem/Agent/TaskManagerAgentBase.py +10 -16
- DIRAC/TransformationSystem/Agent/TransformationAgent.py +22 -1
- DIRAC/TransformationSystem/Agent/TransformationCleaningAgent.py +15 -15
- DIRAC/TransformationSystem/Client/Transformation.py +2 -1
- DIRAC/TransformationSystem/Client/TransformationClient.py +0 -7
- DIRAC/TransformationSystem/Client/Utilities.py +9 -0
- DIRAC/TransformationSystem/Service/TransformationManagerHandler.py +0 -336
- DIRAC/TransformationSystem/Utilities/ReplicationCLIParameters.py +3 -3
- DIRAC/TransformationSystem/scripts/dirac_production_runjoblocal.py +2 -4
- DIRAC/TransformationSystem/test/Test_replicationTransformation.py +5 -6
- DIRAC/Workflow/Modules/test/Test_Modules.py +5 -0
- DIRAC/WorkloadManagementSystem/Agent/JobAgent.py +1 -5
- DIRAC/WorkloadManagementSystem/Agent/JobCleaningAgent.py +11 -7
- DIRAC/WorkloadManagementSystem/Agent/PilotSyncAgent.py +4 -3
- DIRAC/WorkloadManagementSystem/Agent/PushJobAgent.py +13 -13
- DIRAC/WorkloadManagementSystem/Agent/SiteDirector.py +10 -13
- DIRAC/WorkloadManagementSystem/Agent/StalledJobAgent.py +18 -51
- DIRAC/WorkloadManagementSystem/Agent/StatesAccountingAgent.py +41 -1
- DIRAC/WorkloadManagementSystem/Agent/test/Test_Agent_JobAgent.py +2 -0
- 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 +8 -2
- DIRAC/WorkloadManagementSystem/Agent/test/Test_Agent_StalledJobAgent.py +4 -5
- DIRAC/WorkloadManagementSystem/Client/DownloadInputData.py +7 -5
- DIRAC/WorkloadManagementSystem/Client/JobMonitoringClient.py +10 -11
- DIRAC/WorkloadManagementSystem/Client/JobState/JobManifest.py +32 -261
- DIRAC/WorkloadManagementSystem/Client/JobStateUpdateClient.py +3 -0
- DIRAC/WorkloadManagementSystem/Client/JobStatus.py +8 -152
- 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 +40 -69
- DIRAC/WorkloadManagementSystem/DB/JobDBUtils.py +18 -147
- DIRAC/WorkloadManagementSystem/DB/JobParametersDB.py +9 -9
- DIRAC/WorkloadManagementSystem/DB/PilotAgentsDB.py +3 -2
- DIRAC/WorkloadManagementSystem/DB/SandboxMetadataDB.py +28 -39
- 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 +3 -3
- DIRAC/WorkloadManagementSystem/FutureClient/JobStateUpdateClient.py +2 -14
- DIRAC/WorkloadManagementSystem/JobWrapper/JobWrapper.py +14 -9
- DIRAC/WorkloadManagementSystem/JobWrapper/test/Test_JobWrapper.py +36 -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 -102
- DIRAC/WorkloadManagementSystem/Service/SandboxStoreHandler.py +5 -51
- DIRAC/WorkloadManagementSystem/Service/WMSAdministratorHandler.py +16 -79
- DIRAC/WorkloadManagementSystem/Utilities/JobModel.py +28 -199
- 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 +2 -0
- 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 -5
- DIRAC/WorkloadManagementSystem/Utilities/test/Test_ParametricJob.py +45 -128
- DIRAC/WorkloadManagementSystem/Utilities/test/Test_PilotWrapper.py +16 -0
- DIRAC/__init__.py +55 -54
- {dirac-9.0.0a54.dist-info → dirac-9.0.7.dist-info}/METADATA +6 -4
- {dirac-9.0.0a54.dist-info → dirac-9.0.7.dist-info}/RECORD +160 -160
- {dirac-9.0.0a54.dist-info → dirac-9.0.7.dist-info}/WHEEL +1 -1
- {dirac-9.0.0a54.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/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.0a54.dist-info → dirac-9.0.7.dist-info}/licenses/LICENSE +0 -0
- {dirac-9.0.0a54.dist-info → dirac-9.0.7.dist-info}/top_level.txt +0 -0
|
@@ -4,17 +4,13 @@
|
|
|
4
4
|
The following methods are available in the Service interface
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
-
import DIRAC.Core.Utilities.TimeUtilities as TimeUtilities
|
|
8
7
|
from DIRAC import S_ERROR, S_OK
|
|
9
8
|
from DIRAC.ConfigurationSystem.Client.Helpers import Registry
|
|
10
|
-
from DIRAC.ConfigurationSystem.Client.Helpers.Operations import Operations
|
|
11
9
|
from DIRAC.Core.DISET.RequestHandler import RequestHandler
|
|
12
10
|
from DIRAC.Core.Utilities.DEncode import ignoreEncodeWarning
|
|
13
11
|
from DIRAC.Core.Utilities.JEncode import strToIntDict
|
|
14
12
|
from DIRAC.Core.Utilities.ObjectLoader import ObjectLoader
|
|
15
|
-
from DIRAC.
|
|
16
|
-
from DIRAC.WorkloadManagementSystem.Client.PilotManagerClient import PilotManagerClient
|
|
17
|
-
from DIRAC.WorkloadManagementSystem.Service.JobPolicy import RIGHT_GET_INFO, JobPolicy
|
|
13
|
+
from DIRAC.WorkloadManagementSystem.Utilities.JobParameters import getJobParameters
|
|
18
14
|
|
|
19
15
|
|
|
20
16
|
class JobMonitoringHandlerMixin:
|
|
@@ -40,51 +36,12 @@ class JobMonitoringHandlerMixin:
|
|
|
40
36
|
return result
|
|
41
37
|
cls.elasticJobParametersDB = result["Value"](parentLogger=cls.log)
|
|
42
38
|
|
|
43
|
-
cls.pilotManager = PilotManagerClient()
|
|
44
39
|
return S_OK()
|
|
45
40
|
|
|
46
41
|
def initializeRequest(self):
|
|
47
42
|
credDict = self.getRemoteCredentials()
|
|
48
43
|
self.vo = credDict.get("VO", Registry.getVOForGroup(credDict["group"]))
|
|
49
44
|
|
|
50
|
-
@classmethod
|
|
51
|
-
def parseSelectors(cls, selectDict=None):
|
|
52
|
-
"""Parse selectors before DB query
|
|
53
|
-
|
|
54
|
-
:param dict selectDict: selectors
|
|
55
|
-
|
|
56
|
-
:return: str, str, dict -- start/end date, selectors
|
|
57
|
-
"""
|
|
58
|
-
selectDict = selectDict or {}
|
|
59
|
-
|
|
60
|
-
# Get time period
|
|
61
|
-
startDate = selectDict.get("FromDate", None)
|
|
62
|
-
if startDate:
|
|
63
|
-
del selectDict["FromDate"]
|
|
64
|
-
# For backward compatibility
|
|
65
|
-
if startDate is None:
|
|
66
|
-
startDate = selectDict.get("LastUpdate", None)
|
|
67
|
-
if startDate:
|
|
68
|
-
del selectDict["LastUpdate"]
|
|
69
|
-
endDate = selectDict.get("ToDate", None)
|
|
70
|
-
if endDate:
|
|
71
|
-
del selectDict["ToDate"]
|
|
72
|
-
|
|
73
|
-
# Provide JobID bound to a specific PilotJobReference
|
|
74
|
-
# There is no reason to have both PilotJobReference and JobID in selectDict
|
|
75
|
-
# If that occurs, use the JobID instead of the PilotJobReference
|
|
76
|
-
pilotJobRefs = selectDict.get("PilotJobReference")
|
|
77
|
-
if pilotJobRefs:
|
|
78
|
-
del selectDict["PilotJobReference"]
|
|
79
|
-
if not selectDict.get("JobID"):
|
|
80
|
-
for pilotJobRef in [pilotJobRefs] if isinstance(pilotJobRefs, str) else pilotJobRefs:
|
|
81
|
-
res = cls.pilotManager.getPilotInfo(pilotJobRef)
|
|
82
|
-
if res["OK"] and "Jobs" in res["Value"][pilotJobRef]:
|
|
83
|
-
selectDict["JobID"] = selectDict.get("JobID", [])
|
|
84
|
-
selectDict["JobID"].extend(res["Value"][pilotJobRef]["Jobs"])
|
|
85
|
-
|
|
86
|
-
return startDate, endDate, selectDict
|
|
87
|
-
|
|
88
45
|
@classmethod
|
|
89
46
|
def getJobsAttributes(cls, *args, **kwargs):
|
|
90
47
|
"""Utility function for unpacking"""
|
|
@@ -93,82 +50,6 @@ class JobMonitoringHandlerMixin:
|
|
|
93
50
|
return res
|
|
94
51
|
return S_OK(strToIntDict(res["Value"]))
|
|
95
52
|
|
|
96
|
-
##############################################################################
|
|
97
|
-
types_getApplicationStates = []
|
|
98
|
-
|
|
99
|
-
@classmethod
|
|
100
|
-
def export_getApplicationStates(cls, condDict=None, older=None, newer=None):
|
|
101
|
-
"""Return Distinct Values of ApplicationStatus job Attribute in WMS"""
|
|
102
|
-
return cls.jobDB.getDistinctJobAttributes("ApplicationStatus", condDict, older, newer)
|
|
103
|
-
|
|
104
|
-
##############################################################################
|
|
105
|
-
types_getJobTypes = []
|
|
106
|
-
|
|
107
|
-
@classmethod
|
|
108
|
-
def export_getJobTypes(cls, condDict=None, older=None, newer=None):
|
|
109
|
-
"""Return Distinct Values of JobType job Attribute in WMS"""
|
|
110
|
-
return cls.jobDB.getDistinctJobAttributes("JobType", condDict, older, newer)
|
|
111
|
-
|
|
112
|
-
##############################################################################
|
|
113
|
-
types_getOwners = []
|
|
114
|
-
|
|
115
|
-
@classmethod
|
|
116
|
-
def export_getOwners(cls, condDict=None, older=None, newer=None):
|
|
117
|
-
"""
|
|
118
|
-
Return Distinct Values of Owner job Attribute in WMS
|
|
119
|
-
"""
|
|
120
|
-
return cls.jobDB.getDistinctJobAttributes("Owner", condDict, older, newer)
|
|
121
|
-
|
|
122
|
-
##############################################################################
|
|
123
|
-
types_getOwnerGroup = []
|
|
124
|
-
|
|
125
|
-
@classmethod
|
|
126
|
-
def export_getOwnerGroup(cls):
|
|
127
|
-
"""
|
|
128
|
-
Return Distinct Values of OwnerGroup from the JobDB
|
|
129
|
-
"""
|
|
130
|
-
return cls.jobDB.getDistinctJobAttributes("OwnerGroup")
|
|
131
|
-
|
|
132
|
-
##############################################################################
|
|
133
|
-
types_getJobGroups = []
|
|
134
|
-
|
|
135
|
-
@classmethod
|
|
136
|
-
def export_getJobGroups(cls, condDict=None, older=None, cutDate=None):
|
|
137
|
-
"""
|
|
138
|
-
Return Distinct Values of ProductionId job Attribute in WMS
|
|
139
|
-
"""
|
|
140
|
-
return cls.jobDB.getDistinctJobAttributes("JobGroup", condDict, older, newer=cutDate)
|
|
141
|
-
|
|
142
|
-
##############################################################################
|
|
143
|
-
types_getSites = []
|
|
144
|
-
|
|
145
|
-
@classmethod
|
|
146
|
-
def export_getSites(cls, condDict=None, older=None, newer=None):
|
|
147
|
-
"""
|
|
148
|
-
Return Distinct Values of Site job Attribute in WMS
|
|
149
|
-
"""
|
|
150
|
-
return cls.jobDB.getDistinctJobAttributes("Site", condDict, older, newer)
|
|
151
|
-
|
|
152
|
-
##############################################################################
|
|
153
|
-
types_getStates = []
|
|
154
|
-
|
|
155
|
-
@classmethod
|
|
156
|
-
def export_getStates(cls, condDict=None, older=None, newer=None):
|
|
157
|
-
"""
|
|
158
|
-
Return Distinct Values of Status job Attribute in WMS
|
|
159
|
-
"""
|
|
160
|
-
return cls.jobDB.getDistinctJobAttributes("Status", condDict, older, newer)
|
|
161
|
-
|
|
162
|
-
##############################################################################
|
|
163
|
-
types_getMinorStates = []
|
|
164
|
-
|
|
165
|
-
@classmethod
|
|
166
|
-
def export_getMinorStates(cls, condDict=None, older=None, newer=None):
|
|
167
|
-
"""
|
|
168
|
-
Return Distinct Values of Minor Status job Attribute in WMS
|
|
169
|
-
"""
|
|
170
|
-
return cls.jobDB.getDistinctJobAttributes("MinorStatus", condDict, older, newer)
|
|
171
|
-
|
|
172
53
|
##############################################################################
|
|
173
54
|
types_getJobs = []
|
|
174
55
|
|
|
@@ -189,36 +70,6 @@ class JobMonitoringHandlerMixin:
|
|
|
189
70
|
|
|
190
71
|
return cls.jobDB.selectJobs(attrDict, newer=cutDate)
|
|
191
72
|
|
|
192
|
-
##############################################################################
|
|
193
|
-
types_getCounters = [list]
|
|
194
|
-
|
|
195
|
-
@classmethod
|
|
196
|
-
def export_getCounters(cls, attrList, attrDict=None, cutDate=""):
|
|
197
|
-
"""
|
|
198
|
-
Retrieve list of distinct attributes values from attrList
|
|
199
|
-
with attrDict as condition.
|
|
200
|
-
For each set of distinct values, count number of occurences.
|
|
201
|
-
Return a list. Each item is a list with 2 items, the list of distinct
|
|
202
|
-
attribute values and the counter
|
|
203
|
-
"""
|
|
204
|
-
|
|
205
|
-
_, _, attrDict = cls.parseSelectors(attrDict)
|
|
206
|
-
return cls.jobDB.getCounters("Jobs", attrList, attrDict, newer=str(cutDate), timeStamp="LastUpdateTime")
|
|
207
|
-
|
|
208
|
-
##############################################################################
|
|
209
|
-
types_getJobOwner = [int]
|
|
210
|
-
|
|
211
|
-
@classmethod
|
|
212
|
-
def export_getJobOwner(cls, jobID):
|
|
213
|
-
return cls.jobDB.getJobAttribute(jobID, "Owner")
|
|
214
|
-
|
|
215
|
-
##############################################################################
|
|
216
|
-
types_getJobSite = [int]
|
|
217
|
-
|
|
218
|
-
@classmethod
|
|
219
|
-
def export_getJobSite(cls, jobID):
|
|
220
|
-
return cls.jobDB.getJobAttribute(jobID, "Site")
|
|
221
|
-
|
|
222
73
|
##############################################################################
|
|
223
74
|
types_getJobJDL = [int, bool]
|
|
224
75
|
|
|
@@ -233,14 +84,6 @@ class JobMonitoringHandlerMixin:
|
|
|
233
84
|
def export_getJobLoggingInfo(cls, jobID):
|
|
234
85
|
return cls.jobLoggingDB.getJobLoggingInfo(jobID)
|
|
235
86
|
|
|
236
|
-
##############################################################################
|
|
237
|
-
types_getJobsParameters = [[str, int, list], list]
|
|
238
|
-
|
|
239
|
-
@classmethod
|
|
240
|
-
@ignoreEncodeWarning
|
|
241
|
-
def export_getJobsParameters(cls, jobIDs, parameters):
|
|
242
|
-
return cls.getJobsAttributes(jobIDs, parameters)
|
|
243
|
-
|
|
244
87
|
##############################################################################
|
|
245
88
|
types_getJobsStates = [[str, int, list]]
|
|
246
89
|
|
|
@@ -295,122 +138,6 @@ class JobMonitoringHandlerMixin:
|
|
|
295
138
|
def export_getJobsSummary(cls, jobIDs):
|
|
296
139
|
return cls.getJobsAttributes(jobIDs)
|
|
297
140
|
|
|
298
|
-
##############################################################################
|
|
299
|
-
types_getJobPageSummaryWeb = [dict, list, int, int]
|
|
300
|
-
|
|
301
|
-
def export_getJobPageSummaryWeb(self, selectDict, sortList, startItem, maxItems, selectJobs=True):
|
|
302
|
-
"""Get the summary of the job information for a given page in the
|
|
303
|
-
job monitor in a generic format
|
|
304
|
-
"""
|
|
305
|
-
|
|
306
|
-
resultDict = {}
|
|
307
|
-
|
|
308
|
-
startDate, endDate, selectDict = self.parseSelectors(selectDict)
|
|
309
|
-
|
|
310
|
-
# initialize jobPolicy
|
|
311
|
-
credDict = self.getRemoteCredentials()
|
|
312
|
-
owner = credDict["username"]
|
|
313
|
-
ownerGroup = credDict["group"]
|
|
314
|
-
operations = Operations(group=ownerGroup)
|
|
315
|
-
globalJobsInfo = operations.getValue("/Services/JobMonitoring/GlobalJobsInfo", True)
|
|
316
|
-
jobPolicy = JobPolicy(owner, ownerGroup, globalJobsInfo)
|
|
317
|
-
jobPolicy.jobDB = self.jobDB
|
|
318
|
-
result = jobPolicy.getControlledUsers(RIGHT_GET_INFO)
|
|
319
|
-
if not result["OK"]:
|
|
320
|
-
return result
|
|
321
|
-
if not result["Value"]:
|
|
322
|
-
return S_ERROR(f"User and group combination has no job rights ({owner!r}, {ownerGroup!r})")
|
|
323
|
-
if result["Value"] != "ALL":
|
|
324
|
-
selectDict[("Owner", "OwnerGroup")] = result["Value"]
|
|
325
|
-
|
|
326
|
-
# Sorting instructions. Only one for the moment.
|
|
327
|
-
if sortList:
|
|
328
|
-
orderAttribute = sortList[0][0] + ":" + sortList[0][1]
|
|
329
|
-
else:
|
|
330
|
-
orderAttribute = None
|
|
331
|
-
|
|
332
|
-
result = self.jobDB.getCounters(
|
|
333
|
-
"Jobs", ["Status"], selectDict, newer=startDate, older=endDate, timeStamp="LastUpdateTime"
|
|
334
|
-
)
|
|
335
|
-
if not result["OK"]:
|
|
336
|
-
return result
|
|
337
|
-
|
|
338
|
-
statusDict = {}
|
|
339
|
-
nJobs = 0
|
|
340
|
-
for stDict, count in result["Value"]:
|
|
341
|
-
nJobs += count
|
|
342
|
-
statusDict[stDict["Status"]] = count
|
|
343
|
-
|
|
344
|
-
resultDict["TotalRecords"] = nJobs
|
|
345
|
-
if nJobs == 0:
|
|
346
|
-
return S_OK(resultDict)
|
|
347
|
-
|
|
348
|
-
resultDict["Extras"] = statusDict
|
|
349
|
-
|
|
350
|
-
if selectJobs:
|
|
351
|
-
iniJob = startItem
|
|
352
|
-
if iniJob >= nJobs:
|
|
353
|
-
return S_ERROR("Item number out of range")
|
|
354
|
-
|
|
355
|
-
result = self.jobDB.selectJobs(
|
|
356
|
-
selectDict, orderAttribute=orderAttribute, newer=startDate, older=endDate, limit=(maxItems, iniJob)
|
|
357
|
-
)
|
|
358
|
-
if not result["OK"]:
|
|
359
|
-
return result
|
|
360
|
-
|
|
361
|
-
summaryJobList = result["Value"]
|
|
362
|
-
if not globalJobsInfo:
|
|
363
|
-
validJobs, _invalidJobs, _nonauthJobs, _ownJobs = jobPolicy.evaluateJobRights(
|
|
364
|
-
summaryJobList, RIGHT_GET_INFO
|
|
365
|
-
)
|
|
366
|
-
summaryJobList = validJobs
|
|
367
|
-
|
|
368
|
-
result = self.getJobsAttributes(summaryJobList)
|
|
369
|
-
if not result["OK"]:
|
|
370
|
-
return result
|
|
371
|
-
|
|
372
|
-
summaryDict = result["Value"]
|
|
373
|
-
# If no jobs can be selected after the properties check
|
|
374
|
-
if not summaryDict:
|
|
375
|
-
return S_OK(resultDict)
|
|
376
|
-
|
|
377
|
-
# Evaluate last sign of life time
|
|
378
|
-
for jobDict in summaryDict.values():
|
|
379
|
-
if not jobDict.get("HeartBeatTime") or jobDict["HeartBeatTime"] == "None":
|
|
380
|
-
jobDict["LastSignOfLife"] = jobDict["LastUpdateTime"]
|
|
381
|
-
else:
|
|
382
|
-
jobDict["LastSignOfLife"] = jobDict["HeartBeatTime"]
|
|
383
|
-
|
|
384
|
-
# prepare the standard structure now
|
|
385
|
-
# This should be faster than making a list of values()
|
|
386
|
-
for jobDict in summaryDict.values():
|
|
387
|
-
paramNames = list(jobDict)
|
|
388
|
-
break
|
|
389
|
-
records = [list(jobDict.values()) for jobDict in summaryDict.values()]
|
|
390
|
-
|
|
391
|
-
resultDict["ParameterNames"] = paramNames
|
|
392
|
-
resultDict["Records"] = records
|
|
393
|
-
|
|
394
|
-
return S_OK(resultDict)
|
|
395
|
-
|
|
396
|
-
##############################################################################
|
|
397
|
-
types_getJobStats = [str, dict]
|
|
398
|
-
|
|
399
|
-
@classmethod
|
|
400
|
-
def export_getJobStats(cls, attribute, selectDict):
|
|
401
|
-
"""Get job statistics distribution per attribute value with a given selection"""
|
|
402
|
-
startDate, endDate, selectDict = cls.parseSelectors(selectDict)
|
|
403
|
-
result = cls.jobDB.getCounters(
|
|
404
|
-
"Jobs", [attribute], selectDict, newer=startDate, older=endDate, timeStamp="LastUpdateTime"
|
|
405
|
-
)
|
|
406
|
-
if not result["OK"]:
|
|
407
|
-
return result
|
|
408
|
-
resultDict = {}
|
|
409
|
-
for cDict, count in result["Value"]:
|
|
410
|
-
resultDict[cDict[attribute]] = count
|
|
411
|
-
|
|
412
|
-
return S_OK(resultDict)
|
|
413
|
-
|
|
414
141
|
##############################################################################
|
|
415
142
|
types_getJobParameter = [[str, int], str]
|
|
416
143
|
|
|
@@ -420,18 +147,11 @@ class JobMonitoringHandlerMixin:
|
|
|
420
147
|
:param str/int jobID: one single Job ID
|
|
421
148
|
:param str parName: one single parameter name
|
|
422
149
|
"""
|
|
423
|
-
res =
|
|
150
|
+
res = getJobParameters([int(jobID)], parName, self.vo or "")
|
|
424
151
|
if not res["OK"]:
|
|
425
152
|
return res
|
|
426
153
|
return S_OK(res["Value"].get(int(jobID), {}))
|
|
427
154
|
|
|
428
|
-
##############################################################################
|
|
429
|
-
types_getJobOptParameters = [int]
|
|
430
|
-
|
|
431
|
-
@classmethod
|
|
432
|
-
def export_getJobOptParameters(cls, jobID):
|
|
433
|
-
return cls.jobDB.getJobOptParameters(jobID)
|
|
434
|
-
|
|
435
155
|
##############################################################################
|
|
436
156
|
types_getJobParameters = [[str, int, list]]
|
|
437
157
|
|
|
@@ -439,41 +159,13 @@ class JobMonitoringHandlerMixin:
|
|
|
439
159
|
def export_getJobParameters(self, jobIDs, parName=None):
|
|
440
160
|
"""
|
|
441
161
|
:param str/int/list jobIDs: one single job ID or a list of them
|
|
442
|
-
:param str parName: one single parameter name,
|
|
162
|
+
:param str parName: one single parameter name, or None (meaning all of them)
|
|
443
163
|
"""
|
|
444
164
|
if not isinstance(jobIDs, list):
|
|
445
165
|
jobIDs = [jobIDs]
|
|
446
166
|
jobIDs = [int(jobID) for jobID in jobIDs]
|
|
447
|
-
res = self.elasticJobParametersDB.getJobParameters(jobIDs, self.vo, parName)
|
|
448
|
-
if not res["OK"]:
|
|
449
|
-
return res
|
|
450
|
-
parameters = res["Value"]
|
|
451
167
|
|
|
452
|
-
|
|
453
|
-
res = self.jobDB.getJobParameters(jobIDs, parName)
|
|
454
|
-
if not res["OK"]:
|
|
455
|
-
return res
|
|
456
|
-
parametersM = res["Value"]
|
|
457
|
-
|
|
458
|
-
# and now combine
|
|
459
|
-
final = dict(parametersM)
|
|
460
|
-
# if job in JobDB, update with parameters from ES if any
|
|
461
|
-
for jobID in final:
|
|
462
|
-
final[jobID].update(parameters.get(jobID, {}))
|
|
463
|
-
# if job in ES and not in JobDB, take ES
|
|
464
|
-
for jobID in parameters:
|
|
465
|
-
if jobID not in final:
|
|
466
|
-
final[jobID] = parameters[jobID]
|
|
467
|
-
return S_OK(final)
|
|
468
|
-
|
|
469
|
-
##############################################################################
|
|
470
|
-
types_getAtticJobParameters = [int]
|
|
471
|
-
|
|
472
|
-
@classmethod
|
|
473
|
-
def export_getAtticJobParameters(cls, jobID, parameters=None, rescheduleCycle=-1):
|
|
474
|
-
if not parameters:
|
|
475
|
-
parameters = []
|
|
476
|
-
return cls.jobDB.getAtticJobParameters(jobID, parameters, rescheduleCycle)
|
|
168
|
+
return getJobParameters(jobIDs, parName, self.vo or "")
|
|
477
169
|
|
|
478
170
|
##############################################################################
|
|
479
171
|
types_getJobAttributes = [int]
|
|
@@ -499,13 +191,6 @@ class JobMonitoringHandlerMixin:
|
|
|
499
191
|
|
|
500
192
|
return cls.jobDB.getJobAttribute(jobID, attribute)
|
|
501
193
|
|
|
502
|
-
##############################################################################
|
|
503
|
-
types_getSiteSummary = []
|
|
504
|
-
|
|
505
|
-
@classmethod
|
|
506
|
-
def export_getSiteSummary(cls):
|
|
507
|
-
return cls.jobDB.getSiteSummary()
|
|
508
|
-
|
|
509
194
|
##############################################################################
|
|
510
195
|
types_getJobHeartBeatData = [int]
|
|
511
196
|
|
|
@@ -514,7 +199,7 @@ class JobMonitoringHandlerMixin:
|
|
|
514
199
|
return cls.jobDB.getHeartBeatData(jobID)
|
|
515
200
|
|
|
516
201
|
##############################################################################
|
|
517
|
-
types_getInputData = [int]
|
|
202
|
+
types_getInputData = [(int, list)]
|
|
518
203
|
|
|
519
204
|
@classmethod
|
|
520
205
|
def export_getInputData(cls, jobID):
|
|
@@ -522,9 +207,6 @@ class JobMonitoringHandlerMixin:
|
|
|
522
207
|
return cls.jobDB.getInputData(jobID)
|
|
523
208
|
|
|
524
209
|
|
|
525
|
-
##############################################################################
|
|
526
|
-
|
|
527
|
-
|
|
528
210
|
class JobMonitoringHandler(JobMonitoringHandlerMixin, RequestHandler):
|
|
529
211
|
def initialize(self):
|
|
530
212
|
return self.initializeRequest()
|
|
@@ -128,22 +128,6 @@ class JobStateUpdateHandlerMixin:
|
|
|
128
128
|
"""Allows the site attribute to be set for a job specified by its jobID."""
|
|
129
129
|
return cls.jobDB.setJobAttribute(int(jobID), "Site", site)
|
|
130
130
|
|
|
131
|
-
###########################################################################
|
|
132
|
-
types_setJobFlag = [[str, int], str]
|
|
133
|
-
|
|
134
|
-
@classmethod
|
|
135
|
-
def export_setJobFlag(cls, jobID, flag):
|
|
136
|
-
"""Set job flag for job with jobID"""
|
|
137
|
-
return cls.jobDB.setJobAttribute(int(jobID), flag, "True")
|
|
138
|
-
|
|
139
|
-
###########################################################################
|
|
140
|
-
types_unsetJobFlag = [[str, int], str]
|
|
141
|
-
|
|
142
|
-
@classmethod
|
|
143
|
-
def export_unsetJobFlag(cls, jobID, flag):
|
|
144
|
-
"""Unset job flag for job with jobID"""
|
|
145
|
-
return cls.jobDB.setJobAttribute(int(jobID), flag, "False")
|
|
146
|
-
|
|
147
131
|
###########################################################################
|
|
148
132
|
types_setJobApplicationStatus = [[str, int], str, str]
|
|
149
133
|
|
|
@@ -13,7 +13,6 @@ from DIRAC.WorkloadManagementSystem.Client import PilotStatus
|
|
|
13
13
|
from DIRAC.WorkloadManagementSystem.Service.WMSUtilities import (
|
|
14
14
|
getPilotCE,
|
|
15
15
|
getPilotRef,
|
|
16
|
-
killPilotsInQueues,
|
|
17
16
|
setPilotCredentials,
|
|
18
17
|
)
|
|
19
18
|
|
|
@@ -94,10 +93,10 @@ class PilotManagerHandler(RequestHandler):
|
|
|
94
93
|
|
|
95
94
|
result = self.pilotAgentsDB.getPilotInfo(pilotReference)
|
|
96
95
|
if not result["OK"]:
|
|
97
|
-
self.log.error("Failed to get info for pilot", result[
|
|
96
|
+
self.log.error("Failed to get info for pilot", f"{pilotReference}: {result['Message']}")
|
|
98
97
|
return S_ERROR("Failed to get info for pilot")
|
|
99
98
|
if not result["Value"]:
|
|
100
|
-
self.log.warn("The pilot info is empty", pilotReference)
|
|
99
|
+
self.log.warn("The pilot info is empty for", pilotReference)
|
|
101
100
|
return S_ERROR("Pilot info is empty")
|
|
102
101
|
|
|
103
102
|
pilotDict = result["Value"][pilotReference]
|
|
@@ -106,11 +105,14 @@ class PilotManagerHandler(RequestHandler):
|
|
|
106
105
|
# classic logs first, by default
|
|
107
106
|
funcs = [self._getPilotOutput, self._getRemotePilotOutput]
|
|
108
107
|
if remote:
|
|
108
|
+
self.log.info("Trying to retrieve output of pilot", f"{pilotReference} remotely first")
|
|
109
109
|
funcs.reverse()
|
|
110
110
|
|
|
111
111
|
result = funcs[0](pilotReference, pilotDict)
|
|
112
112
|
if not result["OK"]:
|
|
113
|
-
self.log.warn(
|
|
113
|
+
self.log.warn(
|
|
114
|
+
"Failed getting output for pilot", f"{pilotReference}. Will try another approach: {result['Message']}"
|
|
115
|
+
)
|
|
114
116
|
result = funcs[1](pilotReference, pilotDict)
|
|
115
117
|
return result
|
|
116
118
|
else:
|
|
@@ -275,37 +277,6 @@ class PilotManagerHandler(RequestHandler):
|
|
|
275
277
|
|
|
276
278
|
return cls.pilotAgentsDB.getPilotSummary(startdate, enddate)
|
|
277
279
|
|
|
278
|
-
##############################################################################
|
|
279
|
-
types_getPilotMonitorWeb = [dict, list, int, int]
|
|
280
|
-
|
|
281
|
-
@classmethod
|
|
282
|
-
def export_getPilotMonitorWeb(cls, selectDict, sortList, startItem, maxItems):
|
|
283
|
-
"""Get the summary of the pilot information for a given page in the
|
|
284
|
-
pilot monitor in a generic format
|
|
285
|
-
"""
|
|
286
|
-
|
|
287
|
-
return cls.pilotAgentsDB.getPilotMonitorWeb(selectDict, sortList, startItem, maxItems)
|
|
288
|
-
|
|
289
|
-
##############################################################################
|
|
290
|
-
types_getPilotMonitorSelectors = []
|
|
291
|
-
|
|
292
|
-
@classmethod
|
|
293
|
-
def export_getPilotMonitorSelectors(cls):
|
|
294
|
-
"""Get all the distinct selector values for the Pilot Monitor web portal page"""
|
|
295
|
-
|
|
296
|
-
return cls.pilotAgentsDB.getPilotMonitorSelectors()
|
|
297
|
-
|
|
298
|
-
##############################################################################
|
|
299
|
-
types_getPilotSummaryWeb = [dict, list, int, int]
|
|
300
|
-
|
|
301
|
-
@classmethod
|
|
302
|
-
def export_getPilotSummaryWeb(cls, selectDict, sortList, startItem, maxItems):
|
|
303
|
-
"""Get the summary of the pilot information for a given page in the
|
|
304
|
-
pilot monitor in a generic format
|
|
305
|
-
"""
|
|
306
|
-
|
|
307
|
-
return cls.pilotAgentsDB.getPilotSummaryWeb(selectDict, sortList, startItem, maxItems)
|
|
308
|
-
|
|
309
280
|
##############################################################################
|
|
310
281
|
types_getGroupedPilotSummary = [list]
|
|
311
282
|
|
|
@@ -332,35 +303,6 @@ class PilotManagerHandler(RequestHandler):
|
|
|
332
303
|
|
|
333
304
|
return cls.pilotAgentsDB.getPilotInfo(pilotID=result["Value"])
|
|
334
305
|
|
|
335
|
-
##############################################################################
|
|
336
|
-
types_killPilot = [[str, list]]
|
|
337
|
-
|
|
338
|
-
@classmethod
|
|
339
|
-
def export_killPilot(cls, pilotRefList):
|
|
340
|
-
"""Kill the specified pilots"""
|
|
341
|
-
# Make a list if it is not yet
|
|
342
|
-
if isinstance(pilotRefList, str):
|
|
343
|
-
pilotRefList = [pilotRefList]
|
|
344
|
-
|
|
345
|
-
# Regroup pilots per site
|
|
346
|
-
pilotRefDict = {}
|
|
347
|
-
for pilotReference in pilotRefList:
|
|
348
|
-
result = cls.pilotAgentsDB.getPilotInfo(pilotReference)
|
|
349
|
-
if not result["OK"] or not result["Value"]:
|
|
350
|
-
return S_ERROR(f"Failed to get info for pilot {pilotReference}")
|
|
351
|
-
|
|
352
|
-
pilotDict = result["Value"][pilotReference]
|
|
353
|
-
queue = "@@@".join(
|
|
354
|
-
[pilotDict["VO"], pilotDict["GridSite"], pilotDict["DestinationSite"], pilotDict["Queue"]]
|
|
355
|
-
)
|
|
356
|
-
gridType = pilotDict["GridType"]
|
|
357
|
-
pilotRefDict.setdefault(queue, {})
|
|
358
|
-
pilotRefDict[queue].setdefault("PilotList", [])
|
|
359
|
-
pilotRefDict[queue]["PilotList"].append(pilotReference)
|
|
360
|
-
pilotRefDict[queue]["GridType"] = gridType
|
|
361
|
-
|
|
362
|
-
return killPilotsInQueues(pilotRefDict)
|
|
363
|
-
|
|
364
306
|
##############################################################################
|
|
365
307
|
types_setJobForPilot = [[str, int], str]
|
|
366
308
|
|
|
@@ -416,44 +358,6 @@ class PilotManagerHandler(RequestHandler):
|
|
|
416
358
|
return cls.pilotAgentsDB.countPilots(condDict, older, newer, timeStamp)
|
|
417
359
|
|
|
418
360
|
##########################################################################################
|
|
419
|
-
types_getCounters = [str, list, dict]
|
|
420
|
-
|
|
421
|
-
@classmethod
|
|
422
|
-
def export_getCounters(cls, table, keys, condDict, newer=None, timeStamp="SubmissionTime"):
|
|
423
|
-
"""Set the pilot agent status"""
|
|
424
|
-
|
|
425
|
-
return cls.pilotAgentsDB.getCounters(table, keys, condDict, newer=newer, timeStamp=timeStamp)
|
|
426
|
-
|
|
427
|
-
##############################################################################
|
|
428
|
-
types_getPilotStatistics = [str, dict]
|
|
429
|
-
|
|
430
|
-
@classmethod
|
|
431
|
-
def export_getPilotStatistics(cls, attribute, selectDict):
|
|
432
|
-
"""Get pilot statistics distribution per attribute value with a given selection"""
|
|
433
|
-
|
|
434
|
-
startDate = selectDict.get("FromDate", None)
|
|
435
|
-
if startDate:
|
|
436
|
-
del selectDict["FromDate"]
|
|
437
|
-
|
|
438
|
-
if startDate is None:
|
|
439
|
-
startDate = selectDict.get("LastUpdate", None)
|
|
440
|
-
if startDate:
|
|
441
|
-
del selectDict["LastUpdate"]
|
|
442
|
-
endDate = selectDict.get("ToDate", None)
|
|
443
|
-
if endDate:
|
|
444
|
-
del selectDict["ToDate"]
|
|
445
|
-
|
|
446
|
-
result = cls.pilotAgentsDB.getCounters(
|
|
447
|
-
"PilotAgents", [attribute], selectDict, newer=startDate, older=endDate, timeStamp="LastUpdateTime"
|
|
448
|
-
)
|
|
449
|
-
statistics = {}
|
|
450
|
-
if result["OK"]:
|
|
451
|
-
for status, count in result["Value"]:
|
|
452
|
-
statistics[status[attribute]] = count
|
|
453
|
-
|
|
454
|
-
return S_OK(statistics)
|
|
455
|
-
|
|
456
|
-
##############################################################################
|
|
457
361
|
types_deletePilots = [[list, str, int]]
|
|
458
362
|
|
|
459
363
|
@classmethod
|