DIRAC 9.0.6__py3-none-any.whl → 9.0.8__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.
@@ -110,19 +110,18 @@ class SSLTransport(BaseTransport):
110
110
  if self.serverMode():
111
111
  raise RuntimeError("SSLTransport is in server mode.")
112
112
 
113
- error = None
113
+ errors = []
114
114
  host, port = self.stServerAddress
115
115
 
116
116
  # The following piece of code was inspired by the python socket documentation
117
117
  # as well as the implementation of M2Crypto.httpslib.HTTPSConnection
118
118
 
119
- # We ignore the returned sockaddr because SSL.Connection.connect needs
120
- # a host name.
119
+ # Get all available addresses (IPv6 and IPv4) and try them in order
121
120
  try:
122
121
  addrInfoList = socket.getaddrinfo(host, port, socket.AF_UNSPEC, socket.SOCK_STREAM)
123
122
  except OSError as e:
124
123
  return S_ERROR(f"DNS lookup failed {e!r}")
125
- for family, _socketType, _proto, _canonname, _socketAddress in addrInfoList:
124
+ for family, _socketType, _proto, _canonname, socketAddress in addrInfoList:
126
125
  try:
127
126
  self.oSocket = SSL.Connection(self.__ctx, family=family)
128
127
 
@@ -138,7 +137,10 @@ class SSLTransport(BaseTransport):
138
137
  # set SNI server name since we know it at this point
139
138
  self.oSocket.set_tlsext_host_name(host)
140
139
 
141
- self.oSocket.connect((host, port))
140
+ # tell the connection which host we are connecting to so we can
141
+ # use the address we obtained from DNS
142
+ self.oSocket.set1_host(host)
143
+ self.oSocket.connect(socketAddress)
142
144
 
143
145
  # Once the connection is established, we can use the timeout
144
146
  # asked for RPC
@@ -151,12 +153,12 @@ class SSLTransport(BaseTransport):
151
153
  # They should be propagated upwards and caught by the BaseClient
152
154
  # not to enter the retry loop
153
155
  except OSError as e:
154
- error = f"{e}:{repr(e)}"
156
+ errors.append(f"{socketAddress} {e}:{repr(e)}")
155
157
 
156
158
  if self.oSocket is not None:
157
159
  self.close()
158
160
 
159
- return S_ERROR(error)
161
+ return S_ERROR("; ".join(errors))
160
162
 
161
163
  def initAsServer(self):
162
164
  """Prepare this server socket for use."""
@@ -719,10 +719,11 @@ class FTS3Agent(AgentModule):
719
719
  return self.dataOpSender.concludeSending()
720
720
 
721
721
  def __sendAccounting(self, ftsJob):
722
- self.dataOpSender.sendData(
723
- ftsJob.accountingDict,
724
- commitFlag=True,
725
- delayedCommit=True,
726
- startTime=fromString(ftsJob.submitTime),
727
- endTime=fromString(ftsJob.lastUpdate),
728
- )
722
+ for accountingDict in ftsJob.accountingDicts:
723
+ self.dataOpSender.sendData(
724
+ accountingDict,
725
+ commitFlag=True,
726
+ delayedCommit=True,
727
+ startTime=fromString(ftsJob.submitTime),
728
+ endTime=fromString(ftsJob.lastUpdate),
729
+ )
@@ -3,9 +3,13 @@
3
3
  import datetime
4
4
  import errno
5
5
  import os
6
+ import requests
6
7
  from packaging.version import Version
7
8
 
8
- from cachetools import cachedmethod, LRUCache
9
+ from cachetools import cachedmethod, LRUCache, TTLCache, cached
10
+ from threading import Lock
11
+ from typing import Optional
12
+
9
13
 
10
14
  # Requires at least version 3.3.3
11
15
  from fts3 import __version__ as fts3_version
@@ -44,6 +48,50 @@ BRING_ONLINE_TIMEOUT = 259200
44
48
  IDP_CACHE_SIZE = 8
45
49
 
46
50
 
51
+ _scitag_cache = TTLCache(maxsize=10, ttl=3600)
52
+ _scitag_lock = Lock()
53
+ _scitag_json_cache = TTLCache(maxsize=1, ttl=86400)
54
+ _scitag_json_lock = Lock()
55
+
56
+
57
+ @cached(_scitag_cache, lock=_scitag_lock)
58
+ def get_scitag(vo: str, activity: Optional[str] = None) -> int:
59
+ """
60
+ Get the scitag based on the VO and activity.
61
+ If the VO is not found in the scitag.json, it defaults to 1.
62
+ If no specific activity is provided, it defaults to the "default" activityName.
63
+
64
+ :param vo: The VO for which to get the scitag
65
+ :param activity: The activity for which to get the scitag
66
+ :return: The scitag value
67
+ """
68
+
69
+ @cached(_scitag_json_cache, lock=_scitag_json_lock)
70
+ def get_remote_json():
71
+ gLogger.verbose("Fetching https://scitags.org/api.json from the network")
72
+ response = requests.get("https://scitags.org/api.json")
73
+ response.raise_for_status()
74
+ return response.json()
75
+
76
+ vo_id = 1 # Default VO ID
77
+ activity_id = 1 # Default activity ID
78
+
79
+ try:
80
+ # Load the JSON data from the cache or network
81
+ sj = get_remote_json()
82
+
83
+ for experiment in sj.get("experiments", []):
84
+ if experiment.get("expName") == vo.lower():
85
+ vo_id = experiment.get("expId")
86
+ for act in experiment.get("activities", []):
87
+ if act.get("activityName") == activity:
88
+ activity_id = act.get("activityId")
89
+ except Exception as e:
90
+ gLogger.error(f"Error fetching or parsing scitag.json. Using default scitag values.", repr(e))
91
+ # Logic to determine the scitag based on vo and activity (this is what FTS wants)
92
+ return vo_id << 6 | activity_id # Example logic, replace with actual implementation
93
+
94
+
47
95
  class FTS3Job(JSerializable):
