DIRAC 9.0.0a69__py3-none-any.whl → 9.0.2__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/ConfigurationSystem/Client/Helpers/CSGlobals.py +0 -9
- DIRAC/ConfigurationSystem/Client/SyncPlugins/CERNLDAPSyncPlugin.py +4 -1
- DIRAC/ConfigurationSystem/private/RefresherBase.py +4 -2
- DIRAC/Core/DISET/ServiceReactor.py +11 -3
- DIRAC/Core/Security/DiracX.py +11 -6
- DIRAC/Core/Security/test/test_diracx_token_from_pem.py +161 -0
- DIRAC/Core/Tornado/Server/TornadoService.py +1 -1
- DIRAC/Core/Utilities/test/Test_Profiler.py +20 -20
- DIRAC/DataManagementSystem/DB/FileCatalogComponents/DatasetManager/DatasetManager.py +1 -1
- DIRAC/DataManagementSystem/scripts/dirac_dms_create_moving_request.py +2 -0
- DIRAC/Interfaces/API/Dirac.py +3 -6
- DIRAC/MonitoringSystem/DB/MonitoringDB.py +6 -5
- DIRAC/MonitoringSystem/Service/WebAppHandler.py +13 -3
- DIRAC/MonitoringSystem/private/MainReporter.py +0 -3
- DIRAC/RequestManagementSystem/Agent/RequestExecutingAgent.py +8 -6
- DIRAC/RequestManagementSystem/ConfigTemplate.cfg +6 -6
- DIRAC/Resources/IdProvider/CheckInIdProvider.py +13 -0
- DIRAC/TransformationSystem/Agent/TaskManagerAgentBase.py +0 -3
- DIRAC/TransformationSystem/scripts/dirac_production_runjoblocal.py +2 -4
- DIRAC/WorkloadManagementSystem/Agent/SiteDirector.py +2 -6
- DIRAC/WorkloadManagementSystem/Agent/test/Test_Agent_SiteDirector.py +8 -2
- DIRAC/WorkloadManagementSystem/DB/JobParametersDB.py +8 -8
- DIRAC/WorkloadManagementSystem/DB/SandboxMetadataDB.py +1 -1
- DIRAC/WorkloadManagementSystem/DB/StatusUtils.py +1 -1
- DIRAC/WorkloadManagementSystem/JobWrapper/JobWrapper.py +1 -1
- DIRAC/WorkloadManagementSystem/JobWrapper/test/Test_JobWrapper.py +15 -5
- {dirac-9.0.0a69.dist-info → dirac-9.0.2.dist-info}/METADATA +2 -3
- {dirac-9.0.0a69.dist-info → dirac-9.0.2.dist-info}/RECORD +32 -31
- {dirac-9.0.0a69.dist-info → dirac-9.0.2.dist-info}/WHEEL +0 -0
- {dirac-9.0.0a69.dist-info → dirac-9.0.2.dist-info}/entry_points.txt +0 -0
- {dirac-9.0.0a69.dist-info → dirac-9.0.2.dist-info}/licenses/LICENSE +0 -0
- {dirac-9.0.0a69.dist-info → dirac-9.0.2.dist-info}/top_level.txt +0 -0
|
@@ -4,15 +4,6 @@ Some Helper functions to retrieve common location from the CS
|
|
|
4
4
|
from DIRAC.Core.Utilities.Extensions import extensionsByPriority
|
|
5
5
|
|
|
6
6
|
|
|
7
|
-
def getSetup() -> str:
|
|
8
|
-
"""
|
|
9
|
-
Return setup name
|
|
10
|
-
"""
|
|
11
|
-
from DIRAC import gConfig
|
|
12
|
-
|
|
13
|
-
return gConfig.getValue("/DIRAC/Setup", "")
|
|
14
|
-
|
|
15
|
-
|
|
16
7
|
def getVO(defaultVO: str = "") -> str:
|
|
17
8
|
"""
|
|
18
9
|
Return VO from configuration
|
|
@@ -32,6 +32,9 @@ class CERNLDAPSyncPlugin:
|
|
|
32
32
|
else:
|
|
33
33
|
userDict["PrimaryCERNAccount"] = self._findOwnerAccountName(username, attributes)
|
|
34
34
|
|
|
35
|
+
if userDict["CERNAccountType"] in ["Primary", "Secondary"]:
|
|
36
|
+
userDict["CERNPersonId"] = attributes.get("employeeId", [None])[0]
|
|
37
|
+
|
|
35
38
|
def _findOwnerAccountName(self, username, attributes):
|
|
36
39
|
"""Find the owner account from a CERN LDAP entry.
|
|
37
40
|
|
|
@@ -64,7 +67,7 @@ class CERNLDAPSyncPlugin:
|
|
|
64
67
|
status, result, response, _ = self._connection.search(
|
|
65
68
|
"OU=Users,OU=Organic Units,DC=cern,DC=ch",
|
|
66
69
|
f"(CN={commonName})",
|
|
67
|
-
attributes=["cernAccountOwner", "cernAccountType"],
|
|
70
|
+
attributes=["cernAccountOwner", "cernAccountType", "employeeId"],
|
|
68
71
|
)
|
|
69
72
|
if not status:
|
|
70
73
|
raise ValueError(f"Bad status from LDAP search: {result}")
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import time
|
|
2
2
|
|
|
3
3
|
from DIRAC.ConfigurationSystem.Client.ConfigurationData import gConfigurationData
|
|
4
|
-
from DIRAC.ConfigurationSystem.Client.PathFinder import getGatewayURLs
|
|
4
|
+
from DIRAC.ConfigurationSystem.Client.PathFinder import getGatewayURLs, groupURLsByPriority
|
|
5
5
|
from DIRAC.Core.Utilities import List
|
|
6
6
|
from DIRAC.Core.Utilities.EventDispatcher import gEventDispatcher
|
|
7
7
|
from DIRAC.Core.Utilities.ReturnValues import S_ERROR, S_OK
|
|
@@ -138,7 +138,9 @@ class RefresherBase:
|
|
|
138
138
|
if not initialServerList:
|
|
139
139
|
return S_OK()
|
|
140
140
|
|
|
141
|
-
randomServerList =
|
|
141
|
+
randomServerList = []
|
|
142
|
+
for urlGroup in groupURLsByPriority(initialServerList):
|
|
143
|
+
randomServerList.extend(List.randomize(urlGroup))
|
|
142
144
|
gLogger.debug(f"Randomized server list is {', '.join(randomServerList)}")
|
|
143
145
|
|
|
144
146
|
for sServer in randomServerList:
|
|
@@ -200,6 +200,7 @@ class ServiceReactor:
|
|
|
200
200
|
services at the same time
|
|
201
201
|
"""
|
|
202
202
|
sel = self.__getListeningSelector(svcName)
|
|
203
|
+
throttleExpires = None
|
|
203
204
|
while self.__alive:
|
|
204
205
|
clientTransport = None
|
|
205
206
|
try:
|
|
@@ -223,12 +224,19 @@ class ServiceReactor:
|
|
|
223
224
|
gLogger.warn(f"Client connected from banned ip {clientIP}")
|
|
224
225
|
clientTransport.close()
|
|
225
226
|
continue
|
|
227
|
+
# Handle throttling
|
|
228
|
+
if self.__services[svcName].wantsThrottle and throttleExpires is None:
|
|
229
|
+
throttleExpires = time.time() + THROTTLE_SERVICE_SLEEP_SECONDS
|
|
230
|
+
if throttleExpires:
|
|
231
|
+
if time.time() > throttleExpires:
|
|
232
|
+
throttleExpires = None
|
|
233
|
+
else:
|
|
234
|
+
gLogger.warn("Rejecting client due to throttling", str(clientTransport.getRemoteAddress()))
|
|
235
|
+
clientTransport.close()
|
|
236
|
+
continue
|
|
226
237
|
# Handle connection
|
|
227
238
|
self.__stats.connectionStablished()
|
|
228
239
|
self.__services[svcName].handleConnection(clientTransport)
|
|
229
|
-
while self.__services[svcName].wantsThrottle:
|
|
230
|
-
gLogger.warn("Sleeping as service requested throttling", svcName)
|
|
231
|
-
time.sleep(THROTTLE_SERVICE_SLEEP_SECONDS)
|
|
232
240
|
# Renew context?
|
|
233
241
|
now = time.time()
|
|
234
242
|
renewed = False
|
DIRAC/Core/Security/DiracX.py
CHANGED
|
@@ -40,7 +40,7 @@ from DIRAC.Core.Utilities.ReturnValues import convertToReturnValue, returnValueO
|
|
|
40
40
|
|
|
41
41
|
PEM_BEGIN = "-----BEGIN DIRACX-----"
|
|
42
42
|
PEM_END = "-----END DIRACX-----"
|
|
43
|
-
RE_DIRACX_PEM = re.compile(rf"{PEM_BEGIN}\n(
|
|
43
|
+
RE_DIRACX_PEM = re.compile(rf"{PEM_BEGIN}\n(.*?)\n{PEM_END}", re.DOTALL)
|
|
44
44
|
|
|
45
45
|
|
|
46
46
|
@convertToReturnValue
|
|
@@ -62,21 +62,26 @@ def addTokenToPEM(pemPath, group):
|
|
|
62
62
|
token_type=token_content.get("token_type"),
|
|
63
63
|
refresh_token=token_content.get("refresh_token"),
|
|
64
64
|
)
|
|
65
|
-
|
|
66
65
|
token_pem = f"{PEM_BEGIN}\n"
|
|
67
66
|
data = base64.b64encode(serialize_credentials(token).encode("utf-8")).decode()
|
|
68
67
|
token_pem += textwrap.fill(data, width=64)
|
|
69
68
|
token_pem += f"\n{PEM_END}\n"
|
|
70
69
|
|
|
71
|
-
|
|
72
|
-
|
|
70
|
+
pem = Path(pemPath).read_text()
|
|
71
|
+
# Remove any existing DiracX token there would be
|
|
72
|
+
new_pem = re.sub(RE_DIRACX_PEM, "", pem)
|
|
73
|
+
new_pem += token_pem
|
|
74
|
+
|
|
75
|
+
Path(pemPath).write_text(new_pem)
|
|
73
76
|
|
|
74
77
|
|
|
75
78
|
def diracxTokenFromPEM(pemPath) -> dict[str, Any] | None:
|
|
76
79
|
"""Extract the DiracX token from the proxy PEM file"""
|
|
77
80
|
pem = Path(pemPath).read_text()
|
|
78
|
-
if match := RE_DIRACX_PEM.
|
|
79
|
-
match
|
|
81
|
+
if match := RE_DIRACX_PEM.findall(pem):
|
|
82
|
+
if len(match) > 1:
|
|
83
|
+
raise ValueError("Found multiple DiracX tokens, this should never happen")
|
|
84
|
+
match = match[0]
|
|
80
85
|
return json.loads(base64.b64decode(match).decode("utf-8"))
|
|
81
86
|
|
|
82
87
|
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import base64
|
|
2
|
+
import json
|
|
3
|
+
import pytest
|
|
4
|
+
import tempfile
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from unittest.mock import patch, mock_open
|
|
7
|
+
|
|
8
|
+
from DIRAC.Core.Security.DiracX import diracxTokenFromPEM, PEM_BEGIN, PEM_END, RE_DIRACX_PEM
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class TestDiracxTokenFromPEM:
|
|
12
|
+
"""Test cases for diracxTokenFromPEM function"""
|
|
13
|
+
|
|
14
|
+
def create_valid_token_data(self):
|
|
15
|
+
"""Create valid token data for testing"""
|
|
16
|
+
return {
|
|
17
|
+
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.test",
|
|
18
|
+
"refresh_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.refresh",
|
|
19
|
+
"expires_in": 3600,
|
|
20
|
+
"token_type": "Bearer",
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
def create_pem_content(self, token_data=None, include_other_content=True):
|
|
24
|
+
"""Create PEM content with embedded DiracX token"""
|
|
25
|
+
if token_data is None:
|
|
26
|
+
token_data = self.create_valid_token_data()
|
|
27
|
+
|
|
28
|
+
# Encode token data
|
|
29
|
+
token_json = json.dumps(token_data)
|
|
30
|
+
encoded_token = base64.b64encode(token_json.encode("utf-8")).decode()
|
|
31
|
+
|
|
32
|
+
# Create PEM content
|
|
33
|
+
pem_content = ""
|
|
34
|
+
if include_other_content:
|
|
35
|
+
pem_content += "-----BEGIN CERTIFICATE-----\n"
|
|
36
|
+
pem_content += "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...\n"
|
|
37
|
+
pem_content += "-----END CERTIFICATE-----\n"
|
|
38
|
+
|
|
39
|
+
pem_content += f"{PEM_BEGIN}\n"
|
|
40
|
+
pem_content += encoded_token + "\n"
|
|
41
|
+
pem_content += f"{PEM_END}\n"
|
|
42
|
+
|
|
43
|
+
return pem_content
|
|
44
|
+
|
|
45
|
+
def test_valid_token_extraction(self):
|
|
46
|
+
"""Test successful extraction of valid token from PEM file"""
|
|
47
|
+
token_data = self.create_valid_token_data()
|
|
48
|
+
pem_content = self.create_pem_content(token_data)
|
|
49
|
+
|
|
50
|
+
with tempfile.NamedTemporaryFile(mode="w", delete=False, suffix=".pem") as f:
|
|
51
|
+
f.write(pem_content)
|
|
52
|
+
temp_path = f.name
|
|
53
|
+
|
|
54
|
+
try:
|
|
55
|
+
result = diracxTokenFromPEM(temp_path)
|
|
56
|
+
assert result == token_data
|
|
57
|
+
finally:
|
|
58
|
+
Path(temp_path).unlink()
|
|
59
|
+
|
|
60
|
+
def test_no_token_in_pem(self):
|
|
61
|
+
"""Test behavior when no DiracX token is present in PEM file"""
|
|
62
|
+
pem_content = """-----BEGIN CERTIFICATE-----
|
|
63
|
+
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...
|
|
64
|
+
-----END CERTIFICATE-----"""
|
|
65
|
+
|
|
66
|
+
with tempfile.NamedTemporaryFile(mode="w", delete=False, suffix=".pem") as f:
|
|
67
|
+
f.write(pem_content)
|
|
68
|
+
temp_path = f.name
|
|
69
|
+
|
|
70
|
+
try:
|
|
71
|
+
result = diracxTokenFromPEM(temp_path)
|
|
72
|
+
assert result is None
|
|
73
|
+
finally:
|
|
74
|
+
Path(temp_path).unlink()
|
|
75
|
+
|
|
76
|
+
def test_multiple_tokens_error(self):
|
|
77
|
+
"""Test that multiple tokens raise ValueError"""
|
|
78
|
+
token_data = self.create_valid_token_data()
|
|
79
|
+
|
|
80
|
+
# Create PEM with two tokens
|
|
81
|
+
pem_content = self.create_pem_content(token_data)
|
|
82
|
+
pem_content += "\n" + self.create_pem_content(token_data, include_other_content=False)
|
|
83
|
+
|
|
84
|
+
with tempfile.NamedTemporaryFile(mode="w", delete=False, suffix=".pem") as f:
|
|
85
|
+
f.write(pem_content)
|
|
86
|
+
temp_path = f.name
|
|
87
|
+
|
|
88
|
+
try:
|
|
89
|
+
with pytest.raises(ValueError, match="Found multiple DiracX tokens"):
|
|
90
|
+
diracxTokenFromPEM(temp_path)
|
|
91
|
+
finally:
|
|
92
|
+
Path(temp_path).unlink()
|
|
93
|
+
|
|
94
|
+
def test_malformed_base64(self):
|
|
95
|
+
"""Test behavior with malformed base64 data"""
|
|
96
|
+
pem_content = f"""{PEM_BEGIN}
|
|
97
|
+
invalid_base64_data_that_will_cause_error!
|
|
98
|
+
{PEM_END}"""
|
|
99
|
+
|
|
100
|
+
with tempfile.NamedTemporaryFile(mode="w", delete=False, suffix=".pem") as f:
|
|
101
|
+
f.write(pem_content)
|
|
102
|
+
temp_path = f.name
|
|
103
|
+
|
|
104
|
+
try:
|
|
105
|
+
with pytest.raises(Exception): # base64.b64decode will raise an exception
|
|
106
|
+
diracxTokenFromPEM(temp_path)
|
|
107
|
+
finally:
|
|
108
|
+
Path(temp_path).unlink()
|
|
109
|
+
|
|
110
|
+
def test_invalid_json_in_token(self):
|
|
111
|
+
"""Test behavior with invalid JSON in token data"""
|
|
112
|
+
invalid_json = "this is not valid json"
|
|
113
|
+
encoded_invalid = base64.b64encode(invalid_json.encode("utf-8")).decode()
|
|
114
|
+
|
|
115
|
+
pem_content = f"""{PEM_BEGIN}
|
|
116
|
+
{encoded_invalid}
|
|
117
|
+
{PEM_END}"""
|
|
118
|
+
|
|
119
|
+
with tempfile.NamedTemporaryFile(mode="w", delete=False, suffix=".pem") as f:
|
|
120
|
+
f.write(pem_content)
|
|
121
|
+
temp_path = f.name
|
|
122
|
+
|
|
123
|
+
try:
|
|
124
|
+
with pytest.raises(json.JSONDecodeError):
|
|
125
|
+
diracxTokenFromPEM(temp_path)
|
|
126
|
+
finally:
|
|
127
|
+
Path(temp_path).unlink()
|
|
128
|
+
|
|
129
|
+
def test_token_with_unicode_characters(self):
|
|
130
|
+
"""Test token with unicode characters"""
|
|
131
|
+
unicode_token = {
|
|
132
|
+
"access_token": "token_with_unicode_ñ_é_ü",
|
|
133
|
+
"refresh_token": "refresh_with_emoji_🚀_🎉",
|
|
134
|
+
"expires_in": 3600,
|
|
135
|
+
"token_type": "Bearer",
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
pem_content = self.create_pem_content(unicode_token)
|
|
139
|
+
|
|
140
|
+
with tempfile.NamedTemporaryFile(mode="w", delete=False, suffix=".pem") as f:
|
|
141
|
+
f.write(pem_content)
|
|
142
|
+
temp_path = f.name
|
|
143
|
+
|
|
144
|
+
try:
|
|
145
|
+
result = diracxTokenFromPEM(temp_path)
|
|
146
|
+
assert result == unicode_token
|
|
147
|
+
finally:
|
|
148
|
+
Path(temp_path).unlink()
|
|
149
|
+
|
|
150
|
+
def test_regex_pattern_validation(self):
|
|
151
|
+
"""Test that the regex pattern correctly identifies DiracX tokens"""
|
|
152
|
+
# Test that the regex matches the expected pattern
|
|
153
|
+
token_data = self.create_valid_token_data()
|
|
154
|
+
token_json = json.dumps(token_data)
|
|
155
|
+
encoded_token = base64.b64encode(token_json.encode("utf-8")).decode()
|
|
156
|
+
|
|
157
|
+
test_content = f"{PEM_BEGIN}\n{encoded_token}\n{PEM_END}"
|
|
158
|
+
matches = RE_DIRACX_PEM.findall(test_content)
|
|
159
|
+
|
|
160
|
+
assert len(matches) == 1
|
|
161
|
+
assert matches[0] == encoded_token
|
|
@@ -73,7 +73,7 @@ class TornadoService(BaseRequestHandler): # pylint: disable=abstract-method
|
|
|
73
73
|
:py:class:`BaseRequestHandler <DIRAC.Core.Tornado.Server.private.BaseRequestHandler.BaseRequestHandler>` for more details.
|
|
74
74
|
|
|
75
75
|
In order to pass information around and keep some states, we use instance attributes.
|
|
76
|
-
These are initialized in the
|
|
76
|
+
These are initialized in the ``initialize`` methods.
|
|
77
77
|
|
|
78
78
|
The handler only define the ``post`` verb. Please refer to :py:meth:`.post` for the details.
|
|
79
79
|
|
|
@@ -29,50 +29,50 @@ def test_base():
|
|
|
29
29
|
time.sleep(1)
|
|
30
30
|
p = Profiler(mainProcess.pid)
|
|
31
31
|
res = p.pid()
|
|
32
|
-
assert res["OK"] is True
|
|
32
|
+
assert res["OK"] is True, res
|
|
33
33
|
res = p.status()
|
|
34
|
-
assert res["OK"] is True
|
|
34
|
+
assert res["OK"] is True, res
|
|
35
35
|
res = p.runningTime()
|
|
36
|
-
assert res["OK"] is True
|
|
36
|
+
assert res["OK"] is True, res
|
|
37
37
|
assert res["Value"] > 0
|
|
38
38
|
|
|
39
39
|
res = p.memoryUsage()
|
|
40
|
-
assert res["OK"] is True
|
|
40
|
+
assert res["OK"] is True, res
|
|
41
41
|
assert res["Value"] > 0
|
|
42
42
|
resWC = p.memoryUsage(withChildren=True)
|
|
43
|
-
assert resWC["OK"] is True
|
|
43
|
+
assert resWC["OK"] is True, res
|
|
44
44
|
assert resWC["Value"] > 0
|
|
45
45
|
assert resWC["Value"] >= res["Value"]
|
|
46
46
|
|
|
47
47
|
res = p.vSizeUsage()
|
|
48
|
-
assert res["OK"] is True
|
|
48
|
+
assert res["OK"] is True, res
|
|
49
49
|
assert res["Value"] > 0
|
|
50
50
|
resWC = p.vSizeUsage(withChildren=True)
|
|
51
|
-
assert resWC["OK"] is True
|
|
51
|
+
assert resWC["OK"] is True, res
|
|
52
52
|
assert resWC["Value"] > 0
|
|
53
53
|
assert resWC["Value"] >= res["Value"]
|
|
54
54
|
|
|
55
55
|
res = p.vSizeUsage()
|
|
56
|
-
assert res["OK"] is True
|
|
56
|
+
assert res["OK"] is True, res
|
|
57
57
|
assert res["Value"] > 0
|
|
58
58
|
resWC = p.vSizeUsage(withChildren=True)
|
|
59
|
-
assert resWC["OK"] is True
|
|
59
|
+
assert resWC["OK"] is True, res
|
|
60
60
|
assert resWC["Value"] > 0
|
|
61
61
|
assert resWC["Value"] >= res["Value"]
|
|
62
62
|
|
|
63
63
|
res = p.numThreads()
|
|
64
|
-
assert res["OK"] is True
|
|
64
|
+
assert res["OK"] is True, res
|
|
65
65
|
assert res["Value"] > 0
|
|
66
66
|
resWC = p.numThreads(withChildren=True)
|
|
67
|
-
assert resWC["OK"] is True
|
|
67
|
+
assert resWC["OK"] is True, res
|
|
68
68
|
assert resWC["Value"] > 0
|
|
69
69
|
assert resWC["Value"] >= res["Value"]
|
|
70
70
|
|
|
71
71
|
res = p.cpuPercentage()
|
|
72
|
-
assert res["OK"] is True
|
|
72
|
+
assert res["OK"] is True, res
|
|
73
73
|
assert res["Value"] >= 0
|
|
74
74
|
resWC = p.cpuPercentage(withChildren=True)
|
|
75
|
-
assert resWC["OK"] is True
|
|
75
|
+
assert resWC["OK"] is True, res
|
|
76
76
|
assert resWC["Value"] >= 0
|
|
77
77
|
assert resWC["Value"] >= res["Value"]
|
|
78
78
|
|
|
@@ -88,13 +88,13 @@ def test_cpuUsage():
|
|
|
88
88
|
time.sleep(2)
|
|
89
89
|
p = Profiler(mainProcess.pid)
|
|
90
90
|
res = p.pid()
|
|
91
|
-
assert res["OK"] is True
|
|
91
|
+
assert res["OK"] is True, res
|
|
92
92
|
res = p.status()
|
|
93
|
-
assert res["OK"] is True
|
|
93
|
+
assert res["OK"] is True, res
|
|
94
94
|
|
|
95
95
|
# user
|
|
96
96
|
res = p.cpuUsageUser()
|
|
97
|
-
assert res["OK"] is True
|
|
97
|
+
assert res["OK"] is True, res
|
|
98
98
|
assert res["Value"] > 0
|
|
99
99
|
resC = p.cpuUsageUser(withChildren=True)
|
|
100
100
|
assert resC["OK"] is True
|
|
@@ -102,7 +102,7 @@ def test_cpuUsage():
|
|
|
102
102
|
assert resC["Value"] >= res["Value"]
|
|
103
103
|
|
|
104
104
|
res = p.cpuUsageUser()
|
|
105
|
-
assert res["OK"] is True
|
|
105
|
+
assert res["OK"] is True, res
|
|
106
106
|
assert res["Value"] > 0
|
|
107
107
|
resC = p.cpuUsageUser(withChildren=True)
|
|
108
108
|
assert resC["OK"] is True
|
|
@@ -121,15 +121,15 @@ def test_cpuUsage():
|
|
|
121
121
|
|
|
122
122
|
# system
|
|
123
123
|
res = p.cpuUsageSystem()
|
|
124
|
-
assert res["OK"] is True
|
|
124
|
+
assert res["OK"] is True, res
|
|
125
125
|
assert res["Value"] >= 0
|
|
126
126
|
resWC = p.cpuUsageSystem(withChildren=True)
|
|
127
|
-
assert resWC["OK"] is True
|
|
127
|
+
assert resWC["OK"] is True, res
|
|
128
128
|
assert resWC["Value"] >= 0
|
|
129
129
|
assert resWC["Value"] >= res["Value"]
|
|
130
130
|
|
|
131
131
|
res = p.cpuUsageSystem()
|
|
132
|
-
assert res["OK"] is True
|
|
132
|
+
assert res["OK"] is True, res
|
|
133
133
|
assert res["Value"] > 0
|
|
134
134
|
resC = p.cpuUsageSystem(withChildren=True)
|
|
135
135
|
assert resC["OK"] is True
|
|
@@ -12,7 +12,7 @@ class DatasetManager:
|
|
|
12
12
|
_tables["FC_MetaDatasets"] = {
|
|
13
13
|
"Fields": {
|
|
14
14
|
"DatasetID": "INT AUTO_INCREMENT",
|
|
15
|
-
"DatasetName": "VARCHAR(128) CHARACTER SET
|
|
15
|
+
"DatasetName": "VARCHAR(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL",
|
|
16
16
|
"MetaQuery": "VARCHAR(512)",
|
|
17
17
|
"DirID": "INT NOT NULL DEFAULT 0",
|
|
18
18
|
"TotalSize": "BIGINT UNSIGNED NOT NULL",
|
|
@@ -41,6 +41,7 @@ class CreateMovingRequest:
|
|
|
41
41
|
self.flags = [
|
|
42
42
|
("C", "CheckMigration", "Ensure the LFNs are migrated to tape before removing any replicas"),
|
|
43
43
|
("X", "Execute", "Put Requests, else dryrun"),
|
|
44
|
+
("", "SourceOnly", "Only treat files that are already at the Source-SE"),
|
|
44
45
|
]
|
|
45
46
|
self.registerSwitchesAndParseCommandLine()
|
|
46
47
|
self.getLFNList()
|
|
@@ -208,6 +209,7 @@ class CreateMovingRequest:
|
|
|
208
209
|
|
|
209
210
|
replicate = Operation()
|
|
210
211
|
replicate.Type = "ReplicateAndRegister"
|
|
212
|
+
replicate.SourceSE = ",".join(self.switches.get("SourceSE", []))
|
|
211
213
|
replicate.TargetSE = self.switches.get("TargetSE")
|
|
212
214
|
self.addLFNs(replicate, lfnChunk, addPFN=True)
|
|
213
215
|
request.addOperation(replicate)
|
DIRAC/Interfaces/API/Dirac.py
CHANGED
|
@@ -1463,9 +1463,8 @@ class Dirac(API):
|
|
|
1463
1463
|
res = JobMonitoringClient().getJobsStatus(jobIDs)
|
|
1464
1464
|
if not res["OK"]:
|
|
1465
1465
|
return res
|
|
1466
|
-
js = {k: v["Status"] for k, v in res["Value"].items()}
|
|
1467
1466
|
# then filter
|
|
1468
|
-
filteredJobs.update(_filterJobStateTransition(
|
|
1467
|
+
filteredJobs.update(_filterJobStateTransition(res["Value"], filterState))
|
|
1469
1468
|
|
|
1470
1469
|
return WMSClient(useCertificates=self.useCertificates).deleteJob(list(filteredJobs))
|
|
1471
1470
|
|
|
@@ -1496,9 +1495,8 @@ class Dirac(API):
|
|
|
1496
1495
|
res = JobMonitoringClient().getJobsStatus(jobIDs)
|
|
1497
1496
|
if not res["OK"]:
|
|
1498
1497
|
return res
|
|
1499
|
-
js = {k: v["Status"] for k, v in res["Value"].items()}
|
|
1500
1498
|
# then filter
|
|
1501
|
-
jobIDsToReschedule = _filterJobStateTransition(
|
|
1499
|
+
jobIDsToReschedule = _filterJobStateTransition(res["Value"], JobStatus.RESCHEDULED)
|
|
1502
1500
|
|
|
1503
1501
|
return WMSClient(useCertificates=self.useCertificates).rescheduleJob(jobIDsToReschedule)
|
|
1504
1502
|
|
|
@@ -1528,9 +1526,8 @@ class Dirac(API):
|
|
|
1528
1526
|
res = JobMonitoringClient().getJobsStatus(jobIDs)
|
|
1529
1527
|
if not res["OK"]:
|
|
1530
1528
|
return res
|
|
1531
|
-
js = {k: v["Status"] for k, v in res["Value"].items()}
|
|
1532
1529
|
# then filter
|
|
1533
|
-
filteredJobs.update(_filterJobStateTransition(
|
|
1530
|
+
filteredJobs.update(_filterJobStateTransition(res["Value"], filterState))
|
|
1534
1531
|
|
|
1535
1532
|
return WMSClient(useCertificates=self.useCertificates).killJob(list(filteredJobs))
|
|
1536
1533
|
|
|
@@ -5,8 +5,7 @@ Wrapper on top of ElasticDB. It is used to manage the DIRAC monitoring types.
|
|
|
5
5
|
|
|
6
6
|
The following option can be set in `Systems/Monitoring/Databases/MonitoringDB`
|
|
7
7
|
|
|
8
|
-
* *IndexPrefix*: Prefix used to prepend to indexes created in the
|
|
9
|
-
is not present in the CS, the indexes are prefixed with the setup name.
|
|
8
|
+
* *IndexPrefix*: Prefix used to prepend to indexes created in the OpenSearch instance.
|
|
10
9
|
|
|
11
10
|
For each monitoring types managed, the Period (how often a new index is created)
|
|
12
11
|
can be defined with::
|
|
@@ -33,7 +32,6 @@ import time
|
|
|
33
32
|
|
|
34
33
|
from DIRAC import S_ERROR, S_OK
|
|
35
34
|
from DIRAC.ConfigurationSystem.Client.Config import gConfig
|
|
36
|
-
from DIRAC.ConfigurationSystem.Client.Helpers import CSGlobals
|
|
37
35
|
from DIRAC.ConfigurationSystem.Client.PathFinder import getDatabaseSection
|
|
38
36
|
from DIRAC.Core.Base.ElasticDB import ElasticDB
|
|
39
37
|
from DIRAC.Core.Utilities.Plotting.TypeLoader import TypeLoader
|
|
@@ -48,7 +46,7 @@ class MonitoringDB(ElasticDB):
|
|
|
48
46
|
|
|
49
47
|
try:
|
|
50
48
|
section = getDatabaseSection("Monitoring/MonitoringDB")
|
|
51
|
-
indexPrefix = gConfig.getValue(f"{section}/IndexPrefix",
|
|
49
|
+
indexPrefix = gConfig.getValue(f"{section}/IndexPrefix", "").lower()
|
|
52
50
|
# Connecting to the ES cluster
|
|
53
51
|
super().__init__(fullName=name, indexPrefix=indexPrefix)
|
|
54
52
|
except RuntimeError as ex:
|
|
@@ -192,7 +190,10 @@ class MonitoringDB(ElasticDB):
|
|
|
192
190
|
# and now we group with bucket aggregation
|
|
193
191
|
groupingAggregation = self._A("terms", field=grouping, size=self.RESULT_SIZE)
|
|
194
192
|
groupingAggregation.bucket(
|
|
195
|
-
"end_data",
|
|
193
|
+
"end_data",
|
|
194
|
+
"date_histogram",
|
|
195
|
+
field="timestamp",
|
|
196
|
+
interval=interval,
|
|
196
197
|
).metric("timeAggregation", timeAggregation).pipeline(
|
|
197
198
|
"timeAggregation_avg_bucket", "avg_bucket", buckets_path="timeAggregation>total", gap_policy="insert_zeros"
|
|
198
199
|
)
|
|
@@ -28,19 +28,29 @@ class WebAppHandler(RequestHandler):
|
|
|
28
28
|
result = ObjectLoader().loadObject("WorkloadManagementSystem.DB.PilotAgentsDB", "PilotAgentsDB")
|
|
29
29
|
if not result["OK"]:
|
|
30
30
|
return result
|
|
31
|
-
|
|
31
|
+
try:
|
|
32
|
+
cls.pilotAgentsDB = result["Value"](parentLogger=cls.log)
|
|
33
|
+
except RuntimeError:
|
|
34
|
+
cls.log.warn("Could not connect to PilotAgentsDB")
|
|
32
35
|
|
|
33
36
|
result = ObjectLoader().loadObject("WorkloadManagementSystem.DB.JobDB", "JobDB")
|
|
34
37
|
if not result["OK"]:
|
|
35
38
|
return result
|
|
36
|
-
|
|
39
|
+
try:
|
|
40
|
+
cls.jobDB = result["Value"](parentLogger=cls.log)
|
|
41
|
+
except RuntimeError:
|
|
42
|
+
cls.log.warn("Could not connect to JobDB")
|
|
37
43
|
|
|
38
44
|
result = ObjectLoader().loadObject("TransformationSystem.DB.TransformationDB", "TransformationDB")
|
|
39
45
|
if not result["OK"]:
|
|
40
46
|
return result
|
|
41
|
-
|
|
47
|
+
try:
|
|
48
|
+
cls.transformationDB = result["Value"](parentLogger=cls.log)
|
|
49
|
+
except RuntimeError:
|
|
50
|
+
cls.log.warn("Could not connect to TransformationDB")
|
|
42
51
|
|
|
43
52
|
except RuntimeError as excp:
|
|
53
|
+
cls.log.exception()
|
|
44
54
|
return S_ERROR(f"Can't connect to DB: {excp}")
|
|
45
55
|
|
|
46
56
|
return S_OK()
|
|
@@ -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):
|
|
@@ -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):
|
|
@@ -44,19 +44,19 @@ Agents
|
|
|
44
44
|
{
|
|
45
45
|
PollingTime = 60
|
|
46
46
|
# number of Requests to execute per cycle
|
|
47
|
-
RequestsPerCycle =
|
|
47
|
+
RequestsPerCycle = 300
|
|
48
48
|
# minimum number of workers process in the ProcessPool
|
|
49
|
-
MinProcess =
|
|
49
|
+
MinProcess = 50
|
|
50
50
|
# maximum number of workers process in the ProcessPool; recommended to set it to the same value as MinProcess
|
|
51
|
-
MaxProcess =
|
|
51
|
+
MaxProcess = 50
|
|
52
52
|
# queue depth of the ProcessPool
|
|
53
|
-
ProcessPoolQueueSize =
|
|
53
|
+
ProcessPoolQueueSize = 100
|
|
54
54
|
# timeout for the ProcessPool finalization
|
|
55
55
|
ProcessPoolTimeout = 900
|
|
56
56
|
# sleep time before retrying to get a free slot in the ProcessPool
|
|
57
|
-
ProcessPoolSleep =
|
|
57
|
+
ProcessPoolSleep = 1
|
|
58
58
|
# If a positive integer n is given, we fetch n requests at once from the DB. Otherwise, one by one
|
|
59
|
-
BulkRequest =
|
|
59
|
+
BulkRequest = 300
|
|
60
60
|
OperationHandlers
|
|
61
61
|
{
|
|
62
62
|
ForwardDISET
|
|
@@ -26,3 +26,16 @@ class CheckInIdProvider(OAuth2IdProvider):
|
|
|
26
26
|
|
|
27
27
|
idPScope = f"eduperson_entitlement?value=urn:mace:egi.eu:group:{vo}:role={groupElements[1]}#aai.egi.eu"
|
|
28
28
|
return scope_to_list(idPScope)
|
|
29
|
+
|
|
30
|
+
def fetchToken(self, **kwargs):
|
|
31
|
+
"""Fetch token
|
|
32
|
+
|
|
33
|
+
:param kwargs:
|
|
34
|
+
:return: dict
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
if "audience" in kwargs:
|
|
38
|
+
kwargs["resource"] = kwargs["audience"]
|
|
39
|
+
kwargs.pop("audience")
|
|
40
|
+
|
|
41
|
+
return super().fetchToken(**kwargs)
|
|
@@ -22,7 +22,6 @@ from DIRAC.TransformationSystem.Client.FileReport import FileReport
|
|
|
22
22
|
from DIRAC.TransformationSystem.Client.TransformationClient import TransformationClient
|
|
23
23
|
from DIRAC.TransformationSystem.Client.WorkflowTasks import WorkflowTasks
|
|
24
24
|
from DIRAC.WorkloadManagementSystem.Client import JobStatus
|
|
25
|
-
from DIRAC.WorkloadManagementSystem.Client.JobManagerClient import JobManagerClient
|
|
26
25
|
|
|
27
26
|
AGENT_NAME = "Transformation/TaskManagerAgentBase"
|
|
28
27
|
|
|
@@ -39,7 +38,6 @@ class TaskManagerAgentBase(AgentModule, TransformationAgentsUtilities):
|
|
|
39
38
|
TransformationAgentsUtilities.__init__(self)
|
|
40
39
|
|
|
41
40
|
self.transClient = None
|
|
42
|
-
self.jobManagerClient = None
|
|
43
41
|
self.transType = []
|
|
44
42
|
|
|
45
43
|
self.tasksPerLoop = 50
|
|
@@ -68,7 +66,6 @@ class TaskManagerAgentBase(AgentModule, TransformationAgentsUtilities):
|
|
|
68
66
|
|
|
69
67
|
# Default clients
|
|
70
68
|
self.transClient = TransformationClient()
|
|
71
|
-
self.jobManagerClient = JobManagerClient()
|
|
72
69
|
|
|
73
70
|
# Bulk submission flag
|
|
74
71
|
self.bulkSubmissionFlag = self.am_getOption("BulkSubmission", self.bulkSubmissionFlag)
|
|
@@ -16,7 +16,7 @@ from urllib.request import urlopen
|
|
|
16
16
|
from DIRAC.Interfaces.API.Dirac import Dirac
|
|
17
17
|
from DIRAC.Core.Utilities.File import mkDir
|
|
18
18
|
from DIRAC.Core.Base.Script import Script
|
|
19
|
-
from DIRAC.ConfigurationSystem.Client.Helpers.CSGlobals import getVO
|
|
19
|
+
from DIRAC.ConfigurationSystem.Client.Helpers.CSGlobals import getVO
|
|
20
20
|
from DIRAC.ConfigurationSystem.Client.ConfigurationData import gConfigurationData
|
|
21
21
|
|
|
22
22
|
|
|
@@ -79,14 +79,12 @@ def __configurePilot(basepath, vo):
|
|
|
79
79
|
This method was created specifically for LHCb pilots, more info
|
|
80
80
|
about othe VOs is needed to make it more general.
|
|
81
81
|
"""
|
|
82
|
-
currentSetup = getSetup()
|
|
83
82
|
masterCS = gConfigurationData.getMasterServer()
|
|
84
83
|
|
|
85
84
|
os.system(
|
|
86
85
|
"python "
|
|
87
86
|
+ basepath
|
|
88
|
-
+ "dirac-pilot.py -
|
|
89
|
-
% (currentSetup, vo, masterCS)
|
|
87
|
+
+ f"dirac-pilot.py -l {vo} -C {masterCS} -N ce.debug.ch -Q default -n DIRAC.JobDebugger.ch -dd"
|
|
90
88
|
)
|
|
91
89
|
|
|
92
90
|
diracdir = os.path.expanduser("~") + os.path.sep
|
|
@@ -229,12 +229,8 @@ class SiteDirector(AgentModule):
|
|
|
229
229
|
site = self.queueDict[queueName]["Site"]
|
|
230
230
|
ce = self.queueDict[queueName]["CEName"]
|
|
231
231
|
|
|
232
|
-
# Check the status of the Site
|
|
233
|
-
if site in siteMaskList:
|
|
234
|
-
continue
|
|
235
|
-
|
|
236
|
-
# Check the status of the CE (only for RSS=Active)
|
|
237
|
-
if ce not in ceMaskList:
|
|
232
|
+
# Check the status of the Site and CE
|
|
233
|
+
if site in siteMaskList and ce in ceMaskList:
|
|
238
234
|
continue
|
|
239
235
|
|
|
240
236
|
self.log.warn("Queue not considered because not usable:", queueName)
|
|
@@ -169,10 +169,16 @@ def sd(mocker, config):
|
|
|
169
169
|
gConfig.getSections("Resources/Sites/LCG")["Value"] + gConfig.getSections("Resources/Sites/DIRAC")["Value"]
|
|
170
170
|
)
|
|
171
171
|
mocker.patch(
|
|
172
|
-
"DIRAC.WorkloadManagementSystem.Agent.SiteDirector.SiteStatus.getUsableSites",
|
|
172
|
+
"DIRAC.WorkloadManagementSystem.Agent.SiteDirector.SiteStatus.getUsableSites", return_value=S_OK(usableSites)
|
|
173
173
|
)
|
|
174
|
+
|
|
175
|
+
# Mock getElementStatus to return a properly formatted dictionary
|
|
176
|
+
def mock_getElementStatus(ceNamesList, *args, **kwargs):
|
|
177
|
+
return S_OK({ceName: {"all": "Active"} for ceName in ceNamesList})
|
|
178
|
+
|
|
174
179
|
mocker.patch(
|
|
175
|
-
"DIRAC.WorkloadManagementSystem.Agent.SiteDirector.ResourceStatus.getElementStatus",
|
|
180
|
+
"DIRAC.WorkloadManagementSystem.Agent.SiteDirector.ResourceStatus.getElementStatus",
|
|
181
|
+
side_effect=mock_getElementStatus,
|
|
176
182
|
)
|
|
177
183
|
mocker.patch(
|
|
178
184
|
"DIRAC.WorkloadManagementSystem.Agent.SiteDirector.gProxyManager.downloadProxy", side_effect=mockPMProxyReply
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
"""
|
|
2
|
-
|
|
1
|
+
"""Module containing a front-end to the OpenSearch-based JobParametersDB.
|
|
2
|
+
This is a drop-in replacement for MySQL-based table JobDB.JobParameters.
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
The following class methods are provided for public usage
|
|
5
|
+
- getJobParameters()
|
|
6
|
+
- setJobParameter()
|
|
7
|
+
- deleteJobParameters()
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
10
|
from DIRAC import S_ERROR, S_OK
|
|
@@ -37,11 +37,11 @@ class JobParametersDB(ElasticDB):
|
|
|
37
37
|
def __init__(self, parentLogger=None):
|
|
38
38
|
"""Standard Constructor"""
|
|
39
39
|
|
|
40
|
-
self.fullname = "WorkloadManagement/
|
|
40
|
+
self.fullname = "WorkloadManagement/JobParametersDB"
|
|
41
41
|
self.index_name = self.getCSOption("index_name", "job_parameters")
|
|
42
42
|
|
|
43
43
|
try:
|
|
44
|
-
# Connecting to the
|
|
44
|
+
# Connecting to the OpenSearch cluster
|
|
45
45
|
super().__init__(self.fullname, self.index_name, parentLogger=parentLogger)
|
|
46
46
|
except Exception:
|
|
47
47
|
RuntimeError("Can't connect to JobParameters index")
|
|
@@ -64,7 +64,7 @@ class SandboxMetadataDB(DB):
|
|
|
64
64
|
"Type": "VARCHAR(64) NOT NULL",
|
|
65
65
|
},
|
|
66
66
|
"Indexes": {"Entity": ["EntityId"], "SBIndex": ["SBId"]},
|
|
67
|
-
"
|
|
67
|
+
"PrimaryKey": ["SBId", "EntityId", "Type"],
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
for tableName in self.__tablesDesc:
|
|
@@ -79,7 +79,7 @@ def kill_delete_jobs(right, validJobList, nonauthJobList=[], force=False):
|
|
|
79
79
|
killJobList = []
|
|
80
80
|
deleteJobList = []
|
|
81
81
|
if validJobList:
|
|
82
|
-
result = JobDB().getJobsAttributes(
|
|
82
|
+
result = JobDB().getJobsAttributes(validJobList, ["Status"])
|
|
83
83
|
if not result["OK"]:
|
|
84
84
|
return result
|
|
85
85
|
jobStates = result["Value"]
|
|
@@ -1215,8 +1215,8 @@ class JobWrapper:
|
|
|
1215
1215
|
lfn = str(basePath / outputPath / os.path.basename(localfile))
|
|
1216
1216
|
else:
|
|
1217
1217
|
# if LFN is given, take it as it is
|
|
1218
|
-
localfile = str(self.jobIDPath / outputFile.replace("LFN:", ""))
|
|
1219
1218
|
lfn = outputFile.replace("LFN:", "")
|
|
1219
|
+
localfile = str(self.jobIDPath / os.path.basename(lfn))
|
|
1220
1220
|
|
|
1221
1221
|
return (lfn, localfile)
|
|
1222
1222
|
|
|
@@ -664,6 +664,7 @@ def jobIDPath():
|
|
|
664
664
|
# Output data files
|
|
665
665
|
(p / "00232454_00000244_1.sim").touch()
|
|
666
666
|
(p / "1720442808testFileUpload.txt").touch()
|
|
667
|
+
(p / "testFileUploadFullLFN.txt").touch()
|
|
667
668
|
|
|
668
669
|
with open(p / "pool_xml_catalog.xml", "w") as f:
|
|
669
670
|
f.write(
|
|
@@ -863,7 +864,11 @@ def test_processJobOutputs_output_data_upload(mocker, setup_another_job_wrapper)
|
|
|
863
864
|
# BTW, isn't the concept of pool_xml_catalog.xml from lhcbdirac?
|
|
864
865
|
jw.jobArgs = {
|
|
865
866
|
"OutputSandbox": [],
|
|
866
|
-
"OutputData": [
|
|
867
|
+
"OutputData": [
|
|
868
|
+
"1720442808testFileUpload.txt",
|
|
869
|
+
"LFN:00232454_00000244_1.sim",
|
|
870
|
+
"LFN:/dirac/user/u/unknown/testFileUploadFullLFN.txt",
|
|
871
|
+
],
|
|
867
872
|
"Owner": "Jane Doe",
|
|
868
873
|
}
|
|
869
874
|
|
|
@@ -879,10 +884,15 @@ def test_processJobOutputs_output_data_upload(mocker, setup_another_job_wrapper)
|
|
|
879
884
|
assert jw.jobReport.jobStatusInfo[1][:-1] == ("", JobMinorStatus.UPLOADING_OUTPUT_DATA)
|
|
880
885
|
assert jw.jobReport.jobStatusInfo[2][:-1] == (JobStatus.COMPLETING, JobMinorStatus.OUTPUT_DATA_UPLOADED)
|
|
881
886
|
assert len(jw.jobReport.jobParameters) == 1
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
"00232454_00000244_1.sim
|
|
885
|
-
|
|
887
|
+
|
|
888
|
+
expected_files = {
|
|
889
|
+
"00232454_00000244_1.sim",
|
|
890
|
+
"/dirac/user/u/unknown/0/123/1720442808testFileUpload.txt",
|
|
891
|
+
"/dirac/user/u/unknown/testFileUploadFullLFN.txt",
|
|
892
|
+
}
|
|
893
|
+
assert jw.jobReport.jobParameters[0][0] == "UploadedOutputData"
|
|
894
|
+
uploaded_files = set(jw.jobReport.jobParameters[0][1].split(", "))
|
|
895
|
+
assert uploaded_files == expected_files
|
|
886
896
|
|
|
887
897
|
|
|
888
898
|
# -------------------------------------------------------------------------------------------------
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: DIRAC
|
|
3
|
-
Version: 9.0.
|
|
3
|
+
Version: 9.0.2
|
|
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.
|
|
22
|
+
Requires-Dist: DIRACCommon==v9.0.2
|
|
23
23
|
Requires-Dist: diracx-client>=v0.0.1a18
|
|
24
24
|
Requires-Dist: diracx-core>=v0.0.1a18
|
|
25
25
|
Requires-Dist: db12
|
|
@@ -40,7 +40,6 @@ Requires-Dist: python-dateutil
|
|
|
40
40
|
Requires-Dist: pytz
|
|
41
41
|
Requires-Dist: requests
|
|
42
42
|
Requires-Dist: rucio-clients>=34.4.2
|
|
43
|
-
Requires-Dist: setuptools
|
|
44
43
|
Requires-Dist: sqlalchemy
|
|
45
44
|
Requires-Dist: typing_extensions>=4.3.0
|
|
46
45
|
Requires-Dist: Authlib>=1.0.0.a2
|
|
@@ -63,7 +63,7 @@ DIRAC/ConfigurationSystem/Client/PathFinder.py,sha256=wxOWC0_UznF7XJc0LP9DX8y3yl
|
|
|
63
63
|
DIRAC/ConfigurationSystem/Client/Utilities.py,sha256=lQepoCgaAvg9GW3_-s-IXkWb3fN3HJJP95pYhNEC2_4,27200
|
|
64
64
|
DIRAC/ConfigurationSystem/Client/VOMS2CSSynchronizer.py,sha256=7gcA6eqKIeRBLxETR5CjCdqXHZeQMVDNZfHkz28W20k,31433
|
|
65
65
|
DIRAC/ConfigurationSystem/Client/__init__.py,sha256=Jkxofl9cI04MqJcu_ZP8Wdk3WXOmiESFJS9e81LnG2Y,52
|
|
66
|
-
DIRAC/ConfigurationSystem/Client/Helpers/CSGlobals.py,sha256=
|
|
66
|
+
DIRAC/ConfigurationSystem/Client/Helpers/CSGlobals.py,sha256=taQyqusXtK3zAtoQY9tpCyHAr9jU7U7cjRDvW8YmUwk,911
|
|
67
67
|
DIRAC/ConfigurationSystem/Client/Helpers/Operations.py,sha256=jrpeauEwV6_xXQwVEbs6DDboB8oUmzkZkB_Xg8ZgdBQ,5991
|
|
68
68
|
DIRAC/ConfigurationSystem/Client/Helpers/Path.py,sha256=ghRMD2qNaKejwg4RZ3m4LzfCG5bg1afvTnwJQydl94w,930
|
|
69
69
|
DIRAC/ConfigurationSystem/Client/Helpers/Registry.py,sha256=svibVaHyRKRKPEs-k4pXgcTzr74qe72m4jo2Ue9Xqts,20775
|
|
@@ -71,7 +71,7 @@ DIRAC/ConfigurationSystem/Client/Helpers/Resources.py,sha256=g6ZRdAydAnyKHjL9Gh6
|
|
|
71
71
|
DIRAC/ConfigurationSystem/Client/Helpers/ResourcesDefaults.py,sha256=m6s-ZvjtYcLGsuu6mkCpIzxA8rEUYnwOOw1HvjecuJQ,3314
|
|
72
72
|
DIRAC/ConfigurationSystem/Client/Helpers/__init__.py,sha256=syOASwgkZHn6b6ybYYu15wO8mrZXj7T-gIHk3EDlpjc,206
|
|
73
73
|
DIRAC/ConfigurationSystem/Client/Helpers/test/Test_Helpers.py,sha256=_pfEyd5tw5OGCluNWT8cN2PIX_XEr1gLZPHPXEG0zXs,5543
|
|
74
|
-
DIRAC/ConfigurationSystem/Client/SyncPlugins/CERNLDAPSyncPlugin.py,sha256=
|
|
74
|
+
DIRAC/ConfigurationSystem/Client/SyncPlugins/CERNLDAPSyncPlugin.py,sha256=RuTjybzvD-ioxuDKHmOsyzMMZIAaJHqE5WOrHdMN8vE,3538
|
|
75
75
|
DIRAC/ConfigurationSystem/Client/SyncPlugins/DummySyncPlugin.py,sha256=hGXcNMxh3r7sCXkTs5r1Mlvz6FjlZ1lBo9NzavQzoBo,1420
|
|
76
76
|
DIRAC/ConfigurationSystem/Client/SyncPlugins/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
77
77
|
DIRAC/ConfigurationSystem/Client/test/Test_LocalConfiguration.py,sha256=bGuaALxrvTYNo9eAYJzzL-q0FXgWdd6vguvGI1c4jA0,7432
|
|
@@ -83,7 +83,7 @@ DIRAC/ConfigurationSystem/private/ConfigurationClient.py,sha256=zRqHURAz2uE96fDW
|
|
|
83
83
|
DIRAC/ConfigurationSystem/private/ConfigurationData.py,sha256=KaoCw6yhNTFHPYRf_gE8vllJIlOvrvTq_zI7rOQiHqo,15180
|
|
84
84
|
DIRAC/ConfigurationSystem/private/Modificator.py,sha256=Ek5pKk-HJ2f7TF4zcHdPifugELBo6bpl4dVo0qbr9Ww,10537
|
|
85
85
|
DIRAC/ConfigurationSystem/private/Refresher.py,sha256=bdBEp4dVtE8RBdYHmFREftrUniGbe7AwXZK-vBZnAV0,4097
|
|
86
|
-
DIRAC/ConfigurationSystem/private/RefresherBase.py,sha256=
|
|
86
|
+
DIRAC/ConfigurationSystem/private/RefresherBase.py,sha256=STbCWT3fJvNqyQNwsrzTQAuG6OndlBzTJfnwGrAOAnQ,6552
|
|
87
87
|
DIRAC/ConfigurationSystem/private/ServiceInterface.py,sha256=HzFWXFd6aWmlEJfcBNr5nVCG3tXuYmQunR9_xjuueX4,1919
|
|
88
88
|
DIRAC/ConfigurationSystem/private/ServiceInterfaceBase.py,sha256=bLa6xxydThtsGalaiiYhsSWWXEfA9laJBOLU8ZaMiy0,15644
|
|
89
89
|
DIRAC/ConfigurationSystem/private/ServiceInterfaceTornado.py,sha256=gEUyxpQM1kJDl_zUI7__OCbqS0-CAD7CCMS9JiWtFgY,1414
|
|
@@ -121,7 +121,7 @@ DIRAC/Core/DISET/AuthManager.py,sha256=-aSXHK4Lxtr_jd4efVEL2xuqnsIaKHGyPNiq2H111
|
|
|
121
121
|
DIRAC/Core/DISET/MessageClient.py,sha256=tOluMqcZmvM7wIQm0X957_lXNdlYpxST-LZitYbK9NQ,6007
|
|
122
122
|
DIRAC/Core/DISET/RPCClient.py,sha256=Sg3wIpy_I0Z6x2w_hs1Z1qtBdiStkvEkESPtXuagno0,3816
|
|
123
123
|
DIRAC/Core/DISET/RequestHandler.py,sha256=42NoL2_2lN_N7YIHSBWpPPBYtF2OQ4PLqxBX1ca3_Ys,24044
|
|
124
|
-
DIRAC/Core/DISET/ServiceReactor.py,sha256=
|
|
124
|
+
DIRAC/Core/DISET/ServiceReactor.py,sha256=AVLKPkUY3IRoADVzMjLMXtOBhXKanPYHt5_k9e--ZBo,11281
|
|
125
125
|
DIRAC/Core/DISET/ThreadConfig.py,sha256=Q43BnQ8yliFliU65rLxHBV49c4TFzrYq9Ewe5n2vASQ,3086
|
|
126
126
|
DIRAC/Core/DISET/TransferClient.py,sha256=2WDH3Be5NSAY4xWRK0RL2OnKeQLtaPRIJLQeeVYY5V8,7657
|
|
127
127
|
DIRAC/Core/DISET/__init__.py,sha256=ZPbhSIBCK14nC9R5drkX8lfK2YHY7g-WVg0Zuy3uHAc,1085
|
|
@@ -154,7 +154,7 @@ DIRAC/Core/LCG/GGUSTicketsClient.py,sha256=dlt9-cy2lptdiMa56YTV5g7uZrXaPIvbvTK-c
|
|
|
154
154
|
DIRAC/Core/LCG/GOCDBClient.py,sha256=FTxnwJqd3j99vfLkC2ouyrCsnVLFEwg_GHaq6zY1Db8,15439
|
|
155
155
|
DIRAC/Core/LCG/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
156
156
|
DIRAC/Core/LCG/test/Test_LCG.py,sha256=2VsUEgyWDC6BC2KsMz9tB6TsMHYmpg0Qfjs3utiXKcg,32871
|
|
157
|
-
DIRAC/Core/Security/DiracX.py,sha256=
|
|
157
|
+
DIRAC/Core/Security/DiracX.py,sha256=kpPQXYzL_dAf_q3xyBaEHgJS8fKUX3Uvv13GTlP_soI,5266
|
|
158
158
|
DIRAC/Core/Security/IAMService.py,sha256=7LQs3PuDz1KM6r6rMefjiV_9FCpXL-sDUNm8-rrdGOE,6911
|
|
159
159
|
DIRAC/Core/Security/Locations.py,sha256=Ew1-J4tAwfbgkW1_MAlIIkeBi6_MJLsefNAL8vBi7_k,8031
|
|
160
160
|
DIRAC/Core/Security/Properties.py,sha256=CjHN-YQwBiAdZyTos9b6Zpg5a6Sh_hFNUvpszxzEgnE,6180
|
|
@@ -175,6 +175,7 @@ DIRAC/Core/Security/test/Test_X509Certificate.py,sha256=bN51zF-3SepZOcvfScP_-yS4
|
|
|
175
175
|
DIRAC/Core/Security/test/Test_X509Chain.py,sha256=xGYmr_VgYeayf3JEqtauCXVt7INAR7FQj_hmZl8PRCw,18694
|
|
176
176
|
DIRAC/Core/Security/test/Test_X509Request.py,sha256=Cl5fA8xGAiHsmEmGnA2KOriADnzPI1U878jxmw2b4vg,3258
|
|
177
177
|
DIRAC/Core/Security/test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
178
|
+
DIRAC/Core/Security/test/test_diracx_token_from_pem.py,sha256=EYh1WmJhPvsq8PvWbUTax2KPZNH2HAIjZQGq8EAPJiY,5632
|
|
178
179
|
DIRAC/Core/Security/test/x509TestUtilities.py,sha256=pPZTJtVsLy77Xlqjadwcj5TSW30alFx_F7mWpuyKYYE,17234
|
|
179
180
|
DIRAC/Core/Security/test/certs/ca/b236481c.0,sha256=ZShotyOrATnsvKDGbcWJAHfGfuO2ygyvEIeAmjqf0UI,1988
|
|
180
181
|
DIRAC/Core/Security/test/certs/ca/ca.cert.pem,sha256=ZShotyOrATnsvKDGbcWJAHfGfuO2ygyvEIeAmjqf0UI,1988
|
|
@@ -211,7 +212,7 @@ DIRAC/Core/Tornado/Client/private/__init__.py,sha256=cO7z-h1lVEu7RRPYeY3BZLJu-FZ
|
|
|
211
212
|
DIRAC/Core/Tornado/Server/HandlerManager.py,sha256=IQG2_dufNM43TGqfYU6QOTMlJyPdeCSs7TWqHlAls_Q,8181
|
|
212
213
|
DIRAC/Core/Tornado/Server/TornadoREST.py,sha256=-4_gROsCYPrwHifagoZFqUSfu6mlkk4PMeL9G7NTba0,15884
|
|
213
214
|
DIRAC/Core/Tornado/Server/TornadoServer.py,sha256=VAVtrk9zRdm4WiJDB-RhJ0sqmfmUBImZzJh4Cy_E5-o,11823
|
|
214
|
-
DIRAC/Core/Tornado/Server/TornadoService.py,sha256=
|
|
215
|
+
DIRAC/Core/Tornado/Server/TornadoService.py,sha256=ej-5GrKjKi9BNN0VJICIt4NA0vS2Ig2nfQ880wMs10E,9015
|
|
215
216
|
DIRAC/Core/Tornado/Server/__init__.py,sha256=cO7z-h1lVEu7RRPYeY3BZLJu-FZH9p7Gvuukw1ZgcME,31
|
|
216
217
|
DIRAC/Core/Tornado/Server/private/BaseRequestHandler.py,sha256=WbNLdwa3Vz6x7CndZ-7BlHzN1VihFUdyWBOyuzrbXNQ,42813
|
|
217
218
|
DIRAC/Core/Tornado/Server/private/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -301,7 +302,7 @@ DIRAC/Core/Utilities/test/Test_Network.py,sha256=n1m1OB9JIEqT4AGz_DKt9QOgMOsV6m5
|
|
|
301
302
|
DIRAC/Core/Utilities/test/Test_ObjectLoader.py,sha256=PfDjfnPNNByC7Ropkfl8qrkjUWFJ702wRmH7_0_Qg9Q,968
|
|
302
303
|
DIRAC/Core/Utilities/test/Test_Pfn.py,sha256=XWTXejQf_TnicaPbQ4ZyDsl1KXDpq3IMNFlQ2cM3140,7398
|
|
303
304
|
DIRAC/Core/Utilities/test/Test_ProcessPool.py,sha256=NnfHNkhTOgADk-P9ds_ADuvcSNlK_XdoibRkk13r_NE,10890
|
|
304
|
-
DIRAC/Core/Utilities/test/Test_Profiler.py,sha256=
|
|
305
|
+
DIRAC/Core/Utilities/test/Test_Profiler.py,sha256=8QRRXm-PwJpjLGwAOJxnrpnnMbmVzXhJ1ZcQ9gDBX5c,4215
|
|
305
306
|
DIRAC/Core/Utilities/test/Test_ReturnValues.py,sha256=w6Jz-Vblgu8RDXPzVi6BZjuFXcSmW-Zb0mcBgW1RWOw,1926
|
|
306
307
|
DIRAC/Core/Utilities/test/Test_Subprocess.py,sha256=nAiVF5oMnle-4E8ijlWF-ilBfgN2VGkkFQQSKhIKN2o,2141
|
|
307
308
|
DIRAC/Core/Utilities/test/Test_entrypoints.py,sha256=z_3f7m59v3W6ZsqgeCFbJoBnMY-cKR_blKbPqcV7528,413
|
|
@@ -389,7 +390,7 @@ DIRAC/DataManagementSystem/DB/FileCatalogWithFkAndPsDB.sql,sha256=HhPwoKQzpY76Ev
|
|
|
389
390
|
DIRAC/DataManagementSystem/DB/__init__.py,sha256=wYM6m2zwnPwfEDyFr8zn3nxsz8ScG0rcK9o3ZTMS1o0,49
|
|
390
391
|
DIRAC/DataManagementSystem/DB/FileCatalogComponents/Utilities.py,sha256=9ISL04-ODyzbV1L6OJce-NNC8s32JVioZ3ZZ2xRYvNw,584
|
|
391
392
|
DIRAC/DataManagementSystem/DB/FileCatalogComponents/__init__.py,sha256=9cXeiZx0oIpGUDNV_xAak5eTRF8Qgu8HDtLVlb3tclA,38
|
|
392
|
-
DIRAC/DataManagementSystem/DB/FileCatalogComponents/DatasetManager/DatasetManager.py,sha256=
|
|
393
|
+
DIRAC/DataManagementSystem/DB/FileCatalogComponents/DatasetManager/DatasetManager.py,sha256=SUj6xTS3s6l1oWfStLho6HSua-EQzs65VQxnLkVNx5M,31123
|
|
393
394
|
DIRAC/DataManagementSystem/DB/FileCatalogComponents/DatasetManager/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
394
395
|
DIRAC/DataManagementSystem/DB/FileCatalogComponents/DirectoryManager/DirectoryClosure.py,sha256=vsLBKYiZKdgq1MLuZRbofxI23Jio2ha7JIwFzU42tLk,23739
|
|
395
396
|
DIRAC/DataManagementSystem/DB/FileCatalogComponents/DirectoryManager/DirectoryFlatTree.py,sha256=uQzlQ1JMnC9SgL1r0PfBJDF5an--rk-KhbBGWyjPin8,8536
|
|
@@ -460,7 +461,7 @@ DIRAC/DataManagementSystem/scripts/dirac_dms_catalog_metadata.py,sha256=K8Wz_zyb
|
|
|
460
461
|
DIRAC/DataManagementSystem/scripts/dirac_dms_change_replica_status.py,sha256=_3yhBq7gWo_iQQNujT0BDy6sUcroojGyBN1KJnDnhFk,1778
|
|
461
462
|
DIRAC/DataManagementSystem/scripts/dirac_dms_clean_directory.py,sha256=0SzIyRoiu1TlFIOyTyUkTehH8Ltn7arVY9u-67c7XDI,1782
|
|
462
463
|
DIRAC/DataManagementSystem/scripts/dirac_dms_create_archive_request.py,sha256=h1ucu6TooaQIfF26tules2s1YEIN_QC7OomczrJ9MOU,22462
|
|
463
|
-
DIRAC/DataManagementSystem/scripts/dirac_dms_create_moving_request.py,sha256=
|
|
464
|
+
DIRAC/DataManagementSystem/scripts/dirac_dms_create_moving_request.py,sha256=7tPUPevaRaQ4ACM0nJ8DSl0Ad70QfJ8RMzwonJVTs1s,11561
|
|
464
465
|
DIRAC/DataManagementSystem/scripts/dirac_dms_create_removal_request.py,sha256=r_i8wi5-24L7Ij5uFG-TKojkCYFeHuzbjT0mfbbkNos,3535
|
|
465
466
|
DIRAC/DataManagementSystem/scripts/dirac_dms_data_size.py,sha256=XAL34mlKcgE1XfqSHAxMpFiXMBiihKMwBNrD0utiWfs,2478
|
|
466
467
|
DIRAC/DataManagementSystem/scripts/dirac_dms_directory_sync.py,sha256=UaEubXTbVqHkQid7f59BMlPGwigtPUm9vd1NlYt_qgs,18000
|
|
@@ -592,7 +593,7 @@ DIRAC/FrameworkSystem/scripts/dirac_stop_component.py,sha256=RJJy63ilUEV5qyP_r2i
|
|
|
592
593
|
DIRAC/FrameworkSystem/scripts/dirac_sys_sendmail.py,sha256=lJ6OO_vkaSVhXp_p79LYTZoq9jT5qLU0qXOfFEgK9fw,2453
|
|
593
594
|
DIRAC/FrameworkSystem/scripts/dirac_uninstall_component.py,sha256=FTA2zA0cACM31u_uFZgsUYC6S0Fh3xmkqDjgOPdFr4k,2797
|
|
594
595
|
DIRAC/Interfaces/__init__.py,sha256=hycApm2mNnIWcdIzoOKQZLa8-LpSpfG2jdfgyKGN9Gg,34
|
|
595
|
-
DIRAC/Interfaces/API/Dirac.py,sha256=
|
|
596
|
+
DIRAC/Interfaces/API/Dirac.py,sha256=alMGB5YV2Oyo44G2k_jdSSvHRhZz0WmN3bMBeXgN11I,94619
|
|
596
597
|
DIRAC/Interfaces/API/DiracAdmin.py,sha256=PDwWl1KCckL2xhLodeWJhVS4ZondNvfdbTUEE3pukXA,28135
|
|
597
598
|
DIRAC/Interfaces/API/Job.py,sha256=FFYNMWaWvcC9ZGDQ2gZhpnFBijjRUFZvcyIIU4PQqC8,50650
|
|
598
599
|
DIRAC/Interfaces/API/__init__.py,sha256=l_0g05W4nsJ9-kvp9yKYsbdLz3EvWczOfdycoPnwlvU,566
|
|
@@ -694,15 +695,15 @@ DIRAC/MonitoringSystem/Client/Types/RMSMonitoring.py,sha256=DzmMIY22YKazfmfv8kOG
|
|
|
694
695
|
DIRAC/MonitoringSystem/Client/Types/ServiceMonitoring.py,sha256=IZ_SIJbv8Eoub2DbbjKjSqlj0xNMU6wU9tX4EtOFU40,1491
|
|
695
696
|
DIRAC/MonitoringSystem/Client/Types/WMSHistory.py,sha256=MHQ9tIJXoaX4lFPD4XivJRLO8Z1-QK28rzJf_IvNYKk,1488
|
|
696
697
|
DIRAC/MonitoringSystem/Client/Types/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
697
|
-
DIRAC/MonitoringSystem/DB/MonitoringDB.py,sha256=
|
|
698
|
+
DIRAC/MonitoringSystem/DB/MonitoringDB.py,sha256=4PH3x12cF-uyc0eyVVom7zvuZFduVlN10nVxwvJfSyw,19207
|
|
698
699
|
DIRAC/MonitoringSystem/DB/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
699
700
|
DIRAC/MonitoringSystem/DB/test/Test_monitoringdb.py,sha256=Jf4NZgb9V6U4DYk4SCLVoTqxJVBYsj49rIaYB7e6qxw,2788
|
|
700
701
|
DIRAC/MonitoringSystem/Service/MonitoringHandler.py,sha256=JGN1MUsxP8swTuIa4qdPvo-O4UoA6TkxjfDZ1sC6L2w,12332
|
|
701
702
|
DIRAC/MonitoringSystem/Service/TornadoMonitoringHandler.py,sha256=06gIHrrLJTgI-vnCHAGsDDjZrRwJaMsa8ESsdWy0Ir8,1550
|
|
702
|
-
DIRAC/MonitoringSystem/Service/WebAppHandler.py,sha256=
|
|
703
|
+
DIRAC/MonitoringSystem/Service/WebAppHandler.py,sha256=utTyM5L28jEli_ZNeg5S4-prT4c38aeJHDhgyI-Sr-4,23148
|
|
703
704
|
DIRAC/MonitoringSystem/Service/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
704
705
|
DIRAC/MonitoringSystem/private/DBUtils.py,sha256=bBEJoy3KCaYi7tIAmNdCIUF5K5-oJAS3qJn0ngpo-HQ,7163
|
|
705
|
-
DIRAC/MonitoringSystem/private/MainReporter.py,sha256=
|
|
706
|
+
DIRAC/MonitoringSystem/private/MainReporter.py,sha256=a1yTBMA_wQIzohugtV_MXxiwV7Qo1e2bGrJQZFO93Go,3433
|
|
706
707
|
DIRAC/MonitoringSystem/private/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
707
708
|
DIRAC/MonitoringSystem/private/Plotters/BasePlotter.py,sha256=8r0CVv9XyzZ15H_1rwsMFhyMGcV_ZYc8ZmPcFCBqWFE,16710
|
|
708
709
|
DIRAC/MonitoringSystem/private/Plotters/RMSMonitoringPlotter.py,sha256=16oVdQjGo2VcWr02ChG4rEZCsVxqsocHzdLyJpcA3i4,3123
|
|
@@ -734,10 +735,10 @@ DIRAC/ProductionSystem/scripts/dirac_prod_get_description.py,sha256=tKrlr-yIUfMQ
|
|
|
734
735
|
DIRAC/ProductionSystem/scripts/dirac_prod_get_trans.py,sha256=I7JK2IbS-lyI239IMJoZwPIDIoRXxVUtZDHdlkwtIBY,3002
|
|
735
736
|
DIRAC/ProductionSystem/scripts/dirac_prod_start.py,sha256=Xr4tdgN41toQRWPJnLF5Nx3xq40PteVI0OTz3t7ehOI,795
|
|
736
737
|
DIRAC/ProductionSystem/scripts/dirac_prod_stop.py,sha256=sqIvlmTPHtSCn94knJGiPfPiPu7geAngI-IHcfbaE2U,794
|
|
737
|
-
DIRAC/RequestManagementSystem/ConfigTemplate.cfg,sha256=
|
|
738
|
+
DIRAC/RequestManagementSystem/ConfigTemplate.cfg,sha256=IE4HILrLKI9qqnJ3EnoIEH3J3B3qCa7frhTp0DqL7yo,3777
|
|
738
739
|
DIRAC/RequestManagementSystem/__init__.py,sha256=dd54oqlSYTanQrw2iGyzp_dipGTtvP2VlUrYZzGQI5Q,49
|
|
739
740
|
DIRAC/RequestManagementSystem/Agent/CleanReqDBAgent.py,sha256=wcXEZPfxU9yoiOSM7qQi9lzA-ilsIezc45xWWxLXKJA,7286
|
|
740
|
-
DIRAC/RequestManagementSystem/Agent/RequestExecutingAgent.py,sha256=
|
|
741
|
+
DIRAC/RequestManagementSystem/Agent/RequestExecutingAgent.py,sha256=U2MzS_eYuQykpwyR7XkWQjXKhmp3CoBCXxnBK7cBVeM,20138
|
|
741
742
|
DIRAC/RequestManagementSystem/Agent/__init__.py,sha256=hr-uMJaL3v8Mrx1Mm-xPOpI7xJCzWmoRt21mHQLjGJc,55
|
|
742
743
|
DIRAC/RequestManagementSystem/Agent/RequestOperations/ForwardDISET.py,sha256=tre5SjRM-9U0uZJ-Ajup1_6pe2bc3UjwsIXueJtHe7E,3418
|
|
743
744
|
DIRAC/RequestManagementSystem/Agent/RequestOperations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -945,7 +946,7 @@ DIRAC/Resources/Computing/test/Test_InProcessComputingElement.py,sha256=j_ESF_f7
|
|
|
945
946
|
DIRAC/Resources/Computing/test/Test_PoolComputingElement.py,sha256=Vmil6Z9bazv_AKeenma7LznzJAdrUf2xKMQ6HP0PhLE,11860
|
|
946
947
|
DIRAC/Resources/Computing/test/Test_SSHComputingElement.py,sha256=ahYUZ9hySaEXik3nvUMWJ7eP87xj6u-LMDpX7A1OQd4,2425
|
|
947
948
|
DIRAC/Resources/Computing/test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
948
|
-
DIRAC/Resources/IdProvider/CheckInIdProvider.py,sha256=
|
|
949
|
+
DIRAC/Resources/IdProvider/CheckInIdProvider.py,sha256=Tq8ENK6yhC7Tl6JkTF1q8mCOrFRfsN3ediF251iU4oM,1163
|
|
949
950
|
DIRAC/Resources/IdProvider/IAMIdProvider.py,sha256=kk2ty2mLevxGmJRBpLYlQXce_vy4cxp-dO2w7b1rCz0,822
|
|
950
951
|
DIRAC/Resources/IdProvider/IdProviderFactory.py,sha256=-MbDuQ7bIGcBhaHDAlA9NUzgC6VwMlujfHUOwf8uzEE,3899
|
|
951
952
|
DIRAC/Resources/IdProvider/OAuth2IdProvider.py,sha256=smoGhSD1JsyjJDot9XmMUmT7fw8kcfS3w392s2Lg9P8,23650
|
|
@@ -1048,7 +1049,7 @@ DIRAC/TransformationSystem/Agent/DataRecoveryAgent.py,sha256=JUfOBQd0U2uz9WvvArB
|
|
|
1048
1049
|
DIRAC/TransformationSystem/Agent/InputDataAgent.py,sha256=YdxfB1wb55MBgZAuWNuqx_zXHaxTAEGCKYikr0eZaD8,8085
|
|
1049
1050
|
DIRAC/TransformationSystem/Agent/MCExtensionAgent.py,sha256=0pmfiy8FTH670Vv3Md6TPo5iAXsu9y1e-1ybIOTQJPY,5266
|
|
1050
1051
|
DIRAC/TransformationSystem/Agent/RequestTaskAgent.py,sha256=0FxuRVONDkC6DtDqfSC4LeZmheaevBsrh4yvan0DtVc,2689
|
|
1051
|
-
DIRAC/TransformationSystem/Agent/TaskManagerAgentBase.py,sha256=
|
|
1052
|
+
DIRAC/TransformationSystem/Agent/TaskManagerAgentBase.py,sha256=v61j-e_qMQXACENK0JYWa7lMgL0-xNT9irzEdXDHs-8,30652
|
|
1052
1053
|
DIRAC/TransformationSystem/Agent/TransformationAgent.py,sha256=rUPyfX_Ip3ZUyBrmVBrYiddVmgeTx6gKiYPEzwUDOcY,33813
|
|
1053
1054
|
DIRAC/TransformationSystem/Agent/TransformationAgentsUtilities.py,sha256=XrgrjQWSDQm0uxG-wyEY-W0A_MBJyIE-22TafqrLP3A,2805
|
|
1054
1055
|
DIRAC/TransformationSystem/Agent/TransformationCleaningAgent.py,sha256=uAu_aQxko4GF_cTxDxY4KmARqjuytBO89e4XVy5PPUM,32898
|
|
@@ -1094,7 +1095,7 @@ DIRAC/TransformationSystem/Utilities/ScriptUtilities.py,sha256=5HMW2uVoFVQyJGwxe
|
|
|
1094
1095
|
DIRAC/TransformationSystem/Utilities/TransformationInfo.py,sha256=Y1k5JjkODJUZeLQuWaBqJUGK1bPm9flWQD6cn9F-Mf4,8629
|
|
1095
1096
|
DIRAC/TransformationSystem/Utilities/__init__.py,sha256=CrAP4Orxp0lk-GXnu9Gm46BXDNbidViM7YT0FNn1rRo,37
|
|
1096
1097
|
DIRAC/TransformationSystem/scripts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
1097
|
-
DIRAC/TransformationSystem/scripts/dirac_production_runjoblocal.py,sha256=
|
|
1098
|
+
DIRAC/TransformationSystem/scripts/dirac_production_runjoblocal.py,sha256=A8RnNV60icEWAPjuskMVU27pguzoXAz_VBUzmrUAr4o,4708
|
|
1098
1099
|
DIRAC/TransformationSystem/scripts/dirac_transformation_add_files.py,sha256=hY7gaTvfRiNvT7zi1OG2hTFV36U0C5W3AWFcXmKMuhA,1553
|
|
1099
1100
|
DIRAC/TransformationSystem/scripts/dirac_transformation_cli.py,sha256=qhLTZqbnZSrRai3J7102ZQUMJTNxJfSvdK1lb3BCnik,363
|
|
1100
1101
|
DIRAC/TransformationSystem/scripts/dirac_transformation_get_files.py,sha256=bV_vPkeu42ScP-rGXEeBT8JcmZS9O2ZifbHwQsIHECA,802
|
|
@@ -1125,7 +1126,7 @@ DIRAC/WorkloadManagementSystem/Agent/PilotLoggingAgent.py,sha256=ZIgvFpasGTh76GW
|
|
|
1125
1126
|
DIRAC/WorkloadManagementSystem/Agent/PilotStatusAgent.py,sha256=qY6TbYCPOFFXhHffmRJLNEbWvZPyg5Lc5B_8BbyQ7zc,9711
|
|
1126
1127
|
DIRAC/WorkloadManagementSystem/Agent/PilotSyncAgent.py,sha256=qzDFCGZ8EtjxDUaPgyFDlSmJfyF2KLuyXTC7au3-p2Q,4860
|
|
1127
1128
|
DIRAC/WorkloadManagementSystem/Agent/PushJobAgent.py,sha256=IvHshnw2xN0AZrruEu86C47GDez8enBD6jjNIZd6QcA,38594
|
|
1128
|
-
DIRAC/WorkloadManagementSystem/Agent/SiteDirector.py,sha256=
|
|
1129
|
+
DIRAC/WorkloadManagementSystem/Agent/SiteDirector.py,sha256=NkAyYGtht9NO53CX9OmbxBkeUFcfv7tc9CKogD8TtVU,45131
|
|
1129
1130
|
DIRAC/WorkloadManagementSystem/Agent/StalledJobAgent.py,sha256=foEbmRotEmfeQG6nyIsJv1kSJkm4flkQsPYbSylS3SM,24572
|
|
1130
1131
|
DIRAC/WorkloadManagementSystem/Agent/StatesAccountingAgent.py,sha256=iNIlWQEDBk6R1S8oHOIusZUwxOwLtgwuzR_4s32-o5w,8707
|
|
1131
1132
|
DIRAC/WorkloadManagementSystem/Agent/TaskQueuesAgent.py,sha256=ypsmo233TFXq9IC5uz6pum7_joOh2gFPUYNmmCpukAY,943
|
|
@@ -1135,7 +1136,7 @@ DIRAC/WorkloadManagementSystem/Agent/test/Test_Agent_JobCleaningAgent.py,sha256=
|
|
|
1135
1136
|
DIRAC/WorkloadManagementSystem/Agent/test/Test_Agent_PilotLoggingAgent.py,sha256=KpvaqAaTaCXUpbdBpA_n7At3284XKYwx8GpC3Ah7cHg,8611
|
|
1136
1137
|
DIRAC/WorkloadManagementSystem/Agent/test/Test_Agent_PilotStatusAgent.py,sha256=qOA_U2NYvJprLdrUJirbEVSnvEF9-FuRXNi78MBoffc,2806
|
|
1137
1138
|
DIRAC/WorkloadManagementSystem/Agent/test/Test_Agent_PushJobAgent.py,sha256=Uf5jlnw8mWvQJcOnJXEASEf3Ryo63wZKv8IavQVaOVY,14887
|
|
1138
|
-
DIRAC/WorkloadManagementSystem/Agent/test/Test_Agent_SiteDirector.py,sha256=
|
|
1139
|
+
DIRAC/WorkloadManagementSystem/Agent/test/Test_Agent_SiteDirector.py,sha256=o6imUULkKrvbmkfpvER8wyg0Ncn3gxvJNTNO8xKX7_w,11670
|
|
1139
1140
|
DIRAC/WorkloadManagementSystem/Agent/test/Test_Agent_StalledJobAgent.py,sha256=BgDP1um-5WLSJYDbyHgLUkZocN8TrrG6QvRcffzD02E,1829
|
|
1140
1141
|
DIRAC/WorkloadManagementSystem/Client/CPUNormalization.py,sha256=txBgRfnTAY5KykpKRrK1jp5x4FInWjv-Rja4R7Dqdis,5423
|
|
1141
1142
|
DIRAC/WorkloadManagementSystem/Client/DownloadInputData.py,sha256=JfidM3U2b0z64hk6j0VpQ7fh6eSkRjm1Hw8X-DAspwI,16303
|
|
@@ -1179,12 +1180,12 @@ DIRAC/WorkloadManagementSystem/DB/JobDB.sql,sha256=Fo3cXMrVs6CKZgpTLGXfJrwq3VK0k
|
|
|
1179
1180
|
DIRAC/WorkloadManagementSystem/DB/JobDBUtils.py,sha256=Tj7DrkKFrSZxkW9eqlw9_d66PgoeH83VAwWAqVVr_ZI,1595
|
|
1180
1181
|
DIRAC/WorkloadManagementSystem/DB/JobLoggingDB.py,sha256=YiXQQu6WvBWwkknTch9_z43Ubzj0aRhw18SFNzni2z8,7603
|
|
1181
1182
|
DIRAC/WorkloadManagementSystem/DB/JobLoggingDB.sql,sha256=hYmXOj5qGeLVSPZdipGjyVRaCcLmIxrFb7nXQ1QJrI0,1869
|
|
1182
|
-
DIRAC/WorkloadManagementSystem/DB/JobParametersDB.py,sha256=
|
|
1183
|
+
DIRAC/WorkloadManagementSystem/DB/JobParametersDB.py,sha256=KZd55o8VryjbWn2CdgKixAmAbj8W9lwmD_n_jlPb7z0,7771
|
|
1183
1184
|
DIRAC/WorkloadManagementSystem/DB/PilotAgentsDB.py,sha256=tUSuhv59CQgB7NkxsXo5r-VGXRTZ6Q4dOdhjmRi1yyg,44480
|
|
1184
1185
|
DIRAC/WorkloadManagementSystem/DB/PilotAgentsDB.sql,sha256=RnCDCDGa__7sDxjSFGlu_5OwKbzxeK3a9TOMpV5ftRw,2738
|
|
1185
|
-
DIRAC/WorkloadManagementSystem/DB/SandboxMetadataDB.py,sha256=
|
|
1186
|
+
DIRAC/WorkloadManagementSystem/DB/SandboxMetadataDB.py,sha256=L_ywrVuoKlZpx07xydRY1JbMjj5-UteB1Eg8fJKF6CI,15615
|
|
1186
1187
|
DIRAC/WorkloadManagementSystem/DB/SandboxMetadataDB.sql,sha256=2TcyLiewFuPWqBhD43geHG0obCFRGTSLbQwPUwENYnQ,23
|
|
1187
|
-
DIRAC/WorkloadManagementSystem/DB/StatusUtils.py,sha256=
|
|
1188
|
+
DIRAC/WorkloadManagementSystem/DB/StatusUtils.py,sha256=cVVNiZlVbp0B-4MpkpXATlSLRtubsL6iGx4-U4KP2A4,5125
|
|
1188
1189
|
DIRAC/WorkloadManagementSystem/DB/TaskQueueDB.py,sha256=4ClljoQUnHKq1KHAIFpUwL_5-NrUUuM8oHKzOZULXZg,54623
|
|
1189
1190
|
DIRAC/WorkloadManagementSystem/DB/TaskQueueDB.sql,sha256=GfeceE3VY7l15pMwt6MzI8pGqdk772XuIg_DE0vkj74,541
|
|
1190
1191
|
DIRAC/WorkloadManagementSystem/DB/__init__.py,sha256=1H5briNEaZlSL6pMxzjDmkZkVvGxHix8DtfkM-mOwGc,53
|
|
@@ -1203,13 +1204,13 @@ DIRAC/WorkloadManagementSystem/FutureClient/JobMonitoringClient.py,sha256=3Mjq3h
|
|
|
1203
1204
|
DIRAC/WorkloadManagementSystem/FutureClient/JobStateUpdateClient.py,sha256=PG3JkQPgmPacjTLTCHTobZeKys4nxObs0D_Axfrl2Uw,6650
|
|
1204
1205
|
DIRAC/WorkloadManagementSystem/FutureClient/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
1205
1206
|
DIRAC/WorkloadManagementSystem/JobWrapper/JobExecutionCoordinator.py,sha256=Y64YnkrKklOkXnV5wKsgzBONFljVJ0ByFVUMFNkiGAU,2461
|
|
1206
|
-
DIRAC/WorkloadManagementSystem/JobWrapper/JobWrapper.py,sha256=
|
|
1207
|
+
DIRAC/WorkloadManagementSystem/JobWrapper/JobWrapper.py,sha256=s_YHg_PsTGVHBLrS1QkbPGcarWf2xDHeXAKSS3s2fxc,74795
|
|
1207
1208
|
DIRAC/WorkloadManagementSystem/JobWrapper/JobWrapperOfflineTemplate.py,sha256=wem5VDN9XiC7szAzdsbgHUxpIOQB2Hj36DIVMoV9px8,2490
|
|
1208
1209
|
DIRAC/WorkloadManagementSystem/JobWrapper/JobWrapperTemplate.py,sha256=4QgcFPMLRaTagP9e_Vvsla8pFH8HdewklHfS-gyS4-g,3313
|
|
1209
1210
|
DIRAC/WorkloadManagementSystem/JobWrapper/JobWrapperUtilities.py,sha256=5w_4PMnaHhuexChADDvt1L9Ih1PstdUuYWObnlv9Dto,10072
|
|
1210
1211
|
DIRAC/WorkloadManagementSystem/JobWrapper/Watchdog.py,sha256=wGpIdnyVzI5T9agxNp94gmPZPceXWREaJiEtZg1lAzk,39997
|
|
1211
1212
|
DIRAC/WorkloadManagementSystem/JobWrapper/__init__.py,sha256=e9Oa_ddNLweR3Lp_HOMK6WqqCWWj2SLPxF5UH4F19ic,61
|
|
1212
|
-
DIRAC/WorkloadManagementSystem/JobWrapper/test/Test_JobWrapper.py,sha256=
|
|
1213
|
+
DIRAC/WorkloadManagementSystem/JobWrapper/test/Test_JobWrapper.py,sha256=R9onrrnfyc1v4USt2nnvrYHFo5tKbpLjhMkXl4n0y2Y,39177
|
|
1213
1214
|
DIRAC/WorkloadManagementSystem/JobWrapper/test/Test_JobWrapperTemplate.py,sha256=dC_SvC5Rlchlj2NvBfN7FH1ioXgC8bf9U8BQnEL5GYg,21982
|
|
1214
1215
|
DIRAC/WorkloadManagementSystem/JobWrapper/test/Test_Watchdog.py,sha256=a-QJ1E1ZcWObhOVgxZYD_nYjseCWsbjT0KxjZDNWyAQ,882
|
|
1215
1216
|
DIRAC/WorkloadManagementSystem/JobWrapper/test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -1294,9 +1295,9 @@ DIRAC/tests/Workflow/Integration/exe-script.py,sha256=B_slYdTocEzqfQLRhwuPiLyYUn
|
|
|
1294
1295
|
DIRAC/tests/Workflow/Integration/helloWorld.py,sha256=tBgEHH3ZF7ZiTS57gtmm3DW-Qxgm_57HWHpM-Y8XSws,205
|
|
1295
1296
|
DIRAC/tests/Workflow/Regression/helloWorld.py,sha256=69eCgFuVSYo-mK3Dj2dw1c6g86sF5FksKCf8V2aGVoM,509
|
|
1296
1297
|
DIRAC/tests/Workflow/Regression/helloWorld.xml,sha256=xwydIcFTAHIX-YPfQfyxuQ7hzvIO3IhR3UAF7ORgkGg,5310
|
|
1297
|
-
dirac-9.0.
|
|
1298
|
-
dirac-9.0.
|
|
1299
|
-
dirac-9.0.
|
|
1300
|
-
dirac-9.0.
|
|
1301
|
-
dirac-9.0.
|
|
1302
|
-
dirac-9.0.
|
|
1298
|
+
dirac-9.0.2.dist-info/licenses/LICENSE,sha256=uyr4oV6jmjUeepXZPPjkJRwa5q5MrI7jqJz5sVXNblQ,32452
|
|
1299
|
+
dirac-9.0.2.dist-info/METADATA,sha256=NsAJ9M22XU_J_isgLyqx_7xbnY537MZjVkISWDPJE3c,9988
|
|
1300
|
+
dirac-9.0.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
1301
|
+
dirac-9.0.2.dist-info/entry_points.txt,sha256=hupzIL8aVmjK3nn7RLKdhcaiPmLOiD3Kulh3CSDHKmw,16492
|
|
1302
|
+
dirac-9.0.2.dist-info/top_level.txt,sha256=RISrnN9kb_mPqmVu8_o4jF-DSX8-h6AcgfkO9cgfkHA,6
|
|
1303
|
+
dirac-9.0.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|