rucio 38.3.0__py3-none-any.whl → 38.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 might be problematic. Click here for more details.

Files changed (126) hide show
  1. rucio/cli/did.py +1 -1
  2. rucio/cli/opendata.py +19 -2
  3. rucio/client/accountclient.py +20 -19
  4. rucio/client/accountlimitclient.py +5 -4
  5. rucio/client/baseclient.py +25 -25
  6. rucio/client/configclient.py +7 -6
  7. rucio/client/credentialclient.py +2 -1
  8. rucio/client/didclient.py +33 -32
  9. rucio/client/diracclient.py +2 -1
  10. rucio/client/exportclient.py +2 -1
  11. rucio/client/importclient.py +2 -1
  12. rucio/client/lifetimeclient.py +3 -2
  13. rucio/client/lockclient.py +4 -3
  14. rucio/client/metaconventionsclient.py +5 -4
  15. rucio/client/opendataclient.py +8 -7
  16. rucio/client/pingclient.py +2 -1
  17. rucio/client/replicaclient.py +27 -26
  18. rucio/client/requestclient.py +8 -8
  19. rucio/client/rseclient.py +31 -28
  20. rucio/client/ruleclient.py +13 -12
  21. rucio/client/scopeclient.py +4 -3
  22. rucio/client/subscriptionclient.py +6 -5
  23. rucio/common/constants.py +18 -0
  24. rucio/common/exception.py +20 -0
  25. rucio/common/plugins.py +9 -7
  26. rucio/core/credential.py +19 -26
  27. rucio/core/did.py +1 -1
  28. rucio/core/opendata.py +150 -8
  29. rucio/core/rule_grouping.py +3 -3
  30. rucio/gateway/account.py +8 -7
  31. rucio/gateway/opendata.py +2 -2
  32. rucio/gateway/request.py +2 -117
  33. rucio/rse/protocols/webdav.py +5 -2
  34. rucio/transfertool/fts3.py +0 -19
  35. rucio/vcsversion.py +3 -3
  36. rucio/web/rest/flaskapi/v1/accountlimits.py +4 -3
  37. rucio/web/rest/flaskapi/v1/accounts.py +26 -25
  38. rucio/web/rest/flaskapi/v1/archives.py +2 -2
  39. rucio/web/rest/flaskapi/v1/auth.py +15 -14
  40. rucio/web/rest/flaskapi/v1/common.py +4 -4
  41. rucio/web/rest/flaskapi/v1/config.py +6 -4
  42. rucio/web/rest/flaskapi/v1/credentials.py +3 -3
  43. rucio/web/rest/flaskapi/v1/dids.py +25 -24
  44. rucio/web/rest/flaskapi/v1/dirac.py +3 -2
  45. rucio/web/rest/flaskapi/v1/export.py +4 -2
  46. rucio/web/rest/flaskapi/v1/heartbeats.py +2 -1
  47. rucio/web/rest/flaskapi/v1/identities.py +5 -4
  48. rucio/web/rest/flaskapi/v1/import.py +3 -2
  49. rucio/web/rest/flaskapi/v1/lifetime_exceptions.py +3 -2
  50. rucio/web/rest/flaskapi/v1/locks.py +4 -3
  51. rucio/web/rest/flaskapi/v1/meta_conventions.py +4 -3
  52. rucio/web/rest/flaskapi/v1/metrics.py +2 -1
  53. rucio/web/rest/flaskapi/v1/nongrid_traces.py +2 -1
  54. rucio/web/rest/flaskapi/v1/opendata.py +7 -6
  55. rucio/web/rest/flaskapi/v1/opendata_public.py +6 -5
  56. rucio/web/rest/flaskapi/v1/ping.py +3 -2
  57. rucio/web/rest/flaskapi/v1/redirect.py +4 -3
  58. rucio/web/rest/flaskapi/v1/replicas.py +31 -31
  59. rucio/web/rest/flaskapi/v1/requests.py +7 -7
  60. rucio/web/rest/flaskapi/v1/rses.py +23 -16
  61. rucio/web/rest/flaskapi/v1/rules.py +9 -8
  62. rucio/web/rest/flaskapi/v1/scopes.py +4 -3
  63. rucio/web/rest/flaskapi/v1/subscriptions.py +9 -8
  64. rucio/web/rest/flaskapi/v1/traces.py +2 -1
  65. rucio/web/rest/flaskapi/v1/vos.py +4 -3
  66. {rucio-38.3.0.dist-info → rucio-38.4.0.dist-info}/METADATA +1 -1
  67. {rucio-38.3.0.dist-info → rucio-38.4.0.dist-info}/RECORD +126 -126
  68. {rucio-38.3.0.data → rucio-38.4.0.data}/data/rucio/etc/alembic.ini.template +0 -0
  69. {rucio-38.3.0.data → rucio-38.4.0.data}/data/rucio/etc/alembic_offline.ini.template +0 -0
  70. {rucio-38.3.0.data → rucio-38.4.0.data}/data/rucio/etc/globus-config.yml.template +0 -0
  71. {rucio-38.3.0.data → rucio-38.4.0.data}/data/rucio/etc/ldap.cfg.template +0 -0
  72. {rucio-38.3.0.data → rucio-38.4.0.data}/data/rucio/etc/mail_templates/rule_approval_request.tmpl +0 -0
  73. {rucio-38.3.0.data → rucio-38.4.0.data}/data/rucio/etc/mail_templates/rule_approved_admin.tmpl +0 -0
  74. {rucio-38.3.0.data → rucio-38.4.0.data}/data/rucio/etc/mail_templates/rule_approved_user.tmpl +0 -0
  75. {rucio-38.3.0.data → rucio-38.4.0.data}/data/rucio/etc/mail_templates/rule_denied_admin.tmpl +0 -0
  76. {rucio-38.3.0.data → rucio-38.4.0.data}/data/rucio/etc/mail_templates/rule_denied_user.tmpl +0 -0
  77. {rucio-38.3.0.data → rucio-38.4.0.data}/data/rucio/etc/mail_templates/rule_ok_notification.tmpl +0 -0
  78. {rucio-38.3.0.data → rucio-38.4.0.data}/data/rucio/etc/rse-accounts.cfg.template +0 -0
  79. {rucio-38.3.0.data → rucio-38.4.0.data}/data/rucio/etc/rucio.cfg.atlas.client.template +0 -0
  80. {rucio-38.3.0.data → rucio-38.4.0.data}/data/rucio/etc/rucio.cfg.template +0 -0
  81. {rucio-38.3.0.data → rucio-38.4.0.data}/data/rucio/etc/rucio_multi_vo.cfg.template +0 -0
  82. {rucio-38.3.0.data → rucio-38.4.0.data}/data/rucio/requirements.server.txt +0 -0
  83. {rucio-38.3.0.data → rucio-38.4.0.data}/data/rucio/tools/bootstrap.py +0 -0
  84. {rucio-38.3.0.data → rucio-38.4.0.data}/data/rucio/tools/merge_rucio_configs.py +0 -0
  85. {rucio-38.3.0.data → rucio-38.4.0.data}/data/rucio/tools/reset_database.py +0 -0
  86. {rucio-38.3.0.data → rucio-38.4.0.data}/scripts/rucio +0 -0
  87. {rucio-38.3.0.data → rucio-38.4.0.data}/scripts/rucio-abacus-account +0 -0
  88. {rucio-38.3.0.data → rucio-38.4.0.data}/scripts/rucio-abacus-collection-replica +0 -0
  89. {rucio-38.3.0.data → rucio-38.4.0.data}/scripts/rucio-abacus-rse +0 -0
  90. {rucio-38.3.0.data → rucio-38.4.0.data}/scripts/rucio-admin +0 -0
  91. {rucio-38.3.0.data → rucio-38.4.0.data}/scripts/rucio-atropos +0 -0
  92. {rucio-38.3.0.data → rucio-38.4.0.data}/scripts/rucio-auditor +0 -0
  93. {rucio-38.3.0.data → rucio-38.4.0.data}/scripts/rucio-automatix +0 -0
  94. {rucio-38.3.0.data → rucio-38.4.0.data}/scripts/rucio-bb8 +0 -0
  95. {rucio-38.3.0.data → rucio-38.4.0.data}/scripts/rucio-cache-client +0 -0
  96. {rucio-38.3.0.data → rucio-38.4.0.data}/scripts/rucio-cache-consumer +0 -0
  97. {rucio-38.3.0.data → rucio-38.4.0.data}/scripts/rucio-conveyor-finisher +0 -0
  98. {rucio-38.3.0.data → rucio-38.4.0.data}/scripts/rucio-conveyor-poller +0 -0
  99. {rucio-38.3.0.data → rucio-38.4.0.data}/scripts/rucio-conveyor-preparer +0 -0
  100. {rucio-38.3.0.data → rucio-38.4.0.data}/scripts/rucio-conveyor-receiver +0 -0
  101. {rucio-38.3.0.data → rucio-38.4.0.data}/scripts/rucio-conveyor-stager +0 -0
  102. {rucio-38.3.0.data → rucio-38.4.0.data}/scripts/rucio-conveyor-submitter +0 -0
  103. {rucio-38.3.0.data → rucio-38.4.0.data}/scripts/rucio-conveyor-throttler +0 -0
  104. {rucio-38.3.0.data → rucio-38.4.0.data}/scripts/rucio-dark-reaper +0 -0
  105. {rucio-38.3.0.data → rucio-38.4.0.data}/scripts/rucio-dumper +0 -0
  106. {rucio-38.3.0.data → rucio-38.4.0.data}/scripts/rucio-follower +0 -0
  107. {rucio-38.3.0.data → rucio-38.4.0.data}/scripts/rucio-hermes +0 -0
  108. {rucio-38.3.0.data → rucio-38.4.0.data}/scripts/rucio-judge-cleaner +0 -0
  109. {rucio-38.3.0.data → rucio-38.4.0.data}/scripts/rucio-judge-evaluator +0 -0
  110. {rucio-38.3.0.data → rucio-38.4.0.data}/scripts/rucio-judge-injector +0 -0
  111. {rucio-38.3.0.data → rucio-38.4.0.data}/scripts/rucio-judge-repairer +0 -0
  112. {rucio-38.3.0.data → rucio-38.4.0.data}/scripts/rucio-kronos +0 -0
  113. {rucio-38.3.0.data → rucio-38.4.0.data}/scripts/rucio-minos +0 -0
  114. {rucio-38.3.0.data → rucio-38.4.0.data}/scripts/rucio-minos-temporary-expiration +0 -0
  115. {rucio-38.3.0.data → rucio-38.4.0.data}/scripts/rucio-necromancer +0 -0
  116. {rucio-38.3.0.data → rucio-38.4.0.data}/scripts/rucio-oauth-manager +0 -0
  117. {rucio-38.3.0.data → rucio-38.4.0.data}/scripts/rucio-reaper +0 -0
  118. {rucio-38.3.0.data → rucio-38.4.0.data}/scripts/rucio-replica-recoverer +0 -0
  119. {rucio-38.3.0.data → rucio-38.4.0.data}/scripts/rucio-rse-decommissioner +0 -0
  120. {rucio-38.3.0.data → rucio-38.4.0.data}/scripts/rucio-storage-consistency-actions +0 -0
  121. {rucio-38.3.0.data → rucio-38.4.0.data}/scripts/rucio-transmogrifier +0 -0
  122. {rucio-38.3.0.data → rucio-38.4.0.data}/scripts/rucio-undertaker +0 -0
  123. {rucio-38.3.0.dist-info → rucio-38.4.0.dist-info}/WHEEL +0 -0
  124. {rucio-38.3.0.dist-info → rucio-38.4.0.dist-info}/licenses/AUTHORS.rst +0 -0
  125. {rucio-38.3.0.dist-info → rucio-38.4.0.dist-info}/licenses/LICENSE +0 -0
  126. {rucio-38.3.0.dist-info → rucio-38.4.0.dist-info}/top_level.txt +0 -0