48
96
  """Abstract class to represent a job to be executed by FTS. It belongs
49
97
  to an FTS3Operation
@@ -120,7 +168,7 @@ class FTS3Job(JSerializable):
120
168
  # temporary used only for accounting
121
169
  # it is set by the monitor method
122
170
  # when a job is in a final state
123
- self.accountingDict = None
171
+ self.accountingDicts = None
124
172
 
125
173
  @classmethod
126
174
  @cachedmethod(lambda cls: cls._idp_cache)
@@ -157,7 +205,6 @@ class FTS3Job(JSerializable):
157
205
 
158
206
  if not self.ftsGUID:
159
207
  return S_ERROR("FTSGUID not set, FTS job not submitted?")
160
-
161
208
  if not context:
162
209
  if not ftsServer:
163
210
  ftsServer = self.ftsServer
@@ -184,13 +231,14 @@ class FTS3Job(JSerializable):
184
231
  self.error = jobStatusDict["reason"]
185
232
 
186
233
  if newStatus in self.FINAL_STATES:
187
- self._fillAccountingDict(jobStatusDict)
234
+ self._fillAccountingDicts(jobStatusDict)
188
235
 
189
236
  filesInfoList = jobStatusDict["files"]
190
237
  filesStatus = {}
191
238
  statusSummary = {}
192
239
 
193
240
  # Make a copy, since we are potentially
241
+
194
242
  # deleting objects
195
243
  for fileDict in list(filesInfoList):
196
244
  file_state = fileDict["file_state"].capitalize()
@@ -245,7 +293,7 @@ class FTS3Job(JSerializable):
245
293
  # so we put this back into the monitoring data such that the accounting is done properly
246
294
  jobStatusDict["files"] = filesInfoList
247
295
  if newStatus in self.FINAL_STATES:
248
- self._fillAccountingDict(jobStatusDict)
296
+ self._fillAccountingDicts(jobStatusDict)
249
297
 
250
298
  total = len(filesInfoList)
251
299
  completed = sum(statusSummary.get(state, 0) for state in FTS3File.FTS_FINAL_STATES)
@@ -470,6 +518,9 @@ class FTS3Job(JSerializable):
470
518
 
471
519
  ftsFileID = getattr(ftsFile, "fileID")
472
520
 
521
+ # scitag 65 is 1 << 6 | 1 (default experiment, default activity)
522
+ scitag = get_scitag(vo=self.vo, activity=self.activity)
523
+
473
524
  # Under normal circumstances, we simply submit an fts transfer as such:
474
525
  # * srcProto://myFile -> destProto://myFile
475
526
  #
@@ -499,6 +550,7 @@ class FTS3Job(JSerializable):
499
550
  filesize=ftsFile.size,
500
551
  metadata=stageTrans_metadata,
501
552
  activity=self.activity,
553
+ scitag=scitag,
502
554
  )
503
555
  transfers.append(stageTrans)
504
556
 
@@ -572,6 +624,7 @@ class FTS3Job(JSerializable):
572
624
  activity=self.activity,
573
625
  source_token=srcToken,
574
626
  destination_token=dstToken,
627
+ scitag=scitag,
575
628
  )
576
629
 
577
630
  transfers.append(trans)
@@ -902,9 +955,9 @@ class FTS3Job(JSerializable):
902
955
  gLogger.exception("Error generating context", repr(e))
903
956
  return S_ERROR(repr(e))
904
957
 
905
- def _fillAccountingDict(self, jobStatusDict):
906
- """This methods generates the necessary information to create a DataOperation
907
- accounting record, and stores them as a instance attribute.
958
+ def _fillAccountingDicts(self, jobStatusDict):
959
+ """This methods generates the necessary information to create DataOperation
960
+ accounting records, and stores them as a instance attribute.
908
961
 
909
962
  For it to be relevant, it should be called only when the job is in a final state.
910
963
 
@@ -913,6 +966,7 @@ class FTS3Job(JSerializable):
913
966
  :returns: None
914
967
  """
915
968
 
969
+ accountingDicts = []
916
970
  accountingDict = dict()
917
971
  sourceSE = None
918
972
  targetSE = None
@@ -923,16 +977,24 @@ class FTS3Job(JSerializable):
923
977
  accountingDict["Protocol"] = "FTS3"
924
978
  accountingDict["ExecutionSite"] = self.ftsServer
925
979
 
980
+ # Registration values must be set anyway
981
+ accountingDict["RegistrationTime"] = 0.0
982
+ accountingDict["RegistrationOK"] = 0
983
+ accountingDict["RegistrationTotal"] = 0
984
+
926
985
  # We cannot rely on all the transient attributes (like self.filesToSubmit)
927
986
  # because it is probably not filed by the time we monitor !
928
987
 
929
988
  filesInfoList = jobStatusDict["files"]
930
989
  successfulFiles = []
990
+ failedFiles = []
931
991
 
932
992
  for fileDict in filesInfoList:
933
993
  file_state = fileDict["file_state"].capitalize()
934
994
  if file_state in FTS3File.FTS_SUCCESS_STATES:
935
995
  successfulFiles.append(fileDict)
996
+ else:
997
+ failedFiles.append(fileDict)
936
998
 
937
999
  job_metadata = jobStatusDict["job_metadata"]
938
1000
  # previous version of the code did not have dictionary as
@@ -941,23 +1003,31 @@ class FTS3Job(JSerializable):
941
1003
  sourceSE = job_metadata.get("sourceSE")
942
1004
  targetSE = job_metadata.get("targetSE")
943
1005
 
944
- accountingDict["TransferOK"] = len(successfulFiles)
945
- accountingDict["TransferTotal"] = len(filesInfoList)
946
- # We need this if in the list comprehension because staging only jobs have `None` as filesize
947
- accountingDict["TransferSize"] = sum(
948
- fileDict["filesize"] for fileDict in successfulFiles if fileDict["filesize"]
949
- )
950
- accountingDict["FinalStatus"] = self.status
951
1006
  accountingDict["Source"] = sourceSE
952
1007
  accountingDict["Destination"] = targetSE
953
- # We need this if in the list comprehension because staging only jobs have `None` as tx_duration
954
- accountingDict["TransferTime"] = sum(
955
- int(fileDict["tx_duration"]) for fileDict in successfulFiles if fileDict["tx_duration"]
956
- )
957
1008
 
958
- # Registration values must be set anyway
959
- accountingDict["RegistrationTime"] = 0.0
960
- accountingDict["RegistrationOK"] = 0
961
- accountingDict["RegistrationTotal"] = 0
1009
+ if successfulFiles:
1010
+ successfulDict = accountingDict.copy()
1011
+ successfulDict["TransferOK"] = len(successfulFiles)
1012
+ successfulDict["TransferTotal"] = len(successfulFiles)
1013
+ # We need this if in the list comprehension because staging only jobs have `None` as filesize
1014
+ successfulDict["TransferSize"] = sum(
1015
+ fileDict["filesize"] for fileDict in successfulFiles if fileDict["filesize"]
1016
+ )
1017
+ successfulDict["FinalStatus"] = "Finished"
962
1018
 
