rucio 38.4.0__py3-none-any.whl → 38.5.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.
- rucio/cli/bin_legacy/rucio.py +12 -7
- rucio/cli/bin_legacy/rucio_admin.py +9 -2
- rucio/cli/replica.py +6 -2
- rucio/cli/rule.py +0 -1
- rucio/cli/scope.py +9 -0
- rucio/cli/utils.py +11 -0
- rucio/client/downloadclient.py +3 -1
- rucio/client/scopeclient.py +40 -1
- rucio/common/didtype.py +18 -11
- rucio/core/did_meta_plugins/__init__.py +2 -1
- rucio/core/did_meta_plugins/did_column_meta.py +2 -10
- rucio/core/did_meta_plugins/did_meta_plugin_interface.py +39 -25
- rucio/core/did_meta_plugins/elasticsearch_meta.py +3 -11
- rucio/core/did_meta_plugins/json_meta.py +2 -8
- rucio/core/did_meta_plugins/mongo_meta.py +3 -12
- rucio/core/did_meta_plugins/postgres_meta.py +7 -14
- rucio/core/dirac.py +1 -1
- rucio/core/rse.py +6 -2
- rucio/core/scope.py +47 -7
- rucio/daemons/automatix/automatix.py +2 -0
- rucio/db/sqla/models.py +22 -0
- rucio/gateway/did.py +1 -1
- rucio/gateway/dirac.py +1 -1
- rucio/gateway/scope.py +35 -3
- rucio/vcsversion.py +3 -3
- rucio/web/rest/flaskapi/v1/opendata.py +21 -21
- rucio/web/rest/flaskapi/v1/opendata_public.py +8 -8
- rucio/web/rest/flaskapi/v1/scopes.py +63 -11
- {rucio-38.4.0.data → rucio-38.5.0.data}/data/rucio/etc/rucio.cfg.template +2 -3
- {rucio-38.4.0.data → rucio-38.5.0.data}/data/rucio/etc/rucio_multi_vo.cfg.template +2 -3
- {rucio-38.4.0.dist-info → rucio-38.5.0.dist-info}/METADATA +1 -1
- {rucio-38.4.0.dist-info → rucio-38.5.0.dist-info}/RECORD +89 -89
- {rucio-38.4.0.data → rucio-38.5.0.data}/data/rucio/etc/alembic.ini.template +0 -0
- {rucio-38.4.0.data → rucio-38.5.0.data}/data/rucio/etc/alembic_offline.ini.template +0 -0
- {rucio-38.4.0.data → rucio-38.5.0.data}/data/rucio/etc/globus-config.yml.template +0 -0
- {rucio-38.4.0.data → rucio-38.5.0.data}/data/rucio/etc/ldap.cfg.template +0 -0
- {rucio-38.4.0.data → rucio-38.5.0.data}/data/rucio/etc/mail_templates/rule_approval_request.tmpl +0 -0
- {rucio-38.4.0.data → rucio-38.5.0.data}/data/rucio/etc/mail_templates/rule_approved_admin.tmpl +0 -0
- {rucio-38.4.0.data → rucio-38.5.0.data}/data/rucio/etc/mail_templates/rule_approved_user.tmpl +0 -0
- {rucio-38.4.0.data → rucio-38.5.0.data}/data/rucio/etc/mail_templates/rule_denied_admin.tmpl +0 -0
- {rucio-38.4.0.data → rucio-38.5.0.data}/data/rucio/etc/mail_templates/rule_denied_user.tmpl +0 -0
- {rucio-38.4.0.data → rucio-38.5.0.data}/data/rucio/etc/mail_templates/rule_ok_notification.tmpl +0 -0
- {rucio-38.4.0.data → rucio-38.5.0.data}/data/rucio/etc/rse-accounts.cfg.template +0 -0
- {rucio-38.4.0.data → rucio-38.5.0.data}/data/rucio/etc/rucio.cfg.atlas.client.template +0 -0
- {rucio-38.4.0.data → rucio-38.5.0.data}/data/rucio/requirements.server.txt +0 -0
- {rucio-38.4.0.data → rucio-38.5.0.data}/data/rucio/tools/bootstrap.py +0 -0
- {rucio-38.4.0.data → rucio-38.5.0.data}/data/rucio/tools/merge_rucio_configs.py +0 -0
- {rucio-38.4.0.data → rucio-38.5.0.data}/data/rucio/tools/reset_database.py +0 -0
- {rucio-38.4.0.data → rucio-38.5.0.data}/scripts/rucio +0 -0
- {rucio-38.4.0.data → rucio-38.5.0.data}/scripts/rucio-abacus-account +0 -0
- {rucio-38.4.0.data → rucio-38.5.0.data}/scripts/rucio-abacus-collection-replica +0 -0
- {rucio-38.4.0.data → rucio-38.5.0.data}/scripts/rucio-abacus-rse +0 -0
- {rucio-38.4.0.data → rucio-38.5.0.data}/scripts/rucio-admin +0 -0
- {rucio-38.4.0.data → rucio-38.5.0.data}/scripts/rucio-atropos +0 -0
- {rucio-38.4.0.data → rucio-38.5.0.data}/scripts/rucio-auditor +0 -0
- {rucio-38.4.0.data → rucio-38.5.0.data}/scripts/rucio-automatix +0 -0
- {rucio-38.4.0.data → rucio-38.5.0.data}/scripts/rucio-bb8 +0 -0
- {rucio-38.4.0.data → rucio-38.5.0.data}/scripts/rucio-cache-client +0 -0
- {rucio-38.4.0.data → rucio-38.5.0.data}/scripts/rucio-cache-consumer +0 -0
- {rucio-38.4.0.data → rucio-38.5.0.data}/scripts/rucio-conveyor-finisher +0 -0
- {rucio-38.4.0.data → rucio-38.5.0.data}/scripts/rucio-conveyor-poller +0 -0
- {rucio-38.4.0.data → rucio-38.5.0.data}/scripts/rucio-conveyor-preparer +0 -0
- {rucio-38.4.0.data → rucio-38.5.0.data}/scripts/rucio-conveyor-receiver +0 -0
- {rucio-38.4.0.data → rucio-38.5.0.data}/scripts/rucio-conveyor-stager +0 -0
- {rucio-38.4.0.data → rucio-38.5.0.data}/scripts/rucio-conveyor-submitter +0 -0
- {rucio-38.4.0.data → rucio-38.5.0.data}/scripts/rucio-conveyor-throttler +0 -0
- {rucio-38.4.0.data → rucio-38.5.0.data}/scripts/rucio-dark-reaper +0 -0
- {rucio-38.4.0.data → rucio-38.5.0.data}/scripts/rucio-dumper +0 -0
- {rucio-38.4.0.data → rucio-38.5.0.data}/scripts/rucio-follower +0 -0
- {rucio-38.4.0.data → rucio-38.5.0.data}/scripts/rucio-hermes +0 -0
- {rucio-38.4.0.data → rucio-38.5.0.data}/scripts/rucio-judge-cleaner +0 -0
- {rucio-38.4.0.data → rucio-38.5.0.data}/scripts/rucio-judge-evaluator +0 -0
- {rucio-38.4.0.data → rucio-38.5.0.data}/scripts/rucio-judge-injector +0 -0
- {rucio-38.4.0.data → rucio-38.5.0.data}/scripts/rucio-judge-repairer +0 -0
- {rucio-38.4.0.data → rucio-38.5.0.data}/scripts/rucio-kronos +0 -0
- {rucio-38.4.0.data → rucio-38.5.0.data}/scripts/rucio-minos +0 -0
- {rucio-38.4.0.data → rucio-38.5.0.data}/scripts/rucio-minos-temporary-expiration +0 -0
- {rucio-38.4.0.data → rucio-38.5.0.data}/scripts/rucio-necromancer +0 -0
- {rucio-38.4.0.data → rucio-38.5.0.data}/scripts/rucio-oauth-manager +0 -0
- {rucio-38.4.0.data → rucio-38.5.0.data}/scripts/rucio-reaper +0 -0
- {rucio-38.4.0.data → rucio-38.5.0.data}/scripts/rucio-replica-recoverer +0 -0
- {rucio-38.4.0.data → rucio-38.5.0.data}/scripts/rucio-rse-decommissioner +0 -0
- {rucio-38.4.0.data → rucio-38.5.0.data}/scripts/rucio-storage-consistency-actions +0 -0
- {rucio-38.4.0.data → rucio-38.5.0.data}/scripts/rucio-transmogrifier +0 -0
- {rucio-38.4.0.data → rucio-38.5.0.data}/scripts/rucio-undertaker +0 -0
- {rucio-38.4.0.dist-info → rucio-38.5.0.dist-info}/WHEEL +0 -0
- {rucio-38.4.0.dist-info → rucio-38.5.0.dist-info}/licenses/AUTHORS.rst +0 -0
- {rucio-38.4.0.dist-info → rucio-38.5.0.dist-info}/licenses/LICENSE +0 -0
- {rucio-38.4.0.dist-info → rucio-38.5.0.dist-info}/top_level.txt +0 -0
rucio/core/scope.py
CHANGED
|
@@ -14,21 +14,24 @@
|
|
|
14
14
|
|
|
15
15
|
from re import match
|
|
16
16
|
from traceback import format_exc
|
|
17
|
-
from typing import TYPE_CHECKING, Any, Optional
|
|
17
|
+
from typing import TYPE_CHECKING, Any, Literal, Optional
|
|
18
18
|
|
|
19
|
-
from sqlalchemy import and_, select
|
|
19
|
+
from sqlalchemy import and_, select, update
|
|
20
20
|
from sqlalchemy.exc import IntegrityError
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
import rucio.core.account as account_core
|
|
23
|
+
from rucio.common.exception import AccountNotFound, Duplicate, RucioException, ScopeNotFound, VONotFound
|
|
23
24
|
from rucio.core.vo import vo_exists
|
|
24
25
|
from rucio.db.sqla import models
|
|
25
26
|
from rucio.db.sqla.constants import AccountStatus, ScopeStatus
|
|
26
27
|
from rucio.db.sqla.session import read_session, transactional_session
|
|
27
28
|
|
|
28
29
|
if TYPE_CHECKING:
|
|
30
|
+
from collections.abc import Iterable
|
|
31
|
+
|
|
29
32
|
from sqlalchemy.orm import Session
|
|
30
33
|
|
|
31
|
-
from rucio.common.types import InternalScope
|
|
34
|
+
from rucio.common.types import InternalAccount, InternalScope
|
|
32
35
|
|
|
33
36
|
|
|
34
37
|
@transactional_session
|
|
@@ -87,7 +90,7 @@ def bulk_add_scopes(scopes, account, skip_existing=False, *, session: "Session")
|
|
|
87
90
|
|
|
88
91
|
|
|
89
92
|
@read_session
|
|
90
|
-
def list_scopes(filter_: Optional[dict[str, Any]] = None, *, session: "Session") ->
|
|
93
|
+
def list_scopes(filter_: Optional[dict[str, Any]] = None, *, session: "Session") -> "Iterable[dict[Literal['scope', 'account'], Any]]":
|
|
91
94
|
"""
|
|
92
95
|
Lists all scopes.
|
|
93
96
|
:param filter_: Dictionary of attributes by which the input data should be filtered
|
|
@@ -97,7 +100,8 @@ def list_scopes(filter_: Optional[dict[str, Any]] = None, *, session: "Session")
|
|
|
97
100
|
"""
|
|
98
101
|
filter_ = filter_ or {}
|
|
99
102
|
stmt = select(
|
|
100
|
-
models.Scope.scope
|
|
103
|
+
models.Scope.scope,
|
|
104
|
+
models.Scope.account
|
|
101
105
|
).where(
|
|
102
106
|
models.Scope.status != ScopeStatus.DELETED
|
|
103
107
|
)
|
|
@@ -112,8 +116,14 @@ def list_scopes(filter_: Optional[dict[str, Any]] = None, *, session: "Session")
|
|
|
112
116
|
stmt = stmt.where(
|
|
113
117
|
models.Scope.scope == filter_['scope']
|
|
114
118
|
)
|
|
119
|
+
scopes = []
|
|
120
|
+
for scope, account in session.execute(stmt):
|
|
121
|
+
scopes.append({
|
|
122
|
+
"scope": scope,
|
|
123
|
+
"account": account
|
|
124
|
+
})
|
|
115
125
|
|
|
116
|
-
return
|
|
126
|
+
return scopes
|
|
117
127
|
|
|
118
128
|
|
|
119
129
|
@read_session
|
|
@@ -179,3 +189,33 @@ def is_scope_owner(scope, account, *, session: "Session"):
|
|
|
179
189
|
models.Scope.account == account)
|
|
180
190
|
)
|
|
181
191
|
return bool(session.execute(stmt).scalar())
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
@transactional_session
|
|
195
|
+
def update_scope(scope: "InternalScope", account: "InternalAccount", *, session: "Session") -> None:
|
|
196
|
+
""" Give the scope a new owner
|
|
197
|
+
|
|
198
|
+
:param scope: the name for the existing scope.
|
|
199
|
+
:param account: the account to add the scope to.
|
|
200
|
+
:param session: The database session in use.
|
|
201
|
+
"""
|
|
202
|
+
|
|
203
|
+
if not vo_exists(vo=scope.vo, session=session):
|
|
204
|
+
raise VONotFound('VO {} not found'.format(scope.vo))
|
|
205
|
+
|
|
206
|
+
# Verify both the scope and account exist
|
|
207
|
+
account_core.get_account(account, session=session)
|
|
208
|
+
if not check_scope(scope):
|
|
209
|
+
raise ScopeNotFound
|
|
210
|
+
|
|
211
|
+
stmt = update(
|
|
212
|
+
models.Scope
|
|
213
|
+
).where(
|
|
214
|
+
models.Scope.scope == scope
|
|
215
|
+
).values({
|
|
216
|
+
models.Scope.account: account
|
|
217
|
+
})
|
|
218
|
+
try:
|
|
219
|
+
session.execute(stmt)
|
|
220
|
+
except Exception:
|
|
221
|
+
raise RucioException(str(format_exc()))
|
|
@@ -177,6 +177,8 @@ def run_once(heartbeat_handler: HeartbeatHandler, inputfile: str, **_kwargs) ->
|
|
|
177
177
|
vo = map_vo(client.vo) # type: ignore
|
|
178
178
|
filters = {"scope": InternalScope("*", vo=vo)}
|
|
179
179
|
scopes = list_scopes(filter_=filters)
|
|
180
|
+
if not isinstance(scopes[0], str): # TODO Backwards Compat - Remove in v40, #8125
|
|
181
|
+
scopes = [scope['scope'] for scope in scopes]
|
|
180
182
|
if InternalScope(scope, vo=vo) not in scopes:
|
|
181
183
|
logger(logging.ERROR, "Scope %s does not exist. Exiting", scope)
|
|
182
184
|
return True
|
rucio/db/sqla/models.py
CHANGED
|
@@ -877,6 +877,28 @@ class RSE(BASE, SoftModelBase):
|
|
|
877
877
|
CheckConstraint('RSE_TYPE IS NOT NULL', name='RSES_TYPE_NN'),
|
|
878
878
|
ForeignKeyConstraint(['vo'], ['vos.vo'], name='RSES_VOS_FK'), )
|
|
879
879
|
|
|
880
|
+
@staticmethod
|
|
881
|
+
def from_str(key: str, value: str) -> Any:
|
|
882
|
+
"""Parses str value to key-specific database type."""
|
|
883
|
+
|
|
884
|
+
if key in ['deterministic', 'volatile', 'staging_area', 'availability_read', 'availability_write', 'availability_delete']:
|
|
885
|
+
# boolean types
|
|
886
|
+
if value == '1' or value.casefold() == 'true'.casefold():
|
|
887
|
+
return True
|
|
888
|
+
elif value == '0' or value.casefold() == 'false'.casefold():
|
|
889
|
+
return False
|
|
890
|
+
else:
|
|
891
|
+
raise ValueError(f'Invalid boolean value: {value}')
|
|
892
|
+
|
|
893
|
+
elif key == 'rse_type':
|
|
894
|
+
try:
|
|
895
|
+
return RSEType[value]
|
|
896
|
+
except KeyError:
|
|
897
|
+
raise ValueError(f'Invalid rse_type: {value}')
|
|
898
|
+
|
|
899
|
+
else:
|
|
900
|
+
return value
|
|
901
|
+
|
|
880
902
|
|
|
881
903
|
class RSELimit(BASE, ModelBase):
|
|
882
904
|
"""Represents RSE limits"""
|
rucio/gateway/did.py
CHANGED
|
@@ -62,7 +62,7 @@ def list_dids(
|
|
|
62
62
|
if 'account' in or_group:
|
|
63
63
|
or_group['account'] = InternalAccount(or_group['account'], vo=vo)
|
|
64
64
|
if 'scope' in or_group:
|
|
65
|
-
or_group['
|
|
65
|
+
or_group['scope'] = InternalScope(or_group['scope'], vo=vo)
|
|
66
66
|
|
|
67
67
|
with db_session(DatabaseOperationType.READ) as session:
|
|
68
68
|
result = did.list_dids(scope=internal_scope, filters=filters, did_type=did_type, ignore_case=ignore_case,
|
rucio/gateway/dirac.py
CHANGED
|
@@ -52,7 +52,7 @@ def add_files(
|
|
|
52
52
|
|
|
53
53
|
with db_session(DatabaseOperationType.WRITE) as session:
|
|
54
54
|
filter_ = {'scope': InternalScope(scope='*', vo=vo)}
|
|
55
|
-
scopes = [scope.external for scope in list_scopes(filter_=filter_, session=session)]
|
|
55
|
+
scopes = [scope['scope'].external for scope in list_scopes(filter_=filter_, session=session)]
|
|
56
56
|
dids = []
|
|
57
57
|
rses = {}
|
|
58
58
|
for lfn in lfns:
|
rucio/gateway/scope.py
CHANGED
|
@@ -12,19 +12,23 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
|
-
from typing import Any, Optional
|
|
15
|
+
from typing import TYPE_CHECKING, Any, Optional
|
|
16
16
|
|
|
17
17
|
import rucio.gateway.permission
|
|
18
18
|
from rucio.common.constants import DEFAULT_VO
|
|
19
19
|
from rucio.common.exception import AccessDenied
|
|
20
20
|
from rucio.common.schema import validate_schema
|
|
21
21
|
from rucio.common.types import InternalAccount, InternalScope
|
|
22
|
+
from rucio.common.utils import gateway_update_return_dict
|
|
22
23
|
from rucio.core import scope as core_scope
|
|
23
24
|
from rucio.db.sqla.constants import DatabaseOperationType
|
|
24
25
|
from rucio.db.sqla.session import db_session
|
|
25
26
|
|
|
27
|
+
if TYPE_CHECKING:
|
|
28
|
+
from collections.abc import Generator
|
|
26
29
|
|
|
27
|
-
|
|
30
|
+
|
|
31
|
+
def list_scopes(filter_: Optional[dict[str, Any]] = None, vo: str = DEFAULT_VO) -> 'Generator[dict[str, Any]]':
|
|
28
32
|
"""
|
|
29
33
|
Lists all scopes.
|
|
30
34
|
|
|
@@ -42,7 +46,9 @@ def list_scopes(filter_: Optional[dict[str, Any]] = None, vo: str = DEFAULT_VO)
|
|
|
42
46
|
filter_['scope'] = InternalScope(scope='*', vo=vo)
|
|
43
47
|
|
|
44
48
|
with db_session(DatabaseOperationType.READ) as session:
|
|
45
|
-
|
|
49
|
+
scopes = core_scope.list_scopes(filter_=filter_, session=session)
|
|
50
|
+
for scope in scopes:
|
|
51
|
+
yield gateway_update_return_dict(scope, session=session)
|
|
46
52
|
|
|
47
53
|
|
|
48
54
|
def add_scope(
|
|
@@ -92,3 +98,29 @@ def get_scopes(
|
|
|
92
98
|
|
|
93
99
|
with db_session(DatabaseOperationType.READ) as session:
|
|
94
100
|
return [scope.external for scope in core_scope.get_scopes(internal_account, session=session)]
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def update_scope(
|
|
104
|
+
scope: str,
|
|
105
|
+
account: str,
|
|
106
|
+
issuer: str,
|
|
107
|
+
vo: str = DEFAULT_VO
|
|
108
|
+
) -> None:
|
|
109
|
+
"""
|
|
110
|
+
Change ownership of a scope
|
|
111
|
+
|
|
112
|
+
:param account: New owner for the scope
|
|
113
|
+
:param scope: Scope to change
|
|
114
|
+
param issuer: User making the request
|
|
115
|
+
:param vo: VO to act on
|
|
116
|
+
|
|
117
|
+
"""
|
|
118
|
+
kwargs = {'scope': scope, 'account': account}
|
|
119
|
+
with db_session(DatabaseOperationType.WRITE) as session:
|
|
120
|
+
auth_result = rucio.gateway.permission.has_permission(issuer=issuer, vo=vo, action='update_scope', kwargs=kwargs, session=session)
|
|
121
|
+
if not auth_result.allowed:
|
|
122
|
+
raise AccessDenied('Account %s can not add scope. %s' % (issuer, auth_result.message))
|
|
123
|
+
|
|
124
|
+
internal_account = InternalAccount(account, vo=vo)
|
|
125
|
+
internal_scope = InternalScope(scope, vo=vo)
|
|
126
|
+
core_scope.update_scope(internal_scope, internal_account, session=session)
|
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.
|
|
7
|
+
'version': '38.5.0',
|
|
8
8
|
'branch_nick': 'release-38-LTS',
|
|
9
|
-
'revision_id': '
|
|
10
|
-
'revno':
|
|
9
|
+
'revision_id': '430fd3dd8f4dc5103e1e932c9515421e1c515c3e',
|
|
10
|
+
'revno': 14073
|
|
11
11
|
}
|
|
@@ -48,10 +48,10 @@ class OpenDataView(ErrorHandlingMethodView):
|
|
|
48
48
|
def get(self) -> "Response":
|
|
49
49
|
"""
|
|
50
50
|
---
|
|
51
|
-
summary: List
|
|
52
|
-
description: "Retrieves a list of
|
|
51
|
+
summary: List Open Data DIDs
|
|
52
|
+
description: "Retrieves a list of Open Data DIDs. Supports optional query parameters for pagination and filtering by state."
|
|
53
53
|
tags:
|
|
54
|
-
-
|
|
54
|
+
- Open Data
|
|
55
55
|
parameters:
|
|
56
56
|
- name: limit
|
|
57
57
|
in: query
|
|
@@ -76,7 +76,7 @@ class OpenDataView(ErrorHandlingMethodView):
|
|
|
76
76
|
style: form
|
|
77
77
|
responses:
|
|
78
78
|
200:
|
|
79
|
-
description: "Successful retrieval of the list of
|
|
79
|
+
description: "Successful retrieval of the list of Open Data DIDs."
|
|
80
80
|
content:
|
|
81
81
|
application/json:
|
|
82
82
|
schema:
|
|
@@ -126,10 +126,10 @@ class OpenDataDIDsView(ErrorHandlingMethodView):
|
|
|
126
126
|
def get(self, scope: str, name: str) -> "Response":
|
|
127
127
|
"""
|
|
128
128
|
---
|
|
129
|
-
summary: Get
|
|
130
|
-
description: "Retrieves detailed
|
|
129
|
+
summary: Get Open Data DID Information
|
|
130
|
+
description: "Retrieves detailed Open Data information for the given scope and name. Supports optional query parameters to control the inclusion of files, metadata, and DOI information."
|
|
131
131
|
tags:
|
|
132
|
-
-
|
|
132
|
+
- Open Data
|
|
133
133
|
parameters:
|
|
134
134
|
- name: scope
|
|
135
135
|
in: path
|
|
@@ -178,7 +178,7 @@ class OpenDataDIDsView(ErrorHandlingMethodView):
|
|
|
178
178
|
style: form
|
|
179
179
|
responses:
|
|
180
180
|
200:
|
|
181
|
-
description: "Successful retrieval of
|
|
181
|
+
description: "Successful retrieval of Open Data DID information."
|
|
182
182
|
content:
|
|
183
183
|
application/json:
|
|
184
184
|
schema:
|
|
@@ -195,10 +195,10 @@ class OpenDataDIDsView(ErrorHandlingMethodView):
|
|
|
195
195
|
def post(self, scope: str, name: str) -> "Response":
|
|
196
196
|
"""
|
|
197
197
|
---
|
|
198
|
-
summary: Register
|
|
199
|
-
description: "Registers an existing DID as
|
|
198
|
+
summary: Register Open Data DID
|
|
199
|
+
description: "Registers an existing DID as Open Data."
|
|
200
200
|
tags:
|
|
201
|
-
-
|
|
201
|
+
- Open Data
|
|
202
202
|
parameters:
|
|
203
203
|
- name: scope
|
|
204
204
|
in: path
|
|
@@ -216,7 +216,7 @@ class OpenDataDIDsView(ErrorHandlingMethodView):
|
|
|
216
216
|
style: simple
|
|
217
217
|
responses:
|
|
218
218
|
201:
|
|
219
|
-
description: "
|
|
219
|
+
description: "Open Data DID successfully registered."
|
|
220
220
|
content:
|
|
221
221
|
application/json:
|
|
222
222
|
schema:
|
|
@@ -229,7 +229,7 @@ class OpenDataDIDsView(ErrorHandlingMethodView):
|
|
|
229
229
|
404:
|
|
230
230
|
description: "Data Identifier not found."
|
|
231
231
|
409:
|
|
232
|
-
description: "Data Identifier already exists in the
|
|
232
|
+
description: "Data Identifier already exists in the Open Data catalog."
|
|
233
233
|
"""
|
|
234
234
|
vo = request.environ.get("vo", DEFAULT_VO)
|
|
235
235
|
try:
|
|
@@ -249,10 +249,10 @@ class OpenDataDIDsView(ErrorHandlingMethodView):
|
|
|
249
249
|
def put(self, scope: str, name: str) -> "Response":
|
|
250
250
|
"""
|
|
251
251
|
---
|
|
252
|
-
summary: Update
|
|
253
|
-
description: "Updates the properties of an existing
|
|
252
|
+
summary: Update Open Data DID
|
|
253
|
+
description: "Updates the properties of an existing Open Data DID."
|
|
254
254
|
tags:
|
|
255
|
-
-
|
|
255
|
+
- Open Data
|
|
256
256
|
parameters:
|
|
257
257
|
- name: scope
|
|
258
258
|
in: path
|
|
@@ -291,7 +291,7 @@ class OpenDataDIDsView(ErrorHandlingMethodView):
|
|
|
291
291
|
example: '10.1234/abcd.efgh'."
|
|
292
292
|
responses:
|
|
293
293
|
200:
|
|
294
|
-
description: "
|
|
294
|
+
description: "Open Data DID successfully updated."
|
|
295
295
|
content:
|
|
296
296
|
application/json:
|
|
297
297
|
schema:
|
|
@@ -329,10 +329,10 @@ class OpenDataDIDsView(ErrorHandlingMethodView):
|
|
|
329
329
|
def delete(self, scope: str, name: str) -> "Response":
|
|
330
330
|
"""
|
|
331
331
|
---
|
|
332
|
-
summary: Delete
|
|
333
|
-
description: "Deletes an entry in the
|
|
332
|
+
summary: Delete Open Data DID
|
|
333
|
+
description: "Deletes an entry in the Open Data catalog."
|
|
334
334
|
tags:
|
|
335
|
-
-
|
|
335
|
+
- Open Data
|
|
336
336
|
parameters:
|
|
337
337
|
- name: scope
|
|
338
338
|
in: path
|
|
@@ -350,7 +350,7 @@ class OpenDataDIDsView(ErrorHandlingMethodView):
|
|
|
350
350
|
style: simple
|
|
351
351
|
responses:
|
|
352
352
|
204:
|
|
353
|
-
description: "
|
|
353
|
+
description: "Open Data DID successfully deleted. No content is returned."
|
|
354
354
|
400:
|
|
355
355
|
description: "Invalid input: The provided scope/name is not valid."
|
|
356
356
|
401:
|
|
@@ -25,10 +25,10 @@ class OpenDataPublicView(ErrorHandlingMethodView):
|
|
|
25
25
|
def get(self) -> "Response":
|
|
26
26
|
"""
|
|
27
27
|
---
|
|
28
|
-
summary: List
|
|
29
|
-
description: "Retrieves a list of public
|
|
28
|
+
summary: List Open Data DIDs marked as public
|
|
29
|
+
description: "Retrieves a list of public Open Data DIDs. Supports optional query parameters for pagination."
|
|
30
30
|
tags:
|
|
31
|
-
-
|
|
31
|
+
- Open Data Public
|
|
32
32
|
parameters:
|
|
33
33
|
- name: limit
|
|
34
34
|
in: query
|
|
@@ -46,7 +46,7 @@ class OpenDataPublicView(ErrorHandlingMethodView):
|
|
|
46
46
|
style: form
|
|
47
47
|
responses:
|
|
48
48
|
200:
|
|
49
|
-
description: "Successful retrieval of the list of
|
|
49
|
+
description: "Successful retrieval of the list of Open Data DIDs."
|
|
50
50
|
content:
|
|
51
51
|
application/json:
|
|
52
52
|
schema:
|
|
@@ -65,10 +65,10 @@ class OpenDataPublicDIDsView(ErrorHandlingMethodView):
|
|
|
65
65
|
def get(self, scope: str, name: str) -> "Response":
|
|
66
66
|
"""
|
|
67
67
|
---
|
|
68
|
-
summary: Get
|
|
69
|
-
description: "Retrieves detailed
|
|
68
|
+
summary: Get Open Data DID Information for public Open Data DIDs
|
|
69
|
+
description: "Retrieves detailed Open Data information for the given scope and name. Only works for public opendata DIDs. Supports optional query parameters to control the inclusion of files, metadata, and DOI information."
|
|
70
70
|
tags:
|
|
71
|
-
-
|
|
71
|
+
- Open Data Public
|
|
72
72
|
parameters:
|
|
73
73
|
- name: scope
|
|
74
74
|
in: path
|
|
@@ -110,7 +110,7 @@ class OpenDataPublicDIDsView(ErrorHandlingMethodView):
|
|
|
110
110
|
style: form
|
|
111
111
|
responses:
|
|
112
112
|
200:
|
|
113
|
-
description: "Successful retrieval of
|
|
113
|
+
description: "Successful retrieval of Open Data DID information."
|
|
114
114
|
content:
|
|
115
115
|
application/json:
|
|
116
116
|
schema:
|
|
@@ -12,11 +12,12 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
|
|
16
|
+
from flask import Flask, Response, jsonify, request
|
|
16
17
|
|
|
17
18
|
from rucio.common.constants import HTTPMethod
|
|
18
|
-
from rucio.common.exception import AccountNotFound, Duplicate, ScopeNotFound
|
|
19
|
-
from rucio.gateway.scope import add_scope, get_scopes, list_scopes
|
|
19
|
+
from rucio.common.exception import AccountNotFound, Duplicate, ScopeNotFound, VONotFound
|
|
20
|
+
from rucio.gateway.scope import add_scope, get_scopes, list_scopes, update_scope
|
|
20
21
|
from rucio.web.rest.flaskapi.authenticated_bp import AuthenticatedBlueprint
|
|
21
22
|
from rucio.web.rest.flaskapi.v1.common import ErrorHandlingMethodView, check_accept_header_wrapper_flask, generate_http_error_flask, response_headers
|
|
22
23
|
|
|
@@ -24,7 +25,7 @@ from rucio.web.rest.flaskapi.v1.common import ErrorHandlingMethodView, check_acc
|
|
|
24
25
|
class Scope(ErrorHandlingMethodView):
|
|
25
26
|
|
|
26
27
|
@check_accept_header_wrapper_flask(['application/json'])
|
|
27
|
-
def get(self):
|
|
28
|
+
def get(self) -> Response:
|
|
28
29
|
"""
|
|
29
30
|
---
|
|
30
31
|
summary: List Scopes
|
|
@@ -40,16 +41,27 @@ class Scope(ErrorHandlingMethodView):
|
|
|
40
41
|
description: "All scopes."
|
|
41
42
|
type: array
|
|
42
43
|
items:
|
|
43
|
-
|
|
44
|
-
|
|
44
|
+
type: object
|
|
45
|
+
properties:
|
|
46
|
+
scope:
|
|
47
|
+
description: "A scope."
|
|
48
|
+
type: string
|
|
49
|
+
account:
|
|
50
|
+
description: "The owner account."
|
|
51
|
+
type: string
|
|
52
|
+
|
|
45
53
|
401:
|
|
46
54
|
description: "Invalid Auth Token"
|
|
47
55
|
406:
|
|
48
56
|
description: "Not acceptable"
|
|
49
57
|
"""
|
|
50
|
-
|
|
58
|
+
scopes = list_scopes(vo=request.environ['vo'])
|
|
59
|
+
res = []
|
|
60
|
+
for dictionary in scopes:
|
|
61
|
+
res.append(dictionary)
|
|
62
|
+
return jsonify(res)
|
|
51
63
|
|
|
52
|
-
def post(self, account, scope):
|
|
64
|
+
def post(self, account: str, scope: str) -> Response:
|
|
53
65
|
"""
|
|
54
66
|
---
|
|
55
67
|
summary: Add Scope
|
|
@@ -91,13 +103,53 @@ class Scope(ErrorHandlingMethodView):
|
|
|
91
103
|
except AccountNotFound as error:
|
|
92
104
|
return generate_http_error_flask(404, error)
|
|
93
105
|
|
|
94
|
-
return 'Created', 201
|
|
106
|
+
return Response('Created', 201)
|
|
107
|
+
|
|
108
|
+
def put(self, account: str, scope: str) -> Response:
|
|
109
|
+
"""
|
|
110
|
+
---
|
|
111
|
+
summary: Change ownership of a scope.
|
|
112
|
+
description: "Changes ownership of a scope.."
|
|
113
|
+
tags:
|
|
114
|
+
- Scopes
|
|
115
|
+
parameters:
|
|
116
|
+
- name: account
|
|
117
|
+
in: path
|
|
118
|
+
description: "The new owner account"
|
|
119
|
+
schema:
|
|
120
|
+
type: string
|
|
121
|
+
style: simple
|
|
122
|
+
- name: scope
|
|
123
|
+
in: path
|
|
124
|
+
description: "The name of the scope."
|
|
125
|
+
schema:
|
|
126
|
+
type: string
|
|
127
|
+
style: simple
|
|
128
|
+
responses:
|
|
129
|
+
201:
|
|
130
|
+
description: "OK"
|
|
131
|
+
content:
|
|
132
|
+
application/json:
|
|
133
|
+
schema:
|
|
134
|
+
type: string
|
|
135
|
+
enum: ['']
|
|
136
|
+
401:
|
|
137
|
+
description: "Invalid Auth Token"
|
|
138
|
+
403:
|
|
139
|
+
description: "Scope or already exists"
|
|
140
|
+
"""
|
|
141
|
+
try:
|
|
142
|
+
update_scope(scope=scope, account=account, issuer=request.environ['issuer'], vo=request.environ['vo'])
|
|
143
|
+
except (ScopeNotFound, AccountNotFound, VONotFound) as error:
|
|
144
|
+
return generate_http_error_flask(404, error)
|
|
145
|
+
|
|
146
|
+
return Response("", 200)
|
|
95
147
|
|
|
96
148
|
|
|
97
149
|
class AccountScopeList(ErrorHandlingMethodView):
|
|
98
150
|
|
|
99
151
|
@check_accept_header_wrapper_flask(['application/json'])
|
|
100
|
-
def get(self, account):
|
|
152
|
+
def get(self, account: str) -> Response:
|
|
101
153
|
"""
|
|
102
154
|
---
|
|
103
155
|
summary: List Account Scopes
|
|
@@ -145,7 +197,7 @@ def blueprint() -> AuthenticatedBlueprint:
|
|
|
145
197
|
|
|
146
198
|
scope_view = Scope.as_view('scope')
|
|
147
199
|
bp.add_url_rule('/', view_func=scope_view, methods=[HTTPMethod.GET.value])
|
|
148
|
-
bp.add_url_rule('/<account>/<scope>', view_func=scope_view, methods=[HTTPMethod.POST.value])
|
|
200
|
+
bp.add_url_rule('/<account>/<scope>', view_func=scope_view, methods=[HTTPMethod.POST.value, HTTPMethod.PUT.value])
|
|
149
201
|
account_scope_list_view = AccountScopeList.as_view('account_scope_list')
|
|
150
202
|
bp.add_url_rule('/<account>/scopes', view_func=account_scope_list_view, methods=[HTTPMethod.GET.value])
|
|
151
203
|
|
|
@@ -121,8 +121,8 @@ usercert = /opt/rucio/tools/x509up
|
|
|
121
121
|
|
|
122
122
|
[messaging-fts3]
|
|
123
123
|
port = 61123
|
|
124
|
-
ssl_key_file = /
|
|
125
|
-
ssl_cert_file = /
|
|
124
|
+
ssl_key_file = /etc/grid-security/hostkey.pem
|
|
125
|
+
ssl_cert_file = /etc/grid-security/hostcert.pem
|
|
126
126
|
destination = /topic/transfer.fts_monitoring_queue_state
|
|
127
127
|
brokers = dashb-test-mb.cern.ch
|
|
128
128
|
voname = atlas
|
|
@@ -199,7 +199,6 @@ account = cache_mb
|
|
|
199
199
|
cacert = /opt/rucio/etc/web/ca.crt
|
|
200
200
|
#cacert = /etc/pki/tls/certs/CERN-bundle.pem
|
|
201
201
|
usercert = /opt/rucio/etc/web/usercert.pem
|
|
202
|
-
#usercert = /home/mario/.ssh/usercert_with_key.pem
|
|
203
202
|
|
|
204
203
|
[nagios]
|
|
205
204
|
proxy = /opt/rucio/etc/ddmadmin.proxy.nagios
|
|
@@ -102,8 +102,8 @@ usercert = /opt/rucio/tools/x509up
|
|
|
102
102
|
|
|
103
103
|
[messaging-fts3]
|
|
104
104
|
port = 61123
|
|
105
|
-
ssl_key_file = /
|
|
106
|
-
ssl_cert_file = /
|
|
105
|
+
ssl_key_file = /etc/grid-security/hostkey.pem
|
|
106
|
+
ssl_cert_file = /etc/grid-security/hostcert.pem
|
|
107
107
|
destination = /topic/transfer.fts_monitoring_queue_state
|
|
108
108
|
brokers = dashb-test-mb.cern.ch
|
|
109
109
|
voname = atlas
|
|
@@ -179,7 +179,6 @@ account = cache_mb
|
|
|
179
179
|
cacert = /opt/rucio/etc/web/ca.crt
|
|
180
180
|
#cacert = /etc/pki/tls/certs/CERN-bundle.pem
|
|
181
181
|
usercert = /opt/rucio/etc/web/usercert.pem
|
|
182
|
-
#usercert = /home/mario/.ssh/usercert_with_key.pem
|
|
183
182
|
|
|
184
183
|
[nagios]
|
|
185
184
|
proxy = /opt/rucio/etc/ddmadmin.proxy.nagios
|