rucio/gateway/opendata.py CHANGED
@@ -151,7 +151,7 @@ def update_opendata_did(
151
151
  meta: Optional[dict] = None,
152
152
  doi: Optional[str] = None,
153
153
  vo: str = DEFAULT_VO,
154
- ) -> None:
154
+ ) -> dict[str, Any]:
155
155
  """
156
156
  Update an existing Opendata DID in the Opendata catalog.
157
157
 
@@ -164,7 +164,7 @@ def update_opendata_did(
164
164
  vo: The virtual organization.
165
165
 
166
166
  Returns:
167
- None
167
+ A dictionary containing the scope and name of the DID and details of the updates performed. (e.g., new/old state, new/old DOI, etc.)
168
168
 
169
169
  Raises:
170
170
  ValueError: If meta is a string and cannot be parsed as valid JSON.
rucio/gateway/request.py CHANGED
@@ -20,7 +20,7 @@ from typing import TYPE_CHECKING, Any, Optional
20
20
 
21
21
  from rucio.common import exception
22
22
  from rucio.common.constants import DEFAULT_VO, TransferLimitDirection
23
- from rucio.common.types import InternalAccount, InternalScope, RequestGatewayDict
23
+ from rucio.common.types import InternalScope
24
24
  from rucio.common.utils import gateway_update_return_dict
25
25
  from rucio.core import request
26
26
  from rucio.core.rse import get_rse_id
@@ -31,122 +31,7 @@ from rucio.gateway import permission
31
31
  if TYPE_CHECKING:
32
32
  from collections.abc import Iterable, Iterator, Sequence
33
33
 
34
- from rucio.db.sqla.constants import RequestState, RequestType
35
-
36
-
37
- def queue_requests(
38
- requests: "Iterable[RequestGatewayDict]",
39
- issuer: str,
40
- vo: str = DEFAULT_VO,
41
- ) -> list[dict[str, Any]]:
42
- """
43
- Submit transfer or deletion requests on destination RSEs for data identifiers.
44
-
45
- :param requests: List of dictionaries containing 'scope', 'name', 'dest_rse_id', 'request_type', 'attributes'
46
- :param issuer: Issuing account as a string.
47
- :param vo: The VO to act on.
48
- :returns: List of Request-IDs as 32 character hex strings
49
- """
50
-
51
- kwargs = {'requests': requests, 'issuer': issuer}
52
- with db_session(DatabaseOperationType.WRITE) as session:
53
- auth_result = permission.has_permission(issuer=issuer, vo=vo, action='queue_requests', kwargs=kwargs, session=session)
54
- if not auth_result.allowed:
55
- raise exception.AccessDenied(f'{issuer} can not queue request. {auth_result.message}')
56
-
57
- for req in requests:
58
- req['scope'] = InternalScope(req['scope'], vo=vo) # type: ignore (type reassignment)
59
- if 'account' in req:
60
- req['account'] = InternalAccount(req['account'], vo=vo) # type: ignore (type reassignment)
61
-
62
- new_requests = request.queue_requests(requests, session=session)
63
- return [gateway_update_return_dict(r, session=session) for r in new_requests]
64
-
65
-
66
- def cancel_request(
67
- request_id: str,
68
- issuer: str,
69
- account: str,
70
- vo: str = DEFAULT_VO,
71
- ) -> None:
72
- """
73
- Cancel a request.
74
-
75
- :param request_id: Request Identifier as a 32 character hex string.
76
- :param issuer: Issuing account as a string.
77
- :param account: Account identifier as a string.
78
- :param vo: The VO to act on.
79
- """
80
-
81
- kwargs = {'account': account, 'issuer': issuer, 'request_id': request_id}
82
- with db_session(DatabaseOperationType.WRITE) as session:
83
- auth_result = permission.has_permission(issuer=issuer, vo=vo, action='cancel_request_', kwargs=kwargs, session=session)
84
- if not auth_result.allowed:
85
- raise exception.AccessDenied('%s cannot cancel request %s. %s' % (account, request_id, auth_result.message))
86
-
87
- raise NotImplementedError
88
-
89
-
90
- def cancel_request_did(
91
- scope: str,
92
- name: str,
93
- dest_rse: str,
94
- request_type: str,
95
- issuer: str,
96
- account: str,
97
- vo: str = DEFAULT_VO,
98
- ) -> dict[str, Any]:
99
- """
100
- Cancel a request based on a DID and request type.
101
-
102
- :param scope: Data identifier scope as a string.
103
- :param name: Data identifier name as a string.
104
- :param dest_rse: RSE name as a string.
105
- :param request_type: Type of the request as a string.
106
- :param issuer: Issuing account as a string.
107
- :param account: Account identifier as a string.
108
- :param vo: The VO to act on.
109
- """
110
-
111
- with db_session(DatabaseOperationType.WRITE) as session:
112
- dest_rse_id = get_rse_id(rse=dest_rse, vo=vo, session=session)
113
-
114
- kwargs = {'account': account, 'issuer': issuer}
115
- auth_result = permission.has_permission(issuer=issuer, vo=vo, action='cancel_request_did', kwargs=kwargs, session=session)
116
- if not auth_result.allowed:
117
- raise exception.AccessDenied(f'{account} cannot cancel {request_type} request for {scope}:{name}. {auth_result.message}')
118
-
119
- internal_scope = InternalScope(scope, vo=vo)
120
- return request.cancel_request_did(internal_scope, name, dest_rse_id, request_type, session=session)
121
-
122
-
123
- def get_next(
124
- request_type: "RequestType",
125
- state: "RequestState",
126
- issuer: str,
127
- account: str,
128
- vo: str = DEFAULT_VO,
129
- ) -> list[dict[str, Any]]:
130
- """
131
- Retrieve the next request matching the request type and state.
132
-
133
- :param request_type: Type of the request as a string.
134
- :param state: State of the request as a string.
135
- :param issuer: Issuing account as a string.
136
- :param account: Account identifier as a string.
137
- :param vo: The VO to act on.
138
- :returns: Request as a dictionary.
139
- """
140
-
141
- kwargs = {'account': account, 'issuer': issuer, 'request_type': request_type, 'state': state}
142
-
143
- with db_session(DatabaseOperationType.WRITE) as session:
144
- auth_result = permission.has_permission(issuer=issuer, vo=vo, action='get_next', kwargs=kwargs, session=session)
145
- if not auth_result.allowed:
146
- raise exception.AccessDenied(f'{account} cannot get the next request of type {request_type} in state {state}. {auth_result.message}')
147
-
148
- reqs = request.get_and_mark_next(request_type, state, session=session)
149
- return [gateway_update_return_dict(r, session=session) for r in reqs]
34
+ from rucio.db.sqla.constants import RequestState
150
35
 
151
36
 
152
37
  def get_request_by_did(
@@ -25,6 +25,7 @@ from requests.adapters import HTTPAdapter
25
25
  from urllib3.poolmanager import PoolManager
26
26
 
27
27
  from rucio.common import exception
28
+ from rucio.common.constants import HTTPMethod
28
29
  from rucio.rse.protocols import protocol
29
30
 
30
31
 
@@ -259,9 +260,11 @@ class Default(protocol.RSEProtocol):
259
260
  try:
260
261
  # use GET instead of HEAD for presigned urls
261
262
  if not using_presigned_urls:
262
- result = self.session.request('HEAD', path, verify=False, timeout=self.timeout, cert=self.cert)
263
+ result = self.session.request(HTTPMethod.HEAD.value, path, verify=False, timeout=self.timeout,
264
+ cert=self.cert)
263
265
  else:
264
- result = self.session.request('GET', path, verify=False, timeout=self.timeout, cert=self.cert)
266
+ result = self.session.request(HTTPMethod.GET.value, path, verify=False, timeout=self.timeout,
267
+ cert=self.cert)
265
268
  if result.status_code == 200:
266
269
  return True
267
270
  elif result.status_code in [401, ]:
@@ -76,7 +76,6 @@ BULK_QUERY_COUNTER = METRICS.counter(name='{host}.bulk_query.{state}',
76
76
  QUERY_DETAILS_COUNTER = METRICS.counter(name='{host}.query_details.{state}',
77
77
  documentation='Number of detailed status queries', labelnames=('state', 'host'))
78
78
 
79
- REWRITE_HTTPS_TO_DAVS = config_get_bool('transfers', 'rewrite_https_to_davs', default=False)
80
79
  VO_CERTS_PATH = config_get('conveyor', 'vo_certs_path', False, None)
81
80
 
82
81
  # https://fts3-docs.web.cern.ch/fts3-docs/docs/state_machine.html
@@ -1073,24 +1072,6 @@ class FTS3Transfertool(Transfertool):
1073
1072
  if not transfer_file['sources'] or transfer_file['sources'] == []:
1074
1073
  raise Exception('No sources defined')
1075
1074
 
1076
- # TODO: remove the following logic in rucio 1.31
1077
- if REWRITE_HTTPS_TO_DAVS:
1078
- new_src_urls = []
1079
- new_dst_urls = []
1080
- for url in transfer_file['sources']:
1081
- if url.startswith('https'):
1082
- new_src_urls.append(':'.join(['davs'] + url.split(':')[1:]))
1083
- else:
1084
- new_src_urls.append(url)
1085
- for url in transfer_file['destinations']:
1086
- if url.startswith('https'):
1087
- new_dst_urls.append(':'.join(['davs'] + url.split(':')[1:]))
1088
- else:
1089
- new_dst_urls.append(url)
1090
-
1091
- transfer_file['sources'] = new_src_urls
1092
- transfer_file['destinations'] = new_dst_urls
1093
-
1094
1075
  transfer_id = None
1095
1076
  expected_transfer_id = None
1096
1077
  if self.deterministic_id:
rucio/vcsversion.py CHANGED
@@ -4,8 +4,8 @@ This file is automatically generated; Do not edit it. :)
4
4
  '''
5
5
  VERSION_INFO = {
6
6
  'final': True,
7
- 'version': '38.3.0',
7
+ 'version': '38.4.0',
8
8
  'branch_nick': 'release-38-LTS',
9
- 'revision_id': '5eebc4e67a544dcb2d689bd45260cb73fb10066a',
10
- 'revno': 14003
9
+ 'revision_id': '945ab71be90243fe96148bb3bd13c1c3ae410765',
10
+ 'revno': 14030
11
11
  }
@@ -16,6 +16,7 @@ from typing import TYPE_CHECKING
16
16
 
17
17
  from flask import Flask, request
18
18
 
19
+ from rucio.common.constants import HTTPMethod
19
20
  from rucio.common.exception import AccessDenied, AccountNotFound, RSENotFound
20
21
  from rucio.gateway.account_limit import delete_global_account_limit, delete_local_account_limit, set_global_account_limit, set_local_account_limit
21
22
  from rucio.web.rest.flaskapi.authenticated_bp import AuthenticatedBlueprint
@@ -219,11 +220,11 @@ def blueprint(with_doc: bool = False) -> AuthenticatedBlueprint:
219
220
  bp = AuthenticatedBlueprint('accountlimits', __name__, url_prefix='/accountlimits')
220
221
 
221
222
  local_account_limit_view = LocalAccountLimit.as_view('local_account_limit')
222
- bp.add_url_rule('/local/<account>/<rse>', view_func=local_account_limit_view, methods=['post', 'delete'])
223
+ bp.add_url_rule('/local/<account>/<rse>', view_func=local_account_limit_view, methods=[HTTPMethod.POST.value, HTTPMethod.DELETE.value])
223
224
  if not with_doc:
224
- bp.add_url_rule('/<account>/<rse>', view_func=local_account_limit_view, methods=['post', 'delete'])
225
+ bp.add_url_rule('/<account>/<rse>', view_func=local_account_limit_view, methods=[HTTPMethod.POST.value, HTTPMethod.DELETE.value])
225
226
  global_account_limit_view = GlobalAccountLimit.as_view('global_account_limit')
226
- bp.add_url_rule('/global/<account>/<rse_expression>', view_func=global_account_limit_view, methods=['post', 'delete'])
227
+ bp.add_url_rule('/global/<account>/<rse_expression>', view_func=global_account_limit_view, methods=[HTTPMethod.POST.value, HTTPMethod.DELETE.value])
227
228
 
228
229
  bp.after_request(response_headers)
229
230
  return bp
@@ -18,7 +18,8 @@ from typing import TYPE_CHECKING, Any, Literal, Optional, Union
18
18
 
19
19
  from flask import Flask, Response, jsonify, redirect, request
20
20
 
21
- from rucio.common.exception import AccessDenied, AccountNotFound, CounterNotFound, Duplicate, IdentityError, InvalidObject, RSENotFound, RuleNotFound, ScopeNotFound
21
+ from rucio.common.constants import HTTPMethod
22
+ from rucio.common.exception import AccessDenied, AccountNotFound, CounterNotFound, Duplicate, IdentityError, InvalidAccountType, InvalidObject, RSENotFound, RuleNotFound, ScopeNotFound
22
23
  from rucio.common.utils import APIEncoder, render_json
23
24
  from rucio.gateway.account import add_account, add_account_attribute, del_account, del_account_attribute, get_account_info, get_usage_history, list_account_attributes, list_accounts, list_identities, update_account
24
25
  from rucio.gateway.account_limit import get_global_account_limit, get_global_account_usage, get_local_account_limit, get_local_account_usage
@@ -447,7 +448,7 @@ class AccountParameter(ErrorHandlingMethodView):
447
448
  return generate_http_error_flask(409, error)
448
449
  except AccessDenied as error:
449
450
  return generate_http_error_flask(401, error)
450
- except InvalidObject as error:
451
+ except (InvalidObject, InvalidAccountType) as error:
451
452
  return generate_http_error_flask(400, error)
452
453
 
453
454
  return 'Created', 201
@@ -1047,44 +1048,44 @@ def blueprint(with_doc: bool = False) -> AuthenticatedBlueprint:
1047
1048
  bp = AuthenticatedBlueprint('accounts', __name__, url_prefix='/accounts')
1048
1049
 
1049
1050
  attributes_view = Attributes.as_view('attributes')
1050
- bp.add_url_rule('/<account>/attr/', view_func=attributes_view, methods=['get', ])
1051
- bp.add_url_rule('/<account>/attr/<key>', view_func=attributes_view, methods=['post', 'delete'])
1051
+ bp.add_url_rule('/<account>/attr/', view_func=attributes_view, methods=[HTTPMethod.GET.value])
1052
+ bp.add_url_rule('/<account>/attr/<key>', view_func=attributes_view, methods=[HTTPMethod.POST.value, HTTPMethod.DELETE.value])
1052
1053
  scopes_view = Scopes.as_view('scopes')
1053
- bp.add_url_rule('/<account>/scopes/', view_func=scopes_view, methods=['get', ])
1054
- bp.add_url_rule('/<account>/scopes/<scope>', view_func=scopes_view, methods=['post', ])
1054
+ bp.add_url_rule('/<account>/scopes/', view_func=scopes_view, methods=[HTTPMethod.GET.value])
1055
+ bp.add_url_rule('/<account>/scopes/<scope>', view_func=scopes_view, methods=[HTTPMethod.POST.value])
1055
1056
  local_account_limits_view = LocalAccountLimits.as_view('local_account_limit')
1056
- bp.add_url_rule('/<account>/limits/local', view_func=local_account_limits_view, methods=['get', ])
1057
- bp.add_url_rule('/<account>/limits', view_func=local_account_limits_view, methods=['get', ])
1058
- bp.add_url_rule('/<account>/limits/local/<rse>', view_func=local_account_limits_view, methods=['get', ])
1059
- bp.add_url_rule('/<account>/limits/<rse>', view_func=local_account_limits_view, methods=['get', ])
1057
+ bp.add_url_rule('/<account>/limits/local', view_func=local_account_limits_view, methods=[HTTPMethod.GET.value])
1058
+ bp.add_url_rule('/<account>/limits', view_func=local_account_limits_view, methods=[HTTPMethod.GET.value])
1059
+ bp.add_url_rule('/<account>/limits/local/<rse>', view_func=local_account_limits_view, methods=[HTTPMethod.GET.value])
1060
+ bp.add_url_rule('/<account>/limits/<rse>', view_func=local_account_limits_view, methods=[HTTPMethod.GET.value])
1060
1061
  global_account_limits_view = GlobalAccountLimits.as_view('global_account_limit')
1061
- bp.add_url_rule('/<account>/limits/global', view_func=global_account_limits_view, methods=['get', ])
1062
- bp.add_url_rule('/<account>/limits/global/<rse_expression>', view_func=global_account_limits_view, methods=['get', ])
1062
+ bp.add_url_rule('/<account>/limits/global', view_func=global_account_limits_view, methods=[HTTPMethod.GET.value])
1063
+ bp.add_url_rule('/<account>/limits/global/<rse_expression>', view_func=global_account_limits_view, methods=[HTTPMethod.GET.value])
1063
1064
  identities_view = Identities.as_view('identities')
1064
- bp.add_url_rule('/<account>/identities', view_func=identities_view, methods=['get', 'post', 'delete'])
1065
+ bp.add_url_rule('/<account>/identities', view_func=identities_view, methods=[HTTPMethod.GET.value, HTTPMethod.POST.value, HTTPMethod.DELETE.value])
1065
1066
  rules_view = Rules.as_view('rules')
1066
- bp.add_url_rule('/<account>/rules', view_func=rules_view, methods=['get', ])
1067
+ bp.add_url_rule('/<account>/rules', view_func=rules_view, methods=[HTTPMethod.GET.value])
1067
1068
  usagehistory_view = UsageHistory.as_view('usagehistory')
1068
- bp.add_url_rule('/<account>/usage/history/<rse>', view_func=usagehistory_view, methods=['get', ])
1069
+ bp.add_url_rule('/<account>/usage/history/<rse>', view_func=usagehistory_view, methods=[HTTPMethod.GET.value])
1069
1070
  usage_view = LocalUsage.as_view('usage')
1070
- bp.add_url_rule('/<account>/usage/local', view_func=usage_view, methods=['get', ])
1071
- bp.add_url_rule('/<account>/usage', view_func=usage_view, methods=['get', ])
1071
+ bp.add_url_rule('/<account>/usage/local', view_func=usage_view, methods=[HTTPMethod.GET.value])
1072
+ bp.add_url_rule('/<account>/usage', view_func=usage_view, methods=[HTTPMethod.GET.value])
1072
1073
  if not with_doc:
1073
1074
  # for backwards-compatibility
1074
1075
  # rule without trailing slash needs to be added before rule with trailing slash
1075
- bp.add_url_rule('/<account>/usage/', view_func=usage_view, methods=['get', ])
1076
- bp.add_url_rule('/<account>/usage/local/<rse>', view_func=usage_view, methods=['get', ])
1077
- bp.add_url_rule('/<account>/usage/<rse>', view_func=usage_view, methods=['get', ])
1076
+ bp.add_url_rule('/<account>/usage/', view_func=usage_view, methods=[HTTPMethod.GET.value])
1077
+ bp.add_url_rule('/<account>/usage/local/<rse>', view_func=usage_view, methods=[HTTPMethod.GET.value])
1078
+ bp.add_url_rule('/<account>/usage/<rse>', view_func=usage_view, methods=[HTTPMethod.GET.value])
1078
1079
  global_usage_view = GlobalUsage.as_view('global_usage')
1079
- bp.add_url_rule('/<account>/usage/global', view_func=global_usage_view, methods=['get', ])
1080
- bp.add_url_rule('/<account>/usage/global/<rse_expression>', view_func=global_usage_view, methods=['get', ])
1080
+ bp.add_url_rule('/<account>/usage/global', view_func=global_usage_view, methods=[HTTPMethod.GET.value])
1081
+ bp.add_url_rule('/<account>/usage/global/<rse_expression>', view_func=global_usage_view, methods=[HTTPMethod.GET.value])
1081
1082
  account_parameter_view = AccountParameter.as_view('account_parameter')
1082
- bp.add_url_rule('/<account>', view_func=account_parameter_view, methods=['get', 'put', 'post', 'delete'])
1083
+ bp.add_url_rule('/<account>', view_func=account_parameter_view, methods=[HTTPMethod.GET.value, HTTPMethod.PUT.value, HTTPMethod.POST.value, HTTPMethod.DELETE.value])
1083
1084
  account_view = Account.as_view('account')
1084
1085
  if not with_doc:
1085
1086
  # rule without trailing slash needs to be added before rule with trailing slash
1086
- bp.add_url_rule('', view_func=account_view, methods=['get', ])
1087
- bp.add_url_rule('/', view_func=account_view, methods=['get', ])
1087
+ bp.add_url_rule('', view_func=account_view, methods=[HTTPMethod.GET.value])
1088
+ bp.add_url_rule('/', view_func=account_view, methods=[HTTPMethod.GET.value])
1088
1089
 
1089
1090
  bp.after_request(response_headers)
1090
1091
  return bp
@@ -17,7 +17,7 @@ from typing import TYPE_CHECKING
17
17
 
18
18
  from flask import Flask, Response, request
19
19
 
20
- from rucio.common.constants import DEFAULT_VO
20
+ from rucio.common.constants import DEFAULT_VO, HTTPMethod
21
21
  from rucio.gateway.did import list_archive_content
22
22
  from rucio.web.rest.flaskapi.authenticated_bp import AuthenticatedBlueprint
23
23
  from rucio.web.rest.flaskapi.v1.common import ErrorHandlingMethodView, check_accept_header_wrapper_flask, generate_http_error_flask, parse_scope_name, response_headers, try_stream
@@ -90,7 +90,7 @@ def blueprint() -> AuthenticatedBlueprint:
90
90
  bp = AuthenticatedBlueprint('archives', __name__, url_prefix='/archives')
91
91
 
92
92
  archive_view = Archive.as_view('archive')
93
- bp.add_url_rule('/<path:scope_name>/files', view_func=archive_view, methods=['get', ])
93
+ bp.add_url_rule('/<path:scope_name>/files', view_func=archive_view, methods=[HTTPMethod.GET.value])
94
94
 
95
95
  bp.after_request(response_headers)
96
96
  return bp
@@ -23,6 +23,7 @@ from jinja2.exceptions import TemplateNotFound
23
23
  from werkzeug.datastructures import Headers
24
24
 
25
25
  from rucio.common.config import config_get
26
+ from rucio.common.constants import HTTPMethod
26
27
  from rucio.common.exception import AccessDenied, CannotAuthenticate, CannotAuthorize, ConfigurationError, IdentityError, IdentityNotFound, InvalidRequest
27
28
  from rucio.common.extra import import_extras
28
29
  from rucio.common.utils import date_to_str
@@ -1632,31 +1633,31 @@ def blueprint() -> Blueprint:
1632
1633
  bp = Blueprint('auth', __name__, url_prefix='/auth')
1633
1634
 
1634
1635
  user_pass_view = UserPass.as_view('user_pass')
1635
- bp.add_url_rule('/userpass', view_func=user_pass_view, methods=['get', 'options'])
1636
+ bp.add_url_rule('/userpass', view_func=user_pass_view, methods=[HTTPMethod.GET.value, HTTPMethod.OPTIONS.value])
1636
1637
  gss_view = GSS.as_view('gss')
1637
- bp.add_url_rule('/gss', view_func=gss_view, methods=['get', 'options'])
1638
+ bp.add_url_rule('/gss', view_func=gss_view, methods=[HTTPMethod.GET.value, HTTPMethod.OPTIONS.value])
1638
1639
  x509_view = x509.as_view('x509')
1639
- bp.add_url_rule('/x509', view_func=x509_view, methods=['get', 'options'])
1640
- bp.add_url_rule('/x509/webui', view_func=x509_view, methods=['get', 'options'])
1641
- bp.add_url_rule('/x509_proxy', view_func=x509_view, methods=['get', 'options'])
1640
+ bp.add_url_rule('/x509', view_func=x509_view, methods=[HTTPMethod.GET.value, HTTPMethod.OPTIONS.value])
1641
+ bp.add_url_rule('/x509/webui', view_func=x509_view, methods=[HTTPMethod.GET.value, HTTPMethod.OPTIONS.value])
1642
+ bp.add_url_rule('/x509_proxy', view_func=x509_view, methods=[HTTPMethod.GET.value, HTTPMethod.OPTIONS.value])
1642
1643
  ssh_view = SSH.as_view('ssh')
1643
- bp.add_url_rule('/ssh', view_func=ssh_view, methods=['get', 'options'])
1644
+ bp.add_url_rule('/ssh', view_func=ssh_view, methods=[HTTPMethod.GET.value, HTTPMethod.OPTIONS.value])
1644
1645
  ssh_challenge_token_view = SSHChallengeToken.as_view('ssh_challenge_token')
1645
- bp.add_url_rule('/ssh_challenge_token', view_func=ssh_challenge_token_view, methods=['get', 'options'])
1646
+ bp.add_url_rule('/ssh_challenge_token', view_func=ssh_challenge_token_view, methods=[HTTPMethod.GET.value, HTTPMethod.OPTIONS.value])
1646
1647
  saml_view = SAML.as_view('saml')
1647
- bp.add_url_rule('/saml', view_func=saml_view, methods=['get', 'post', 'options'])
1648
+ bp.add_url_rule('/saml', view_func=saml_view, methods=[HTTPMethod.GET.value, HTTPMethod.POST.value, HTTPMethod.OPTIONS.value])
1648
1649
  validate_view = Validate.as_view('validate')
1649
- bp.add_url_rule('/validate', view_func=validate_view, methods=['get', 'options'])
1650
+ bp.add_url_rule('/validate', view_func=validate_view, methods=[HTTPMethod.GET.value, HTTPMethod.OPTIONS.value])
1650
1651
  oidc_view = OIDC.as_view('oidc_view')
1651
- bp.add_url_rule('/oidc', view_func=oidc_view, methods=['get', 'options'])
1652
+ bp.add_url_rule('/oidc', view_func=oidc_view, methods=[HTTPMethod.GET.value, HTTPMethod.OPTIONS.value])
1652
1653
  token_oidc_view = TokenOIDC.as_view('token_oidc_view')
1653
- bp.add_url_rule('/oidc_token', view_func=token_oidc_view, methods=['get', 'options'])
1654
+ bp.add_url_rule('/oidc_token', view_func=token_oidc_view, methods=[HTTPMethod.GET.value, HTTPMethod.OPTIONS.value])
1654
1655
  code_oidc_view = CodeOIDC.as_view('code_oidc_view')
1655
- bp.add_url_rule('/oidc_code', view_func=code_oidc_view, methods=['get', 'options'])
1656
+ bp.add_url_rule('/oidc_code', view_func=code_oidc_view, methods=[HTTPMethod.GET.value, HTTPMethod.OPTIONS.value])
1656
1657
  redirect_oidc_view = RedirectOIDC.as_view('redirect_oidc_view')
1657
- bp.add_url_rule('/oidc_redirect', view_func=redirect_oidc_view, methods=['get', 'options'])
1658
+ bp.add_url_rule('/oidc_redirect', view_func=redirect_oidc_view, methods=[HTTPMethod.GET.value, HTTPMethod.OPTIONS.value])
1658
1659
  refresh_oidc_view = RefreshOIDC.as_view('refresh_oidc_view')
1659
- bp.add_url_rule('/oidc_refresh', view_func=refresh_oidc_view, methods=['get', 'options'])
1660
+ bp.add_url_rule('/oidc_refresh', view_func=refresh_oidc_view, methods=[HTTPMethod.GET.value, HTTPMethod.OPTIONS.value])
1660
1661
 
1661
1662
  return bp
1662
1663
 
@@ -31,7 +31,7 @@ from werkzeug.exceptions import HTTPException
31
31
  from werkzeug.wrappers import Request, Response
32
32
 
33
33
  from rucio.common import config
34
- from rucio.common.constants import DEFAULT_VO
34
+ from rucio.common.constants import DEFAULT_VO, HTTPMethod
35
35
  from rucio.common.exception import CannotAuthenticate, DatabaseException, IdentityError, RucioException, UnsupportedRequestedContentType
36
36
  from rucio.common.schema import get_schema_value
37
37
  from rucio.common.utils import generate_uuid, render_json
@@ -66,7 +66,7 @@ class CORSMiddleware:
66
66
  def __call__(self, environ: 'WSGIEnvironment', start_response: 'StartResponse') -> 'Iterable[bytes]':
67
67
  request: Request = Request(environ)
68
68
 
69
- if request.environ.get('REQUEST_METHOD') == 'OPTIONS':
69
+ if request.environ.get('REQUEST_METHOD') == HTTPMethod.OPTIONS.value:
70
70
  try:
71
71
  webui_urls = config.config_get_list('webui', 'urls')
72
72
  except (NoOptionError, NoSectionError, RuntimeError) as error:
@@ -145,7 +145,7 @@ class ErrorHandlingMethodView(MethodView):
145
145
 
146
146
 
147
147
  def request_auth_env() -> Optional['ResponseReturnValue']:
148
- if flask.request.environ.get('REQUEST_METHOD') == 'OPTIONS':
148
+ if flask.request.environ.get('REQUEST_METHOD') == HTTPMethod.OPTIONS.value:
149
149
  return '', 200
150
150
 
151
151
  auth_token = flask.request.headers.get('X-Rucio-Auth-Token', default=None)
@@ -176,7 +176,7 @@ def response_headers(response: ResponseTypeVar) -> ResponseTypeVar:
176
176
  response.headers['Access-Control-Allow-Methods'] = '*'
177
177
  response.headers['Access-Control-Allow-Credentials'] = 'true'
178
178
 
179
- if flask.request.environ.get('REQUEST_METHOD') == 'GET':
179
+ if flask.request.environ.get('REQUEST_METHOD') == HTTPMethod.GET.value:
180
180
  response.headers['Cache-Control'] = 'no-cache, no-store, max-age=0, must-revalidate'
181
181
  response.headers['Cache-Control'] = 'post-check=0, pre-check=0'
182
182
  response.headers['Pragma'] = 'no-cache'
@@ -17,6 +17,7 @@ from typing import TYPE_CHECKING
17
17
  from flask import Flask, jsonify
18
18
  from flask import request as request
19
19
 
20
+ from rucio.common.constants import HTTPMethod
20
21
  from rucio.common.exception import AccessDenied, ConfigNotFound, ConfigurationError
21
22
  from rucio.gateway import config
22
23
  from rucio.web.rest.flaskapi.authenticated_bp import AuthenticatedBlueprint
@@ -323,13 +324,14 @@ def blueprint() -> AuthenticatedBlueprint:
323
324
  bp = AuthenticatedBlueprint('config', __name__, url_prefix='/config')
324
325
 
325
326
  option_set_view = OptionSet.as_view('option_set')
326
- bp.add_url_rule('/<section>/<option>/<value>', view_func=option_set_view, methods=['put', ])
327
+ bp.add_url_rule('/<section>/<option>/<value>', view_func=option_set_view, methods=[HTTPMethod.PUT.value])
327
328
  option_get_del_view = OptionGetDel.as_view('option_get_del')
328
- bp.add_url_rule('/<section>/<option>', view_func=option_get_del_view, methods=['get', 'delete'])
329
+ bp.add_url_rule('/<section>/<option>', view_func=option_get_del_view, methods=[HTTPMethod.GET.value, HTTPMethod.DELETE.value])
329
330
  section_view = Section.as_view('section')
330
- bp.add_url_rule('/<section>', view_func=section_view, methods=['get', 'delete'])
331
+
332
+ bp.add_url_rule('/<section>', view_func=section_view, methods=[HTTPMethod.GET.value, HTTPMethod.DELETE.value])
331
333
  config_view = Config.as_view('config')
332
- bp.add_url_rule('', view_func=config_view, methods=['get', 'post'])
334
+ bp.add_url_rule('', view_func=config_view, methods=[HTTPMethod.GET.value, HTTPMethod.POST.value])
333
335
 
334
336
  bp.after_request(response_headers)
335
337
  return bp
@@ -17,7 +17,7 @@ from typing import TYPE_CHECKING, cast
17
17
  from flask import Flask, request
18
18
  from werkzeug.datastructures import Headers
19
19
 
20
- from rucio.common.constants import RSE_BASE_SUPPORTED_PROTOCOL_OPERATIONS, RSE_BASE_SUPPORTED_PROTOCOL_OPERATIONS_LITERAL, SUPPORTED_SIGN_URL_SERVICES, SUPPORTED_SIGN_URL_SERVICES_LITERAL
20
+ from rucio.common.constants import RSE_BASE_SUPPORTED_PROTOCOL_OPERATIONS, RSE_BASE_SUPPORTED_PROTOCOL_OPERATIONS_LITERAL, SUPPORTED_SIGN_URL_SERVICES, SUPPORTED_SIGN_URL_SERVICES_LITERAL, HTTPMethod
21
21
  from rucio.common.exception import CannotAuthenticate
22
22
  from rucio.gateway.credential import get_signed_url
23
23
  from rucio.web.rest.flaskapi.authenticated_bp import AuthenticatedBlueprint
@@ -203,10 +203,10 @@ def blueprint(with_doc=False):
203
203
  bp = AuthenticatedBlueprint('credentials', __name__, url_prefix='/credentials')
204
204
 
205
205
  signurl_view = SignURL.as_view('signurl')
206
- bp.add_url_rule('/signurl', view_func=signurl_view, methods=['get', 'options'])
206
+ bp.add_url_rule('/signurl', view_func=signurl_view, methods=[HTTPMethod.GET.value, HTTPMethod.OPTIONS.value])
207
207
  if not with_doc:
208
208
  # yes, /signur ~= '/signurl?$'
209
- bp.add_url_rule('/signur', view_func=signurl_view, methods=['get', 'options'])
209
+ bp.add_url_rule('/signur', view_func=signurl_view, methods=[HTTPMethod.GET.value, HTTPMethod.OPTIONS.value])
210
210
 
211
211
  bp.after_request(response_headers)
212
212