rucio 35.7.0__py3-none-any.whl → 37.0.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/alembicrevision.py +1 -1
- rucio/{daemons/c3po/collectors → cli}/__init__.py +1 -0
- rucio/cli/account.py +216 -0
- rucio-35.7.0.data/scripts/rucio → rucio/cli/bin_legacy/rucio.py +769 -486
- rucio-35.7.0.data/scripts/rucio-admin → rucio/cli/bin_legacy/rucio_admin.py +476 -423
- rucio/cli/command.py +272 -0
- rucio/cli/config.py +72 -0
- rucio/cli/did.py +191 -0
- rucio/cli/download.py +128 -0
- rucio/cli/lifetime_exception.py +33 -0
- rucio/cli/replica.py +162 -0
- rucio/cli/rse.py +293 -0
- rucio/cli/rule.py +158 -0
- rucio/cli/scope.py +40 -0
- rucio/cli/subscription.py +73 -0
- rucio/cli/upload.py +60 -0
- rucio/cli/utils.py +226 -0
- rucio/client/accountclient.py +0 -1
- rucio/client/baseclient.py +33 -24
- rucio/client/client.py +45 -1
- rucio/client/didclient.py +5 -3
- rucio/client/downloadclient.py +6 -8
- rucio/client/replicaclient.py +0 -2
- rucio/client/richclient.py +317 -0
- rucio/client/rseclient.py +4 -4
- rucio/client/uploadclient.py +26 -12
- rucio/common/bittorrent.py +234 -0
- rucio/common/cache.py +66 -29
- rucio/common/checksum.py +168 -0
- rucio/common/client.py +122 -0
- rucio/common/config.py +22 -35
- rucio/common/constants.py +61 -3
- rucio/common/didtype.py +72 -24
- rucio/common/dumper/__init__.py +45 -38
- rucio/common/dumper/consistency.py +75 -30
- rucio/common/dumper/data_models.py +63 -19
- rucio/common/dumper/path_parsing.py +19 -8
- rucio/common/exception.py +65 -8
- rucio/common/extra.py +5 -10
- rucio/common/logging.py +13 -13
- rucio/common/pcache.py +8 -7
- rucio/common/plugins.py +59 -27
- rucio/common/policy.py +12 -3
- rucio/common/schema/__init__.py +84 -34
- rucio/common/schema/generic.py +0 -17
- rucio/common/schema/generic_multi_vo.py +0 -17
- rucio/common/test_rucio_server.py +12 -6
- rucio/common/types.py +132 -52
- rucio/common/utils.py +93 -643
- rucio/core/account_limit.py +14 -12
- rucio/core/authentication.py +2 -2
- rucio/core/config.py +23 -42
- rucio/core/credential.py +14 -15
- rucio/core/did.py +5 -1
- rucio/core/did_meta_plugins/elasticsearch_meta.py +407 -0
- rucio/core/did_meta_plugins/filter_engine.py +62 -3
- rucio/core/did_meta_plugins/json_meta.py +2 -2
- rucio/core/did_meta_plugins/mongo_meta.py +43 -30
- rucio/core/did_meta_plugins/postgres_meta.py +75 -39
- rucio/core/identity.py +6 -5
- rucio/core/importer.py +4 -3
- rucio/core/lifetime_exception.py +2 -2
- rucio/core/lock.py +8 -7
- rucio/core/message.py +6 -0
- rucio/core/monitor.py +30 -29
- rucio/core/naming_convention.py +2 -2
- rucio/core/nongrid_trace.py +2 -2
- rucio/core/oidc.py +11 -9
- rucio/core/permission/__init__.py +79 -37
- rucio/core/permission/generic.py +1 -7
- rucio/core/permission/generic_multi_vo.py +1 -7
- rucio/core/quarantined_replica.py +4 -3
- rucio/core/replica.py +464 -139
- rucio/core/replica_sorter.py +55 -59
- rucio/core/request.py +34 -32
- rucio/core/rse.py +301 -97
- rucio/core/rse_counter.py +1 -2
- rucio/core/rse_expression_parser.py +7 -7
- rucio/core/rse_selector.py +9 -7
- rucio/core/rule.py +41 -40
- rucio/core/rule_grouping.py +42 -40
- rucio/core/scope.py +5 -4
- rucio/core/subscription.py +26 -28
- rucio/core/topology.py +11 -11
- rucio/core/trace.py +2 -2
- rucio/core/transfer.py +29 -15
- rucio/core/volatile_replica.py +4 -3
- rucio/daemons/atropos/atropos.py +1 -1
- rucio/daemons/auditor/__init__.py +2 -2
- rucio/daemons/auditor/srmdumps.py +6 -6
- rucio/daemons/automatix/automatix.py +32 -21
- rucio/daemons/badreplicas/necromancer.py +2 -2
- rucio/daemons/bb8/nuclei_background_rebalance.py +1 -1
- rucio/daemons/bb8/t2_background_rebalance.py +1 -1
- rucio/daemons/common.py +15 -25
- rucio/daemons/conveyor/finisher.py +2 -2
- rucio/daemons/conveyor/poller.py +18 -28
- rucio/daemons/conveyor/receiver.py +2 -2
- rucio/daemons/conveyor/stager.py +1 -0
- rucio/daemons/conveyor/submitter.py +3 -3
- rucio/daemons/hermes/hermes.py +91 -30
- rucio/daemons/judge/evaluator.py +2 -2
- rucio/daemons/oauthmanager/oauthmanager.py +3 -3
- rucio/daemons/reaper/dark_reaper.py +7 -3
- rucio/daemons/reaper/reaper.py +12 -16
- rucio/daemons/rsedecommissioner/config.py +1 -1
- rucio/daemons/rsedecommissioner/profiles/generic.py +5 -4
- rucio/daemons/rsedecommissioner/profiles/types.py +7 -6
- rucio/daemons/rsedecommissioner/rse_decommissioner.py +1 -1
- rucio/daemons/storage/consistency/actions.py +8 -6
- rucio/daemons/tracer/kronos.py +4 -4
- rucio/db/sqla/constants.py +5 -0
- rucio/db/sqla/migrate_repo/versions/1677d4d803c8_split_rse_availability_into_multiple.py +4 -4
- rucio/db/sqla/migrate_repo/versions/30d5206e9cad_increase_oauthrequest_redirect_msg_.py +37 -0
- rucio/db/sqla/models.py +157 -154
- rucio/db/sqla/session.py +58 -27
- rucio/db/sqla/types.py +2 -2
- rucio/db/sqla/util.py +2 -2
- rucio/gateway/account.py +18 -12
- rucio/gateway/account_limit.py +137 -60
- rucio/gateway/authentication.py +18 -12
- rucio/gateway/config.py +30 -20
- rucio/gateway/credential.py +9 -10
- rucio/gateway/did.py +70 -53
- rucio/gateway/dirac.py +6 -4
- rucio/gateway/exporter.py +3 -2
- rucio/gateway/heartbeat.py +6 -4
- rucio/gateway/identity.py +36 -51
- rucio/gateway/importer.py +3 -2
- rucio/gateway/lifetime_exception.py +3 -2
- rucio/gateway/meta_conventions.py +17 -6
- rucio/gateway/permission.py +4 -1
- rucio/gateway/quarantined_replica.py +3 -2
- rucio/gateway/replica.py +31 -22
- rucio/gateway/request.py +27 -18
- rucio/gateway/rse.py +69 -37
- rucio/gateway/rule.py +46 -26
- rucio/gateway/scope.py +3 -2
- rucio/gateway/subscription.py +14 -11
- rucio/gateway/vo.py +12 -8
- rucio/rse/__init__.py +3 -3
- rucio/rse/protocols/bittorrent.py +11 -1
- rucio/rse/protocols/cache.py +0 -11
- rucio/rse/protocols/dummy.py +0 -11
- rucio/rse/protocols/gfal.py +14 -9
- rucio/rse/protocols/globus.py +1 -1
- rucio/rse/protocols/http_cache.py +1 -1
- rucio/rse/protocols/posix.py +2 -2
- rucio/rse/protocols/protocol.py +84 -317
- rucio/rse/protocols/rclone.py +2 -1
- rucio/rse/protocols/rfio.py +10 -1
- rucio/rse/protocols/ssh.py +2 -1
- rucio/rse/protocols/storm.py +2 -13
- rucio/rse/protocols/webdav.py +74 -30
- rucio/rse/protocols/xrootd.py +2 -1
- rucio/rse/rsemanager.py +170 -53
- rucio/rse/translation.py +260 -0
- rucio/tests/common.py +23 -13
- rucio/tests/common_server.py +26 -9
- rucio/transfertool/bittorrent.py +15 -14
- rucio/transfertool/bittorrent_driver.py +5 -7
- rucio/transfertool/bittorrent_driver_qbittorrent.py +9 -8
- rucio/transfertool/fts3.py +20 -16
- rucio/transfertool/mock.py +2 -3
- rucio/vcsversion.py +4 -4
- rucio/version.py +7 -0
- rucio/web/rest/flaskapi/v1/accounts.py +17 -3
- rucio/web/rest/flaskapi/v1/auth.py +5 -5
- rucio/web/rest/flaskapi/v1/credentials.py +3 -2
- rucio/web/rest/flaskapi/v1/dids.py +21 -15
- rucio/web/rest/flaskapi/v1/identities.py +33 -9
- rucio/web/rest/flaskapi/v1/redirect.py +5 -4
- rucio/web/rest/flaskapi/v1/replicas.py +12 -8
- rucio/web/rest/flaskapi/v1/rses.py +15 -4
- rucio/web/rest/flaskapi/v1/traces.py +56 -19
- {rucio-35.7.0.data → rucio-37.0.0.data}/data/rucio/etc/alembic.ini.template +1 -1
- {rucio-35.7.0.data → rucio-37.0.0.data}/data/rucio/etc/alembic_offline.ini.template +1 -1
- {rucio-35.7.0.data → rucio-37.0.0.data}/data/rucio/etc/rucio.cfg.atlas.client.template +3 -2
- {rucio-35.7.0.data → rucio-37.0.0.data}/data/rucio/etc/rucio.cfg.template +3 -19
- {rucio-35.7.0.data → rucio-37.0.0.data}/data/rucio/etc/rucio_multi_vo.cfg.template +1 -18
- {rucio-35.7.0.data → rucio-37.0.0.data}/data/rucio/requirements.server.txt +97 -68
- rucio-37.0.0.data/scripts/rucio +133 -0
- rucio-37.0.0.data/scripts/rucio-admin +97 -0
- {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-atropos +2 -2
- {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-auditor +2 -1
- {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-automatix +2 -2
- {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-cache-client +17 -10
- {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-conveyor-receiver +1 -0
- {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-kronos +1 -0
- {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-minos +2 -2
- {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-minos-temporary-expiration +2 -2
- {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-necromancer +2 -2
- {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-reaper +6 -6
- {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-transmogrifier +2 -2
- rucio-37.0.0.dist-info/METADATA +92 -0
- {rucio-35.7.0.dist-info → rucio-37.0.0.dist-info}/RECORD +237 -243
- {rucio-35.7.0.dist-info → rucio-37.0.0.dist-info}/licenses/AUTHORS.rst +3 -0
- rucio/common/schema/atlas.py +0 -413
- rucio/common/schema/belleii.py +0 -408
- rucio/common/schema/domatpc.py +0 -401
- rucio/common/schema/escape.py +0 -426
- rucio/common/schema/icecube.py +0 -406
- rucio/core/permission/atlas.py +0 -1348
- rucio/core/permission/belleii.py +0 -1077
- rucio/core/permission/escape.py +0 -1078
- rucio/daemons/c3po/algorithms/__init__.py +0 -13
- rucio/daemons/c3po/algorithms/simple.py +0 -134
- rucio/daemons/c3po/algorithms/t2_free_space.py +0 -128
- rucio/daemons/c3po/algorithms/t2_free_space_only_pop.py +0 -130
- rucio/daemons/c3po/algorithms/t2_free_space_only_pop_with_network.py +0 -294
- rucio/daemons/c3po/c3po.py +0 -371
- rucio/daemons/c3po/collectors/agis.py +0 -108
- rucio/daemons/c3po/collectors/free_space.py +0 -81
- rucio/daemons/c3po/collectors/jedi_did.py +0 -57
- rucio/daemons/c3po/collectors/mock_did.py +0 -51
- rucio/daemons/c3po/collectors/network_metrics.py +0 -71
- rucio/daemons/c3po/collectors/workload.py +0 -112
- rucio/daemons/c3po/utils/__init__.py +0 -13
- rucio/daemons/c3po/utils/dataset_cache.py +0 -50
- rucio/daemons/c3po/utils/expiring_dataset_cache.py +0 -56
- rucio/daemons/c3po/utils/expiring_list.py +0 -62
- rucio/daemons/c3po/utils/popularity.py +0 -85
- rucio/daemons/c3po/utils/timeseries.py +0 -89
- rucio/rse/protocols/gsiftp.py +0 -92
- rucio-35.7.0.data/scripts/rucio-c3po +0 -85
- rucio-35.7.0.dist-info/METADATA +0 -72
- /rucio/{daemons/c3po → cli/bin_legacy}/__init__.py +0 -0
- {rucio-35.7.0.data → rucio-37.0.0.data}/data/rucio/etc/globus-config.yml.template +0 -0
- {rucio-35.7.0.data → rucio-37.0.0.data}/data/rucio/etc/ldap.cfg.template +0 -0
- {rucio-35.7.0.data → rucio-37.0.0.data}/data/rucio/etc/mail_templates/rule_approval_request.tmpl +0 -0
- {rucio-35.7.0.data → rucio-37.0.0.data}/data/rucio/etc/mail_templates/rule_approved_admin.tmpl +0 -0
- {rucio-35.7.0.data → rucio-37.0.0.data}/data/rucio/etc/mail_templates/rule_approved_user.tmpl +0 -0
- {rucio-35.7.0.data → rucio-37.0.0.data}/data/rucio/etc/mail_templates/rule_denied_admin.tmpl +0 -0
- {rucio-35.7.0.data → rucio-37.0.0.data}/data/rucio/etc/mail_templates/rule_denied_user.tmpl +0 -0
- {rucio-35.7.0.data → rucio-37.0.0.data}/data/rucio/etc/mail_templates/rule_ok_notification.tmpl +0 -0
- {rucio-35.7.0.data → rucio-37.0.0.data}/data/rucio/etc/rse-accounts.cfg.template +0 -0
- {rucio-35.7.0.data → rucio-37.0.0.data}/data/rucio/tools/bootstrap.py +0 -0
- {rucio-35.7.0.data → rucio-37.0.0.data}/data/rucio/tools/merge_rucio_configs.py +0 -0
- {rucio-35.7.0.data → rucio-37.0.0.data}/data/rucio/tools/reset_database.py +0 -0
- {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-abacus-account +0 -0
- {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-abacus-collection-replica +0 -0
- {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-abacus-rse +0 -0
- {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-bb8 +0 -0
- {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-cache-consumer +0 -0
- {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-conveyor-finisher +0 -0
- {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-conveyor-poller +0 -0
- {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-conveyor-preparer +0 -0
- {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-conveyor-stager +0 -0
- {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-conveyor-submitter +0 -0
- {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-conveyor-throttler +0 -0
- {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-dark-reaper +0 -0
- {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-dumper +0 -0
- {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-follower +0 -0
- {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-hermes +0 -0
- {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-judge-cleaner +0 -0
- {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-judge-evaluator +0 -0
- {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-judge-injector +0 -0
- {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-judge-repairer +0 -0
- {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-oauth-manager +0 -0
- {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-replica-recoverer +0 -0
- {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-rse-decommissioner +0 -0
- {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-storage-consistency-actions +0 -0
- {rucio-35.7.0.data → rucio-37.0.0.data}/scripts/rucio-undertaker +0 -0
- {rucio-35.7.0.dist-info → rucio-37.0.0.dist-info}/WHEEL +0 -0
- {rucio-35.7.0.dist-info → rucio-37.0.0.dist-info}/licenses/LICENSE +0 -0
- {rucio-35.7.0.dist-info → rucio-37.0.0.dist-info}/top_level.txt +0 -0
rucio/common/logging.py
CHANGED
|
@@ -18,13 +18,13 @@ import json
|
|
|
18
18
|
import logging
|
|
19
19
|
import re
|
|
20
20
|
import sys
|
|
21
|
-
from collections.abc import Callable, Iterator, Mapping, Sequence
|
|
22
21
|
from traceback import format_tb
|
|
23
22
|
from typing import TYPE_CHECKING, Any, Literal, Optional, Union, get_args
|
|
24
23
|
|
|
25
24
|
from rucio.common.config import config_get, config_get_bool
|
|
26
25
|
|
|
27
26
|
if TYPE_CHECKING:
|
|
27
|
+
from collections.abc import Callable, Iterator, Mapping, Sequence
|
|
28
28
|
from logging import LogRecord, _SysExcInfoType
|
|
29
29
|
|
|
30
30
|
from _typeshed import OptExcInfo
|
|
@@ -76,7 +76,7 @@ def _json_serializable(obj: Any) -> Union[dict[Any, Any], str]:
|
|
|
76
76
|
return str(obj)
|
|
77
77
|
|
|
78
78
|
|
|
79
|
-
def _navigate_path(obj: Any, path: Sequence[str]) -> Optional[Any]:
|
|
79
|
+
def _navigate_path(obj: Any, path: 'Sequence[str]') -> Optional[Any]:
|
|
80
80
|
"""
|
|
81
81
|
Traverse the path in the given object either via attributes or via dict-like subscriptions.
|
|
82
82
|
Returns the found value; None if navigation fails
|
|
@@ -136,7 +136,7 @@ def _unflatten_dict(dictionary: dict[str, Any]) -> dict[str, Any]:
|
|
|
136
136
|
return ret
|
|
137
137
|
|
|
138
138
|
|
|
139
|
-
def _get_request_data(request_path: Sequence[str]) -> "Callable[[LogDataSource, LogRecord], Iterator[tuple[str, Optional[Any]]]]":
|
|
139
|
+
def _get_request_data(request_path: 'Sequence[str]') -> "Callable[[LogDataSource, LogRecord], Iterator[tuple[str, Optional[Any]]]]":
|
|
140
140
|
"""
|
|
141
141
|
Returns a function which, when called, will resolve the value
|
|
142
142
|
in the flask request object at request_path
|
|
@@ -146,7 +146,7 @@ def _get_request_data(request_path: Sequence[str]) -> "Callable[[LogDataSource,
|
|
|
146
146
|
# TODO: move to top of file once we got rid of/refactored rsemanager
|
|
147
147
|
from flask import has_request_context, request
|
|
148
148
|
|
|
149
|
-
def _request_data_formatter(record_formatter: "LogDataSource", record: "LogRecord") -> Iterator[tuple[str, Optional[Any]]]:
|
|
149
|
+
def _request_data_formatter(record_formatter: "LogDataSource", record: "LogRecord") -> 'Iterator[tuple[str, Optional[Any]]]':
|
|
150
150
|
value = None
|
|
151
151
|
if has_request_context() and request_path:
|
|
152
152
|
value = _navigate_path(request, request_path)
|
|
@@ -161,7 +161,7 @@ def _get_record_attribute(attribute: str) -> "Callable[[LogDataSource, LogRecord
|
|
|
161
161
|
the record passed in argument.
|
|
162
162
|
"""
|
|
163
163
|
|
|
164
|
-
def _record_attribute_formatter(record_formatter: "LogDataSource", record: "LogRecord") -> Iterator[tuple[str, Optional[Any]]]:
|
|
164
|
+
def _record_attribute_formatter(record_formatter: "LogDataSource", record: "LogRecord") -> 'Iterator[tuple[str, Optional[Any]]]':
|
|
165
165
|
value = None
|
|
166
166
|
try:
|
|
167
167
|
value = getattr(record, attribute)
|
|
@@ -172,7 +172,7 @@ def _get_record_attribute(attribute: str) -> "Callable[[LogDataSource, LogRecord
|
|
|
172
172
|
return _record_attribute_formatter
|
|
173
173
|
|
|
174
174
|
|
|
175
|
-
def _timestamp_formatter(record_formatter: "LogDataSource", record: "LogRecord") -> Iterator[tuple[str, Optional[Any]]]:
|
|
175
|
+
def _timestamp_formatter(record_formatter: "LogDataSource", record: "LogRecord") -> 'Iterator[tuple[str, Optional[Any]]]':
|
|
176
176
|
"""
|
|
177
177
|
Format a timestamp
|
|
178
178
|
"""
|
|
@@ -214,7 +214,7 @@ class LogDataSource:
|
|
|
214
214
|
def __str__(self):
|
|
215
215
|
return self.__class__.__name__ + '(' + ', '.join(self.ecs_fields) + ')'
|
|
216
216
|
|
|
217
|
-
def format(self, record: "LogRecord") -> Optional[Iterator[tuple[str, Any]]]:
|
|
217
|
+
def format(self, record: "LogRecord") -> Optional['Iterator[tuple[str, Any]]']:
|
|
218
218
|
if not self._formatter:
|
|
219
219
|
return
|
|
220
220
|
for field_name, field_value in self._formatter(self, record):
|
|
@@ -241,7 +241,7 @@ class MessageLogDataSource(LogDataSource):
|
|
|
241
241
|
return exc_info
|
|
242
242
|
return None
|
|
243
243
|
|
|
244
|
-
def format(self, record: "LogRecord") -> Iterator[tuple[str, Optional[str]]]:
|
|
244
|
+
def format(self, record: "LogRecord") -> 'Iterator[tuple[str, Optional[str]]]':
|
|
245
245
|
exc_info = self._get_exc_info(record)
|
|
246
246
|
message = record.getMessage()
|
|
247
247
|
error_type, error_message, stack_trace = None, None, None
|
|
@@ -276,7 +276,7 @@ class ConstantStrDataSource(LogDataSource):
|
|
|
276
276
|
log_record = ECS_TO_LOG_RECORD_MAP.get(ecs_field, None)
|
|
277
277
|
self._str = _str
|
|
278
278
|
|
|
279
|
-
def _formatter(data_source: LogDataSource, record: "LogRecord") -> Iterator[tuple[str, str]]:
|
|
279
|
+
def _formatter(data_source: LogDataSource, record: "LogRecord") -> 'Iterator[tuple[str, str]]':
|
|
280
280
|
yield self.ecs_fields[0], self._str
|
|
281
281
|
|
|
282
282
|
super().__init__(ecs_fields=(ecs_field,), formatter=_formatter, dst_record_attr=log_record)
|
|
@@ -303,7 +303,7 @@ class RucioFormatter(logging.Formatter):
|
|
|
303
303
|
fmt: Optional[str] = None,
|
|
304
304
|
validate: Optional[bool] = None,
|
|
305
305
|
output_json: bool = False,
|
|
306
|
-
additional_fields: Optional[Mapping[ECS_FIELDS, str]] = None
|
|
306
|
+
additional_fields: Optional['Mapping[ECS_FIELDS, str]'] = None
|
|
307
307
|
):
|
|
308
308
|
_kwargs = {}
|
|
309
309
|
if validate is not None:
|
|
@@ -384,7 +384,7 @@ class RucioFormatter(logging.Formatter):
|
|
|
384
384
|
def rucio_log_formatter(process_name: Optional[str] = None) -> RucioFormatter:
|
|
385
385
|
config_logformat = config_get('common', 'logformat', raise_exception=False, default='%(asctime)s\t%(name)s\t%(process)d\t%(levelname)s\t%(message)s')
|
|
386
386
|
output_json = config_get_bool('common', 'logjson', default=False)
|
|
387
|
-
additional_fields = {}
|
|
387
|
+
additional_fields: 'Mapping[ECS_FIELDS, str]' = {}
|
|
388
388
|
if process_name:
|
|
389
389
|
additional_fields['process.name'] = process_name
|
|
390
390
|
return RucioFormatter(fmt=config_logformat, output_json=output_json, additional_fields=additional_fields)
|
|
@@ -406,7 +406,7 @@ def setup_logging(application: Optional["Flask"] = None, process_name: Optional[
|
|
|
406
406
|
application.logger.addHandler(stdouthandler)
|
|
407
407
|
|
|
408
408
|
|
|
409
|
-
def formatted_logger(innerfunc: Callable, formatstr: str = "%s") -> Callable:
|
|
409
|
+
def formatted_logger(innerfunc: 'Callable', formatstr: str = "%s") -> 'Callable':
|
|
410
410
|
"""
|
|
411
411
|
Decorates the passed function, formatting log input by
|
|
412
412
|
the passed formatstr. The format string must always include a %s.
|
|
@@ -415,6 +415,6 @@ def formatted_logger(innerfunc: Callable, formatstr: str = "%s") -> Callable:
|
|
|
415
415
|
:param formatstr: format string with %s as placeholder.
|
|
416
416
|
"""
|
|
417
417
|
@functools.wraps(innerfunc)
|
|
418
|
-
def log_format(level: int, msg: object, *args, **kwargs) -> Callable:
|
|
418
|
+
def log_format(level: int, msg: object, *args, **kwargs) -> 'Callable':
|
|
419
419
|
return innerfunc(level, formatstr % msg, *args, **kwargs)
|
|
420
420
|
return log_format
|
rucio/common/pcache.py
CHANGED
|
@@ -44,6 +44,8 @@ DEBUG, INFO, WARN, ERROR = "DEBUG", "INFO ", "WARN ", "ERROR"
|
|
|
44
44
|
# filename for locking
|
|
45
45
|
LOCK_NAME = ".LOCK"
|
|
46
46
|
|
|
47
|
+
MAXFD = 1024
|
|
48
|
+
|
|
47
49
|
# Session ID
|
|
48
50
|
sessid = "%s.%s" % (int(time.time()), os.getpid())
|
|
49
51
|
|
|
@@ -131,7 +133,7 @@ def unitize(x: int) -> str:
|
|
|
131
133
|
|
|
132
134
|
class Pcache:
|
|
133
135
|
|
|
134
|
-
def
|
|
136
|
+
def usage(self) -> None:
|
|
135
137
|
msg = """Usage: %s [flags] copy_prog [copy_flags] input output""" % self.progname
|
|
136
138
|
sys.stderr.write("%s\n" % msg) # py3, py2
|
|
137
139
|
# print>>sys.stderr, " flags are: "
|
|
@@ -227,7 +229,7 @@ class Pcache:
|
|
|
227
229
|
# TODO: move checksum/size validation from lsm to pcache
|
|
228
230
|
except getopt.GetoptError as err:
|
|
229
231
|
sys.stderr.write("%s\n" % str(err))
|
|
230
|
-
self.
|
|
232
|
+
self.usage()
|
|
231
233
|
self.fail(100)
|
|
232
234
|
|
|
233
235
|
for opt, arg in opts:
|
|
@@ -356,7 +358,7 @@ class Pcache:
|
|
|
356
358
|
|
|
357
359
|
# Fail on extra args
|
|
358
360
|
if not self.scratch_dir:
|
|
359
|
-
self.
|
|
361
|
+
self.usage()
|
|
360
362
|
self.fail(100)
|
|
361
363
|
|
|
362
364
|
# hardcoded pcache dir
|
|
@@ -417,7 +419,7 @@ class Pcache:
|
|
|
417
419
|
|
|
418
420
|
# Fail on extra args
|
|
419
421
|
if not scratch_dir:
|
|
420
|
-
self.
|
|
422
|
+
self.usage()
|
|
421
423
|
self.fail(100)
|
|
422
424
|
|
|
423
425
|
# If the source is lfn:, execute original command, no further action
|
|
@@ -491,7 +493,7 @@ class Pcache:
|
|
|
491
493
|
|
|
492
494
|
# Must have a list of arguments
|
|
493
495
|
if (self.parse_args(args[1:])):
|
|
494
|
-
self.
|
|
496
|
+
self.usage()
|
|
495
497
|
self.fail(100)
|
|
496
498
|
|
|
497
499
|
# Cache dir may have been wiped
|
|
@@ -522,7 +524,7 @@ class Pcache:
|
|
|
522
524
|
|
|
523
525
|
# Fail on extra args
|
|
524
526
|
if (len(self.args) < 3):
|
|
525
|
-
self.
|
|
527
|
+
self.usage()
|
|
526
528
|
self.fail(100)
|
|
527
529
|
|
|
528
530
|
self.copy_util = self.args[0]
|
|
@@ -1059,7 +1061,6 @@ class Pcache:
|
|
|
1059
1061
|
os.dup2(n, i)
|
|
1060
1062
|
os.dup2(n, o)
|
|
1061
1063
|
os.dup2(n, e)
|
|
1062
|
-
MAXFD = 1024
|
|
1063
1064
|
try:
|
|
1064
1065
|
import resource # Resource usage information.
|
|
1065
1066
|
maxfd = resource.getrlimit(resource.RLIMIT_NOFILE)[1]
|
rucio/common/plugins.py
CHANGED
|
@@ -13,25 +13,73 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
15
|
import importlib
|
|
16
|
+
import logging
|
|
16
17
|
import os
|
|
17
|
-
from collections.abc import Callable
|
|
18
18
|
from configparser import NoOptionError, NoSectionError
|
|
19
|
-
from typing import Any, TypeVar
|
|
19
|
+
from typing import TYPE_CHECKING, Any, TypeVar
|
|
20
|
+
|
|
21
|
+
from packaging.specifiers import SpecifierSet
|
|
20
22
|
|
|
21
23
|
from rucio.common import config
|
|
22
|
-
from rucio.common.
|
|
24
|
+
from rucio.common.client import get_client_vo, is_client
|
|
25
|
+
from rucio.common.exception import InvalidAlgorithmName, PolicyPackageIsNotVersioned, PolicyPackageVersionError
|
|
26
|
+
from rucio.version import current_version
|
|
27
|
+
|
|
28
|
+
if TYPE_CHECKING:
|
|
29
|
+
from collections.abc import Callable
|
|
30
|
+
|
|
31
|
+
from rucio.common.types import LoggerFunction
|
|
23
32
|
|
|
24
33
|
PolicyPackageAlgorithmsT = TypeVar('PolicyPackageAlgorithmsT', bound='PolicyPackageAlgorithms')
|
|
25
34
|
|
|
26
35
|
|
|
36
|
+
def check_policy_package_version(package: str, logger: 'LoggerFunction' = logging.log) -> None:
|
|
37
|
+
|
|
38
|
+
'''
|
|
39
|
+
Checks that the Rucio version supported by the policy package is compatible
|
|
40
|
+
with this version. Raises an exception if not.
|
|
41
|
+
:param package: the fully qualified name of the policy package
|
|
42
|
+
'''
|
|
43
|
+
try:
|
|
44
|
+
supported_versionset = _get_supported_versions_from_policy_package(package)
|
|
45
|
+
except ImportError:
|
|
46
|
+
logger(logging.DEBUG, 'Policy package %s not found' % package)
|
|
47
|
+
return
|
|
48
|
+
except PolicyPackageIsNotVersioned:
|
|
49
|
+
logger(logging.DEBUG, 'Policy package %s does not include information about which Rucio versions it supports' % package)
|
|
50
|
+
return
|
|
51
|
+
|
|
52
|
+
rucio_version = current_version()
|
|
53
|
+
if rucio_version not in supported_versionset:
|
|
54
|
+
raise PolicyPackageVersionError(rucio_version=rucio_version, supported_versionset=str(supported_versionset), package=package)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def _get_supported_versions_from_policy_package(package: str) -> SpecifierSet:
|
|
58
|
+
try:
|
|
59
|
+
module = importlib.import_module(package)
|
|
60
|
+
except ImportError as e:
|
|
61
|
+
raise e
|
|
62
|
+
|
|
63
|
+
if not hasattr(module, 'SUPPORTED_VERSION'):
|
|
64
|
+
raise PolicyPackageIsNotVersioned(package)
|
|
65
|
+
|
|
66
|
+
supported_versionset = module.SUPPORTED_VERSION
|
|
67
|
+
|
|
68
|
+
if isinstance(supported_versionset, list):
|
|
69
|
+
supported_versionset = ','.join(supported_versionset)
|
|
70
|
+
|
|
71
|
+
return SpecifierSet(supported_versionset)
|
|
72
|
+
|
|
73
|
+
|
|
27
74
|
class PolicyPackageAlgorithms:
|
|
28
75
|
"""
|
|
29
76
|
Base class for Rucio Policy Package Algorithms
|
|
30
77
|
|
|
31
|
-
ALGORITHMS is
|
|
32
|
-
|
|
78
|
+
ALGORITHMS is a dict where:
|
|
79
|
+
- the key is the algorithm type
|
|
80
|
+
- the value is a dictionary of algorithm names and their callables
|
|
33
81
|
"""
|
|
34
|
-
_ALGORITHMS: dict[str, dict[str, Callable[..., Any]]] = {}
|
|
82
|
+
_ALGORITHMS: dict[str, dict[str, 'Callable[..., Any]']] = {}
|
|
35
83
|
_loaded_policy_modules = False
|
|
36
84
|
|
|
37
85
|
def __init__(self) -> None:
|
|
@@ -40,14 +88,14 @@ class PolicyPackageAlgorithms:
|
|
|
40
88
|
self._loaded_policy_modules = True
|
|
41
89
|
|
|
42
90
|
@classmethod
|
|
43
|
-
def _get_one_algorithm(cls: type[PolicyPackageAlgorithmsT], algorithm_type: str, name: str) -> Callable[..., Any]:
|
|
91
|
+
def _get_one_algorithm(cls: type[PolicyPackageAlgorithmsT], algorithm_type: str, name: str) -> 'Callable[..., Any]':
|
|
44
92
|
"""
|
|
45
93
|
Get the algorithm from the dictionary of algorithms
|
|
46
94
|
"""
|
|
47
95
|
return cls._ALGORITHMS[algorithm_type][name]
|
|
48
96
|
|
|
49
97
|
@classmethod
|
|
50
|
-
def _get_algorithms(cls: type[PolicyPackageAlgorithmsT], algorithm_type: str) -> dict[str, Callable[..., Any]]:
|
|
98
|
+
def _get_algorithms(cls: type[PolicyPackageAlgorithmsT], algorithm_type: str) -> dict[str, 'Callable[..., Any]']:
|
|
51
99
|
"""
|
|
52
100
|
Get the dictionary of algorithms for a given type
|
|
53
101
|
"""
|
|
@@ -56,7 +104,7 @@ class PolicyPackageAlgorithms:
|
|
|
56
104
|
@classmethod
|
|
57
105
|
def _register(
|
|
58
106
|
cls: type[PolicyPackageAlgorithmsT],
|
|
59
|
-
algorithm_type: str, algorithm_dict: dict[str, Callable[..., Any]]) -> None:
|
|
107
|
+
algorithm_type: str, algorithm_dict: dict[str, 'Callable[..., Any]']) -> None:
|
|
60
108
|
"""
|
|
61
109
|
Provided a dictionary of callable function,
|
|
62
110
|
and the associated algorithm type,
|
|
@@ -90,24 +138,9 @@ class PolicyPackageAlgorithms:
|
|
|
90
138
|
# single policy package
|
|
91
139
|
cls._try_importing_policy()
|
|
92
140
|
else:
|
|
93
|
-
# determine whether on client or server
|
|
94
|
-
client = False
|
|
95
|
-
if 'RUCIO_CLIENT_MODE' not in os.environ:
|
|
96
|
-
if not config.config_has_section('database') and config.config_has_section('client'):
|
|
97
|
-
client = True
|
|
98
|
-
else:
|
|
99
|
-
if os.environ['RUCIO_CLIENT_MODE']:
|
|
100
|
-
client = True
|
|
101
|
-
|
|
102
141
|
# on client, only register algorithms for selected VO
|
|
103
|
-
if
|
|
104
|
-
|
|
105
|
-
vo = os.environ['RUCIO_VO']
|
|
106
|
-
else:
|
|
107
|
-
try:
|
|
108
|
-
vo = str(config.config_get('client', 'vo'))
|
|
109
|
-
except (NoOptionError, NoSectionError):
|
|
110
|
-
vo = 'def'
|
|
142
|
+
if is_client():
|
|
143
|
+
vo = get_client_vo()
|
|
111
144
|
cls._try_importing_policy(vo)
|
|
112
145
|
# on server, list all VOs and register their algorithms
|
|
113
146
|
else:
|
|
@@ -121,7 +154,6 @@ class PolicyPackageAlgorithms:
|
|
|
121
154
|
def _try_importing_policy(cls: type[PolicyPackageAlgorithmsT], vo: str = "") -> None:
|
|
122
155
|
try:
|
|
123
156
|
# import from utils here to avoid circular import
|
|
124
|
-
from rucio.common.utils import check_policy_package_version
|
|
125
157
|
|
|
126
158
|
env_name = 'RUCIO_POLICY_PACKAGE' + ('' if not vo else '_' + vo.upper())
|
|
127
159
|
package = getattr(os.environ, env_name, "")
|
rucio/common/policy.py
CHANGED
|
@@ -13,10 +13,11 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
15
|
import json
|
|
16
|
+
import logging
|
|
16
17
|
import os
|
|
17
18
|
from configparser import NoOptionError, NoSectionError
|
|
18
19
|
from functools import wraps
|
|
19
|
-
from typing import Any
|
|
20
|
+
from typing import TYPE_CHECKING, Any
|
|
20
21
|
|
|
21
22
|
from dogpile.cache import make_region
|
|
22
23
|
from dogpile.cache.api import NoValue
|
|
@@ -24,17 +25,25 @@ from dogpile.cache.api import NoValue
|
|
|
24
25
|
from rucio.common.config import config_get
|
|
25
26
|
from rucio.common.exception import UndefinedPolicy
|
|
26
27
|
|
|
28
|
+
if TYPE_CHECKING:
|
|
29
|
+
from rucio.common.types import LoggerFunction
|
|
30
|
+
|
|
27
31
|
REGION = make_region().configure('dogpile.cache.memory',
|
|
28
32
|
expiration_time=900)
|
|
29
33
|
|
|
30
34
|
|
|
31
|
-
def get_policy() -> str:
|
|
35
|
+
def get_policy(logger: 'LoggerFunction' = logging.log) -> str:
|
|
32
36
|
policy = REGION.get('policy')
|
|
33
37
|
if isinstance(policy, NoValue):
|
|
34
38
|
try:
|
|
35
39
|
policy = config_get('policy', 'permission')
|
|
36
40
|
except (NoOptionError, NoSectionError):
|
|
37
|
-
|
|
41
|
+
try:
|
|
42
|
+
policy = config_get('permission', 'policy')
|
|
43
|
+
except (NoOptionError, NoSectionError):
|
|
44
|
+
policy = 'def'
|
|
45
|
+
logger(logging.WARNING, "Policy not specified, falling back to 'def'")
|
|
46
|
+
policy = os.environ.get('POLICY', policy)
|
|
38
47
|
REGION.set('policy', policy)
|
|
39
48
|
return policy
|
|
40
49
|
|
rucio/common/schema/__init__.py
CHANGED
|
@@ -12,103 +12,153 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
|
+
import functools
|
|
15
16
|
import importlib
|
|
17
|
+
import logging
|
|
16
18
|
from configparser import NoOptionError, NoSectionError
|
|
17
19
|
from os import environ
|
|
18
20
|
from typing import TYPE_CHECKING, Any
|
|
19
21
|
|
|
22
|
+
from jsonschema import ValidationError, validate
|
|
23
|
+
|
|
20
24
|
from rucio.common import config, exception
|
|
21
|
-
from rucio.common.
|
|
25
|
+
from rucio.common.plugins import check_policy_package_version
|
|
22
26
|
|
|
23
27
|
if TYPE_CHECKING:
|
|
24
28
|
from types import ModuleType
|
|
25
29
|
|
|
30
|
+
LOGGER = logging.getLogger('policy')
|
|
31
|
+
|
|
26
32
|
# dictionary of schema modules for each VO
|
|
27
33
|
schema_modules: dict[str, "ModuleType"] = {}
|
|
28
34
|
|
|
29
35
|
# list of unique SCOPE_NAME_REGEXP values from all schemas
|
|
30
36
|
scope_name_regexps: list[str] = []
|
|
31
37
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
38
|
+
|
|
39
|
+
# cached function to check for multivo
|
|
40
|
+
@functools.cache
|
|
41
|
+
def _is_multivo():
|
|
42
|
+
try:
|
|
43
|
+
return config.config_get_bool('common', 'multi_vo', check_config_table=False)
|
|
44
|
+
except (NoOptionError, NoSectionError):
|
|
45
|
+
return False
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
# cached function to get generic schema module
|
|
49
|
+
@functools.cache
|
|
50
|
+
def _get_generic_schema_module():
|
|
51
|
+
generic_fallback = 'generic_multi_vo' if _is_multivo() else 'generic'
|
|
52
|
+
return importlib.import_module('rucio.common.schema.' + generic_fallback)
|
|
53
|
+
|
|
36
54
|
|
|
37
55
|
# multi-VO version loads schema per-VO on demand
|
|
38
56
|
# we can't get a list of VOs here because the database might not
|
|
39
57
|
# be available as this is imported during the bootstrapping process
|
|
40
|
-
if not
|
|
58
|
+
if not _is_multivo():
|
|
41
59
|
GENERIC_FALLBACK = 'generic'
|
|
42
60
|
|
|
43
61
|
if config.config_has_section('policy'):
|
|
44
62
|
try:
|
|
45
63
|
if 'RUCIO_POLICY_PACKAGE' in environ:
|
|
46
|
-
|
|
64
|
+
policy = environ['RUCIO_POLICY_PACKAGE']
|
|
47
65
|
else:
|
|
48
|
-
|
|
49
|
-
check_policy_package_version(
|
|
50
|
-
|
|
66
|
+
policy = config.config_get('policy', 'package', check_config_table=False)
|
|
67
|
+
check_policy_package_version(policy)
|
|
68
|
+
policy = policy + ".schema"
|
|
51
69
|
except (NoOptionError, NoSectionError):
|
|
52
70
|
# fall back to old system for now
|
|
53
71
|
try:
|
|
54
|
-
|
|
72
|
+
policy = config.config_get('policy', 'schema', check_config_table=False)
|
|
55
73
|
except (NoOptionError, NoSectionError):
|
|
56
|
-
|
|
57
|
-
|
|
74
|
+
policy = GENERIC_FALLBACK
|
|
75
|
+
policy = 'rucio.common.schema.' + policy.lower()
|
|
58
76
|
else:
|
|
59
|
-
|
|
77
|
+
policy = 'rucio.common.schema.' + GENERIC_FALLBACK.lower()
|
|
60
78
|
|
|
61
79
|
try:
|
|
62
|
-
module = importlib.import_module(
|
|
80
|
+
module = importlib.import_module(policy)
|
|
63
81
|
except ModuleNotFoundError:
|
|
64
|
-
|
|
82
|
+
# if policy package does not contain schema module, load fallback module instead
|
|
83
|
+
# this allows a policy package to omit modules that do not need customisation
|
|
84
|
+
try:
|
|
85
|
+
LOGGER.warning('Unable to load schema module %s from policy package, falling back to %s'
|
|
86
|
+
% (policy, GENERIC_FALLBACK))
|
|
87
|
+
policy = 'rucio.common.schema.' + GENERIC_FALLBACK.lower()
|
|
88
|
+
module = importlib.import_module(policy)
|
|
89
|
+
except ModuleNotFoundError:
|
|
90
|
+
raise exception.PolicyPackageNotFound(policy)
|
|
91
|
+
except ImportError:
|
|
92
|
+
raise exception.ErrorLoadingPolicyPackage(policy)
|
|
65
93
|
except ImportError:
|
|
66
|
-
raise exception.ErrorLoadingPolicyPackage(
|
|
94
|
+
raise exception.ErrorLoadingPolicyPackage(policy)
|
|
67
95
|
|
|
68
96
|
schema_modules["def"] = module
|
|
69
|
-
|
|
97
|
+
if hasattr(module, 'SCOPE_NAME_REGEXP'):
|
|
98
|
+
scope_name_regexps.append(module.SCOPE_NAME_REGEXP)
|
|
70
99
|
|
|
71
100
|
|
|
72
101
|
def load_schema_for_vo(vo: str) -> None:
|
|
73
|
-
|
|
102
|
+
generic_fallback = 'generic_multi_vo'
|
|
74
103
|
if config.config_has_section('policy'):
|
|
75
104
|
try:
|
|
76
105
|
env_name = 'RUCIO_POLICY_PACKAGE_' + vo.upper()
|
|
77
106
|
if env_name in environ:
|
|
78
|
-
|
|
107
|
+
policy = environ[env_name]
|
|
79
108
|
else:
|
|
80
|
-
|
|
81
|
-
check_policy_package_version(
|
|
82
|
-
|
|
109
|
+
policy = config.config_get('policy', 'package-' + vo, check_config_table=False)
|
|
110
|
+
check_policy_package_version(policy)
|
|
111
|
+
policy = policy + ".schema"
|
|
83
112
|
except (NoOptionError, NoSectionError):
|
|
84
113
|
# fall back to old system for now
|
|
85
114
|
try:
|
|
86
|
-
|
|
115
|
+
policy = config.config_get('policy', 'schema', check_config_table=False)
|
|
87
116
|
except (NoOptionError, NoSectionError):
|
|
88
|
-
|
|
89
|
-
|
|
117
|
+
policy = generic_fallback
|
|
118
|
+
policy = 'rucio.common.schema.' + policy.lower()
|
|
90
119
|
else:
|
|
91
|
-
|
|
120
|
+
policy = 'rucio.common.schema.' + generic_fallback.lower()
|
|
92
121
|
|
|
93
122
|
try:
|
|
94
|
-
module = importlib.import_module(
|
|
123
|
+
module = importlib.import_module(policy)
|
|
95
124
|
except ModuleNotFoundError:
|
|
96
|
-
|
|
125
|
+
# if policy package does not contain schema module, load fallback module instead
|
|
126
|
+
# this allows a policy package to omit modules that do not need customisation
|
|
127
|
+
try:
|
|
128
|
+
LOGGER.warning('Unable to load schema module %s from policy package, falling back to %s'
|
|
129
|
+
% (policy, generic_fallback))
|
|
130
|
+
policy = 'rucio.common.schema.' + generic_fallback.lower()
|
|
131
|
+
module = importlib.import_module(policy)
|
|
132
|
+
except ModuleNotFoundError:
|
|
133
|
+
raise exception.PolicyPackageNotFound(policy)
|
|
134
|
+
except ImportError:
|
|
135
|
+
raise exception.ErrorLoadingPolicyPackage(policy)
|
|
97
136
|
except ImportError:
|
|
98
|
-
raise exception.ErrorLoadingPolicyPackage(
|
|
137
|
+
raise exception.ErrorLoadingPolicyPackage(policy)
|
|
99
138
|
|
|
100
139
|
schema_modules[vo] = module
|
|
101
140
|
|
|
102
141
|
|
|
103
142
|
def validate_schema(name: str, obj: Any, vo: str = 'def') -> None:
|
|
104
|
-
if
|
|
105
|
-
|
|
106
|
-
|
|
143
|
+
if obj:
|
|
144
|
+
if vo not in schema_modules:
|
|
145
|
+
load_schema_for_vo(vo)
|
|
146
|
+
if hasattr(schema_modules[vo], 'SCHEMAS') and name in schema_modules[vo].SCHEMAS:
|
|
147
|
+
schema = schema_modules[vo].SCHEMAS.get(name, {})
|
|
148
|
+
else:
|
|
149
|
+
# if schema not available in VO module, fall back to generic module
|
|
150
|
+
schema = _get_generic_schema_module().SCHEMAS.get(name, {})
|
|
151
|
+
try:
|
|
152
|
+
validate(obj, schema)
|
|
153
|
+
except ValidationError as error: # NOQA: F841
|
|
154
|
+
raise exception.InvalidObject(f'Problem validating {name}: {error}')
|
|
107
155
|
|
|
108
156
|
|
|
109
157
|
def get_schema_value(key: str, vo: str = 'def') -> Any:
|
|
110
158
|
if vo not in schema_modules:
|
|
111
159
|
load_schema_for_vo(vo)
|
|
160
|
+
if not hasattr(schema_modules[vo], key):
|
|
161
|
+
return getattr(_get_generic_schema_module(), key)
|
|
112
162
|
return getattr(schema_modules[vo], key)
|
|
113
163
|
|
|
114
164
|
|
|
@@ -120,7 +170,7 @@ def get_scope_name_regexps() -> list[str]:
|
|
|
120
170
|
from rucio.core.vo import list_vos
|
|
121
171
|
vos = list_vos()
|
|
122
172
|
for vo in vos:
|
|
123
|
-
if
|
|
173
|
+
if vo['vo'] not in schema_modules:
|
|
124
174
|
load_schema_for_vo(vo['vo'])
|
|
125
175
|
scope_name_regexp = schema_modules[vo['vo']].SCOPE_NAME_REGEXP
|
|
126
176
|
if scope_name_regexp not in scope_name_regexps:
|
rucio/common/schema/generic.py
CHANGED
|
@@ -12,9 +12,6 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
|
-
from jsonschema import ValidationError, validate
|
|
16
|
-
|
|
17
|
-
from rucio.common.exception import InvalidObject
|
|
18
15
|
|
|
19
16
|
ACCOUNT_LENGTH = 25
|
|
20
17
|
|
|
@@ -417,17 +414,3 @@ SCHEMAS = {'account': ACCOUNT,
|
|
|
417
414
|
'cache_delete_replicas': CACHE_DELETE_REPLICAS,
|
|
418
415
|
'account_attribute': ACCOUNT_ATTRIBUTE,
|
|
419
416
|
'import': IMPORT}
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
def validate_schema(name, obj):
|
|
423
|
-
"""
|
|
424
|
-
Validate object against json schema
|
|
425
|
-
|
|
426
|
-
:param name: The json schema name.
|
|
427
|
-
:param obj: The object to validate.
|
|
428
|
-
"""
|
|
429
|
-
try:
|
|
430
|
-
if obj:
|
|
431
|
-
validate(obj, SCHEMAS.get(name, {}))
|
|
432
|
-
except ValidationError as error: # NOQA, pylint: disable=W0612
|
|
433
|
-
raise InvalidObject(f'Problem validating {name}: {error}')
|
|
@@ -12,9 +12,6 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
|
-
from jsonschema import ValidationError, validate
|
|
16
|
-
|
|
17
|
-
from rucio.common.exception import InvalidObject
|
|
18
15
|
|
|
19
16
|
ACCOUNT_LENGTH = 29
|
|
20
17
|
|
|
@@ -396,17 +393,3 @@ SCHEMAS = {'account': ACCOUNT,
|
|
|
396
393
|
'account_attribute': ACCOUNT_ATTRIBUTE,
|
|
397
394
|
'import': IMPORT,
|
|
398
395
|
'vo': VO}
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
def validate_schema(name, obj):
|
|
402
|
-
"""
|
|
403
|
-
Validate object against json schema
|
|
404
|
-
|
|
405
|
-
:param name: The json schema name.
|
|
406
|
-
:param obj: The object to validate.
|
|
407
|
-
"""
|
|
408
|
-
try:
|
|
409
|
-
if obj:
|
|
410
|
-
validate(obj, SCHEMAS.get(name, {}))
|
|
411
|
-
except ValidationError as error: # NOQA, pylint: disable=W0612
|
|
412
|
-
raise InvalidObject(f'Problem validating {name}: {error}')
|
|
@@ -36,27 +36,33 @@ def get_scope_and_rses():
|
|
|
36
36
|
|
|
37
37
|
:return: A tuple (scope, rses) for the rucio client where scope is mock/test and rses is a list or (None, [None]) if no suitable rse exists.
|
|
38
38
|
"""
|
|
39
|
-
cmd = "rucio list
|
|
39
|
+
cmd = "rucio rse list 'test_container_xrd=True'"
|
|
40
40
|
print(cmd)
|
|
41
41
|
exitcode, out, err = execute(cmd)
|
|
42
42
|
print(out, err)
|
|
43
43
|
rses = out.split()
|
|
44
44
|
if len(rses) == 0:
|
|
45
45
|
return None, [None]
|
|
46
|
-
|
|
46
|
+
|
|
47
|
+
scope = 'test'
|
|
48
|
+
account = 'root'
|
|
49
|
+
cmd = f"rucio scope add {scope} --account {account}"
|
|
50
|
+
_, out, err = execute(cmd)
|
|
51
|
+
print(out, err)
|
|
52
|
+
return scope, rses
|
|
47
53
|
|
|
48
54
|
|
|
49
55
|
def delete_rules(did):
|
|
50
56
|
# get the rules for the file
|
|
51
57
|
print('Deleting rules')
|
|
52
|
-
cmd = "rucio list
|
|
58
|
+
cmd = "rucio rule list {0} | grep {0} | cut -f1 -d\\ ".format(did)
|
|
53
59
|
print(cmd)
|
|
54
60
|
exitcode, out, err = execute(cmd)
|
|
55
61
|
print(out, err)
|
|
56
62
|
rules = out.split()
|
|
57
63
|
# delete the rules for the file
|
|
58
64
|
for rule in rules:
|
|
59
|
-
cmd = "rucio
|
|
65
|
+
cmd = "rucio rule remove {0}".format(rule)
|
|
60
66
|
print(cmd)
|
|
61
67
|
exitcode, out, err = execute(cmd)
|
|
62
68
|
|
|
@@ -112,7 +118,7 @@ class TestRucioServer(unittest.TestCase):
|
|
|
112
118
|
self.assertEqual(exitcode, 0)
|
|
113
119
|
|
|
114
120
|
# List the files
|
|
115
|
-
cmd = 'rucio list
|
|
121
|
+
cmd = 'rucio did content list --did {0}:{1}'.format(self.scope, tmp_dsn)
|
|
116
122
|
print(self.marker + cmd)
|
|
117
123
|
exitcode, out, err = execute(cmd)
|
|
118
124
|
print(out)
|
|
@@ -120,7 +126,7 @@ class TestRucioServer(unittest.TestCase):
|
|
|
120
126
|
self.assertEqual(exitcode, 0)
|
|
121
127
|
|
|
122
128
|
# List the replicas
|
|
123
|
-
cmd = 'rucio list
|
|
129
|
+
cmd = 'rucio replica list file {0}:{1}'.format(self.scope, tmp_dsn)
|
|
124
130
|
print(self.marker + cmd)
|
|
125
131
|
exitcode, out, err = execute(cmd)
|
|
126
132
|
print(out)
|