rucio-clients 37.2.0__py3-none-any.whl → 37.4.0__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.

Potentially problematic release.


This version of rucio-clients might be problematic. Click here for more details.

Files changed (39) hide show
  1. rucio/cli/rule.py +1 -1
  2. rucio/client/accountclient.py +205 -60
  3. rucio/client/accountlimitclient.py +84 -25
  4. rucio/client/baseclient.py +85 -48
  5. rucio/client/client.py +49 -41
  6. rucio/client/configclient.py +36 -13
  7. rucio/client/credentialclient.py +16 -6
  8. rucio/client/didclient.py +321 -133
  9. rucio/client/diracclient.py +13 -6
  10. rucio/client/downloadclient.py +435 -165
  11. rucio/client/exportclient.py +8 -2
  12. rucio/client/fileclient.py +10 -3
  13. rucio/client/importclient.py +4 -1
  14. rucio/client/lifetimeclient.py +48 -31
  15. rucio/client/lockclient.py +22 -7
  16. rucio/client/metaconventionsclient.py +59 -21
  17. rucio/client/pingclient.py +3 -1
  18. rucio/client/replicaclient.py +213 -96
  19. rucio/client/requestclient.py +123 -16
  20. rucio/client/rseclient.py +385 -160
  21. rucio/client/ruleclient.py +147 -51
  22. rucio/client/scopeclient.py +35 -10
  23. rucio/client/subscriptionclient.py +60 -27
  24. rucio/client/touchclient.py +16 -7
  25. rucio/common/plugins.py +1 -1
  26. rucio/vcsversion.py +3 -3
  27. {rucio_clients-37.2.0.data → rucio_clients-37.4.0.data}/data/etc/rucio.cfg.template +0 -1
  28. {rucio_clients-37.2.0.dist-info → rucio_clients-37.4.0.dist-info}/METADATA +1 -1
  29. {rucio_clients-37.2.0.dist-info → rucio_clients-37.4.0.dist-info}/RECORD +39 -39
  30. {rucio_clients-37.2.0.dist-info → rucio_clients-37.4.0.dist-info}/WHEEL +1 -1
  31. {rucio_clients-37.2.0.data → rucio_clients-37.4.0.data}/data/etc/rse-accounts.cfg.template +0 -0
  32. {rucio_clients-37.2.0.data → rucio_clients-37.4.0.data}/data/etc/rucio.cfg.atlas.client.template +0 -0
  33. {rucio_clients-37.2.0.data → rucio_clients-37.4.0.data}/data/requirements.client.txt +0 -0
  34. {rucio_clients-37.2.0.data → rucio_clients-37.4.0.data}/data/rucio_client/merge_rucio_configs.py +0 -0
  35. {rucio_clients-37.2.0.data → rucio_clients-37.4.0.data}/scripts/rucio +0 -0
  36. {rucio_clients-37.2.0.data → rucio_clients-37.4.0.data}/scripts/rucio-admin +0 -0
  37. {rucio_clients-37.2.0.dist-info → rucio_clients-37.4.0.dist-info}/licenses/AUTHORS.rst +0 -0
  38. {rucio_clients-37.2.0.dist-info → rucio_clients-37.4.0.dist-info}/licenses/LICENSE +0 -0
  39. {rucio_clients-37.2.0.dist-info → rucio_clients-37.4.0.dist-info}/top_level.txt +0 -0
@@ -33,9 +33,14 @@ class ReplicaClient(BaseClient):
33
33
  """
34
34
  Add quaratined replicas for RSE.
35
35
 
36
- :param replicas: List of replica infos: {'scope': <scope> (optional), 'name': <name> (optional), 'path':<path> (required)}.
37
- :param rse: RSE name.
38
- :param rse_id: RSE id. Either RSE name or RSE id must be specified, but not both
36
+ Parameters
37
+ ----------
38
+ replicas :
39
+ List of replica infos: {'scope': <scope> (optional), 'name': <name> (optional), 'path':<path> (required)}.
40
+ rse :
41
+ RSE name.
42
+ rse_id :
43
+ RSE id. Either RSE name or RSE id must be specified, but not both.
39
44
  """
40
45
 
41
46
  if (rse is None) == (rse_id is None):
