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/core/topology.py
CHANGED
|
@@ -17,7 +17,6 @@ import itertools
|
|
|
17
17
|
import logging
|
|
18
18
|
import threading
|
|
19
19
|
import weakref
|
|
20
|
-
from collections.abc import Callable, Iterable, Iterator
|
|
21
20
|
from decimal import Decimal
|
|
22
21
|
from typing import TYPE_CHECKING, Any, Generic, Optional, TypeVar, Union, cast
|
|
23
22
|
|
|
@@ -38,6 +37,7 @@ TE = TypeVar("TE", bound="Edge")
|
|
|
38
37
|
ExpiringObjectCacheNewObject = TypeVar("ExpiringObjectCacheNewObject")
|
|
39
38
|
|
|
40
39
|
if TYPE_CHECKING:
|
|
40
|
+
from collections.abc import Callable, Iterable, Iterator
|
|
41
41
|
from typing import Protocol
|
|
42
42
|
|
|
43
43
|
from sqlalchemy.orm import Session
|
|
@@ -63,7 +63,7 @@ INF = float('inf')
|
|
|
63
63
|
|
|
64
64
|
|
|
65
65
|
class Node(RseData):
|
|
66
|
-
def __init__(self, rse_id: str):
|
|
66
|
+
def __init__(self, rse_id: str) -> None:
|
|
67
67
|
super().__init__(rse_id)
|
|
68
68
|
|
|
69
69
|
self.in_edges = weakref.WeakKeyDictionary()
|
|
@@ -75,7 +75,7 @@ class Node(RseData):
|
|
|
75
75
|
|
|
76
76
|
|
|
77
77
|
class Edge(Generic[TN]):
|
|
78
|
-
def __init__(self, src_node: TN, dst_node: TN):
|
|
78
|
+
def __init__(self, src_node: TN, dst_node: TN) -> None:
|
|
79
79
|
self._src_node = weakref.ref(src_node)
|
|
80
80
|
self._dst_node = weakref.ref(dst_node)
|
|
81
81
|
|
|
@@ -123,11 +123,11 @@ class Topology(RseCollection, Generic[TN, TE]):
|
|
|
123
123
|
"""
|
|
124
124
|
def __init__(
|
|
125
125
|
self,
|
|
126
|
-
rse_ids: Optional[Iterable[str]] = None,
|
|
126
|
+
rse_ids: Optional["Iterable[str]"] = None,
|
|
127
127
|
ignore_availability: bool = False,
|
|
128
128
|
node_cls: type[TN] = Node,
|
|
129
129
|
edge_cls: type[TE] = Edge,
|
|
130
|
-
):
|
|
130
|
+
) -> None:
|
|
131
131
|
super().__init__(rse_ids=rse_ids, rse_data_cls=node_cls)
|
|
132
132
|
self._edge_cls = edge_cls
|
|
133
133
|
self._edges: dict[tuple[TN, TN], TE] = {}
|
|
@@ -284,7 +284,7 @@ class Topology(RseCollection, Generic[TN, TE]):
|
|
|
284
284
|
@read_session
|
|
285
285
|
def search_shortest_paths(
|
|
286
286
|
self,
|
|
287
|
-
src_nodes: Iterable[TN],
|
|
287
|
+
src_nodes: "Iterable[TN]",
|
|
288
288
|
dst_node: TN,
|
|
289
289
|
operation_src: str,
|
|
290
290
|
operation_dest: str,
|
|
@@ -310,7 +310,7 @@ class Topology(RseCollection, Generic[TN, TE]):
|
|
|
310
310
|
class _NodeStateProvider:
|
|
311
311
|
_hop_penalty = self._hop_penalty
|
|
312
312
|
|
|
313
|
-
def __init__(self, node: TN):
|
|
313
|
+
def __init__(self, node: TN) -> None:
|
|
314
314
|
self.enabled: bool = True
|
|
315
315
|
self.cost: _Number = 0
|
|
316
316
|
if node != dst_node:
|
|
@@ -322,7 +322,7 @@ class Topology(RseCollection, Generic[TN, TE]):
|
|
|
322
322
|
scheme_missmatch_found = {}
|
|
323
323
|
|
|
324
324
|
class _EdgeStateProvider:
|
|
325
|
-
def __init__(self, edge: TE):
|
|
325
|
+
def __init__(self, edge: TE) -> None:
|
|
326
326
|
self.edge = edge
|
|
327
327
|
self.chosen_scheme = {}
|
|
328
328
|
|
|
@@ -358,7 +358,7 @@ class Topology(RseCollection, Generic[TN, TE]):
|
|
|
358
358
|
node_state_provider=_NodeStateProvider,
|
|
359
359
|
edge_state_provider=_EdgeStateProvider):
|
|
360
360
|
nh_node = edge_to_next_hop.dst_node
|
|
361
|
-
edge_state = cast(_EdgeStateProvider, edge_state)
|
|
361
|
+
edge_state = cast("_EdgeStateProvider", edge_state)
|
|
362
362
|
hop = {
|
|
363
363
|
'source_rse': node,
|
|
364
364
|
'dest_rse': nh_node,
|
|
@@ -433,8 +433,8 @@ class ExpiringObjectCache(Generic[ExpiringObjectCacheNewObject]):
|
|
|
433
433
|
def __init__(
|
|
434
434
|
self,
|
|
435
435
|
ttl: int,
|
|
436
|
-
new_obj_fnc: Callable[[], ExpiringObjectCacheNewObject]
|
|
437
|
-
):
|
|
436
|
+
new_obj_fnc: "Callable[[], ExpiringObjectCacheNewObject]"
|
|
437
|
+
) -> None:
|
|
438
438
|
self._lock = threading.Lock()
|
|
439
439
|
self._object: Optional[ExpiringObjectCacheNewObject] = None
|
|
440
440
|
self._creation_time: Optional[datetime.datetime] = None
|
rucio/core/trace.py
CHANGED
|
@@ -26,7 +26,7 @@ from typing import TYPE_CHECKING, Any, Union, overload
|
|
|
26
26
|
import stomp
|
|
27
27
|
from jsonschema import Draft7Validator, ValidationError, validate
|
|
28
28
|
|
|
29
|
-
from rucio.common.config import config_get, config_get_int
|
|
29
|
+
from rucio.common.config import config_get, config_get_int, config_get_list
|
|
30
30
|
from rucio.common.exception import InvalidObject, TraceValidationSchemaNotFound
|
|
31
31
|
from rucio.common.logging import rucio_log_formatter
|
|
32
32
|
from rucio.common.schema.generic import TIME_ENTRY, UUID, IPv4orIPv6
|
|
@@ -70,7 +70,7 @@ ROTATING_LOGGER.addHandler(ROTATING_HANDLER)
|
|
|
70
70
|
|
|
71
71
|
BROKERS_ALIAS, BROKERS_RESOLVED = [], []
|
|
72
72
|
try:
|
|
73
|
-
BROKERS_ALIAS =
|
|
73
|
+
BROKERS_ALIAS = config_get_list('trace', 'brokers')
|
|
74
74
|
except:
|
|
75
75
|
raise Exception('Could not load brokers from configuration')
|
|
76
76
|
|
rucio/core/transfer.py
CHANGED
|
@@ -38,7 +38,6 @@ from rucio.core import request as request_core
|
|
|
38
38
|
from rucio.core.account import list_accounts
|
|
39
39
|
from rucio.core.monitor import MetricManager
|
|
40
40
|
from rucio.core.request import DirectTransfer, RequestSource, RequestWithSources, TransferDestination, transition_request_state
|
|
41
|
-
from rucio.core.rse import RseData
|
|
42
41
|
from rucio.core.rse_expression_parser import parse_expression
|
|
43
42
|
from rucio.db.sqla import models
|
|
44
43
|
from rucio.db.sqla.constants import DIDType, RequestState, RequestType, TransferLimitDirection
|
|
@@ -48,7 +47,6 @@ from rucio.transfertool.bittorrent import BittorrentTransfertool
|
|
|
48
47
|
from rucio.transfertool.fts3 import FTS3Transfertool
|
|
49
48
|
from rucio.transfertool.globus import GlobusTransferTool
|
|
50
49
|
from rucio.transfertool.mock import MockTransfertool
|
|
51
|
-
from rucio.transfertool.transfertool import TransferStatusReport, Transfertool
|
|
52
50
|
|
|
53
51
|
if TYPE_CHECKING:
|
|
54
52
|
from collections.abc import Callable, Iterable, Iterator, Mapping, Sequence
|
|
@@ -56,9 +54,11 @@ if TYPE_CHECKING:
|
|
|
56
54
|
|
|
57
55
|
from sqlalchemy.orm import Session
|
|
58
56
|
|
|
59
|
-
from rucio.common.types import InternalAccount
|
|
57
|
+
from rucio.common.types import InternalAccount, LFNDict
|
|
58
|
+
from rucio.core.rse import RseData
|
|
60
59
|
from rucio.core.topology import Topology
|
|
61
60
|
from rucio.rse.protocols.protocol import RSEProtocol
|
|
61
|
+
from rucio.transfertool.transfertool import TransferStatusReport, Transfertool
|
|
62
62
|
|
|
63
63
|
LoggerFunction = Callable[..., Any]
|
|
64
64
|
|
|
@@ -90,7 +90,7 @@ class ProtocolFactory:
|
|
|
90
90
|
def __init__(self):
|
|
91
91
|
self.protocols = {}
|
|
92
92
|
|
|
93
|
-
def protocol(self, rse: RseData, scheme: "Optional[str]", operation: str):
|
|
93
|
+
def protocol(self, rse: 'RseData', scheme: "Optional[str]", operation: str):
|
|
94
94
|
protocol_key = '%s_%s_%s' % (operation, rse.id, scheme)
|
|
95
95
|
protocol = self.protocols.get(protocol_key)
|
|
96
96
|
if not protocol:
|
|
@@ -210,7 +210,12 @@ class DirectTransferImplementation(DirectTransfer):
|
|
|
210
210
|
# Compute the source URL
|
|
211
211
|
source_sign_url = src.rse.attributes.get(RseAttr.SIGN_URL, None)
|
|
212
212
|
dest_sign_url = dst.rse.attributes.get(RseAttr.SIGN_URL, None)
|
|
213
|
-
|
|
213
|
+
lfn: "LFNDict" = {
|
|
214
|
+
'scope': rws.scope.external, # type: ignore (scope.external might be None)
|
|
215
|
+
'name': rws.name,
|
|
216
|
+
'path': src.file_path
|
|
217
|
+
}
|
|
218
|
+
source_url = list(protocol.lfns2pfns(lfns=lfn).values())[0]
|
|
214
219
|
source_url = cls.__rewrite_source_url(source_url, source_sign_url=source_sign_url, dest_sign_url=dest_sign_url, source_scheme=src.scheme)
|
|
215
220
|
return source_url
|
|
216
221
|
|
|
@@ -223,7 +228,11 @@ class DirectTransferImplementation(DirectTransfer):
|
|
|
223
228
|
protocol = protocol_factory.protocol(dst.rse, dst.scheme, operation)
|
|
224
229
|
|
|
225
230
|
if dst.rse.info['deterministic']:
|
|
226
|
-
|
|
231
|
+
lfn: "LFNDict" = {
|
|
232
|
+
'scope': rws.scope.external, # type: ignore (scope.external might be None)
|
|
233
|
+
'name': rws.name
|
|
234
|
+
}
|
|
235
|
+
dest_url = list(protocol.lfns2pfns(lfns=lfn).values())[0]
|
|
227
236
|
else:
|
|
228
237
|
# compute dest url in case of non deterministic
|
|
229
238
|
# naming convention, etc.
|
|
@@ -236,7 +245,12 @@ class DirectTransferImplementation(DirectTransfer):
|
|
|
236
245
|
if rws.retry_count or rws.activity == 'Recovery':
|
|
237
246
|
dest_path = '%s_%i' % (dest_path, int(time.time()))
|
|
238
247
|
|
|
239
|
-
|
|
248
|
+
lfn: "LFNDict" = {
|
|
249
|
+
'scope': rws.scope.external, # type: ignore (scope.external might be None)
|
|
250
|
+
'name': rws.name,
|
|
251
|
+
'path': dest_path
|
|
252
|
+
}
|
|
253
|
+
dest_url = list(protocol.lfns2pfns(lfns=lfn).values())[0]
|
|
240
254
|
|
|
241
255
|
dest_sign_url = dst.rse.attributes.get(RseAttr.SIGN_URL, None)
|
|
242
256
|
dest_url = cls.__rewrite_dest_url(dest_url, dest_sign_url=dest_sign_url)
|
|
@@ -498,7 +512,7 @@ def set_transfers_state(
|
|
|
498
512
|
|
|
499
513
|
@transactional_session
|
|
500
514
|
def update_transfer_state(
|
|
501
|
-
tt_status_report: TransferStatusReport,
|
|
515
|
+
tt_status_report: 'TransferStatusReport',
|
|
502
516
|
stats_manager: request_core.TransferStatsManager,
|
|
503
517
|
*,
|
|
504
518
|
session: "Session",
|
|
@@ -744,7 +758,7 @@ def _create_stagein_definitions(
|
|
|
744
758
|
"""
|
|
745
759
|
transfers_by_source = {
|
|
746
760
|
source.rse: [
|
|
747
|
-
cast(DirectTransfer, StageinTransferImplementation(
|
|
761
|
+
cast('DirectTransfer', StageinTransferImplementation(
|
|
748
762
|
source=RequestSource(
|
|
749
763
|
rse=source.rse,
|
|
750
764
|
file_path=source.file_path,
|
|
@@ -973,7 +987,7 @@ class EnforceSourceRSEExpression(SourceFilterStrategy):
|
|
|
973
987
|
return self._RankingContext(self, rws, allowed_source_rses)
|
|
974
988
|
|
|
975
989
|
def apply(self, ctx: RequestRankingContext, source: RequestSource) -> "Optional[int | _SkipSource]":
|
|
976
|
-
ctx = cast(EnforceSourceRSEExpression._RankingContext, ctx)
|
|
990
|
+
ctx = cast('EnforceSourceRSEExpression._RankingContext', ctx)
|
|
977
991
|
if ctx.allowed_source_rses is not None and source.rse.id not in ctx.allowed_source_rses:
|
|
978
992
|
return SKIP_SOURCE
|
|
979
993
|
|
|
@@ -1049,7 +1063,7 @@ class PathDistance(SourceRankingStrategy):
|
|
|
1049
1063
|
return PathDistance._RankingContext(self, rws, paths_for_rws)
|
|
1050
1064
|
|
|
1051
1065
|
def apply(self, ctx: RequestRankingContext, source: RequestSource) -> "Optional[int | _SkipSource]":
|
|
1052
|
-
path = cast(PathDistance._RankingContext, ctx).paths_for_rws.get(source.rse)
|
|
1066
|
+
path = cast('PathDistance._RankingContext', ctx).paths_for_rws.get(source.rse)
|
|
1053
1067
|
if not path:
|
|
1054
1068
|
return SKIP_SOURCE
|
|
1055
1069
|
return path[0].src.distance
|
|
@@ -1057,7 +1071,7 @@ class PathDistance(SourceRankingStrategy):
|
|
|
1057
1071
|
|
|
1058
1072
|
class PreferSingleHop(PathDistance):
|
|
1059
1073
|
def apply(self, ctx: RequestRankingContext, source: RequestSource) -> "Optional[int | _SkipSource]":
|
|
1060
|
-
path = cast(PathDistance._RankingContext, ctx).paths_for_rws.get(source.rse)
|
|
1074
|
+
path = cast('PathDistance._RankingContext', ctx).paths_for_rws.get(source.rse)
|
|
1061
1075
|
if not path:
|
|
1062
1076
|
return SKIP_SOURCE
|
|
1063
1077
|
return int(len(path) > 1)
|
|
@@ -1097,7 +1111,7 @@ class FailureRate(SourceRankingStrategy):
|
|
|
1097
1111
|
self.source_stats.setdefault(stat['src_rse_id'], self._FailureRateStat()).incorporate_stat(stat)
|
|
1098
1112
|
|
|
1099
1113
|
def apply(self, ctx: RequestRankingContext, source: RequestSource) -> "Optional[int | _SkipSource]":
|
|
1100
|
-
failure_rate = cast(FailureRate, ctx.strategy).source_stats.get(source.rse.id, self._FailureRateStat()).get_failure_rate()
|
|
1114
|
+
failure_rate = cast('FailureRate', ctx.strategy).source_stats.get(source.rse.id, self._FailureRateStat()).get_failure_rate()
|
|
1101
1115
|
return failure_rate
|
|
1102
1116
|
|
|
1103
1117
|
|
|
@@ -1105,7 +1119,7 @@ class SkipSchemeMissmatch(PathDistance):
|
|
|
1105
1119
|
filter_only = True
|
|
1106
1120
|
|
|
1107
1121
|
def apply(self, ctx: RequestRankingContext, source: RequestSource) -> "Optional[int | _SkipSource]":
|
|
1108
|
-
path = cast(PathDistance._RankingContext, ctx).paths_for_rws.get(source.rse)
|
|
1122
|
+
path = cast('PathDistance._RankingContext', ctx).paths_for_rws.get(source.rse)
|
|
1109
1123
|
# path == None means that there is no path;
|
|
1110
1124
|
# path == [] means that a path exists (according to distances) but cannot be used (scheme mismatch)
|
|
1111
1125
|
if path is not None and not path:
|
|
@@ -1117,7 +1131,7 @@ class SkipIntermediateTape(PathDistance):
|
|
|
1117
1131
|
|
|
1118
1132
|
def apply(self, ctx: RequestRankingContext, source: RequestSource) -> "Optional[int | _SkipSource]":
|
|
1119
1133
|
# Discard multihop transfers which contain a tape source as an intermediate hop
|
|
1120
|
-
path = cast(PathDistance._RankingContext, ctx).paths_for_rws.get(source.rse)
|
|
1134
|
+
path = cast('PathDistance._RankingContext', ctx).paths_for_rws.get(source.rse)
|
|
1121
1135
|
if path and any(transfer.src.rse.is_tape_or_staging_required() for transfer in path[1:]):
|
|
1122
1136
|
return SKIP_SOURCE
|
|
1123
1137
|
|
rucio/core/volatile_replica.py
CHANGED
|
@@ -12,7 +12,6 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
|
-
from collections.abc import Iterable
|
|
16
15
|
from datetime import datetime
|
|
17
16
|
from typing import TYPE_CHECKING, Any
|
|
18
17
|
|
|
@@ -26,11 +25,13 @@ from rucio.db.sqla.constants import ReplicaState
|
|
|
26
25
|
from rucio.db.sqla.session import transactional_session
|
|
27
26
|
|
|
28
27
|
if TYPE_CHECKING:
|
|
28
|
+
from collections.abc import Iterable
|
|
29
|
+
|
|
29
30
|
from sqlalchemy.orm import Session
|
|
30
31
|
|
|
31
32
|
|
|
32
33
|
@transactional_session
|
|
33
|
-
def add_volatile_replicas(rse_id: str, replicas: Iterable[dict[str, Any]], *, session: "Session") -> None:
|
|
34
|
+
def add_volatile_replicas(rse_id: str, replicas: "Iterable[dict[str, Any]]", *, session: "Session") -> None:
|
|
34
35
|
"""
|
|
35
36
|
Bulk add volatile replicas.
|
|
36
37
|
|
|
@@ -112,7 +113,7 @@ def add_volatile_replicas(rse_id: str, replicas: Iterable[dict[str, Any]], *, se
|
|
|
112
113
|
|
|
113
114
|
|
|
114
115
|
@transactional_session
|
|
115
|
-
def delete_volatile_replicas(rse_id: str, replicas: Iterable[dict[str, Any]], *, session: "Session") -> None:
|
|
116
|
+
def delete_volatile_replicas(rse_id: str, replicas: "Iterable[dict[str, Any]]", *, session: "Session") -> None:
|
|
116
117
|
"""
|
|
117
118
|
Bulk delete volatile replicas.
|
|
118
119
|
|
rucio/daemons/atropos/atropos.py
CHANGED
|
@@ -16,9 +16,9 @@ import bz2
|
|
|
16
16
|
import glob
|
|
17
17
|
import logging
|
|
18
18
|
import os
|
|
19
|
-
import queue as Queue
|
|
20
19
|
import select
|
|
21
20
|
from datetime import datetime, timedelta
|
|
21
|
+
from queue import Empty as EmptyQueue
|
|
22
22
|
from typing import TYPE_CHECKING, Optional
|
|
23
23
|
|
|
24
24
|
from rucio.common import config
|
|
@@ -238,7 +238,7 @@ def check(
|
|
|
238
238
|
while not terminate.is_set():
|
|
239
239
|
try:
|
|
240
240
|
rse, attempts = queue.get(timeout=30)
|
|
241
|
-
except
|
|
241
|
+
except EmptyQueue:
|
|
242
242
|
continue
|
|
243
243
|
start = datetime.now()
|
|
244
244
|
try:
|
|
@@ -12,15 +12,15 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
|
-
import configparser as ConfigParser
|
|
16
15
|
import datetime
|
|
17
16
|
import glob
|
|
18
17
|
import hashlib
|
|
19
|
-
import html.parser as HTMLParser
|
|
20
18
|
import logging
|
|
21
19
|
import operator
|
|
22
20
|
import os
|
|
23
21
|
import re
|
|
22
|
+
from configparser import RawConfigParser
|
|
23
|
+
from html.parser import HTMLParser
|
|
24
24
|
from typing import IO, TYPE_CHECKING, Any, Optional
|
|
25
25
|
|
|
26
26
|
import gfal2
|
|
@@ -49,7 +49,7 @@ __DUMPERCONFIGDIRS = list(
|
|
|
49
49
|
OBJECTSTORE_NUM_TRIES = 30
|
|
50
50
|
|
|
51
51
|
|
|
52
|
-
class Parser(
|
|
52
|
+
class Parser(RawConfigParser):
|
|
53
53
|
'''
|
|
54
54
|
RawConfigParser subclass that doesn't modify the the name of the options
|
|
55
55
|
and removes any quotes around the string values.
|
|
@@ -137,7 +137,7 @@ def gfal_links(base_url: str) -> list[str]:
|
|
|
137
137
|
return ['/'.join((base_url, f)) for f in ctxt.listdir(str(base_url))]
|
|
138
138
|
|
|
139
139
|
|
|
140
|
-
class _LinkCollector(HTMLParser
|
|
140
|
+
class _LinkCollector(HTMLParser):
|
|
141
141
|
def __init__(self):
|
|
142
142
|
super(_LinkCollector, self).__init__()
|
|
143
143
|
self.links = []
|
|
@@ -244,7 +244,7 @@ def parse_configuration(conf_dirs: Optional[list[str]] = None) -> Parser:
|
|
|
244
244
|
|
|
245
245
|
def download_rse_dump(
|
|
246
246
|
rse: str,
|
|
247
|
-
configuration:
|
|
247
|
+
configuration: RawConfigParser,
|
|
248
248
|
date: Optional[datetime.datetime] = None,
|
|
249
249
|
destdir: str = DUMPS_CACHE_DIR
|
|
250
250
|
) -> tuple[str, datetime.datetime]:
|
|
@@ -331,7 +331,7 @@ def download_rse_dump(
|
|
|
331
331
|
|
|
332
332
|
def generate_url(
|
|
333
333
|
rse: str,
|
|
334
|
-
config:
|
|
334
|
+
config: RawConfigParser
|
|
335
335
|
) -> tuple[str, str]:
|
|
336
336
|
'''
|
|
337
337
|
:param rse: Name of the endpoint.
|
|
@@ -28,7 +28,7 @@ import rucio.db.sqla.util
|
|
|
28
28
|
from rucio.client import Client
|
|
29
29
|
from rucio.client.uploadclient import UploadClient
|
|
30
30
|
from rucio.common import exception
|
|
31
|
-
from rucio.common.config import config_get, config_get_bool, config_get_int
|
|
31
|
+
from rucio.common.config import config_get, config_get_bool, config_get_int, config_get_list
|
|
32
32
|
from rucio.common.logging import setup_logging
|
|
33
33
|
from rucio.common.stopwatch import Stopwatch
|
|
34
34
|
from rucio.common.types import InternalScope, LoggerFunction
|
|
@@ -149,18 +149,14 @@ def run_once(heartbeat_handler: HeartbeatHandler, inputfile: str, **_kwargs) ->
|
|
|
149
149
|
|
|
150
150
|
_, _, logger = heartbeat_handler.live()
|
|
151
151
|
try:
|
|
152
|
-
rses =
|
|
153
|
-
s.strip() for s in config_get("automatix", "rses").split(",")
|
|
154
|
-
] # TODO use config_get_list
|
|
152
|
+
rses = config_get_list("automatix", "rses")
|
|
155
153
|
except (NoOptionError, NoSectionError, RuntimeError):
|
|
156
154
|
logging.log(
|
|
157
155
|
logging.ERROR,
|
|
158
156
|
"Option rses not found in automatix section. Trying the legacy sites option",
|
|
159
157
|
)
|
|
160
158
|
try:
|
|
161
|
-
rses =
|
|
162
|
-
s.strip() for s in config_get("automatix", "sites").split(",")
|
|
163
|
-
] # TODO use config_get_list
|
|
159
|
+
rses = config_get_list("automatix", "sites")
|
|
164
160
|
logging.log(
|
|
165
161
|
logging.WARNING,
|
|
166
162
|
"Option sites found in automatix section. This option will be deprecated soon. Please update your config to use rses.",
|
|
@@ -190,6 +186,8 @@ def run_once(heartbeat_handler: HeartbeatHandler, inputfile: str, **_kwargs) ->
|
|
|
190
186
|
logger(logging.DEBUG, "Probabilities %s", probabilities)
|
|
191
187
|
|
|
192
188
|
cycle_stopwatch = Stopwatch()
|
|
189
|
+
successes = []
|
|
190
|
+
failures = []
|
|
193
191
|
for rse in rses:
|
|
194
192
|
stopwatch = Stopwatch()
|
|
195
193
|
_, _, logger = heartbeat_handler.live()
|
|
@@ -239,24 +237,37 @@ def run_once(heartbeat_handler: HeartbeatHandler, inputfile: str, **_kwargs) ->
|
|
|
239
237
|
file_["dataset_meta"]["lifetime"] = dataset_lifetime
|
|
240
238
|
files.append(file_)
|
|
241
239
|
logger(logging.INFO, "Upload %s:%s to %s", scope, dsn, rse)
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
240
|
+
try:
|
|
241
|
+
upload_client = UploadClient(client)
|
|
242
|
+
ret = upload_client.upload(files)
|
|
243
|
+
if ret == 0:
|
|
244
|
+
logger(logging.INFO, "%s successfully registered on %s", dsn, rse)
|
|
245
|
+
METRICS.counter(name="addnewdataset.done").inc()
|
|
246
|
+
METRICS.counter(name="addnewfile.done").inc(nbfiles)
|
|
247
|
+
METRICS.timer(name='datasetinjection').observe(stopwatch.elapsed)
|
|
248
|
+
successes.append(rse)
|
|
249
|
+
else:
|
|
250
|
+
logger(logging.INFO, "Error uploading files")
|
|
251
|
+
failures.append(rse)
|
|
252
|
+
except Exception as error:
|
|
253
|
+
logger(logging.ERROR, "Error uploading files on %s: %s", rse, str(error))
|
|
254
|
+
failures.append(rse)
|
|
255
|
+
finally:
|
|
256
|
+
for physical_fname in physical_fnames:
|
|
257
|
+
remove(physical_fname)
|
|
258
|
+
rmdir(tmpdir)
|
|
254
259
|
logger(
|
|
255
260
|
logging.INFO,
|
|
256
|
-
"It took %f seconds to upload
|
|
261
|
+
"It took %f seconds to upload datasets on %s RSEs: %s",
|
|
257
262
|
cycle_stopwatch.elapsed,
|
|
258
|
-
|
|
263
|
+
len(successes),
|
|
264
|
+
str(successes),
|
|
259
265
|
)
|
|
266
|
+
if failures:
|
|
267
|
+
logger(
|
|
268
|
+
logging.WARNING,
|
|
269
|
+
"Datasets could not be uploaded on %s RSEs: %s", len(failures), str(failures),
|
|
270
|
+
)
|
|
260
271
|
return True
|
|
261
272
|
|
|
262
273
|
|
|
@@ -25,7 +25,7 @@ from sqlalchemy.exc import DatabaseError
|
|
|
25
25
|
|
|
26
26
|
import rucio.db.sqla.util
|
|
27
27
|
from rucio.common import exception
|
|
28
|
-
from rucio.common.cache import
|
|
28
|
+
from rucio.common.cache import MemcacheRegion
|
|
29
29
|
from rucio.common.config import config_get_int
|
|
30
30
|
from rucio.common.exception import DatabaseException
|
|
31
31
|
from rucio.common.logging import setup_logging
|
|
@@ -41,7 +41,7 @@ if TYPE_CHECKING:
|
|
|
41
41
|
|
|
42
42
|
graceful_stop = threading.Event()
|
|
43
43
|
METRICS = MetricManager(module=__name__)
|
|
44
|
-
REGION =
|
|
44
|
+
REGION = MemcacheRegion(expiration_time=config_get_int('necromancer', 'cache_time', False, 600))
|
|
45
45
|
DAEMON_NAME = 'necromancer'
|
|
46
46
|
|
|
47
47
|
|
|
@@ -61,7 +61,7 @@ total_total = 0
|
|
|
61
61
|
global_ratio = float(0)
|
|
62
62
|
for rse in rses:
|
|
63
63
|
site_name = get_rse_attribute(rse['id'], RseAttr.SITE)
|
|
64
|
-
rse['groupdisk'] = group_space(site_name)
|
|
64
|
+
rse['groupdisk'] = group_space(site_name) # type: ignore (site_name could be None)
|
|
65
65
|
rse['primary'] = get_rse_usage(rse_id=rse['id'], source='rucio')[0]['used'] - get_rse_usage(rse_id=rse['id'], source='expired')[0]['used']
|
|
66
66
|
rse['primary'] += rse['groupdisk']
|
|
67
67
|
rse['secondary'] = get_rse_usage(rse_id=rse['id'], source='expired')[0]['used']
|
|
@@ -61,7 +61,7 @@ total_total = 0
|
|
|
61
61
|
global_ratio = float(0)
|
|
62
62
|
for rse in rses:
|
|
63
63
|
site_name = get_rse_attribute(rse['id'], RseAttr.SITE)
|
|
64
|
-
rse['groupdisk'] = group_space(site_name)
|
|
64
|
+
rse['groupdisk'] = group_space(site_name) # type: ignore (site_name could be None)
|
|
65
65
|
rse['primary'] = get_rse_usage(rse_id=rse['id'], source='rucio')[0]['used'] - get_rse_usage(rse_id=rse['id'], source='expired')[0]['used']
|
|
66
66
|
rse['primary'] += rse['groupdisk']
|
|
67
67
|
rse['secondary'] = get_rse_usage(rse_id=rse['id'], source='expired')[0]['used']
|
rucio/daemons/common.py
CHANGED
|
@@ -20,7 +20,6 @@ import queue
|
|
|
20
20
|
import socket
|
|
21
21
|
import threading
|
|
22
22
|
import time
|
|
23
|
-
from collections.abc import Callable, Generator, Iterator, Sequence
|
|
24
23
|
from typing import TYPE_CHECKING, Any, Generic, Optional, TypeVar, Union
|
|
25
24
|
|
|
26
25
|
from rucio.common.logging import formatted_logger
|
|
@@ -29,6 +28,8 @@ from rucio.core import heartbeat as heartbeat_core
|
|
|
29
28
|
from rucio.core.monitor import MetricManager
|
|
30
29
|
|
|
31
30
|
if TYPE_CHECKING:
|
|
31
|
+
from collections.abc import Callable, Generator, Iterator, Sequence
|
|
32
|
+
|
|
32
33
|
from rucio.common.types import LoggerFunction
|
|
33
34
|
|
|
34
35
|
T = TypeVar('T')
|
|
@@ -85,7 +86,7 @@ class HeartbeatHandler:
|
|
|
85
86
|
self,
|
|
86
87
|
force_renew: bool = False,
|
|
87
88
|
payload: Optional[str] = None
|
|
88
|
-
) -> tuple[int, int, Callable]:
|
|
89
|
+
) -> tuple[int, int, 'Callable']:
|
|
89
90
|
"""
|
|
90
91
|
:return: a tuple: <the number of the current worker>, <total number of workers>, <decorated logger>
|
|
91
92
|
"""
|
|
@@ -115,9 +116,9 @@ class HeartbeatHandler:
|
|
|
115
116
|
def _activity_looper(
|
|
116
117
|
once: bool,
|
|
117
118
|
sleep_time: int,
|
|
118
|
-
activities: Optional[Sequence[str]],
|
|
119
|
+
activities: Optional['Sequence[str]'],
|
|
119
120
|
heartbeat_handler: HeartbeatHandler,
|
|
120
|
-
) -> Generator[tuple[str, float], tuple[float, bool], None]:
|
|
121
|
+
) -> 'Generator[tuple[str, float], tuple[float, bool], None]':
|
|
121
122
|
"""
|
|
122
123
|
Generator which loops (either once, or indefinitely) over all activities while ensuring that `sleep_time`
|
|
123
124
|
passes between handling twice the same activity.
|
|
@@ -164,7 +165,7 @@ def _activity_looper(
|
|
|
164
165
|
if not once:
|
|
165
166
|
if must_sleep:
|
|
166
167
|
time_diff = time.time() - actual_exe_time
|
|
167
|
-
time_to_sleep = max(1, sleep_time - time_diff)
|
|
168
|
+
time_to_sleep = max(1.0, sleep_time - time_diff)
|
|
168
169
|
activity_next_exe_time[activity] = time.time() + time_to_sleep
|
|
169
170
|
else:
|
|
170
171
|
activity_next_exe_time[activity] = time.time() + 1
|
|
@@ -176,19 +177,8 @@ def db_workqueue(
|
|
|
176
177
|
executable: str,
|
|
177
178
|
partition_wait_time: int,
|
|
178
179
|
sleep_time: int,
|
|
179
|
-
activities: Optional[Sequence[str]] = None,
|
|
180
|
-
) -> Callable[
|
|
181
|
-
[
|
|
182
|
-
Callable[
|
|
183
|
-
...,
|
|
184
|
-
Union[bool, tuple[bool, T], None]
|
|
185
|
-
]
|
|
186
|
-
],
|
|
187
|
-
Callable[
|
|
188
|
-
[],
|
|
189
|
-
Iterator[Union[T, None]]
|
|
190
|
-
]
|
|
191
|
-
]:
|
|
180
|
+
activities: Optional['Sequence[str]'] = None,
|
|
181
|
+
) -> 'Callable[[Callable[..., Union[bool, tuple[bool, T], None]]], Callable[[], Iterator[Union[T, None]]]]':
|
|
192
182
|
"""
|
|
193
183
|
Used to wrap a function for interacting with the database as a work queue: i.e. to select
|
|
194
184
|
a set of rows and perform some work on those rows while ensuring that two instances running in parallel don't
|
|
@@ -203,10 +193,10 @@ def db_workqueue(
|
|
|
203
193
|
:param activities: optional list of activities on which to work. The run_once_fnc will be called on activities one by one.
|
|
204
194
|
"""
|
|
205
195
|
|
|
206
|
-
def _decorate(run_once_fnc: Callable[..., Optional[Union[bool, tuple[bool, T]]]]) -> Callable[[], Iterator[Optional[T]]]:
|
|
196
|
+
def _decorate(run_once_fnc: 'Callable[..., Optional[Union[bool, tuple[bool, T]]]]') -> 'Callable[[], Iterator[Optional[T]]]':
|
|
207
197
|
|
|
208
198
|
@functools.wraps(run_once_fnc)
|
|
209
|
-
def _generator() -> Iterator[T]:
|
|
199
|
+
def _generator() -> 'Iterator[T]':
|
|
210
200
|
|
|
211
201
|
with HeartbeatHandler(executable=executable, renewal_interval=sleep_time - 1) as heartbeat_handler:
|
|
212
202
|
logger = heartbeat_handler.logger
|
|
@@ -270,7 +260,7 @@ def run_daemon(
|
|
|
270
260
|
executable: str,
|
|
271
261
|
partition_wait_time: int,
|
|
272
262
|
sleep_time: int,
|
|
273
|
-
run_once_fnc: Callable[..., Optional[Union[bool, tuple[bool, Any]]]],
|
|
263
|
+
run_once_fnc: 'Callable[..., Optional[Union[bool, tuple[bool, Any]]]]',
|
|
274
264
|
activities: Optional[list[str]] = None
|
|
275
265
|
) -> None:
|
|
276
266
|
"""
|
|
@@ -297,8 +287,8 @@ class ProducerConsumerDaemon(Generic[T]):
|
|
|
297
287
|
|
|
298
288
|
def __init__(
|
|
299
289
|
self,
|
|
300
|
-
producers: Sequence[Callable[[], Iterator[T]]],
|
|
301
|
-
consumers: Sequence[Callable[..., None]],
|
|
290
|
+
producers: 'Sequence[Callable[[], Iterator[T]]]',
|
|
291
|
+
consumers: 'Sequence[Callable[..., None]]',
|
|
302
292
|
graceful_stop: threading.Event,
|
|
303
293
|
logger: "LoggerFunction" = logging.log
|
|
304
294
|
):
|
|
@@ -314,7 +304,7 @@ class ProducerConsumerDaemon(Generic[T]):
|
|
|
314
304
|
|
|
315
305
|
def _produce(
|
|
316
306
|
self,
|
|
317
|
-
it: Callable[[], Iterator[T]],
|
|
307
|
+
it: 'Callable[[], Iterator[T]]',
|
|
318
308
|
wait_for_consumers: bool = False
|
|
319
309
|
) -> None:
|
|
320
310
|
"""
|
|
@@ -351,7 +341,7 @@ class ProducerConsumerDaemon(Generic[T]):
|
|
|
351
341
|
|
|
352
342
|
def _consume(
|
|
353
343
|
self,
|
|
354
|
-
fnc: Callable[[T], Any]
|
|
344
|
+
fnc: 'Callable[[T], Any]'
|
|
355
345
|
) -> None:
|
|
356
346
|
"""
|
|
357
347
|
Wait for elements to arrive via the queue and call the given function on each element.
|
|
@@ -29,7 +29,7 @@ from dogpile.cache.api import NoValue
|
|
|
29
29
|
from sqlalchemy.exc import DatabaseError
|
|
30
30
|
|
|
31
31
|
import rucio.db.sqla.util
|
|
32
|
-
from rucio.common.cache import
|
|
32
|
+
from rucio.common.cache import MemcacheRegion
|
|
33
33
|
from rucio.common.config import config_get_bool, config_get_list
|
|
34
34
|
from rucio.common.exception import DatabaseException, ReplicaNotFound, RequestNotFound, RSEProtocolNotSupported, UnsupportedOperation
|
|
35
35
|
from rucio.common.logging import setup_logging
|
|
@@ -55,7 +55,7 @@ if TYPE_CHECKING:
|
|
|
55
55
|
|
|
56
56
|
GRACEFUL_STOP = threading.Event()
|
|
57
57
|
|
|
58
|
-
REGION =
|
|
58
|
+
REGION = MemcacheRegion(expiration_time=900)
|
|
59
59
|
METRICS = MetricManager(module=__name__)
|
|
60
60
|
DAEMON_NAME = 'conveyor-finisher'
|
|
61
61
|
FAILED_DURING_SUBMISSION_DELAY = datetime.timedelta(minutes=120)
|