DIRAC 9.0.9__py3-none-any.whl → 9.0.11__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/Core/Utilities/ElasticSearchDB.py +1 -2
- DIRAC/DataManagementSystem/Client/DataManager.py +6 -7
- DIRAC/FrameworkSystem/DB/InstalledComponentsDB.py +1 -1
- DIRAC/FrameworkSystem/Utilities/MonitoringUtilities.py +1 -0
- DIRAC/Interfaces/Utilities/DConfigCache.py +2 -0
- DIRAC/Resources/Computing/BatchSystems/Condor.py +0 -3
- DIRAC/Resources/Computing/BatchSystems/executeBatch.py +15 -7
- DIRAC/Resources/Computing/LocalComputingElement.py +0 -2
- DIRAC/Resources/Computing/SSHComputingElement.py +61 -38
- DIRAC/TransformationSystem/Agent/InputDataAgent.py +4 -1
- DIRAC/TransformationSystem/Agent/MCExtensionAgent.py +5 -2
- DIRAC/TransformationSystem/Agent/TaskManagerAgentBase.py +3 -1
- DIRAC/TransformationSystem/Agent/TransformationCleaningAgent.py +44 -9
- DIRAC/TransformationSystem/Agent/ValidateOutputDataAgent.py +4 -2
- DIRAC/TransformationSystem/Client/TransformationClient.py +9 -1
- DIRAC/TransformationSystem/DB/TransformationDB.py +105 -43
- DIRAC/WorkloadManagementSystem/Agent/StalledJobAgent.py +39 -7
- DIRAC/WorkloadManagementSystem/Agent/test/Test_Agent_StalledJobAgent.py +24 -4
- DIRAC/WorkloadManagementSystem/DB/StatusUtils.py +48 -21
- DIRAC/WorkloadManagementSystem/DB/tests/Test_StatusUtils.py +19 -4
- DIRAC/WorkloadManagementSystem/Service/JobManagerHandler.py +25 -2
- {dirac-9.0.9.dist-info → dirac-9.0.11.dist-info}/METADATA +2 -2
- {dirac-9.0.9.dist-info → dirac-9.0.11.dist-info}/RECORD +27 -27
- {dirac-9.0.9.dist-info → dirac-9.0.11.dist-info}/WHEEL +0 -0
- {dirac-9.0.9.dist-info → dirac-9.0.11.dist-info}/entry_points.txt +0 -0
- {dirac-9.0.9.dist-info → dirac-9.0.11.dist-info}/licenses/LICENSE +0 -0
- {dirac-9.0.9.dist-info → dirac-9.0.11.dist-info}/top_level.txt +0 -0
|
@@ -82,7 +82,6 @@ def generateDocs(data, withTimeStamp=True):
|
|
|
82
82
|
|
|
83
83
|
|
|
84
84
|
class ElasticSearchDB:
|
|
85
|
-
|
|
86
85
|
"""
|
|
87
86
|
.. class:: ElasticSearchDB
|
|
88
87
|
|
|
@@ -506,7 +505,7 @@ class ElasticSearchDB:
|
|
|
506
505
|
indexName = self.generateFullIndexName(indexPrefix, period)
|
|
507
506
|
else:
|
|
508
507
|
indexName = indexPrefix
|
|
509
|
-
sLog.debug(f"Bulk indexing into {indexName} of {data}")
|
|
508
|
+
sLog.debug(f"Bulk indexing into {indexName} of {len(data)}")
|
|
510
509
|
|
|
511
510
|
res = self.existingIndex(indexName)
|
|
512
511
|
if not res["OK"]:
|
|
@@ -10,11 +10,11 @@ This module consists of DataManager and related classes.
|
|
|
10
10
|
"""
|
|
11
11
|
|
|
12
12
|
# # imports
|
|
13
|
-
|
|
13
|
+
import errno
|
|
14
14
|
import fnmatch
|
|
15
15
|
import os
|
|
16
16
|
import time
|
|
17
|
-
import
|
|
17
|
+
from datetime import datetime, timedelta
|
|
18
18
|
|
|
19
19
|
# # from DIRAC
|
|
20
20
|
import DIRAC
|
|
@@ -25,13 +25,13 @@ from DIRAC.Core.Utilities.File import makeGuid, getSize
|
|
|
25
25
|
from DIRAC.Core.Utilities.List import randomize, breakListIntoChunks
|
|
26
26
|
from DIRAC.Core.Utilities.ReturnValues import returnSingleResult
|
|
27
27
|
from DIRAC.Core.Security.ProxyInfo import getProxyInfo
|
|
28
|
+
from DIRAC.Core.Security.ProxyInfo import getVOfromProxyGroup
|
|
28
29
|
from DIRAC.ConfigurationSystem.Client.Helpers.Operations import Operations
|
|
29
30
|
from DIRAC.DataManagementSystem.Client import MAX_FILENAME_LENGTH
|
|
30
|
-
from DIRAC.MonitoringSystem.Client.DataOperationSender import DataOperationSender
|
|
31
31
|
from DIRAC.DataManagementSystem.Utilities.DMSHelpers import DMSHelpers
|
|
32
|
+
from DIRAC.MonitoringSystem.Client.DataOperationSender import DataOperationSender
|
|
32
33
|
from DIRAC.Resources.Catalog.FileCatalog import FileCatalog
|
|
33
34
|
from DIRAC.Resources.Storage.StorageElement import StorageElement
|
|
34
|
-
from DIRAC.ResourceStatusSystem.Client.ResourceStatus import ResourceStatus
|
|
35
35
|
|
|
36
36
|
|
|
37
37
|
# # RSCID
|
|
@@ -89,7 +89,7 @@ class DataManager:
|
|
|
89
89
|
:param vo: the VO for which the DataManager is created, get VO from the current proxy if not specified
|
|
90
90
|
"""
|
|
91
91
|
self.log = gLogger.getSubLogger(self.__class__.__name__)
|
|
92
|
-
self.voName = vo
|
|
92
|
+
self.voName = vo if vo else getVOfromProxyGroup().get("Value", None)
|
|
93
93
|
|
|
94
94
|
if catalogs is None:
|
|
95
95
|
catalogs = []
|
|
@@ -97,10 +97,9 @@ class DataManager:
|
|
|
97
97
|
|
|
98
98
|
self.fileCatalog = FileCatalog(catalogs=catalogsToUse, vo=self.voName)
|
|
99
99
|
self.accountingClient = None
|
|
100
|
-
self.resourceStatus = ResourceStatus()
|
|
101
100
|
self.ignoreMissingInFC = Operations(vo=self.voName).getValue("DataManagement/IgnoreMissingInFC", False)
|
|
102
101
|
self.useCatalogPFN = Operations(vo=self.voName).getValue("DataManagement/UseCatalogPFN", True)
|
|
103
|
-
self.dmsHelper = DMSHelpers(vo=
|
|
102
|
+
self.dmsHelper = DMSHelpers(vo=self.voName)
|
|
104
103
|
self.registrationProtocol = self.dmsHelper.getRegistrationProtocols()
|
|
105
104
|
self.thirdPartyProtocols = self.dmsHelper.getThirdPartyProtocols()
|
|
106
105
|
self.dataOpSender = DataOperationSender()
|
|
@@ -90,7 +90,7 @@ class Host(componentsBase):
|
|
|
90
90
|
__table_args__ = {"mysql_engine": "InnoDB", "mysql_charset": "utf8mb4"}
|
|
91
91
|
|
|
92
92
|
hostID = Column("HostID", Integer, primary_key=True)
|
|
93
|
-
hostName = Column("HostName", String(
|
|
93
|
+
hostName = Column("HostName", String(64), nullable=False)
|
|
94
94
|
cpu = Column("CPU", String(64), nullable=False)
|
|
95
95
|
installationList = relationship("InstalledComponent", backref="installationHost")
|
|
96
96
|
|
|
@@ -9,6 +9,7 @@ from DIRAC import gLogger
|
|
|
9
9
|
from DIRAC.Core.Base.Script import Script
|
|
10
10
|
from DIRAC.Core.Utilities.File import secureOpenForWrite
|
|
11
11
|
from DIRAC.ConfigurationSystem.Client.ConfigurationData import gConfigurationData
|
|
12
|
+
from DIRAC.ConfigurationSystem.Client.Helpers.Registry import reset_all_caches
|
|
12
13
|
|
|
13
14
|
|
|
14
15
|
class ConfigCache:
|
|
@@ -69,5 +70,6 @@ class ConfigCache:
|
|
|
69
70
|
try:
|
|
70
71
|
with open(self.configCacheName, "rb") as fh:
|
|
71
72
|
gConfigurationData.mergedCFG = pickle.load(fh)
|
|
73
|
+
reset_all_caches()
|
|
72
74
|
except:
|
|
73
75
|
gLogger.error("Cache corrupt or unreadable")
|
|
@@ -203,9 +203,6 @@ class Condor(object):
|
|
|
203
203
|
resultDict["Jobs"] = []
|
|
204
204
|
for i in range(submittedJobs):
|
|
205
205
|
resultDict["Jobs"].append(".".join([cluster, str(i)]))
|
|
206
|
-
# Executable is transferred afterward
|
|
207
|
-
# Inform the caller that Condor cannot delete it before the end of the execution
|
|
208
|
-
resultDict["ExecutableToKeep"] = executable
|
|
209
206
|
else:
|
|
210
207
|
resultDict["Status"] = status
|
|
211
208
|
resultDict["Message"] = error
|
|
@@ -35,8 +35,10 @@ if __name__ == "__main__":
|
|
|
35
35
|
from urllib.parse import unquote as urlunquote
|
|
36
36
|
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
# Read options from JSON file
|
|
39
|
+
optionsFilePath = sys.argv[1]
|
|
40
|
+
with open(optionsFilePath, 'r') as f:
|
|
41
|
+
inputDict = json.load(f)
|
|
40
42
|
|
|
41
43
|
method = inputDict.pop('Method')
|
|
42
44
|
batchSystem = inputDict.pop('BatchSystem')
|
|
@@ -45,9 +47,15 @@ if __name__ == "__main__":
|
|
|
45
47
|
try:
|
|
46
48
|
result = getattr(batch, method)(**inputDict)
|
|
47
49
|
except Exception:
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
50
|
+
# Wrap the traceback in a proper error structure
|
|
51
|
+
result = {
|
|
52
|
+
'Status': -1,
|
|
53
|
+
'Message': 'Exception during batch method execution',
|
|
54
|
+
'Traceback': traceback.format_exc()
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
# Write result to JSON file
|
|
58
|
+
resultFilePath = optionsFilePath.replace('.json', '_result.json')
|
|
59
|
+
with open(resultFilePath, 'w') as f:
|
|
60
|
+
json.dump(result, f)
|
|
53
61
|
"""
|
|
@@ -182,8 +182,6 @@ class LocalComputingElement(ComputingElement):
|
|
|
182
182
|
batchSystemName = self.batchSystem.__class__.__name__.lower()
|
|
183
183
|
jobIDs = ["ssh" + batchSystemName + "://" + self.ceName + "/" + _id for _id in resultSubmit["Jobs"]]
|
|
184
184
|
result = S_OK(jobIDs)
|
|
185
|
-
if "ExecutableToKeep" in resultSubmit:
|
|
186
|
-
result["ExecutableToKeep"] = resultSubmit["ExecutableToKeep"]
|
|
187
185
|
else:
|
|
188
186
|
result = S_ERROR(resultSubmit["Message"])
|
|
189
187
|
|
|
@@ -67,9 +67,10 @@ import json
|
|
|
67
67
|
import os
|
|
68
68
|
import shutil
|
|
69
69
|
import stat
|
|
70
|
+
import tempfile
|
|
70
71
|
import uuid
|
|
71
72
|
from shlex import quote as shlex_quote
|
|
72
|
-
from urllib.parse import
|
|
73
|
+
from urllib.parse import urlparse
|
|
73
74
|
|
|
74
75
|
import pexpect
|
|
75
76
|
|
|
@@ -484,47 +485,69 @@ class SSHComputingElement(ComputingElement):
|
|
|
484
485
|
options["User"] = self.user
|
|
485
486
|
options["Queue"] = self.queue
|
|
486
487
|
|
|
487
|
-
|
|
488
|
-
|
|
488
|
+
localOptionsFile = None
|
|
489
|
+
remoteOptionsFile = None
|
|
490
|
+
localResultFile = None
|
|
491
|
+
remoteResultFile = None
|
|
492
|
+
try:
|
|
493
|
+
# Write options to a local temporary file
|
|
494
|
+
with tempfile.NamedTemporaryFile(mode="w", suffix=".json", delete=False) as f:
|
|
495
|
+
json.dump(options, f)
|
|
496
|
+
localOptionsFile = f.name
|
|
497
|
+
|
|
498
|
+
# Upload the options file to the remote host
|
|
499
|
+
remoteOptionsFile = f"{self.sharedArea}/batch_options_{uuid.uuid4().hex}.json"
|
|
500
|
+
result = ssh.scpCall(30, localOptionsFile, remoteOptionsFile)
|
|
501
|
+
if not result["OK"]:
|
|
502
|
+
return result
|
|
489
503
|
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
504
|
+
# Execute the batch command with the options file path
|
|
505
|
+
cmd = (
|
|
506
|
+
f"bash --login -c 'python3 {self.sharedArea}/execute_batch {remoteOptionsFile} || "
|
|
507
|
+
f"python {self.sharedArea}/execute_batch {remoteOptionsFile} || "
|
|
508
|
+
f"python2 {self.sharedArea}/execute_batch {remoteOptionsFile}'"
|
|
509
|
+
)
|
|
494
510
|
|
|
495
|
-
|
|
511
|
+
self.log.verbose(f"CE submission command: {cmd}")
|
|
496
512
|
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
513
|
+
result = ssh.sshCall(120, cmd)
|
|
514
|
+
if not result["OK"]:
|
|
515
|
+
self.log.error(f"{self.ceType} CE job submission failed", result["Message"])
|
|
516
|
+
return result
|
|
501
517
|
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
518
|
+
sshStatus = result["Value"][0]
|
|
519
|
+
if sshStatus != 0:
|
|
520
|
+
sshStdout = result["Value"][1]
|
|
521
|
+
sshStderr = result["Value"][2]
|
|
522
|
+
return S_ERROR(f"CE job submission command failed with status {sshStatus}: {sshStdout} {sshStderr}")
|
|
523
|
+
|
|
524
|
+
# The result should be written to a JSON file by execute_batch
|
|
525
|
+
# Compute the expected result file path
|
|
526
|
+
remoteResultFile = remoteOptionsFile.replace(".json", "_result.json")
|
|
527
|
+
|
|
528
|
+
# Try to download the result file
|
|
529
|
+
with tempfile.NamedTemporaryFile(mode="r", suffix=".json", delete=False) as f:
|
|
530
|
+
localResultFile = f.name
|
|
531
|
+
|
|
532
|
+
result = ssh.scpCall(30, localResultFile, remoteResultFile, upload=False)
|
|
533
|
+
if not result["OK"]:
|
|
534
|
+
return result
|
|
535
|
+
|
|
536
|
+
# Read the result from the downloaded file
|
|
537
|
+
with open(localResultFile) as f:
|
|
538
|
+
result = json.load(f)
|
|
539
|
+
return S_OK(result)
|
|
540
|
+
finally:
|
|
541
|
+
# Clean up local temporary file
|
|
542
|
+
if localOptionsFile and os.path.exists(localOptionsFile):
|
|
543
|
+
os.remove(localOptionsFile)
|
|
544
|
+
if localResultFile and os.path.exists(localResultFile):
|
|
545
|
+
os.remove(localResultFile)
|
|
546
|
+
# Clean up remote temporary files
|
|
547
|
+
if remoteOptionsFile:
|
|
548
|
+
ssh.sshCall(30, f"rm -f {remoteOptionsFile}")
|
|
549
|
+
if remoteResultFile:
|
|
550
|
+
ssh.sshCall(30, f"rm -f {remoteResultFile}")
|
|
528
551
|
|
|
529
552
|
def submitJob(self, executableFile, proxy, numberOfJobs=1):
|
|
530
553
|
# self.log.verbose( "Executable file path: %s" % executableFile )
|
|
@@ -74,7 +74,10 @@ class InputDataAgent(AgentModule):
|
|
|
74
74
|
"""Main execution method"""
|
|
75
75
|
|
|
76
76
|
# Get all the transformations
|
|
77
|
-
result = self.transClient.getTransformations(
|
|
77
|
+
result = self.transClient.getTransformations(
|
|
78
|
+
{"Status": "Active", "Type": self.transformationTypes},
|
|
79
|
+
columns=["TransformationID", "AuthorDN", "AuthorGroup"],
|
|
80
|
+
)
|
|
78
81
|
if not result["OK"]:
|
|
79
82
|
self.log.error("InputDataAgent.execute: Failed to get transformations.", result["Message"])
|
|
80
83
|
return S_OK()
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""Agent to extend the number of tasks given the Transformation definition
|
|
2
2
|
|
|
3
3
|
The following options can be set for the MCExtensionAgent.
|
|
4
4
|
|
|
@@ -8,6 +8,7 @@ The following options can be set for the MCExtensionAgent.
|
|
|
8
8
|
:dedent: 2
|
|
9
9
|
:caption: MCExtensionAgent options
|
|
10
10
|
"""
|
|
11
|
+
|
|
11
12
|
from DIRAC import S_OK, gLogger
|
|
12
13
|
from DIRAC.Core.Base.AgentModule import AgentModule
|
|
13
14
|
from DIRAC.ConfigurationSystem.Client.Helpers.Operations import Operations
|
|
@@ -54,7 +55,9 @@ class MCExtensionAgent(AgentModule):
|
|
|
54
55
|
return S_OK("Disabled via CS flag")
|
|
55
56
|
|
|
56
57
|
# Obtain the transformations in Cleaning status and remove any mention of the jobs/files
|
|
57
|
-
res = self.transClient.getTransformations(
|
|
58
|
+
res = self.transClient.getTransformations(
|
|
59
|
+
{"Status": "Active", "Type": self.transformationTypes}, columns=["TransformationID", "MaxNumberOfTasks"]
|
|
60
|
+
)
|
|
58
61
|
if res["OK"]:
|
|
59
62
|
for transDict in res["Value"]:
|
|
60
63
|
transID = transDict["TransformationID"]
|
|
@@ -231,7 +231,9 @@ class TaskManagerAgentBase(AgentModule, TransformationAgentsUtilities):
|
|
|
231
231
|
selectCond["Type"] = transType
|
|
232
232
|
if agentType:
|
|
233
233
|
selectCond["AgentType"] = agentType
|
|
234
|
-
res = self.transClient.getTransformations(
|
|
234
|
+
res = self.transClient.getTransformations(
|
|
235
|
+
condDict=selectCond, columns=["TransformationID", "Body", "Author", "AuthorGroup"]
|
|
236
|
+
)
|
|
235
237
|
if not res["OK"]:
|
|
236
238
|
self.log.error("Failed to get transformations:", res["Message"])
|
|
237
239
|
elif not res["Value"]:
|
|
@@ -20,6 +20,7 @@ from DIRAC.ConfigurationSystem.Client.Helpers.Operations import Operations
|
|
|
20
20
|
from DIRAC.Core.Base.AgentModule import AgentModule
|
|
21
21
|
from DIRAC.Core.Utilities.DErrno import cmpError
|
|
22
22
|
from DIRAC.Core.Utilities.List import breakListIntoChunks
|
|
23
|
+
from DIRAC.Core.Utilities.ObjectLoader import ObjectLoader
|
|
23
24
|
from DIRAC.Core.Utilities.Proxy import executeWithUserProxy
|
|
24
25
|
from DIRAC.Core.Utilities.ReturnValues import returnSingleResult
|
|
25
26
|
from DIRAC.RequestManagementSystem.Client.File import File
|
|
@@ -32,7 +33,6 @@ from DIRAC.Resources.Catalog.FileCatalogClient import FileCatalogClient
|
|
|
32
33
|
from DIRAC.Resources.Storage.StorageElement import StorageElement
|
|
33
34
|
from DIRAC.TransformationSystem.Client import TransformationStatus
|
|
34
35
|
from DIRAC.TransformationSystem.Client.TransformationClient import TransformationClient
|
|
35
|
-
from DIRAC.WorkloadManagementSystem.DB.JobDB import JobDB
|
|
36
36
|
from DIRAC.WorkloadManagementSystem.Service.JobPolicy import (
|
|
37
37
|
RIGHT_DELETE,
|
|
38
38
|
RIGHT_KILL,
|
|
@@ -65,8 +65,11 @@ class TransformationCleaningAgent(AgentModule):
|
|
|
65
65
|
self.reqClient = None
|
|
66
66
|
# # file catalog client
|
|
67
67
|
self.metadataClient = None
|
|
68
|
-
# #
|
|
68
|
+
# # databases
|
|
69
69
|
self.jobDB = None
|
|
70
|
+
self.pilotAgentsDB = None
|
|
71
|
+
self.taskQueueDB = None
|
|
72
|
+
self.storageManagementDB = None
|
|
70
73
|
|
|
71
74
|
# # transformations types
|
|
72
75
|
self.transformationTypes = None
|
|
@@ -125,8 +128,26 @@ class TransformationCleaningAgent(AgentModule):
|
|
|
125
128
|
self.reqClient = ReqClient()
|
|
126
129
|
# # file catalog client
|
|
127
130
|
self.metadataClient = FileCatalogClient()
|
|
128
|
-
# #
|
|
129
|
-
|
|
131
|
+
# # databases
|
|
132
|
+
result = ObjectLoader().loadObject("WorkloadManagementSystem.DB.JobDB", "JobDB")
|
|
133
|
+
if not result["OK"]:
|
|
134
|
+
return result
|
|
135
|
+
self.jobDB = result["Value"]()
|
|
136
|
+
|
|
137
|
+
result = ObjectLoader().loadObject("WorkloadManagementSystem.DB.PilotAgentsDB", "PilotAgentsDB")
|
|
138
|
+
if not result["OK"]:
|
|
139
|
+
return result
|
|
140
|
+
self.pilotAgentsDB = result["Value"]()
|
|
141
|
+
|
|
142
|
+
result = ObjectLoader().loadObject("WorkloadManagementSystem.DB.TaskQueueDB", "TaskQueueDB")
|
|
143
|
+
if not result["OK"]:
|
|
144
|
+
return result
|
|
145
|
+
self.taskQueueDB = result["Value"]()
|
|
146
|
+
|
|
147
|
+
result = ObjectLoader().loadObject("StorageManagementSystem.DB.StorageManagementDB", "StorageManagementDB")
|
|
148
|
+
if not result["OK"]:
|
|
149
|
+
return result
|
|
150
|
+
self.storageManagementDB = result["Value"]()
|
|
130
151
|
|
|
131
152
|
return S_OK()
|
|
132
153
|
|
|
@@ -144,7 +165,8 @@ class TransformationCleaningAgent(AgentModule):
|
|
|
144
165
|
|
|
145
166
|
# Obtain the transformations in Cleaning status and remove any mention of the jobs/files
|
|
146
167
|
res = self.transClient.getTransformations(
|
|
147
|
-
{"Status": TransformationStatus.CLEANING, "Type": self.transformationTypes}
|
|
168
|
+
{"Status": TransformationStatus.CLEANING, "Type": self.transformationTypes},
|
|
169
|
+
columns=["TransformationID", "Author", "AuthorGroup", "Type"],
|
|
148
170
|
)
|
|
149
171
|
if res["OK"]:
|
|
150
172
|
for transDict in res["Value"]:
|
|
@@ -161,7 +183,10 @@ class TransformationCleaningAgent(AgentModule):
|
|
|
161
183
|
self.log.error("Failed to get transformations", res["Message"])
|
|
162
184
|
|
|
163
185
|
# Obtain the transformations in RemovingFiles status and removes the output files
|
|
164
|
-
res = self.transClient.getTransformations(
|
|
186
|
+
res = self.transClient.getTransformations(
|
|
187
|
+
{"Status": "RemovingFiles", "Type": self.transformationTypes},
|
|
188
|
+
columns=["TransformationID", "Author", "AuthorGroup"],
|
|
189
|
+
)
|
|
165
190
|
if res["OK"]:
|
|
166
191
|
for transDict in res["Value"]:
|
|
167
192
|
if self.shifterProxy:
|
|
@@ -183,6 +208,7 @@ class TransformationCleaningAgent(AgentModule):
|
|
|
183
208
|
{"Status": TransformationStatus.COMPLETED, "Type": self.transformationTypes},
|
|
184
209
|
older=olderThanTime,
|
|
185
210
|
timeStamp="LastUpdate",
|
|
211
|
+
columns=["TransformationID", "Author", "AuthorGroup"],
|
|
186
212
|
)
|
|
187
213
|
if res["OK"]:
|
|
188
214
|
for transDict in res["Value"]:
|
|
@@ -230,7 +256,10 @@ class TransformationCleaningAgent(AgentModule):
|
|
|
230
256
|
return res
|
|
231
257
|
transformationIDs = res["Value"]
|
|
232
258
|
if transformationIDs:
|
|
233
|
-
res = self.transClient.getTransformations(
|
|
259
|
+
res = self.transClient.getTransformations(
|
|
260
|
+
{"TransformationID": transformationIDs},
|
|
261
|
+
columns=["TransformationID", "Status", "Author", "AuthorGroup", "Type"],
|
|
262
|
+
)
|
|
234
263
|
if not res["OK"]:
|
|
235
264
|
self.log.error("Failed to get transformations", res["Message"])
|
|
236
265
|
return res
|
|
@@ -607,11 +636,17 @@ class TransformationCleaningAgent(AgentModule):
|
|
|
607
636
|
:param self: self reference
|
|
608
637
|
:param list trasnJobIDs: job IDs
|
|
609
638
|
"""
|
|
639
|
+
db_kwargs = dict(
|
|
640
|
+
jobdb=self.jobDB,
|
|
641
|
+
taskqueuedb=self.taskQueueDB,
|
|
642
|
+
pilotagentsdb=self.pilotAgentsDB,
|
|
643
|
+
storagemanagementdb=self.storageManagementDB,
|
|
644
|
+
)
|
|
610
645
|
# Prevent 0 job IDs
|
|
611
646
|
jobIDs = [int(j) for j in transJobIDs if int(j)]
|
|
612
647
|
allRemove = True
|
|
613
648
|
for jobList in breakListIntoChunks(jobIDs, 1000):
|
|
614
|
-
res = kill_delete_jobs(RIGHT_KILL, jobList, force=True)
|
|
649
|
+
res = kill_delete_jobs(RIGHT_KILL, jobList, force=True, **db_kwargs)
|
|
615
650
|
if res["OK"]:
|
|
616
651
|
self.log.info(f"Successfully killed {len(jobList)} jobs from WMS")
|
|
617
652
|
elif ("InvalidJobIDs" in res) and ("NonauthorizedJobIDs" not in res) and ("FailedJobIDs" not in res):
|
|
@@ -623,7 +658,7 @@ class TransformationCleaningAgent(AgentModule):
|
|
|
623
658
|
self.log.error("Failed to kill jobs", f"(n={len(res['FailedJobIDs'])})")
|
|
624
659
|
allRemove = False
|
|
625
660
|
|
|
626
|
-
res = kill_delete_jobs(RIGHT_DELETE, jobList, force=True)
|
|
661
|
+
res = kill_delete_jobs(RIGHT_DELETE, jobList, force=True, **db_kwargs)
|
|
627
662
|
if res["OK"]:
|
|
628
663
|
self.log.info("Successfully deleted jobs from WMS", f"(n={len(jobList)})")
|
|
629
664
|
elif ("InvalidJobIDs" in res) and ("NonauthorizedJobIDs" not in res) and ("FailedJobIDs" not in res):
|
|
@@ -76,7 +76,9 @@ class ValidateOutputDataAgent(AgentModule):
|
|
|
76
76
|
self.updateWaitingIntegrity()
|
|
77
77
|
gLogger.info("-" * 40)
|
|
78
78
|
|
|
79
|
-
res = self.transClient.getTransformations(
|
|
79
|
+
res = self.transClient.getTransformations(
|
|
80
|
+
{"Status": "ValidatingOutput", "Type": self.transformationTypes}, columns=["TransformationID"]
|
|
81
|
+
)
|
|
80
82
|
if not res["OK"]:
|
|
81
83
|
gLogger.error("Failed to get ValidatingOutput transformations", res["Message"])
|
|
82
84
|
return res
|
|
@@ -98,7 +100,7 @@ class ValidateOutputDataAgent(AgentModule):
|
|
|
98
100
|
def updateWaitingIntegrity(self):
|
|
99
101
|
"""Get 'WaitingIntegrity' transformations, update to 'ValidatedOutput'"""
|
|
100
102
|
gLogger.info("Looking for transformations in the WaitingIntegrity status to update")
|
|
101
|
-
res = self.transClient.getTransformations({"Status": "WaitingIntegrity"})
|
|
103
|
+
res = self.transClient.getTransformations({"Status": "WaitingIntegrity"}, columns=["TransformationID"])
|
|
102
104
|
if not res["OK"]:
|
|
103
105
|
gLogger.error("Failed to get WaitingIntegrity transformations", res["Message"])
|
|
104
106
|
return res
|
|
@@ -114,13 +114,21 @@ class TransformationClient(Client):
|
|
|
114
114
|
newer=None,
|
|
115
115
|
timeStamp=None,
|
|
116
116
|
orderAttribute=None,
|
|
117
|
-
limit=
|
|
117
|
+
limit=None,
|
|
118
118
|
extraParams=False,
|
|
119
119
|
columns=None,
|
|
120
120
|
):
|
|
121
121
|
"""gets all the transformations in the system, incrementally. "limit" here is just used to determine the offset."""
|
|
122
122
|
rpcClient = self._getRPC()
|
|
123
123
|
|
|
124
|
+
# If the body is requested (or is served by default)
|
|
125
|
+
# we take smaller chunk, not to take too much memory
|
|
126
|
+
# on the server
|
|
127
|
+
if columns and "Body" not in columns:
|
|
128
|
+
limit = 100_000
|
|
129
|
+
else:
|
|
130
|
+
limit = 1_000
|
|
131
|
+
|
|
124
132
|
transformations = []
|
|
125
133
|
if condDict is None:
|
|
126
134
|
condDict = {}
|