@@ -54,10 +59,19 @@ class ReplicaClient(BaseClient):
54
59
  """
55
60
  Declare a list of bad replicas.
56
61
 
57
- :param replicas: Either a list of PFNs (string) or a list of dicts {'scope': <scope>, 'name': <name>, 'rse_id': <rse_id> or 'rse': <rse_name>}
58
- :param reason: The reason of the loss.
59
- :param force: boolean, tell the serrver to ignore existing replica status in the bad_replicas table. Default: False
60
- :returns: Dictionary {"rse_name": ["did: error",...]} - list of strings for DIDs failed to declare, by RSE
62
+ Parameters
63
+ ----------
64
+ replicas :
65
+ Either a list of PFNs (string) or a list of dicts {'scope': <scope>, 'name': <name>, 'rse_id': <rse_id> or 'rse': <rse_name>}
66
+ reason :
67
+ The reason of the loss.
68
+ force :
69
+ Tell the server to ignore existing replica status in the bad_replicas table. Default: False
70
+
71
+ Returns
72
+ -------
73
+
74
+ Dictionary of the form {"rse_name": ["did: error",...]} - list of strings for DIDs failed to declare, by RSE
61
75
  """
62
76
 
63
77
  out = {} # {rse: ["did: error text",...]}
@@ -79,9 +93,14 @@ class ReplicaClient(BaseClient):
79
93
  """
80
94
  Declare a list of bad replicas.
81
95
 
82
- :param rse: The RSE where the bad replicas reside
83
- :param dids: The DIDs of the bad replicas
84
- :param reason: The reason of the loss.
96
+ Parameters
97
+ ----------
98
+ rse :
99
+ The RSE where the bad replicas reside.
100
+ dids :
101
+ The DIDs of the bad replicas.
102
+ reason :
103
+ The reason of the loss.
85
104
  """
86
105
  data = {'reason': reason, 'rse': rse, 'dids': dids}
87
106
  url = build_url(self.host, path='/'.join([self.REPLICAS_BASEURL, 'bad/dids']))
@@ -96,8 +115,13 @@ class ReplicaClient(BaseClient):
96
115
  """
97
116
  Declare a list of bad replicas.
98
117
 
99
- :param pfns: The list of PFNs.
100
- :param reason: The reason of the loss.
118
+ Parameters
119
+ ----------
120
+ pfns:
121
+ The list of PFNs.
122
+ reason:
123
+ The reason of the loss.
124
+
101
125
  """
102
126
  data = {'reason': reason, 'pfns': pfns}
103
127
  url = build_url(self.host, path='/'.join([self.REPLICAS_BASEURL, 'suspicious']))
@@ -110,11 +134,14 @@ class ReplicaClient(BaseClient):
110
134
 
111
135
  def get_did_from_pfns(self, pfns, rse=None):
112
136
  """
113
- Get the DIDs associated to a PFN on one given RSE
137
+ Get the DIDs associated to a PFN on one given RSE.
114
138
 
115
- :param pfns: The list of PFNs.
116
- :param rse: The RSE name.
117
- :returns: A list of dictionaries {pfn: {'scope': scope, 'name': name}}
139
+ Parameters
140
+ ----------
141
+ pfns :
142
+ The list of PFNs.
143
+ rse :
144
+ The RSE name.
118
145
  """
119
146
  data = {'rse': rse, 'pfns': pfns}
120
147
  url = build_url(self.host, path='/'.join([self.REPLICAS_BASEURL, 'dids']))