963
- self.accountingDict = accountingDict
1019
+ # We need this if in the list comprehension because staging only jobs have `None` as tx_duration
1020
+ successfulDict["TransferTime"] = sum(
1021
+ int(fileDict["tx_duration"]) for fileDict in successfulFiles if fileDict["tx_duration"]
1022
+ )
1023
+ accountingDicts.append(successfulDict)
1024
+ if failedFiles:
1025
+ failedDict = accountingDict.copy()
1026
+ failedDict["TransferOK"] = 0
1027
+ failedDict["TransferTotal"] = len(failedFiles)
1028
+ failedDict["TransferSize"] = 0
1029
+ failedDict["FinalStatus"] = "Failed"
1030
+ failedDict["TransferTime"] = 0
1031
+ accountingDicts.append(failedDict)
1032
+
1033
+ self.accountingDicts = accountingDicts
@@ -204,6 +204,7 @@ def generateFTS3Job(sourceSE, targetSE, lfns, multiHopSE=None):
204
204
  newJob.sourceSE = sourceSE
205
205
  newJob.targetSE = targetSE
206
206
  newJob.multiHopSE = multiHopSE
207
+ newJob.vo = "lhcb"
207
208
  filesToSubmit = []
208
209
 
209
210
  for i, lfn in enumerate(lfns, start=1):
@@ -0,0 +1,69 @@
1
+ from unittest.mock import Mock, patch
2
+
3
+ import pytest
4
+
5
+ from DIRAC.DataManagementSystem.Client.FTS3Job import get_scitag
6
+
7
+
8
+ class TestGetScitag:
9
+ def test_valid_vo_and_activity(self):
10
+ """Test get_scitag with valid VO and activity."""
11
+ result = get_scitag("atlas", "Analysis Input")
12
+ expected = 2 << 6 | 17 # atlas expId=2, analysis activityId=17
13
+ assert result == expected
14
+
15
+ def test_valid_vo_no_activity(self):
16
+ """Test get_scitag with valid VO but no specific activity (should use default)."""
17
+ result = get_scitag("cms")
18
+ expected = 3 << 6 | 1 # cms expId=200, default activityId=1
19
+ assert result == expected
20
+
21
+ def test_invalid_vo(self):
22
+ """Test get_scitag with invalid VO (should use default vo_id=1)."""
23
+ result = get_scitag("nonexistent")
24
+ expected = 1 << 6 | 1 # default vo_id=1, default activity_id=1
25
+ assert result == expected
26
+
27
+ def test_valid_vo_invalid_activity(self):
28
+ """Test get_scitag with valid VO but invalid activity."""
29
+ result = get_scitag("atlas", "nonexistent_activity")
30
+ expected = 2 << 6 | 1 # atlas expId=2, default activity_id=1
31
+ assert result == expected
32
+
33
+ def test_case_insensitive_vo(self):
34
+ """Test that VO matching is case insensitive."""
35
+ result = get_scitag("ATLAS", "Data Brokering")
36
+ expected = 2 << 6 | 3 # atlas expId=2, production activityId=3
37
+ assert result == expected
38
+
39
+
40
+ @pytest.mark.parametrize(
41
+ "vo,activity,expected_vo_id,expected_activity_id",
42
+ [
43
+ ("atlas", "Analysis Output", 2, 18),
44
+ ("atlas", "Debug", 2, 9),
45
+ ("cms", "Cache", 3, 3),
46
+ ("cms", "default", 3, 1),
47
+ ("nonexistent", "any", 1, 1), # defaults
48
+ ("atlas", "nonexistent", 2, 1), # valid vo, invalid activity
49
+ ],
50
+ )
51
+ def test_parametrized_scenarios(vo, activity, expected_vo_id, expected_activity_id):
52
+ """Parametrized test for various VO and activity combinations."""
53
+ result = get_scitag(vo, activity)
54
+ expected = expected_vo_id << 6 | expected_activity_id
55
+ assert result == expected
56
+
57
+
58
+ @pytest.mark.parametrize(
59
+ "vo,expected_result",
60
+ [
61
+ ("atlas", 2 << 6 | 1), # Should use default activity
62
+ ("cms", 3 << 6 | 1), # Should use default activity
63
+ ("unknown", 1 << 6 | 1), # Should use all defaults
64
+ ],
65
+ )
66
+ def test_no_activity_parameter(vo, expected_result):
67
+ """Test behavior when no activity parameter is provided."""
68
+ result = get_scitag(vo)
69
+ assert result == expected_result
@@ -11,7 +11,7 @@
11
11
  import textwrap
12
12
  from threading import Lock
13
13
 
14
- from cachetools import TTLCache, cached
14
+ from cachetools import TTLCache, cachedmethod
15
15
 
16
16
  from DIRAC import S_ERROR, S_OK, gLogger
17
17
  from DIRAC.ConfigurationSystem.Client.Helpers import Registry
@@ -25,6 +25,10 @@ from DIRAC.Resources.ProxyProvider.ProxyProviderFactory import ProxyProviderFact
25
25
 
26
26
  DEFAULT_MAIL_FROM = "proxymanager@diracgrid.org"
27
27
 
28
+ # Module-level cache for getProxyStrength method (shared across ProxyDB instances)
29
+ _get_proxy_strength_cache = TTLCache(maxsize=1000, ttl=600)
30
+ _get_proxy_strength_lock = Lock()
31
+
28
32
 
29
33
  class ProxyDB(DB):
30
34
  NOTIFICATION_TIMES = [2592000, 1296000]
@@ -398,7 +402,7 @@ class ProxyDB(DB):
398
402
  return S_ERROR(", ".join(errMsgs))
399
403
  return result
400
404
 
401
- @cached(TTLCache(maxsize=1000, ttl=600), lock=Lock())
405
+ @cachedmethod(lambda self: _get_proxy_strength_cache, lock=lambda self: _get_proxy_strength_lock)
402
406
  def getProxyStrength(self, userDN, userGroup=None, vomsAttr=None):
