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
|
@@ -0,0 +1,599 @@
|
|
|
1
|
+
"""
|
|
2
|
+
The WebAppHandler module provides a class to handle web requests from the DIRAC WebApp.
|
|
3
|
+
It is not indented to be used in diracx
|
|
4
|
+
"""
|
|
5
|
+
from DIRAC import S_ERROR, S_OK
|
|
6
|
+
from DIRAC.ConfigurationSystem.Client.Helpers.Operations import Operations
|
|
7
|
+
from DIRAC.ConfigurationSystem.Client.Helpers.Resources import getSites
|
|
8
|
+
from DIRAC.Core.DISET.RequestHandler import RequestHandler
|
|
9
|
+
from DIRAC.Core.Utilities.ObjectLoader import ObjectLoader
|
|
10
|
+
from DIRAC.RequestManagementSystem.Client.Operation import Operation
|
|
11
|
+
from DIRAC.RequestManagementSystem.Client.Request import Request
|
|
12
|
+
from DIRAC.TransformationSystem.Client import TransformationFilesStatus
|
|
13
|
+
from DIRAC.WorkloadManagementSystem.Client import JobStatus
|
|
14
|
+
from DIRAC.WorkloadManagementSystem.Service.JobPolicy import RIGHT_GET_INFO, JobPolicy
|
|
15
|
+
|
|
16
|
+
TASKS_STATE_NAMES = ["TotalCreated", "Created"] + sorted(
|
|
17
|
+
set(JobStatus.JOB_STATES) | set(Request.ALL_STATES) | set(Operation.ALL_STATES)
|
|
18
|
+
)
|
|
19
|
+
FILES_STATE_NAMES = ["PercentProcessed", "Total"] + TransformationFilesStatus.TRANSFORMATION_FILES_STATES
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class WebAppHandler(RequestHandler):
|
|
23
|
+
@classmethod
|
|
24
|
+
def initializeHandler(cls, serviceInfoDict):
|
|
25
|
+
"""Initialization of DB objects"""
|
|
26
|
+
|
|
27
|
+
try:
|
|
28
|
+
result = ObjectLoader().loadObject("WorkloadManagementSystem.DB.PilotAgentsDB", "PilotAgentsDB")
|
|
29
|
+
if not result["OK"]:
|
|
30
|
+
return result
|
|
31
|
+
try:
|
|
32
|
+
cls.pilotAgentsDB = result["Value"](parentLogger=cls.log)
|
|
33
|
+
except RuntimeError:
|
|
34
|
+
cls.log.warn("Could not connect to PilotAgentsDB")
|
|
35
|
+
|
|
36
|
+
result = ObjectLoader().loadObject("WorkloadManagementSystem.DB.JobDB", "JobDB")
|
|
37
|
+
if not result["OK"]:
|
|
38
|
+
return result
|
|
39
|
+
try:
|
|
40
|
+
cls.jobDB = result["Value"](parentLogger=cls.log)
|
|
41
|
+
except RuntimeError:
|
|
42
|
+
cls.log.warn("Could not connect to JobDB")
|
|
43
|
+
|
|
44
|
+
result = ObjectLoader().loadObject("TransformationSystem.DB.TransformationDB", "TransformationDB")
|
|
45
|
+
if not result["OK"]:
|
|
46
|
+
return result
|
|
47
|
+
try:
|
|
48
|
+
cls.transformationDB = result["Value"](parentLogger=cls.log)
|
|
49
|
+
except RuntimeError:
|
|
50
|
+
cls.log.warn("Could not connect to TransformationDB")
|
|
51
|
+
|
|
52
|
+
except RuntimeError as excp:
|
|
53
|
+
cls.log.exception()
|
|
54
|
+
return S_ERROR(f"Can't connect to DB: {excp}")
|
|
55
|
+
|
|
56
|
+
return S_OK()
|
|
57
|
+
|
|
58
|
+
##############################################################################
|
|
59
|
+
# PilotAgents
|
|
60
|
+
##############################################################################
|
|
61
|
+
|
|
62
|
+
types_getPilotMonitorWeb = [dict, list, int, int]
|
|
63
|
+
|
|
64
|
+
@classmethod
|
|
65
|
+
def export_getPilotMonitorWeb(cls, selectDict, sortList, startItem, maxItems):
|
|
66
|
+
"""Get the summary of the pilot information for a given page in the
|
|
67
|
+
pilot monitor in a generic format
|
|
68
|
+
"""
|
|
69
|
+
|
|
70
|
+
return cls.pilotAgentsDB.getPilotMonitorWeb(selectDict, sortList, startItem, maxItems)
|
|
71
|
+
|
|
72
|
+
types_getPilotMonitorSelectors = []
|
|
73
|
+
|
|
74
|
+
@classmethod
|
|
75
|
+
def export_getPilotMonitorSelectors(cls):
|
|
76
|
+
"""Get all the distinct selector values for the Pilot Monitor web portal page"""
|
|
77
|
+
|
|
78
|
+
return cls.pilotAgentsDB.getPilotMonitorSelectors()
|
|
79
|
+
|
|
80
|
+
types_getPilotSummaryWeb = [dict, list, int, int]
|
|
81
|
+
|
|
82
|
+
@classmethod
|
|
83
|
+
def export_getPilotSummaryWeb(cls, selectDict, sortList, startItem, maxItems):
|
|
84
|
+
"""Get the summary of the pilot information for a given page in the
|
|
85
|
+
pilot monitor in a generic format
|
|
86
|
+
"""
|
|
87
|
+
|
|
88
|
+
return cls.pilotAgentsDB.getPilotSummaryWeb(selectDict, sortList, startItem, maxItems)
|
|
89
|
+
|
|
90
|
+
types_getPilotStatistics = [str, dict]
|
|
91
|
+
|
|
92
|
+
@classmethod
|
|
93
|
+
def export_getPilotStatistics(cls, attribute, selectDict):
|
|
94
|
+
"""Get pilot statistics distribution per attribute value with a given selection"""
|
|
95
|
+
|
|
96
|
+
startDate = selectDict.get("FromDate", None)
|
|
97
|
+
if startDate:
|
|
98
|
+
del selectDict["FromDate"]
|
|
99
|
+
|
|
100
|
+
if startDate is None:
|
|
101
|
+
startDate = selectDict.get("LastUpdate", None)
|
|
102
|
+
if startDate:
|
|
103
|
+
del selectDict["LastUpdate"]
|
|
104
|
+
endDate = selectDict.get("ToDate", None)
|
|
105
|
+
if endDate:
|
|
106
|
+
del selectDict["ToDate"]
|
|
107
|
+
|
|
108
|
+
result = cls.pilotAgentsDB.getCounters(
|
|
109
|
+
"PilotAgents", [attribute], selectDict, newer=startDate, older=endDate, timeStamp="LastUpdateTime"
|
|
110
|
+
)
|
|
111
|
+
statistics = {}
|
|
112
|
+
if result["OK"]:
|
|
113
|
+
for status, count in result["Value"]:
|
|
114
|
+
statistics[status[attribute]] = count
|
|
115
|
+
|
|
116
|
+
return S_OK(statistics)
|
|
117
|
+
|
|
118
|
+
types_getPilotsCounters = [str, list, dict]
|
|
119
|
+
|
|
120
|
+
# This was PilotManagerHandler.getCounters
|
|
121
|
+
@classmethod
|
|
122
|
+
def export_getPilotsCounters(cls, table, keys, condDict, newer=None, timeStamp="SubmissionTime"):
|
|
123
|
+
"""Set the pilot agent status"""
|
|
124
|
+
|
|
125
|
+
return cls.pilotAgentsDB.getCounters(table, keys, condDict, newer=newer, timeStamp=timeStamp)
|
|
126
|
+
|
|
127
|
+
##############################################################################
|
|
128
|
+
# Jobs
|
|
129
|
+
##############################################################################
|
|
130
|
+
|
|
131
|
+
types_getJobPageSummaryWeb = [dict, list, int, int]
|
|
132
|
+
|
|
133
|
+
def export_getJobPageSummaryWeb(self, selectDict, sortList, startItem, maxItems, selectJobs=True):
|
|
134
|
+
"""Get the summary of the job information for a given page in the
|
|
135
|
+
job monitor in a generic format
|
|
136
|
+
"""
|
|
137
|
+
|
|
138
|
+
resultDict = {}
|
|
139
|
+
|
|
140
|
+
startDate, endDate, selectDict = self.parseSelectors(selectDict)
|
|
141
|
+
|
|
142
|
+
# initialize jobPolicy
|
|
143
|
+
credDict = self.getRemoteCredentials()
|
|
144
|
+
owner = credDict["username"]
|
|
145
|
+
ownerGroup = credDict["group"]
|
|
146
|
+
operations = Operations(group=ownerGroup)
|
|
147
|
+
globalJobsInfo = operations.getValue("/Services/JobMonitoring/GlobalJobsInfo", True)
|
|
148
|
+
jobPolicy = JobPolicy(owner, ownerGroup, globalJobsInfo)
|
|
149
|
+
jobPolicy.jobDB = self.jobDB
|
|
150
|
+
result = jobPolicy.getControlledUsers(RIGHT_GET_INFO)
|
|
151
|
+
if not result["OK"]:
|
|
152
|
+
return result
|
|
153
|
+
if not result["Value"]:
|
|
154
|
+
return S_ERROR(f"User and group combination has no job rights ({owner!r}, {ownerGroup!r})")
|
|
155
|
+
if result["Value"] != "ALL":
|
|
156
|
+
selectDict[("Owner", "OwnerGroup")] = result["Value"]
|
|
157
|
+
|
|
158
|
+
# Sorting instructions. Only one for the moment.
|
|
159
|
+
if sortList:
|
|
160
|
+
orderAttribute = sortList[0][0] + ":" + sortList[0][1]
|
|
161
|
+
else:
|
|
162
|
+
orderAttribute = None
|
|
163
|
+
|
|
164
|
+
result = self.jobDB.getCounters(
|
|
165
|
+
"Jobs", ["Status"], selectDict, newer=startDate, older=endDate, timeStamp="LastUpdateTime"
|
|
166
|
+
)
|
|
167
|
+
if not result["OK"]:
|
|
168
|
+
return result
|
|
169
|
+
|
|
170
|
+
statusDict = {}
|
|
171
|
+
nJobs = 0
|
|
172
|
+
for stDict, count in result["Value"]:
|
|
173
|
+
nJobs += count
|
|
174
|
+
statusDict[stDict["Status"]] = count
|
|
175
|
+
|
|
176
|
+
resultDict["TotalRecords"] = nJobs
|
|
177
|
+
if nJobs == 0:
|
|
178
|
+
return S_OK(resultDict)
|
|
179
|
+
|
|
180
|
+
resultDict["Extras"] = statusDict
|
|
181
|
+
|
|
182
|
+
if selectJobs:
|
|
183
|
+
iniJob = startItem
|
|
184
|
+
if iniJob >= nJobs:
|
|
185
|
+
return S_ERROR("Item number out of range")
|
|
186
|
+
|
|
187
|
+
result = self.jobDB.selectJobs(
|
|
188
|
+
selectDict, orderAttribute=orderAttribute, newer=startDate, older=endDate, limit=(maxItems, iniJob)
|
|
189
|
+
)
|
|
190
|
+
if not result["OK"]:
|
|
191
|
+
return result
|
|
192
|
+
|
|
193
|
+
summaryJobList = result["Value"]
|
|
194
|
+
if not globalJobsInfo:
|
|
195
|
+
validJobs, _invalidJobs, _nonauthJobs, _ownJobs = jobPolicy.evaluateJobRights(
|
|
196
|
+
summaryJobList, RIGHT_GET_INFO
|
|
197
|
+
)
|
|
198
|
+
summaryJobList = validJobs
|
|
199
|
+
|
|
200
|
+
result = self.jobDB.getJobsAttributes(summaryJobList)
|
|
201
|
+
if not result["OK"]:
|
|
202
|
+
return result
|
|
203
|
+
|
|
204
|
+
summaryDict = result["Value"]
|
|
205
|
+
# If no jobs can be selected after the properties check
|
|
206
|
+
if not summaryDict:
|
|
207
|
+
return S_OK(resultDict)
|
|
208
|
+
|
|
209
|
+
# Evaluate last sign of life time
|
|
210
|
+
for jobDict in summaryDict.values():
|
|
211
|
+
if not jobDict.get("HeartBeatTime") or jobDict["HeartBeatTime"] == "None":
|
|
212
|
+
jobDict["LastSignOfLife"] = jobDict["LastUpdateTime"]
|
|
213
|
+
else:
|
|
214
|
+
jobDict["LastSignOfLife"] = jobDict["HeartBeatTime"]
|
|
215
|
+
|
|
216
|
+
# prepare the standard structure now
|
|
217
|
+
# This should be faster than making a list of values()
|
|
218
|
+
for jobDict in summaryDict.values():
|
|
219
|
+
paramNames = list(jobDict)
|
|
220
|
+
break
|
|
221
|
+
records = [list(jobDict.values()) for jobDict in summaryDict.values()]
|
|
222
|
+
|
|
223
|
+
resultDict["ParameterNames"] = paramNames
|
|
224
|
+
resultDict["Records"] = records
|
|
225
|
+
|
|
226
|
+
return S_OK(resultDict)
|
|
227
|
+
|
|
228
|
+
types_getJobStats = [str, dict]
|
|
229
|
+
|
|
230
|
+
@classmethod
|
|
231
|
+
def export_getJobStats(cls, attribute, selectDict):
|
|
232
|
+
"""Get job statistics distribution per attribute value with a given selection"""
|
|
233
|
+
startDate, endDate, selectDict = cls.parseSelectors(selectDict)
|
|
234
|
+
result = cls.jobDB.getCounters(
|
|
235
|
+
"Jobs", [attribute], selectDict, newer=startDate, older=endDate, timeStamp="LastUpdateTime"
|
|
236
|
+
)
|
|
237
|
+
if not result["OK"]:
|
|
238
|
+
return result
|
|
239
|
+
resultDict = {}
|
|
240
|
+
for cDict, count in result["Value"]:
|
|
241
|
+
resultDict[cDict[attribute]] = count
|
|
242
|
+
|
|
243
|
+
return S_OK(resultDict)
|
|
244
|
+
|
|
245
|
+
@classmethod
|
|
246
|
+
def parseSelectors(cls, selectDict=None):
|
|
247
|
+
"""Parse selectors before DB query
|
|
248
|
+
|
|
249
|
+
:param dict selectDict: selectors
|
|
250
|
+
|
|
251
|
+
:return: str, str, dict -- start/end date, selectors
|
|
252
|
+
"""
|
|
253
|
+
selectDict = selectDict or {}
|
|
254
|
+
|
|
255
|
+
# Get time period
|
|
256
|
+
startDate = selectDict.get("FromDate", None)
|
|
257
|
+
if startDate:
|
|
258
|
+
del selectDict["FromDate"]
|
|
259
|
+
# For backward compatibility
|
|
260
|
+
if startDate is None:
|
|
261
|
+
startDate = selectDict.get("LastUpdate", None)
|
|
262
|
+
if startDate:
|
|
263
|
+
del selectDict["LastUpdate"]
|
|
264
|
+
endDate = selectDict.get("ToDate", None)
|
|
265
|
+
if endDate:
|
|
266
|
+
del selectDict["ToDate"]
|
|
267
|
+
|
|
268
|
+
# Provide JobID bound to a specific PilotJobReference
|
|
269
|
+
# There is no reason to have both PilotJobReference and JobID in selectDict
|
|
270
|
+
# If that occurs, use the JobID instead of the PilotJobReference
|
|
271
|
+
pilotJobRefs = selectDict.get("PilotJobReference")
|
|
272
|
+
if pilotJobRefs:
|
|
273
|
+
del selectDict["PilotJobReference"]
|
|
274
|
+
if not selectDict.get("JobID"):
|
|
275
|
+
for pilotJobRef in [pilotJobRefs] if isinstance(pilotJobRefs, str) else pilotJobRefs:
|
|
276
|
+
res = cls.pilotAgentsDB.getPilotInfo(pilotJobRef)
|
|
277
|
+
if res["OK"] and "Jobs" in res["Value"][pilotJobRef]:
|
|
278
|
+
selectDict["JobID"] = selectDict.get("JobID", [])
|
|
279
|
+
selectDict["JobID"].extend(res["Value"][pilotJobRef]["Jobs"])
|
|
280
|
+
|
|
281
|
+
return startDate, endDate, selectDict
|
|
282
|
+
|
|
283
|
+
types_getJobsCounters = [list]
|
|
284
|
+
|
|
285
|
+
# This was JobManagerHanlder.getCounters
|
|
286
|
+
@classmethod
|
|
287
|
+
def export_getJobsCounters(cls, attrList, attrDict=None, cutDate=""):
|
|
288
|
+
"""
|
|
289
|
+
Retrieve list of distinct attributes values from attrList
|
|
290
|
+
with attrDict as condition.
|
|
291
|
+
For each set of distinct values, count number of occurences.
|
|
292
|
+
Return a list. Each item is a list with 2 items, the list of distinct
|
|
293
|
+
attribute values and the counter
|
|
294
|
+
"""
|
|
295
|
+
|
|
296
|
+
_, _, attrDict = cls.parseSelectors(attrDict)
|
|
297
|
+
return cls.jobDB.getCounters("Jobs", attrList, attrDict, newer=str(cutDate), timeStamp="LastUpdateTime")
|
|
298
|
+
|
|
299
|
+
types_getSiteSummaryWeb = [dict, list, int, int]
|
|
300
|
+
|
|
301
|
+
@classmethod
|
|
302
|
+
def export_getSiteSummaryWeb(cls, selectDict, sortList, startItem, maxItems):
|
|
303
|
+
"""Get the summary of the jobs running on sites in a generic format
|
|
304
|
+
|
|
305
|
+
:param dict selectDict: selectors
|
|
306
|
+
:param list sortList: sorting list
|
|
307
|
+
:param int startItem: start item number
|
|
308
|
+
:param int maxItems: maximum of items
|
|
309
|
+
|
|
310
|
+
:return: S_OK(dict)/S_ERROR()
|
|
311
|
+
"""
|
|
312
|
+
return cls.jobDB.getSiteSummaryWeb(selectDict, sortList, startItem, maxItems)
|
|
313
|
+
|
|
314
|
+
types_getSiteSummarySelectors = []
|
|
315
|
+
|
|
316
|
+
@classmethod
|
|
317
|
+
def export_getSiteSummarySelectors(cls):
|
|
318
|
+
"""Get all the distinct selector values for the site summary web portal page
|
|
319
|
+
|
|
320
|
+
:return: S_OK(dict)/S_ERROR()
|
|
321
|
+
"""
|
|
322
|
+
resultDict = {}
|
|
323
|
+
statusList = ["Good", "Fair", "Poor", "Bad", "Idle"]
|
|
324
|
+
resultDict["Status"] = statusList
|
|
325
|
+
maskStatus = ["Active", "Banned", "NoMask", "Reduced"]
|
|
326
|
+
resultDict["MaskStatus"] = maskStatus
|
|
327
|
+
|
|
328
|
+
res = getSites()
|
|
329
|
+
if not res["OK"]:
|
|
330
|
+
return res
|
|
331
|
+
siteList = res["Value"]
|
|
332
|
+
|
|
333
|
+
countryList = []
|
|
334
|
+
for site in siteList:
|
|
335
|
+
if site.find(".") != -1:
|
|
336
|
+
country = site.split(".")[2].lower()
|
|
337
|
+
if country not in countryList:
|
|
338
|
+
countryList.append(country)
|
|
339
|
+
countryList.sort()
|
|
340
|
+
resultDict["Country"] = countryList
|
|
341
|
+
siteList.sort()
|
|
342
|
+
resultDict["Site"] = siteList
|
|
343
|
+
|
|
344
|
+
return S_OK(resultDict)
|
|
345
|
+
|
|
346
|
+
types_getApplicationStates = []
|
|
347
|
+
|
|
348
|
+
@classmethod
|
|
349
|
+
def export_getApplicationStates(cls, condDict=None, older=None, newer=None):
|
|
350
|
+
"""Return Distinct Values of ApplicationStatus job Attribute in WMS"""
|
|
351
|
+
return cls.jobDB.getDistinctJobAttributes("ApplicationStatus", condDict, older, newer)
|
|
352
|
+
|
|
353
|
+
types_getJobTypes = []
|
|
354
|
+
|
|
355
|
+
@classmethod
|
|
356
|
+
def export_getJobTypes(cls, condDict=None, older=None, newer=None):
|
|
357
|
+
"""Return Distinct Values of JobType job Attribute in WMS"""
|
|
358
|
+
return cls.jobDB.getDistinctJobAttributes("JobType", condDict, older, newer)
|
|
359
|
+
|
|
360
|
+
types_getOwners = []
|
|
361
|
+
|
|
362
|
+
@classmethod
|
|
363
|
+
def export_getOwners(cls, condDict=None, older=None, newer=None):
|
|
364
|
+
"""
|
|
365
|
+
Return Distinct Values of Owner job Attribute in WMS
|
|
366
|
+
"""
|
|
367
|
+
return cls.jobDB.getDistinctJobAttributes("Owner", condDict, older, newer)
|
|
368
|
+
|
|
369
|
+
types_getOwnerGroup = []
|
|
370
|
+
|
|
371
|
+
@classmethod
|
|
372
|
+
def export_getOwnerGroup(cls):
|
|
373
|
+
"""
|
|
374
|
+
Return Distinct Values of OwnerGroup from the JobDB
|
|
375
|
+
"""
|
|
376
|
+
return cls.jobDB.getDistinctJobAttributes("OwnerGroup")
|
|
377
|
+
|
|
378
|
+
types_getJobGroups = []
|
|
379
|
+
|
|
380
|
+
@classmethod
|
|
381
|
+
def export_getJobGroups(cls, condDict=None, older=None, cutDate=None):
|
|
382
|
+
"""
|
|
383
|
+
Return Distinct Values of ProductionId job Attribute in WMS
|
|
384
|
+
"""
|
|
385
|
+
return cls.jobDB.getDistinctJobAttributes("JobGroup", condDict, older, newer=cutDate)
|
|
386
|
+
|
|
387
|
+
types_getSites = []
|
|
388
|
+
|
|
389
|
+
@classmethod
|
|
390
|
+
def export_getSites(cls, condDict=None, older=None, newer=None):
|
|
391
|
+
"""
|
|
392
|
+
Return Distinct Values of Site job Attribute in WMS
|
|
393
|
+
"""
|
|
394
|
+
return cls.jobDB.getDistinctJobAttributes("Site", condDict, older, newer)
|
|
395
|
+
|
|
396
|
+
types_getStates = []
|
|
397
|
+
|
|
398
|
+
@classmethod
|
|
399
|
+
def export_getStates(cls, condDict=None, older=None, newer=None):
|
|
400
|
+
"""
|
|
401
|
+
Return Distinct Values of Status job Attribute in WMS
|
|
402
|
+
"""
|
|
403
|
+
return cls.jobDB.getDistinctJobAttributes("Status", condDict, older, newer)
|
|
404
|
+
|
|
405
|
+
types_getMinorStates = []
|
|
406
|
+
|
|
407
|
+
@classmethod
|
|
408
|
+
def export_getMinorStates(cls, condDict=None, older=None, newer=None):
|
|
409
|
+
"""
|
|
410
|
+
Return Distinct Values of Minor Status job Attribute in WMS
|
|
411
|
+
"""
|
|
412
|
+
return cls.jobDB.getDistinctJobAttributes("MinorStatus", condDict, older, newer)
|
|
413
|
+
|
|
414
|
+
##############################################################################
|
|
415
|
+
# Transformations
|
|
416
|
+
##############################################################################
|
|
417
|
+
|
|
418
|
+
types_getDistinctAttributeValues = [str, dict]
|
|
419
|
+
|
|
420
|
+
@classmethod
|
|
421
|
+
def export_getDistinctAttributeValues(cls, attribute, selectDict):
|
|
422
|
+
res = cls.transformationDB.getTableDistinctAttributeValues("Transformations", [attribute], selectDict)
|
|
423
|
+
if not res["OK"]:
|
|
424
|
+
return res
|
|
425
|
+
return S_OK(res["Value"][attribute])
|
|
426
|
+
|
|
427
|
+
types_getTransformationFilesSummaryWeb = [dict, list, int, int]
|
|
428
|
+
|
|
429
|
+
@classmethod
|
|
430
|
+
def export_getTransformationFilesSummaryWeb(cls, selectDict, sortList, startItem, maxItems):
|
|
431
|
+
fromDate = selectDict.get("FromDate", None)
|
|
432
|
+
if fromDate:
|
|
433
|
+
del selectDict["FromDate"]
|
|
434
|
+
toDate = selectDict.get("ToDate", None)
|
|
435
|
+
if toDate:
|
|
436
|
+
del selectDict["ToDate"]
|
|
437
|
+
# Sorting instructions. Only one for the moment.
|
|
438
|
+
if sortList:
|
|
439
|
+
orderAttribute = sortList[0][0] + ":" + sortList[0][1]
|
|
440
|
+
else:
|
|
441
|
+
orderAttribute = None
|
|
442
|
+
# Get the columns that match the selection
|
|
443
|
+
res = cls.transformationDB.getTransformationFiles(
|
|
444
|
+
condDict=selectDict, older=toDate, newer=fromDate, timeStamp="LastUpdate", orderAttribute=orderAttribute
|
|
445
|
+
)
|
|
446
|
+
if not res["OK"]:
|
|
447
|
+
return res
|
|
448
|
+
allRows = res["Value"]
|
|
449
|
+
|
|
450
|
+
# Prepare the standard structure now within the resultDict dictionary
|
|
451
|
+
resultDict = {}
|
|
452
|
+
resultDict["TotalRecords"] = len(allRows)
|
|
453
|
+
|
|
454
|
+
if not allRows:
|
|
455
|
+
return S_OK(resultDict)
|
|
456
|
+
|
|
457
|
+
# Get the rows which are within the selected window
|
|
458
|
+
ini = startItem
|
|
459
|
+
last = ini + maxItems
|
|
460
|
+
if ini >= resultDict["TotalRecords"]:
|
|
461
|
+
return S_ERROR("Item number out of range")
|
|
462
|
+
if last > resultDict["TotalRecords"]:
|
|
463
|
+
last = resultDict["TotalRecords"]
|
|
464
|
+
|
|
465
|
+
selectedRows = allRows[ini:last]
|
|
466
|
+
resultDict["Records"] = []
|
|
467
|
+
for row in selectedRows:
|
|
468
|
+
resultDict["Records"].append(list(row.values()))
|
|
469
|
+
|
|
470
|
+
# Create the ParameterNames entry
|
|
471
|
+
resultDict["ParameterNames"] = list(selectedRows[0].keys())
|
|
472
|
+
|
|
473
|
+
# Generate the status dictionary
|
|
474
|
+
statusDict = {}
|
|
475
|
+
for row in selectedRows:
|
|
476
|
+
status = row["Status"]
|
|
477
|
+
statusDict[status] = statusDict.setdefault(status, 0) + 1
|
|
478
|
+
resultDict["Extras"] = statusDict
|
|
479
|
+
|
|
480
|
+
# Obtain the distinct values of the selection parameters
|
|
481
|
+
res = cls.transformationDB.getTableDistinctAttributeValues(
|
|
482
|
+
"TransformationFiles",
|
|
483
|
+
["TransformationID", "Status", "UsedSE", "TargetSE"],
|
|
484
|
+
selectDict,
|
|
485
|
+
older=toDate,
|
|
486
|
+
newer=fromDate,
|
|
487
|
+
)
|
|
488
|
+
if not res["OK"]:
|
|
489
|
+
return res
|
|
490
|
+
resultDict["Selections"] = res["Value"]
|
|
491
|
+
|
|
492
|
+
return S_OK(resultDict)
|
|
493
|
+
|
|
494
|
+
types_getTransformationSummaryWeb = [dict, list, int, int]
|
|
495
|
+
|
|
496
|
+
@classmethod
|
|
497
|
+
def export_getTransformationSummaryWeb(cls, selectDict, sortList, startItem, maxItems):
|
|
498
|
+
"""Get the summary of the transformation information for a given page in the generic format"""
|
|
499
|
+
|
|
500
|
+
# Obtain the timing information from the selectDict
|
|
501
|
+
last_update = selectDict.get("CreationDate", None)
|
|
502
|
+
if last_update:
|
|
503
|
+
del selectDict["CreationDate"]
|
|
504
|
+
fromDate = selectDict.get("FromDate", None)
|
|
505
|
+
if fromDate:
|
|
506
|
+
del selectDict["FromDate"]
|
|
507
|
+
if not fromDate:
|
|
508
|
+
fromDate = last_update
|
|
509
|
+
toDate = selectDict.get("ToDate", None)
|
|
510
|
+
if toDate:
|
|
511
|
+
del selectDict["ToDate"]
|
|
512
|
+
# Sorting instructions. Only one for the moment.
|
|
513
|
+
if sortList:
|
|
514
|
+
orderAttribute = []
|
|
515
|
+
for i in sortList:
|
|
516
|
+
orderAttribute += [i[0] + ":" + i[1]]
|
|
517
|
+
else:
|
|
518
|
+
orderAttribute = None
|
|
519
|
+
|
|
520
|
+
# Get the transformations that match the selection
|
|
521
|
+
res = cls.transformationDB.getTransformations(
|
|
522
|
+
condDict=selectDict, older=toDate, newer=fromDate, orderAttribute=orderAttribute
|
|
523
|
+
)
|
|
524
|
+
if not res["OK"]:
|
|
525
|
+
return res
|
|
526
|
+
|
|
527
|
+
ops = Operations()
|
|
528
|
+
# Prepare the standard structure now within the resultDict dictionary
|
|
529
|
+
resultDict = {}
|
|
530
|
+
trList = res["Records"]
|
|
531
|
+
# Create the total records entry
|
|
532
|
+
nTrans = len(trList)
|
|
533
|
+
resultDict["TotalRecords"] = nTrans
|
|
534
|
+
# Create the ParameterNames entry
|
|
535
|
+
# As this list is a reference to the list in the DB, we cannot extend it, therefore copy it
|
|
536
|
+
resultDict["ParameterNames"] = list(res["ParameterNames"])
|
|
537
|
+
# Add the job states to the ParameterNames entry
|
|
538
|
+
taskStateNames = TASKS_STATE_NAMES + ops.getValue("Transformations/AdditionalTaskStates", [])
|
|
539
|
+
resultDict["ParameterNames"] += ["Jobs_" + x for x in taskStateNames]
|
|
540
|
+
# Add the file states to the ParameterNames entry
|
|
541
|
+
fileStateNames = FILES_STATE_NAMES + ops.getValue("Transformations/AdditionalFileStates", [])
|
|
542
|
+
resultDict["ParameterNames"] += ["Files_" + x for x in fileStateNames]
|
|
543
|
+
|
|
544
|
+
# Get the transformations which are within the selected window
|
|
545
|
+
if nTrans == 0:
|
|
546
|
+
return S_OK(resultDict)
|
|
547
|
+
ini = startItem
|
|
548
|
+
last = ini + maxItems
|
|
549
|
+
if ini >= nTrans:
|
|
550
|
+
return S_ERROR("Item number out of range")
|
|
551
|
+
if last > nTrans:
|
|
552
|
+
last = nTrans
|
|
553
|
+
transList = trList[ini:last]
|
|
554
|
+
|
|
555
|
+
statusDict = {}
|
|
556
|
+
extendableTranfs = ops.getValue("Transformations/ExtendableTransfTypes", ["Simulation", "MCsimulation"])
|
|
557
|
+
givenUpFileStatus = ops.getValue("Transformations/GivenUpFileStatus", ["MissingInFC"])
|
|
558
|
+
problematicStatuses = ops.getValue("Transformations/ProblematicStatuses", ["Problematic"])
|
|
559
|
+
# Add specific information for each selected transformation
|
|
560
|
+
for trans in transList:
|
|
561
|
+
transDict = dict(zip(resultDict["ParameterNames"], trans))
|
|
562
|
+
|
|
563
|
+
# Update the status counters
|
|
564
|
+
status = transDict["Status"]
|
|
565
|
+
statusDict[status] = statusDict.setdefault(status, 0) + 1
|
|
566
|
+
|
|
567
|
+
# Get the statistics on the number of jobs for the transformation
|
|
568
|
+
transID = transDict["TransformationID"]
|
|
569
|
+
res = cls.transformationDB.getTransformationTaskStats(transID)
|
|
570
|
+
taskDict = {}
|
|
571
|
+
if res["OK"] and res["Value"]:
|
|
572
|
+
taskDict = res["Value"]
|
|
573
|
+
for state in taskStateNames:
|
|
574
|
+
trans.append(taskDict.get(state, 0))
|
|
575
|
+
|
|
576
|
+
# Get the statistics for the number of files for the transformation
|
|
577
|
+
fileDict = {}
|
|
578
|
+
transType = transDict["Type"]
|
|
579
|
+
if transType.lower() in extendableTranfs:
|
|
580
|
+
fileDict["PercentProcessed"] = "-"
|
|
581
|
+
else:
|
|
582
|
+
res = cls.transformationDB.getTransformationStats(transID)
|
|
583
|
+
if res["OK"]:
|
|
584
|
+
fileDict = res["Value"]
|
|
585
|
+
total = fileDict["Total"]
|
|
586
|
+
for stat in givenUpFileStatus:
|
|
587
|
+
total -= fileDict.get(stat, 0)
|
|
588
|
+
processed = fileDict.get(TransformationFilesStatus.PROCESSED, 0)
|
|
589
|
+
fileDict["PercentProcessed"] = f"{int(processed * 1000.0 / total) / 10.0:.1f}" if total else 0.0
|
|
590
|
+
problematic = 0
|
|
591
|
+
for stat in problematicStatuses:
|
|
592
|
+
problematic += fileDict.get(stat, 0)
|
|
593
|
+
fileDict["Problematic"] = problematic
|
|
594
|
+
for state in fileStateNames:
|
|
595
|
+
trans.append(fileDict.get(state, 0))
|
|
596
|
+
|
|
597
|
+
resultDict["Records"] = transList
|
|
598
|
+
resultDict["Extras"] = statusDict
|
|
599
|
+
return S_OK(resultDict)
|
|
@@ -5,7 +5,6 @@ import hashlib
|
|
|
5
5
|
import re
|
|
6
6
|
|
|
7
7
|
from DIRAC import S_OK, S_ERROR, gConfig
|
|
8
|
-
from DIRAC.ConfigurationSystem.Client.Helpers import CSGlobals
|
|
9
8
|
from DIRAC.ConfigurationSystem.Client.PathFinder import getServiceSection
|
|
10
9
|
from DIRAC.MonitoringSystem.private.Plotters.BasePlotter import BasePlotter as myBasePlotter
|
|
11
10
|
from DIRAC.Core.Utilities.ObjectLoader import loadObjects
|
|
@@ -56,7 +55,6 @@ class MainReporter:
|
|
|
56
55
|
:param str setup: DIRAC setup
|
|
57
56
|
"""
|
|
58
57
|
self.__db = db
|
|
59
|
-
self.__setup = CSGlobals.getSetup().lower()
|
|
60
58
|
self.__csSection = getServiceSection("Monitoring/Monitoring")
|
|
61
59
|
self.__plotterList = PlottersList()
|
|
62
60
|
|
|
@@ -75,7 +73,6 @@ class MainReporter:
|
|
|
75
73
|
requestToHash[key] = epoch - epoch % granularity
|
|
76
74
|
md5Hash = hashlib.md5()
|
|
77
75
|
md5Hash.update(repr(requestToHash).encode())
|
|
78
|
-
md5Hash.update(self.__setup.encode())
|
|
79
76
|
return md5Hash.hexdigest()
|
|
80
77
|
|
|
81
78
|
def generate(self, reportRequest):
|
|
@@ -16,14 +16,13 @@ def main():
|
|
|
16
16
|
Script.registerArgument("prodID: Production ID")
|
|
17
17
|
_, args = Script.parseCommandLine()
|
|
18
18
|
|
|
19
|
+
from DIRAC.MonitoringSystem.Client.WebAppClient import WebAppClient
|
|
19
20
|
from DIRAC.ProductionSystem.Client.ProductionClient import ProductionClient
|
|
20
|
-
from DIRAC.TransformationSystem.Client.TransformationClient import TransformationClient
|
|
21
21
|
|
|
22
22
|
# get arguments
|
|
23
23
|
prodID = args[0]
|
|
24
24
|
|
|
25
25
|
prodClient = ProductionClient()
|
|
26
|
-
transClient = TransformationClient()
|
|
27
26
|
|
|
28
27
|
res = prodClient.getProductionTransformations(prodID)
|
|
29
28
|
transIDs = []
|
|
@@ -70,7 +69,7 @@ def main():
|
|
|
70
69
|
]
|
|
71
70
|
resList = []
|
|
72
71
|
|
|
73
|
-
res =
|
|
72
|
+
res = WebAppClient().getTransformationSummaryWeb({"TransformationID": transIDs}, [], 0, len(transIDs))
|
|
74
73
|
|
|
75
74
|
if not res["OK"]:
|
|
76
75
|
DIRAC.gLogger.error(res["Message"])
|
|
@@ -48,13 +48,13 @@ from DIRAC.RequestManagementSystem.private.RequestTask import RequestTask
|
|
|
48
48
|
# # agent name
|
|
49
49
|
AGENT_NAME = "RequestManagement/RequestExecutingAgent"
|
|
50
50
|
# # requests/cycle
|
|
51
|
-
REQUESTSPERCYCLE =
|
|
51
|
+
REQUESTSPERCYCLE = 300
|
|
52
52
|
# # minimal nb of subprocess running
|
|
53
|
-
MINPROCESS =
|
|
53
|
+
MINPROCESS = 50
|
|
54
54
|
# # maximal nb of subprocess executed same time
|
|
55
|
-
MAXPROCESS =
|
|
55
|
+
MAXPROCESS = 50
|
|
56
56
|
# # ProcessPool queue size
|
|
57
|
-
QUEUESIZE =
|
|
57
|
+
QUEUESIZE = 100
|
|
58
58
|
# # file timeout
|
|
59
59
|
FILETIMEOUT = 300
|
|
60
60
|
# # operation timeout
|
|
@@ -62,7 +62,9 @@ OPERATIONTIMEOUT = 300
|
|
|
62
62
|
# # ProcessPool finalization timeout
|
|
63
63
|
POOLTIMEOUT = 900
|
|
64
64
|
# # ProcessPool sleep time
|
|
65
|
-
POOLSLEEP =
|
|
65
|
+
POOLSLEEP = 1
|
|
66
|
+
# # Fetch multiple requests at once from the DB. Otherwise, one by one
|
|
67
|
+
BULKREQUEST = 300
|
|
66
68
|
|
|
67
69
|
|
|
68
70
|
class AgentConfigError(Exception):
|
|
@@ -108,7 +110,7 @@ class RequestExecutingAgent(AgentModule):
|
|
|
108
110
|
self.__poolSleep = POOLSLEEP
|
|
109
111
|
self.__requestClient = None
|
|
110
112
|
# Size of the bulk if use of getRequests. If 0, use getRequest
|
|
111
|
-
self.__bulkRequest =
|
|
113
|
+
self.__bulkRequest = BULKREQUEST
|
|
112
114
|
self.__rmsMonitoring = False
|
|
113
115
|
|
|
114
116
|
def processPool(self):
|