@@ -134,24 +161,44 @@ class ReplicaClient(BaseClient):
134
161
  """
135
162
  List file replicas for a list of data identifiers (DIDs).
136
163
 
137
- :param dids: The list of data identifiers (DIDs) like :
164
+ Parameters
165
+ ----------
166
+ dids:
167
+ The list of data identifiers (DIDs) like :
138
168
  [{'scope': <scope1>, 'name': <name1>}, {'scope': <scope2>, 'name': <name2>}, ...]
139
- :param schemes: A list of schemes to filter the replicas. (e.g. file, http, ...)
140
- :param ignore_availability: Also include replicas from blocked RSEs into the list
141
- :param metalink: ``False`` (default) retrieves as JSON,
142
- ``True`` retrieves as metalink4+xml.
143
- :param rse_expression: The RSE expression to restrict replicas on a set of RSEs.
144
- :param client_location: Client location dictionary for PFN modification {'ip', 'fqdn', 'site', 'latitude', 'longitude'}
145
- :param sort: Sort the replicas: ``geoip`` - based on src/dst IP topographical distance
146
- :param domain: Define the domain. None is fallback to 'wan', otherwise 'wan, 'lan', or 'all'
147
- :param signature_lifetime: If supported, in seconds, restrict the lifetime of the signed PFN.
148
- :param nrandom: pick N random replicas. If the initial number of replicas is smaller than N, returns all replicas.
149
- :param resolve_archives: When set to True, find archives which contain the replicas.
150
- :param resolve_parents: When set to True, find all parent datasets which contain the replicas.
151
- :param updated_after: epoch timestamp or datetime object (UTC time), only return replicas updated after this time
152
-
153
- :returns: A list of dictionaries with replica information.
154
-
169
+ schemes:
170
+ A list of schemes to filter the replicas. (e.g. file, http, ...)
171
+ ignore_availability:
172
+ Also include replicas from blocked RSEs into the list
173
+ all_states:
174
+ Include all states of the replicas. Default: False
175
+ metalink:
176
+ ``False`` (default) retrieves as JSON,
177
+ ``True`` retrieves as metalink4+xml.
178
+ rse_expression:
179
+ The RSE expression to restrict replicas on a set of RSEs.
180
+ client_location:
181
+ Client location dictionary for PFN modification {'ip', 'fqdn', 'site', 'latitude', 'longitude'}
182
+ sort:
183
+ Sort the replicas: ``geoip`` - based on src/dst IP topographical distance
184
+ domain:
185
+ Define the domain. None is fallback to 'wan', otherwise 'wan, 'lan', or 'all'
186
+ signature_lifetime:
187
+ If supported, in seconds, restrict the lifetime of the signed PFN.
188
+ nrandom:
189
+ pick N random replicas. If the initial number of replicas is smaller than N, returns all replicas.
190
+ resolve_archives:
191
+ When set to True, find archives which contain the replicas.
192
+ resolve_parents:
193
+ When set to True, find all parent datasets which contain the replicas.
194
+ updated_after:
195
+ epoch timestamp or datetime object (UTC time), only return replicas updated after this time
196
+
197
+
198
+ Returns
199
+ -------
200
+
201
+ A list of dictionaries with replica information.
155
202
  """
156
203
  data = {'dids': dids,
157
204
  'domain': domain}
@@ -208,11 +255,16 @@ class ReplicaClient(BaseClient):
208
255
  """
209
256
  List file replicas tagged as suspicious.
210
257
 
211
- :param rse_expression: The RSE expression to restrict replicas on a set of RSEs.
212
- :param younger_than: Datetime object to select the replicas which were declared since younger_than date. Default value = 10 days ago.
213
- :param nattempts: The minimum number of replica appearances in the bad_replica DB table from younger_than date. Default value = 0.
214
- :param state: State of the replica, either 'BAD' or 'SUSPICIOUS'. No value returns replicas with either state.
215
-
258
+ Parameters
259
+ ----------
260
+ rse_expression:
261
+ The RSE expression to restrict replicas on a set of RSEs.
262
+ younger_than:
263
+ Datetime object to select the replicas which were declared since younger_than date. Default value = 10 days ago.
264
+ nattempts:
265
+ The minimum number of replica appearances in the bad_replica DB table from younger_than date. Default value = 0.
266
+ state:
267
+ State of the replica, either 'BAD' or 'SUSPICIOUS'. No value returns replicas with either state.
216
268
  """
217
269
  params = {}
218
270
  if rse_expression:
@@ -246,17 +298,29 @@ class ReplicaClient(BaseClient):
246
298
  """
247
299
  Add file replicas to a RSE.
248
300
 
249
- :param rse: the RSE name.
250
- :param scope: The scope of the file.
251
- :param name: The name of the file.
252
- :param bytes_: The size in bytes.
253
- :param adler32: adler32 checksum.
254
- :param pfn: PFN of the file for non deterministic RSE.
255
- :param md5: md5 checksum.
256
- :param meta: Metadata attributes.
257
-
258
- :return: True if files were created successfully.
259
-
301
+ Parameters
302
+ ----------
303
+ rse :
304
+ The RSE name.
305
+ scope :
306
+ The scope of the file.
307
+ name :
308
+ The name of the file.
309
+ bytes_ :
310
+ The size in bytes.
311
+ adler32 :
312
+ adler32 checksum.
313
+ pfn :
314
+ PFN of the file for non deterministic RSE.
315
+ md5 :
316
+ md5 checksum.
317
+ meta :
318
+ Metadata attributes.
319
+
320
+ Returns
321
+ -------
322
+
323
+ True if files were created successfully.
260
324
  """