403
407
  """Load the proxy in cache corresponding to the criteria, and check its strength
404
408
 
@@ -121,7 +121,9 @@ class FreeDiskSpaceCommand(Command):
121
121
  "Site": siteRes["Value"] if siteRes["Value"] else "unassigned",
122
122
  }
123
123
 
124
- results["Used"] = results["Total"] - results["Free"]
124
+ # There are sometimes small discrepencies which can lead to negative
125
+ # used values.
126
+ results["Used"] = max(0, results["Total"] - results["Free"])
125
127
 
126
128
  for sType in ["Total", "Free", "Used"]:
127
129
  spaceTokenAccounting = StorageOccupancy()
@@ -1,4 +1,4 @@
1
- """ AREX Computing Element (ARC REST interface)
1
+ """AREX Computing Element (ARC REST interface)
2
2
 
3
3
  Allows interacting with ARC AREX services via a REST interface.
4
4
 
@@ -807,7 +807,23 @@ class AREXComputingElement(ComputingElement):
807
807
  return S_ERROR(f"Failed decoding the status of the CE")
808
808
 
809
809
  # Look only in the relevant section out of the headache
810
- queueInfo = ceData["Domains"]["AdminDomain"]["Services"]["ComputingService"]["ComputingShare"]
810
+ # This "safe_get" function allows to go down the dictionary
811
+ # even if some elements are lists instead of dictionaries
812
+ # and returns None if any element is not found
813
+ # FIXME: this is a temporary measure to be removed after https://github.com/DIRACGrid/DIRAC/issues/8354
814
+ def safe_get(d, *keys):
815
+ for k in keys:
816
+ if isinstance(d, list):
817
+ d = d[0] # assume first element
818
+ d = d.get(k) if isinstance(d, dict) else None
819
+ if d is None:
820
+ break
821
+ return d
822
+
823
+ queueInfo = safe_get(ceData, "Domains", "AdminDomain", "Services", "ComputingService", "ComputingShare")
824
+ if queueInfo is None:
825
+ self.log.error("Failed to extract queue info")
826
+
811
827
  if not isinstance(queueInfo, list):
812
828
  queueInfo = [queueInfo]
813
829
 
@@ -9,7 +9,7 @@ Utilities for Transformation system
9
9
  import ast
10
10
  import random
11
11
 
12
- from cachetools import LRUCache, cached
12
+ from cachetools import LRUCache, cachedmethod
13
13
  from cachetools.keys import hashkey
14
14
  from DIRAC import S_OK, S_ERROR, gLogger
15
15
 
@@ -24,6 +24,9 @@ from DIRAC.Resources.Catalog.FileCatalog import FileCatalog
24
24
  from DIRAC.Resources.Storage.StorageElement import StorageElement
25
25
  from DIRAC.TransformationSystem.Client.TransformationClient import TransformationClient
26
26
 
27
+ # Module-level cache for isSameSEInList method (shared across PluginUtilities instances)
28
+ _is_same_se_in_list_cache = LRUCache(maxsize=1024)
29
+
27
30
 
28
31
  class PluginUtilities:
29
32
  """
@@ -402,8 +405,8 @@ class PluginUtilities:
402
405
 
403
406
  return StorageElement(se1).isSameSE(StorageElement(se2))
404
407
 