261
325
  meta = meta or {}
262
326
  dict_ = {'scope': scope, 'name': name, 'bytes': bytes_, 'meta': meta, 'adler32': adler32}
@@ -270,13 +334,19 @@ class ReplicaClient(BaseClient):
270
334
  """
271
335
  Bulk add file replicas to a RSE.
272
336
 
273
- :param rse: the RSE name.
274
- :param files: The list of files. This is a list of DIDs like :
337
+ Parameters
338
+ ----------
339
+ rse:
340
+ the RSE name
341
+ files:
342
+ The list of files. This is a list of DIDs like :
275
343
  [{'scope': <scope1>, 'name': <name1>}, {'scope': <scope2>, 'name': <name2>}, ...]
276
- :param ignore_availability: Ignore the RSE blocklsit.
277
-
278
- :return: True if files were created successfully.
344
+ ignore_availability:
345
+ Ignore the RSE blocklist
279
346
 
347
+ Returns
348
+ -------
349
+ True if files were created successfully.
280
350
  """
281
351
  url = build_url(choice(self.list_hosts), path=self.REPLICAS_BASEURL)
282
352
  data = {'rse': rse, 'files': files, 'ignore_availability': ignore_availability}
@@ -289,14 +359,19 @@ class ReplicaClient(BaseClient):
289
359
  def delete_replicas(self, rse, files, ignore_availability=True):
290
360
  """
291
361
  Bulk delete file replicas from a RSE.
292
-
293
- :param rse: the RSE name.
294
- :param files: The list of files. This is a list of DIDs like :
362
+ Parameters
363
+ ----------
364
+ rse:
365
+ the RSE name
366
+ files:
367
+ The list of files. This is a list of DIDs like :
295
368
  [{'scope': <scope1>, 'name': <name1>}, {'scope': <scope2>, 'name': <name2>}, ...]
296
- :param ignore_availability: Ignore the RSE blocklist.
297
-
298
- :return: True if files have been deleted successfully.
369
+ ignore_availability:
370
+ Ignore the RSE blocklist
299
371
 
372
+ Returns
373
+ -------
374
+ True if files have been deleted successfully.
300
375
  """
301
376
  url = build_url(choice(self.list_hosts), path=self.REPLICAS_BASEURL)
302
377
  data = {'rse': rse, 'files': files, 'ignore_availability': ignore_availability}
@@ -307,21 +382,29 @@ class ReplicaClient(BaseClient):
307
382
  raise exc_cls(exc_msg)
308
383
 
309
384
  def update_replicas_states(self, rse, files):
385
+
310
386
  """
387
+
311
388
  Bulk update the file replicas states from a RSE.
312
389
 
313
- :param rse: the RSE name.
314
- :param files: The list of files. This is a list of DIDs like :
390
+ Parameters
391
+ ----------
392
+ rse :
393
+ The RSE name.
394
+ files :
395
+ The list of files. This is a list of DIDs like :
315
396
  [{'scope': <scope1>, 'name': <name1>, 'state': <state1>}, {'scope': <scope2>, 'name': <name2>, 'state': <state2>}, ...],
316
- where a state value can be either of:
317
- 'A' (AVAILABLE)
318
- 'U' (UNAVAILABLE)
319
- 'C' (COPYING)
320
- 'B' (BEING_DELETED)
321
- 'D' (BAD)
322
- 'T' (TEMPORARY_UNAVAILABLE)
323
- :return: True if replica states have been updated successfully, otherwise an exception is raised.
324
-
397
+ Where a state value can be any of:
398
+ * 'A' (AVAILABLE)
399
+ * 'U' (UNAVAILABLE)
400
+ * 'C' (COPYING)
401
+ * 'B' (BEING_DELETED)
402
+ * 'D' (BAD)
403
+ * 'T' (TEMPORARY_UNAVAILABLE)
404
+
405
+ Returns
406
+ -------
407
+ True if replica states have been updated successfully, otherwise an exception is raised.
325
408
  """
326
409
  url = build_url(choice(self.list_hosts), path=self.REPLICAS_BASEURL)
327
410
  data = {'rse': rse, 'files': files}
@@ -335,12 +418,18 @@ class ReplicaClient(BaseClient):
335
418
  """
336
419
  List dataset replicas for a did (scope:name).
337
420
 
338
- :param scope: The scope of the dataset.
339
- :param name: The name of the dataset.
340
- :param deep: Lookup at the file level.
341
-
342
- :returns: A list of dict dataset replicas.
421
+ Parameters
422
+ ----------
423
+ scope:
424
+ The scope of the dataset.
425
+ name:
426
+ The name of the dataset.
427
+ deep:
428
+ Lookup at the file level.
343
429
 
430
+ Returns
431
+ -------
432
+ A list of dict dataset replicas
344
433
  """
345
434
  payload = {}
346
435
  if deep:
@@ -359,9 +448,14 @@ class ReplicaClient(BaseClient):
359
448
  """
360
449
  List dataset replicas for a did (scope:name).
361
450
 
362
- :param dids: The list of DIDs of the datasets.
451
+ Parameters
452
+ ----------
453
+ dids:
454
+ The list of DIDs of the datasets
363
455
 
364
- :returns: A list of dict dataset replicas.
456
+ Returns
457
+ -------
458
+ A list of dict dataset replicas
365
459
  """
366
460
  payload = {'dids': list(dids)}
367
461
  url = build_url(self.host, path='/'.join([self.REPLICAS_BASEURL, 'datasets_bulk']))
@@ -378,11 +472,19 @@ class ReplicaClient(BaseClient):
378
472
 
379
473
  NOTICE: This is an RnD function and might change or go away at any time.
380
474
 
381
- :param scope: The scope of the dataset.
382
- :param name: The name of the dataset.
383
- :param deep: Lookup at the file level.
475
+ Parameters
476
+ ----------
477
+ scope:
478
+ The scope of the dataset.
479
+ name:
480
+ The name of the dataset.
481
+ deep:
482
+ Lookup at the file level.
483
+
484
+ Returns
485
+ -------
486
+ If VP exists a list of dicts of sites
384
487
 
385
- :returns: If VP exists a list of dicts of sites
386
488
  """
387
489
  payload = {}
388
490
  if deep:
@@ -401,12 +503,17 @@ class ReplicaClient(BaseClient):
401
503
  """
402
504
  List datasets at a RSE.
403
505
 
404
- :param rse: the rse name.
405
- :param filters: dictionary of attributes by which the results should be filtered.
406
- :param limit: limit number.
407
-
408
- :returns: A list of dict dataset replicas.
409
-
506
+ Parameters
507
+ ----------
508
+ rse:
509
+ The RSE name.
510
+ filters:
511
+ dictionary of attributes by which the results should be filtered.
512
+ limit:
513
+ limit number.
514
+ Returns
515
+ -------
516
+ A list of dict dataset replicas
410
517
  """
411
518
  url = build_url(self.host, path='/'.join([self.REPLICAS_BASEURL, 'rse', rse]))
412
519
  r = self._send_request(url, type_='GET')
@@ -420,13 +527,20 @@ class ReplicaClient(BaseClient):
420
527
  """
421
528
  Declare a list of bad replicas.
422
529
 
423
- :param pfns: The list of PFNs.
424
- :param reason: The reason of the loss.
425
- :param state: The state of the replica. Either BAD, SUSPICIOUS, TEMPORARY_UNAVAILABLE
426
- :param expires_at: Specify a timeout for the TEMPORARY_UNAVAILABLE replicas. None for BAD files.
427
-
428
- :return: True if PFNs were created successfully.
429
-
530
+ Parameters
531
+ ----------
532
+ pfns:
533
+ The list of PFNs.
534
+ reason:
535
+ The reason of the loss.
536
+ state:
537
+ The state of the replica. Either BAD, SUSPICIOUS, TEMPORARY_UNAVAILABLE
538
+ expires_at:
539
+ Specify a timeout for the TEMPORARY_UNAVAILABLE replicas. None for BAD files.
540
+
541
+ Returns
542
+ -------
543
+ True if PFNs were created successfully.
430
544
  """
431
545
  data = {'reason': reason, 'pfns': pfns, 'state': state, 'expires_at': expires_at}
432
546
  url = build_url(self.host, path='/'.join([self.REPLICAS_BASEURL, 'bad/pfns']))
@@ -441,7 +555,10 @@ class ReplicaClient(BaseClient):
441
555
  """