405
- @cached(
406
- LRUCache(maxsize=1024),
408
+ @cachedmethod(
409
+ lambda self: _is_same_se_in_list_cache,
407
410
  key=lambda _, a, b: hashkey(a, *sorted(b)),
408
411
  )
409
412
  def isSameSEInList(self, se1, seList):
@@ -1,4 +1,4 @@
1
- """ The Site Director is an agent performing pilot job submission to particular sites/Computing Elements.
1
+ """The Site Director is an agent performing pilot job submission to particular sites/Computing Elements.
2
2
 
3
3
  .. literalinclude:: ../ConfigTemplate.cfg
4
4
  :start-after: ##BEGIN SiteDirector
@@ -7,6 +7,7 @@
7
7
  :caption: SiteDirector options
8
8
 
9
9
  """
10
+
10
11
  import datetime
11
12
  import os
12
13
  from collections import defaultdict
@@ -147,10 +148,10 @@ class SiteDirector(AgentModule):
147
148
  self.sendSubmissionAccounting = True
148
149
 
149
150
  # Get the site description dictionary
150
- siteNames = self.am_getOption("Site", [])
151
- ceTypes = self.am_getOption("CETypes", [])
152
- ces = self.am_getOption("CEs", [])
153
- tags = self.am_getOption("Tags", [])
151
+ siteNames = self.am_getOption("Site", []) or None
152
+ ceTypes = self.am_getOption("CETypes", []) or None
153
+ ces = self.am_getOption("CEs", []) or None
154
+ tags = self.am_getOption("Tags", []) or None
154
155
 
155
156
  # Display options used
156
157
  self.log.always("VO:", self.vo)
@@ -1,6 +1,7 @@
1
- """ The Download Input Data module wraps around the Replica Management
2
- components to provide access to datasets by downloading locally
1
+ """The Download Input Data module wraps around the Replica Management
2
+ components to provide access to datasets by downloading locally
3
3
  """
4
+
4
5
  import os
5
6
  import random
6
7
  import tempfile
@@ -226,7 +227,7 @@ class DownloadInputData:
226
227
  diskSpace = getDiskSpace(self.__getDownloadDir(False)) # MB
227
228
  availableBytes = diskSpace * 1024 * 1024 # bytes
228
229
  bufferGBs = gConfig.getValue(
229
- os.path.join("/Systems/WorkloadManagement/JobWrapper", "JobWrapper", "MinOutputDataBufferGB"), 5.0
230
+ os.path.join("/Systems/WorkloadManagement/JobWrapper", "MinOutputDataBufferGB"), 5.0
230
231
  )
231
232
  data = bufferGBs * 1024 * 1024 * 1024 # bufferGBs in bytes
232
233
  if (data + totalSize) < availableBytes:
@@ -263,11 +263,11 @@ Agents
263
263
  # the DN of the certificate proxy used to submit pilots. If not found here, what is in Operations/Pilot section of the CS will be used
264
264
  PilotDN =
265
265
 
266
- # List of sites that will be treated by this SiteDirector (No value can refer to any Site defined in the CS)
266
+ # List of Sites that will be treated by this SiteDirector (No value can refer to any CE defined in the CS)
267
267
  Site =
268
- # List of CEs that will be treated by this SiteDirector (No value can refer to any CE defined in the CS)
268
+ # List of CEs that will be treated by this SiteDirector (No value can refer to any type of CE defined in the CS)
269
269
  CEs =
270
- # List of CE types that will be treated by this SiteDirector (No value can refer to any type of CE defined in the CS)
270
+ # List of CETypes that are required to be present in the CE/Queue definition
271
271
  CETypes =
272
272
  # List of Tags that are required to be present in the CE/Queue definition
273
273
  Tags =
@@ -150,37 +150,24 @@ class WMSAdministratorHandlerMixin:
150
150
  :param str jobID: job ID
151
151
  :return: S_OK(dict)/S_ERROR()
152
152
  """
153
- pilotReference = ""
154
- # Get the pilot grid reference first from the job parameters
155
-
156
- credDict = self.getRemoteCredentials()
157
- vo = credDict.get("VO", Registry.getVOForGroup(credDict["group"]))
158
- res = self.elasticJobParametersDB.getJobParameters(int(jobID), vo=vo, paramList=["Pilot_Reference"])
159
- if not res["OK"]:
160
- return res
161
- if res["Value"].get(int(jobID)):
162
- pilotReference = res["Value"][int(jobID)]["Pilot_Reference"]
163
-
164
- if not pilotReference:
165
- res = self.jobDB.getJobParameter(int(jobID), "Pilot_Reference")
166
- if not res["OK"]:
167
- return res
168
- pilotReference = res["Value"]
169
-
170
- if not pilotReference:
171
- # Failed to get the pilot reference, try to look in the attic parameters
172
- res = self.jobDB.getAtticJobParameters(int(jobID), ["Pilot_Reference"])
173
- if res["OK"]:
174
- c = -1
175
- # Get the pilot reference for the last rescheduling cycle
176
- for cycle in res["Value"]:
177
- if cycle > c:
178
- pilotReference = res["Value"][cycle]["Pilot_Reference"]
179
- c = cycle
180
-
181
- if pilotReference:
182
- return self.pilotManager.getPilotOutput(pilotReference)
183
- return S_ERROR("No pilot job reference found")
153
+ result = self.pilotManager.getPilots(jobID)
154
+
155
+ if not result["OK"]:
156
+ return result
157
+ pilotJobReferences = result["Value"].keys()
158
+
159
+ outputs = {"StdOut": "", "StdErr": ""}
160
+ for pilotRef in pilotJobReferences:
161
+ result = self.pilotManager.getPilotOutput(pilotRef)
162
+ if not result["OK"]:
163
+ stdout = f"Could not retrieve output: {result['Message']}"
164
+ error = f"Could not retrieve error: {result['Message']}"
165
+ else:
166
+ stdout, error = result["Value"]["StdOut"], result["Value"]["StdErr"]
167
+ outputs["StdOut"] += f"# PilotJobReference: {pilotRef}\n\n{stdout}\n"
168
+ outputs["StdErr"] += f"# PilotJobReference: {pilotRef}\n\n{error}\n"
169
+
170
+ return S_OK(outputs)
184
171
 
185
172
 
186
173
  class WMSAdministratorHandler(WMSAdministratorHandlerMixin, RequestHandler):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: DIRAC
3
- Version: 9.0.6
3
+ Version: 9.0.8
4
4
  Summary: DIRAC is an interware, meaning a software framework for distributed computing.
5
5
  Home-page: https://github.com/DIRACGrid/DIRAC/
6
6
  License: GPL-3.0-only
@@ -19,7 +19,7 @@ Requires-Dist: cachetools
19
19
  Requires-Dist: certifi
20
20
  Requires-Dist: cwltool
21
21
  Requires-Dist: diraccfg
22
- Requires-Dist: DIRACCommon==v9.0.6
22
+ Requires-Dist: DIRACCommon==v9.0.8
23
23
  Requires-Dist: diracx-client>=v0.0.1
24
24
  Requires-Dist: diracx-core>=v0.0.1
25
25
  Requires-Dist: diracx-cli>=v0.0.1
@@ -138,7 +138,7 @@ DIRAC/Core/DISET/private/ServiceConfiguration.py,sha256=jnJB5AF04m3KhbJ8LQUvT265
138
138
  DIRAC/Core/DISET/private/TransportPool.py,sha256=2zSdCa1Nz9GqZOvzFIbFfSaGkvhG4-7VmoVa98ax8Kg,4745
139
139
  DIRAC/Core/DISET/private/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
140
140
  DIRAC/Core/DISET/private/Transports/BaseTransport.py,sha256=mUsaa7OzbhCADCGDhmjGb0XKaovUCj0aYl9-VoL3yoo,13728
141
- DIRAC/Core/DISET/private/Transports/M2SSLTransport.py,sha256=pMNQJvi1-i4le_9S8G5VWxDMC0_1cV1_Q1zxqWDbv8k,23642
141
+ DIRAC/Core/DISET/private/Transports/M2SSLTransport.py,sha256=mWbkHzTA7K9Hzv_Sr1FGJZXR3kWQXlbbhEZlU4DYwYs,23830
142
142
  DIRAC/Core/DISET/private/Transports/PlainTransport.py,sha256=uQaZD5wN20KMNetQS58jOiqXI3HTTURxVEB1cSft6YU,4647
143
143
  DIRAC/Core/DISET/private/Transports/SSLTransport.py,sha256=xWyyb4VVREHkgUcgM1MokicaJdlH2JQE8PDWXSrqnFg,4111
144
144
  DIRAC/Core/DISET/private/Transports/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -339,7 +339,7 @@ DIRAC/Core/scripts/install_full.cfg,sha256=ady1OUXuqO0LoFiQOX3-tij9DbqQvL_arMW5o
339
339
  DIRAC/Core/test/Test_API.py,sha256=KiX4NEqM4CXOQ_KI8zebW3pIU89E3ettTy6DYjxfQac,236
340
340
  DIRAC/DataManagementSystem/ConfigTemplate.cfg,sha256=tn7uj9u9KB9vy83XcpQCsKA82fkhYWGSYrIVWUUxGCc,3327
341
341
  DIRAC/DataManagementSystem/__init__.py,sha256=AvnxrdyArZPvCB8YNPmp8mS9wZ8hs1rM-npLLJKi2ds,46
342
- DIRAC/DataManagementSystem/Agent/FTS3Agent.py,sha256=Qhb4QY71WBkA6P5XQchOtFcw5ZwkS7tbtg2dc87Cmxk,27034
342
+ DIRAC/DataManagementSystem/Agent/FTS3Agent.py,sha256=4rU9w5Sd-kM402CiL9Mf-roPqdL5_l6DyefQC-xxU6M,27109
343
343
  DIRAC/DataManagementSystem/Agent/__init__.py,sha256=z_25ILvodsjDJSEFpmGzmnYGmY4BcwfVOF_R69oibW8,52
344
344
  DIRAC/DataManagementSystem/Agent/RequestOperations/ArchiveFiles.py,sha256=NPBove4c2Tn-bqE5Ya5iSCjjCyZLhhNzjQCHpA489aI,9479
345
345
  DIRAC/DataManagementSystem/Agent/RequestOperations/CheckMigration.py,sha256=zVFC6QqWFj8m4zCoghdO8AcrAxyNtlH3BT2UiHZIjmY,2593
@@ -365,7 +365,7 @@ DIRAC/DataManagementSystem/Client/DataManager.py,sha256=edLmRUHJtZEYAMyen3y9qwdG
365
365
  DIRAC/DataManagementSystem/Client/DirectoryListing.py,sha256=CvQZ5Da5WhgwdDL8iLk0xVBjKZrBHTdwMKWwSJwzwEI,7582
366
366
  DIRAC/DataManagementSystem/Client/FTS3Client.py,sha256=Kk1wy4YnkYuOI6IltyDYZqkzxV7Zsf7ZuoKT12_VbTw,3531
367
367
  DIRAC/DataManagementSystem/Client/FTS3File.py,sha256=gZFN_Uxc2tblUCETb4qWPJ2M1tSmKUvTMiZUL-yJ6M0,3122
368
- DIRAC/DataManagementSystem/Client/FTS3Job.py,sha256=uiiTDowNrv91OeFHWPCrygZR--JqIdBOgZOv0AS5tEg,39393
368
+ DIRAC/DataManagementSystem/Client/FTS3Job.py,sha256=5MAtSZoWb_rwglNHdYJAuoXzoW5_TAX96E5jUWEYds8,42090
369
369
  DIRAC/DataManagementSystem/Client/FTS3Operation.py,sha256=L3yqc0X0ziluMPegoQU6o3aYDnTYwLtujShgbGFJjsw,24455
370
370
  DIRAC/DataManagementSystem/Client/FailoverTransfer.py,sha256=2V-dKtgAndMuw9iZHYV019V0hLwlezUNP33wvClpsaA,13373
371
371
  DIRAC/DataManagementSystem/Client/FileCatalogClientCLI.py,sha256=sc_6mT0BCbXgj5wOEFtCxNc0AvyQ186A_yLi2lnduvw,80094
@@ -376,7 +376,8 @@ DIRAC/DataManagementSystem/Client/CmdDirCompletion/AbstractFileSystem.py,sha256=
376
376
  DIRAC/DataManagementSystem/Client/CmdDirCompletion/DirectoryCompletion.py,sha256=TdOCEfVQ3QppTl0iHrf472rT3YkDw2EX2sUviKIYL2s,2394
377
377
  DIRAC/DataManagementSystem/Client/CmdDirCompletion/__init__.py,sha256=IU_DNOfkPtg8iBqQatUKTNBMj2LldGrhf6KseBgx14M,236
378
378
  DIRAC/DataManagementSystem/Client/test/Test_Client_DataManagementSystem.py,sha256=qb0mERTlHOysiSfNPDsbLbadWgbuQLulT9Py8RqTIYc,3956
379
- DIRAC/DataManagementSystem/Client/test/Test_FTS3Objects.py,sha256=PwdHIHEJpP4I7plHRhrIBHrftIW0aRHCasYx7AUQfd4,15432
379
+ DIRAC/DataManagementSystem/Client/test/Test_FTS3Objects.py,sha256=DZHRZPfiTJrqinXolneRE06Wf51sVtRw0Fx0bq85AAA,15455
380
+ DIRAC/DataManagementSystem/Client/test/Test_scitag.py,sha256=llvY98ODaBZhyhDquP9IMzCB-uXJz8xL-TO2-sbNf68,2545
380
381
  DIRAC/DataManagementSystem/Client/test/__init__.py,sha256=IL2xDyzb5nr2dkH2hpT4Zx6vvc9m4jDryuUmfyIY_RY,58
381
382
  DIRAC/DataManagementSystem/Client/test/mock_DM.py,sha256=S7qWHjN3ZyjqKIjHkXwuUWJqp75waEchc1IsNB9y-28,1167
382
383
  DIRAC/DataManagementSystem/Client/test/new_dir_completion.py,sha256=_Km7jE4IRe-pY8BJ62hK6IbwRROoj0wxvL7WMClEJ0E,1212
@@ -509,7 +510,7 @@ DIRAC/FrameworkSystem/DB/AuthDB.py,sha256=QLotpINMq45FNoFO2AV3OH5Ij5i__HHk-p-m-b
509
510
  DIRAC/FrameworkSystem/DB/AuthDB.sql,sha256=tcAnRmBBEDxljAXILp8tlLzuEb7vOoN190KQK7NSbQQ,95
510
511
  DIRAC/FrameworkSystem/DB/InstalledComponentsDB.py,sha256=rVarVs61K1kPHZIf1U_kfia-5pxR5uSXsuDutr8EcFY,43156
511
512
  DIRAC/FrameworkSystem/DB/InstalledComponentsDB.sql,sha256=-LFjjn1gRQo7zDOclKmFwmbZi_lXXnx_B17cZPLBUak,113
512
- DIRAC/FrameworkSystem/DB/ProxyDB.py,sha256=5gnttlg9pJpyq9nYZDqEe_TihO6Ug3BImaHGcz0kjnQ,39706
513
+ DIRAC/FrameworkSystem/DB/ProxyDB.py,sha256=wt72y-ZtHyes1oLGgB-LiLuyZRNBelmCaEijad3raxI,39934
513
514
  DIRAC/FrameworkSystem/DB/ProxyDB.sql,sha256=QwWe_mRX_NbZQVBo3TzA60L3FemI-oLY8G7_4uRFPzU,96
514
515
  DIRAC/FrameworkSystem/DB/TokenDB.py,sha256=FjHsPuTYt2KaXs0fST_tOAZyXY1R6417BB-lblxduZ4,8652
515
516
  DIRAC/FrameworkSystem/DB/TokenDB.sql,sha256=D-D78eFUkCRb4YLNZqdCfmyaEIJFupgMhIwgSs91yE4,96
@@ -796,7 +797,7 @@ DIRAC/ResourceStatusSystem/Client/__init__.py,sha256=HyBt2_a0tkIu9-SxlTVN2YPwr39
796
797
  DIRAC/ResourceStatusSystem/Command/Command.py,sha256=joJgiBTyItOencX35hT33LQVjOA0ORNzhTws_IF6Kpo,2404
797
798
  DIRAC/ResourceStatusSystem/Command/CommandCaller.py,sha256=jwDk2VjcikBpVd3FNnXrhRQH8B0chc8F0h6Q-zMvCEw,1275
798
799
  DIRAC/ResourceStatusSystem/Command/DowntimeCommand.py,sha256=HWkyp8hrgSzw16TJnqXSgpylE2HFypAxGkm7Bt2KT6o,15782
799
- DIRAC/ResourceStatusSystem/Command/FreeDiskSpaceCommand.py,sha256=h3DBIeITeIq85f0PHgPUWrnIU1e0UQr0Sk6GDlRYXOk,8541
800
+ DIRAC/ResourceStatusSystem/Command/FreeDiskSpaceCommand.py,sha256=84pPYecmFTYl-7v4hYgqB-kJ89VTm2_-nMgWG3uvbgw,8649
800
801
  DIRAC/ResourceStatusSystem/Command/GGUSTicketsCommand.py,sha256=bCFE7MgnyFXC0JZAvc1tLWSPRVokojEYjY2vb4ha8mE,5216
801
802
  DIRAC/ResourceStatusSystem/Command/GOCDBSyncCommand.py,sha256=GxHnSWIWQFpZEzxqfw9hGW1SelyoJMiJW3rwy5Zrwwc,4575
802
803
  DIRAC/ResourceStatusSystem/Command/JobCommand.py,sha256=CRKdGLwpCiQAS8ACXEwxQ0T7ata0-n3fJCRsJjIfLY4,6371
@@ -899,7 +900,7 @@ DIRAC/Resources/Catalog/test/Test_FileCatalog.py,sha256=6v-T1YDFcGHYLuYr_48Lz3z9
899
900
  DIRAC/Resources/Catalog/test/Test_RucioFileCatalogClient.py,sha256=12F5Laf3-FdnS3HTcmKg-nU7p2XEFi0t_scTzF5hMOk,8525
900
901
  DIRAC/Resources/Catalog/test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
901
902
  DIRAC/Resources/Catalog/test/mock_FC.py,sha256=a3RhfF3FU8RrEkSNvSRwSyHJ67DZ08YkW5347VhVLHc,4658
902
- DIRAC/Resources/Computing/AREXComputingElement.py,sha256=0QmYepoOfcYT6MBdHeG6dY_0sJLB-2JVIJHWdEd0bpk,43258
903
+ DIRAC/Resources/Computing/AREXComputingElement.py,sha256=wJDbFqM8wneCuAeqlxF_72BpjCqkLl_qy9E1GH5akMU,43950
903
904
  DIRAC/Resources/Computing/CloudComputingElement.py,sha256=N8wfRL6ppozkKFzbCuWuVvudNfAqTox1zNeDZY6lED0,21102
904
905
  DIRAC/Resources/Computing/ComputingElement.py,sha256=lAvlx7AOtkftku6sekIaEK4Wp_GlaDHnYeNfxW54zu4,19424
905
906
  DIRAC/Resources/Computing/ComputingElementFactory.py,sha256=gaYP8TvvP7OJsL2o6IMTIYYoBn6flt3Ue7f1NX4HmNY,2541
@@ -1071,7 +1072,7 @@ DIRAC/TransformationSystem/Client/TransformationCLI.py,sha256=EFAbksFDLjX92KcT6V
1071
1072
  DIRAC/TransformationSystem/Client/TransformationClient.py,sha256=6NtwGALJIe7XCrk1XC1HtGCN0IcqeEAL6fiMv1S2rt8,26405
1072
1073
  DIRAC/TransformationSystem/Client/TransformationFilesStatus.py,sha256=3O89wYkPdvYPXnwxyM9x7QLcN6uODEV5yH76LFpmQ80,822
1073
1074
  DIRAC/TransformationSystem/Client/TransformationStatus.py,sha256=f7lzca1m6AfGG09OkA9_bQUthUyojeurS_p02r2oXyQ,1411
1074
- DIRAC/TransformationSystem/Client/Utilities.py,sha256=OHBdF0JpxTUWfx6Y4m-qnSv0lARIRoCizt_B3pjpGfg,20200
1075
+ DIRAC/TransformationSystem/Client/Utilities.py,sha256=OO2XBMYbFCpEs961k676WXDtn-tPUm7lQSxilUQhdiA,20369
1075
1076
  DIRAC/TransformationSystem/Client/WorkflowTasks.py,sha256=fMBIXMYZ8xTEBxgIZ8ouHubHDMb-eb8YRo9zLX7pl1M,28433
1076
1077
  DIRAC/TransformationSystem/Client/__init__.py,sha256=feIGEsKJKa_lcuM7I4BVlzwEtxVzHrq-fLw4XdjcLRk,50
1077
1078
  DIRAC/TransformationSystem/Client/BodyPlugin/BaseBody.py,sha256=oFRyrN46dzw5XbRd1biwwMTtWYv1s6jygl0WYs7VE2s,1022
@@ -1118,7 +1119,7 @@ DIRAC/Workflow/Modules/test/Test_Modules.py,sha256=d92bA2SpF7Wwg9gy3roEvPt_7QlnB
1118
1119
  DIRAC/Workflow/Utilities/Utils.py,sha256=9f395ylWaLRaaC6EExPAyvOhPK3FXD7I_XGevqueRkM,2545
1119
1120
  DIRAC/Workflow/Utilities/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1120
1121
  DIRAC/Workflow/Utilities/test/Test_Utilities.py,sha256=DNjFPpBmpojwCWhZSUSoG3AIhMQvqyiZdSuVkrHkOtk,2595
1121
- DIRAC/WorkloadManagementSystem/ConfigTemplate.cfg,sha256=EpXTiHV-omMuMcWDzQzWZ_LmAZFMRTabfJpfZmVfzEA,9065
1122
+ DIRAC/WorkloadManagementSystem/ConfigTemplate.cfg,sha256=uHa3ZiSC7cyhbJUNvWwqiL0E-m9UmBinrLIQdWmre3k,9030
1122
1123
  DIRAC/WorkloadManagementSystem/__init__.py,sha256=9-_-HOT_8S3i-TMmTR_gFVVlNyktBRk-S2qSuOBKoIc,50
1123
1124
  DIRAC/WorkloadManagementSystem/Agent/JobAgent.py,sha256=LzLypd3m4a6M-J5_nmUMsMqgflb_1Xm77eONDE6G1Vg,40843
1124
1125
  DIRAC/WorkloadManagementSystem/Agent/JobCleaningAgent.py,sha256=TR8nDO43DuJxOQVIdOUrqpWjRjJp52dVzOKUUewL9U4,14708
@@ -1126,7 +1127,7 @@ DIRAC/WorkloadManagementSystem/Agent/PilotLoggingAgent.py,sha256=ZIgvFpasGTh76GW
1126
1127
  DIRAC/WorkloadManagementSystem/Agent/PilotStatusAgent.py,sha256=qY6TbYCPOFFXhHffmRJLNEbWvZPyg5Lc5B_8BbyQ7zc,9711
1127
1128
  DIRAC/WorkloadManagementSystem/Agent/PilotSyncAgent.py,sha256=qzDFCGZ8EtjxDUaPgyFDlSmJfyF2KLuyXTC7au3-p2Q,4860
1128
1129
  DIRAC/WorkloadManagementSystem/Agent/PushJobAgent.py,sha256=IvHshnw2xN0AZrruEu86C47GDez8enBD6jjNIZd6QcA,38594
1129
- DIRAC/WorkloadManagementSystem/Agent/SiteDirector.py,sha256=NkAyYGtht9NO53CX9OmbxBkeUFcfv7tc9CKogD8TtVU,45131
1130
+ DIRAC/WorkloadManagementSystem/Agent/SiteDirector.py,sha256=ZSGWVKO64ztnv_R19I6TT7660jf7LMuYcff_aPq2xCM,45162
1130
1131
  DIRAC/WorkloadManagementSystem/Agent/StalledJobAgent.py,sha256=foEbmRotEmfeQG6nyIsJv1kSJkm4flkQsPYbSylS3SM,24572
1131
1132
  DIRAC/WorkloadManagementSystem/Agent/StatesAccountingAgent.py,sha256=iNIlWQEDBk6R1S8oHOIusZUwxOwLtgwuzR_4s32-o5w,8707
1132
1133
  DIRAC/WorkloadManagementSystem/Agent/TaskQueuesAgent.py,sha256=ypsmo233TFXq9IC5uz6pum7_joOh2gFPUYNmmCpukAY,943
@@ -1139,7 +1140,7 @@ DIRAC/WorkloadManagementSystem/Agent/test/Test_Agent_PushJobAgent.py,sha256=Uf5j
1139
1140
  DIRAC/WorkloadManagementSystem/Agent/test/Test_Agent_SiteDirector.py,sha256=o6imUULkKrvbmkfpvER8wyg0Ncn3gxvJNTNO8xKX7_w,11670
1140
1141
  DIRAC/WorkloadManagementSystem/Agent/test/Test_Agent_StalledJobAgent.py,sha256=BgDP1um-5WLSJYDbyHgLUkZocN8TrrG6QvRcffzD02E,1829
1141
1142
  DIRAC/WorkloadManagementSystem/Client/CPUNormalization.py,sha256=txBgRfnTAY5KykpKRrK1jp5x4FInWjv-Rja4R7Dqdis,5423
1142
- DIRAC/WorkloadManagementSystem/Client/DownloadInputData.py,sha256=JfidM3U2b0z64hk6j0VpQ7fh6eSkRjm1Hw8X-DAspwI,16303
1143
+ DIRAC/WorkloadManagementSystem/Client/DownloadInputData.py,sha256=Ug2mhig5KbC1d4fYsVLpFhE5SvWhUJpVp7TuP8GxJxs,16285
1143
1144
  DIRAC/WorkloadManagementSystem/Client/InputDataByProtocol.py,sha256=tjK6L8iNqWOBENcGJbG0yJsQYwGvFLRFcTMNnrusFAI,12837
1144
1145
  DIRAC/WorkloadManagementSystem/Client/InputDataResolution.py,sha256=z8K8VKoUH4KtlTPe0mfyVsQKH6BQh80YIUhu61Fpgeg,6162
1145
1146
  DIRAC/WorkloadManagementSystem/Client/JobManagerClient.py,sha256=ySi2lxiwuEf8gx3exIbS_HekJRvpXR7q3h2MdwsRcYA,689
@@ -1234,7 +1235,7 @@ DIRAC/WorkloadManagementSystem/Service/TornadoJobStateUpdateHandler.py,sha256=r_
1234
1235
  DIRAC/WorkloadManagementSystem/Service/TornadoPilotLoggingHandler.py,sha256=PtSoXZLlwglOWkS9GcmBjad89TVrfT63gTWu5_zJN7A,4178
1235
1236
  DIRAC/WorkloadManagementSystem/Service/TornadoSandboxStoreHandler.py,sha256=o6ar3Dqz6QF9LO3P2UVOZKDHXXTd9d0KwdKR9qnRdqA,929
1236
1237
  DIRAC/WorkloadManagementSystem/Service/TornadoWMSAdministratorHandler.py,sha256=A9ygBHuDT9rHHvUyzJhL8EibQpFPpoVdBVsEgWFcFzM,484
1237
- DIRAC/WorkloadManagementSystem/Service/WMSAdministratorHandler.py,sha256=Y63hqyLSH3PUzuHZpkFl1Y9MtJ8dm2RI10tRhPit7Rs,6119
1238
+ DIRAC/WorkloadManagementSystem/Service/WMSAdministratorHandler.py,sha256=Hwi6RBQ6WKxjhXOwXid4aExaPd78AYqBtdwWf-Fbalo,5547
1238
1239
  DIRAC/WorkloadManagementSystem/Service/WMSUtilities.py,sha256=VMSOEHkpOrNB_VIGESnxMYdnDjkmR4Qbnf_H7Yp0m88,4528
1239
1240
  DIRAC/WorkloadManagementSystem/Service/__init__.py,sha256=IRaXIxMoS1SbRehm7ONo87SD1l44VBmowjbfkChvdsc,58
1240
1241
  DIRAC/WorkloadManagementSystem/Utilities/JobModel.py,sha256=jN9sFbzMZo9tab6Kp7OeBCMCrfx21gCqRbm1XjLxong,1781
@@ -1295,9 +1296,9 @@ DIRAC/tests/Workflow/Integration/exe-script.py,sha256=B_slYdTocEzqfQLRhwuPiLyYUn
1295
1296
  DIRAC/tests/Workflow/Integration/helloWorld.py,sha256=tBgEHH3ZF7ZiTS57gtmm3DW-Qxgm_57HWHpM-Y8XSws,205
1296
1297
  DIRAC/tests/Workflow/Regression/helloWorld.py,sha256=69eCgFuVSYo-mK3Dj2dw1c6g86sF5FksKCf8V2aGVoM,509
1297
1298
  DIRAC/tests/Workflow/Regression/helloWorld.xml,sha256=xwydIcFTAHIX-YPfQfyxuQ7hzvIO3IhR3UAF7ORgkGg,5310
1298
- dirac-9.0.6.dist-info/licenses/LICENSE,sha256=uyr4oV6jmjUeepXZPPjkJRwa5q5MrI7jqJz5sVXNblQ,32452
1299
- dirac-9.0.6.dist-info/METADATA,sha256=tbETxonTh5kgVSZJNZeZgQNue961cdGH4IXCZEgmWN8,10016
1300
- dirac-9.0.6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
1301
- dirac-9.0.6.dist-info/entry_points.txt,sha256=hupzIL8aVmjK3nn7RLKdhcaiPmLOiD3Kulh3CSDHKmw,16492
1302
- dirac-9.0.6.dist-info/top_level.txt,sha256=RISrnN9kb_mPqmVu8_o4jF-DSX8-h6AcgfkO9cgfkHA,6
1303
- dirac-9.0.6.dist-info/RECORD,,
1299
+ dirac-9.0.8.dist-info/licenses/LICENSE,sha256=uyr4oV6jmjUeepXZPPjkJRwa5q5MrI7jqJz5sVXNblQ,32452
1300
+ dirac-9.0.8.dist-info/METADATA,sha256=gpKRR8YAjDBxrxogcUUGPNXojPku4FhNUVqBVSPRNWg,10016
1301
+ dirac-9.0.8.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
1302
+ dirac-9.0.8.dist-info/entry_points.txt,sha256=hupzIL8aVmjK3nn7RLKdhcaiPmLOiD3Kulh3CSDHKmw,16492
1303
+ dirac-9.0.8.dist-info/top_level.txt,sha256=RISrnN9kb_mPqmVu8_o4jF-DSX8-h6AcgfkO9cgfkHA,6
1304
+ dirac-9.0.8.dist-info/RECORD,,
File without changes