442
556
  Set a tombstone on a list of replicas.
443
557
 
444
- :param replicas: list of replicas.
558
+ Parameters
559
+ ----------
560
+ replicas:
561
+ list of replicas.
445
562
  """
446
563
  url = build_url(self.host, path='/'.join([self.REPLICAS_BASEURL, 'tombstone']))
447
564
  data = {'replicas': replicas}
@@ -12,13 +12,15 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- from typing import TYPE_CHECKING, Any, Optional
15
+ from json import dumps
16
+ from typing import TYPE_CHECKING, Any, Literal, Optional
16
17
  from urllib.parse import quote_plus
17
18
 
18
19
  from requests.status_codes import codes
19
20
 
20
21
  from rucio.client.baseclient import BaseClient, choice
21
22
  from rucio.common.utils import build_url
23
+ from rucio.db.sqla.constants import TransferLimitDirection
22
24
 
23
25
  if TYPE_CHECKING:
24
26
  from collections.abc import Iterator, Sequence
@@ -36,7 +38,9 @@ class RequestClient(BaseClient):
36
38
  ) -> 'Iterator[dict[str, Any]]':
37
39
  """Return latest request details
38
40
 
39
- :return: request information
41
+ Returns
42
+ -------
43
+ request information
40
44
  """
41
45
  path = '/'.join([self.REQUEST_BASEURL, 'list']) + '?' + '&'.join(['src_rse={}'.format(src_rse), 'dst_rse={}'.format(
42
46
  dst_rse), 'request_states={}'.format(request_states)])
@@ -59,7 +63,9 @@ class RequestClient(BaseClient):
59
63
  ) -> 'Iterator[dict[str, Any]]':
60
64
  """Return historical request details
61
65
 
62
- :return: request information
66
+ Returns
67
+ -------
68
+ request information
63
69
  """
64
70
  path = '/'.join([self.REQUEST_BASEURL, 'history', 'list']) + '?' + '&'.join(['src_rse={}'.format(src_rse), 'dst_rse={}'.format(
65
71
  dst_rse), 'request_states={}'.format(request_states), 'offset={}'.format(offset), 'limit={}'.format(limit)])
@@ -79,12 +85,22 @@ class RequestClient(BaseClient):
79
85
  scope: Optional[str] = None
80
86
  ) -> 'Iterator[dict[str, Any]]':
81
87
  """Return latest request details for a DID
82
-
83
- :param name: DID
84
- :param rse: Destination RSE name
85
- :param scope: rucio scope, defaults to None
86
- :raises exc_cls: from BaseClient._get_exception
87
- :return: request information
88
+ Parameters
89
+ ----------
90
+ name:
91
+ DID
92
+ rse:
93
+ Destination RSE name
94
+ scope:
95
+ rucio scope, defaults to None
96
+
97
+ Raises
98
+ -------
99
+ exc_cls: from BaseClient._get_exception
100
+
101
+ Returns
102
+ -------
103
+ request information
88
104
  """
89
105
 
90
106
  if scope is not None:
@@ -104,13 +120,25 @@ class RequestClient(BaseClient):
104
120
  rse: str,
105
121
  scope: Optional[str] = None
106
122
  ) -> 'Iterator[dict[str, Any]]':
107
- """Return latest request details for a DID
108
-
109
- :param name: DID
110
- :param rse: Destination RSE name
111
- :param scope: rucio scope, defaults to None
112
- :raises exc_cls: from BaseClient._get_exception
113
- :return: request information
123
+ """
124
+ Return latest request details for a DID
125
+
126
+ Parameters
127
+ ----------
128
+ name:
129
+ DID
130
+ rse:
131
+ Destination RSE name
132
+ scope:
133
+ rucio scope, defaults to None
134
+
135
+ Raises
136
+ -------
137
+ exc_cls: from BaseClient._get_exception
138
+
139
+ Returns
140
+ -------
141
+ request information
114
142
  """
115
143
 
116
144
  if scope is not None:
@@ -123,3 +151,82 @@ class RequestClient(BaseClient):
123
151
  else:
124
152
  exc_cls, exc_msg = self._get_exception(headers=r.headers, status_code=r.status_code, data=r.content)
125
153
  raise exc_cls(exc_msg)
154
+
155
+ def list_transfer_limits(
156
+ self
157
+ ) -> 'Iterator[dict[str, Any]]':
158
+ """Returns all the transfer limits
159
+
160
+ :returns: transfer limits
161
+ """
162
+ path = '/'.join([self.REQUEST_BASEURL, 'transfer_limits'])
163
+ url = build_url(choice(self.list_hosts), path=path)
164
+ r = self._send_request(url, type_='GET')
165
+
166
+ if r.status_code == codes.ok:
167
+ return self._load_json_data(r)
168
+ else:
169
+ exc_cls, exc_msg = self._get_exception(headers=r.headers, status_code=r.status_code, data=r.content)
170
+ raise exc_cls(exc_msg)
171
+
172
+ def set_transfer_limit(
173
+ self,
174
+ rse_expression: str,
175
+ activity: Optional[str] = None,
176
+ direction: TransferLimitDirection = TransferLimitDirection.DESTINATION,
177
+ max_transfers: Optional[int] = None,
178
+ volume: Optional[int] = None,
179
+ deadline: Optional[int] = None,
180
+ strategy: Optional[str] = None,
181
+ transfers: Optional[int] = None,
182
+ waitings: Optional[int] = None,
183
+ ) -> Literal[True]:
184
+ """Set the transfer limit for a given RSE
185
+
186
+ :param rse_expression: RSE expression string.
187
+ :param activity: The activity.
188
+ :param direction: The direction in which this limit applies (source/destination)
189
+ :param max_transfers: Maximum transfers.
190
+ :param volume: Maximum transfer volume in bytes.
191
+ :param deadline: Maximum waiting time in hours until a datasets gets released.
192
+ :param strategy: defines how to handle datasets: `fifo` (each file released separately) or `grouped_fifo` (wait for the entire dataset to fit)
193
+ :param transfers: Current number of active transfers
194
+ :param waitings: Current number of waiting transfers
195
+
196
+ :returns: True if the transfer limit was deleted
197
+ """
198
+ path = '/'.join([self.REQUEST_BASEURL, 'transfer_limits'])
199
+ url = build_url(choice(self.list_hosts), path=path)
200
+ data = dumps({'rse_expression': rse_expression, 'activity': activity, 'direction': direction.value,
201
+ 'max_transfers': max_transfers, 'volume': volume, 'deadline': deadline, 'strategy': strategy,
202
+ 'transfers': transfers, 'waitings': waitings})
203
+ r = self._send_request(url, type_='PUT', data=data)
204
+
205
+ if r.status_code == codes.created:
206
+ return True
207
+ exc_cls, exc_msg = self._get_exception(headers=r.headers, status_code=r.status_code, data=r.content)
208
+ raise exc_cls(exc_msg)
209
+
210
+ def delete_transfer_limit(
211
+ self,
212
+ rse_expression: str,
213
+ activity: Optional[str] = None,
214
+ direction: TransferLimitDirection = TransferLimitDirection.DESTINATION
215
+ ) -> Literal[True]:
216
+ """Delete the transfer limit for a given RSE
217
+
218
+ :param rse_expression: RSE expression string.
219
+ :param activity: The activity.
220
+ :param direction: The direction in which this limit applies (source/destination)
221
+
222
+ :returns: True if the transfer limit was deleted
223
+ """
224
+ path = '/'.join([self.REQUEST_BASEURL, 'transfer_limits'])
225
+ url = build_url(choice(self.list_hosts), path=path)
226
+ data = dumps({'rse_expression': rse_expression, 'activity': activity, 'direction': direction.value})
227
+ r = self._send_request(url, type_='DEL', data=data)
228
+
229
+ if r.status_code == codes.ok:
230
+ return True
231
+ exc_cls, exc_msg = self._get_exception(headers=r.headers, status_code=r.status_code, data=r.content)
232
+ raise exc_cls(exc_msg)