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/replica_sorter.py
CHANGED
|
@@ -21,7 +21,7 @@ from datetime import datetime, timedelta
|
|
|
21
21
|
from math import asin, cos, radians, sin, sqrt
|
|
22
22
|
from pathlib import Path
|
|
23
23
|
from tempfile import TemporaryDirectory, TemporaryFile
|
|
24
|
-
from typing import Optional, Union
|
|
24
|
+
from typing import IO, TYPE_CHECKING, Any, Optional, Union
|
|
25
25
|
from urllib.parse import urlparse
|
|
26
26
|
|
|
27
27
|
import geoip2.database
|
|
@@ -29,20 +29,29 @@ import requests
|
|
|
29
29
|
from dogpile.cache.api import NO_VALUE
|
|
30
30
|
|
|
31
31
|
from rucio.common import utils
|
|
32
|
-
from rucio.common.cache import
|
|
32
|
+
from rucio.common.cache import MemcacheRegion
|
|
33
33
|
from rucio.common.config import config_get, config_get_bool, config_get_int
|
|
34
34
|
from rucio.common.constants import SORTING_ALGORITHMS
|
|
35
35
|
from rucio.common.exception import InvalidRSEExpression, SortingAlgorithmNotSupported
|
|
36
36
|
from rucio.core.rse_expression_parser import parse_expression
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
if TYPE_CHECKING:
|
|
39
|
+
from _typeshed import StrPath
|
|
40
|
+
|
|
41
|
+
from rucio.common.types import IPDict, ReplicaDict
|
|
42
|
+
|
|
43
|
+
REGION = MemcacheRegion(expiration_time=900, function_key_generator=utils.my_key_generator)
|
|
39
44
|
|
|
40
45
|
# This product uses GeoLite data created by MaxMind,
|
|
41
46
|
# available from <a href="http://www.maxmind.com">http://www.maxmind.com</a>
|
|
42
47
|
GEOIP_DB_EDITION = 'GeoLite2-City'
|
|
43
48
|
|
|
44
49
|
|
|
45
|
-
def extract_file_from_tar_gz(
|
|
50
|
+
def extract_file_from_tar_gz(
|
|
51
|
+
archive_file_obj: IO,
|
|
52
|
+
file_name: str,
|
|
53
|
+
destination: 'StrPath'
|
|
54
|
+
) -> None:
|
|
46
55
|
"""
|
|
47
56
|
Extract one file from the archive and put it at the destination
|
|
48
57
|
|
|
@@ -58,7 +67,7 @@ def extract_file_from_tar_gz(archive_file_obj, file_name, destination):
|
|
|
58
67
|
shutil.move(tmp_dir / entry.name, destination)
|
|
59
68
|
|
|
60
69
|
|
|
61
|
-
def __download_geoip_db(destination):
|
|
70
|
+
def __download_geoip_db(destination: 'StrPath') -> None:
|
|
62
71
|
edition_id = GEOIP_DB_EDITION
|
|
63
72
|
download_url = config_get('core', 'geoip_download_url', raise_exception=False, default=None)
|
|
64
73
|
verify_tls = config_get_bool('core', 'geoip_download_verify_tls', raise_exception=False, default=True)
|
|
@@ -82,7 +91,7 @@ def __download_geoip_db(destination):
|
|
|
82
91
|
result.text))
|
|
83
92
|
|
|
84
93
|
|
|
85
|
-
def __geoip_db():
|
|
94
|
+
def __geoip_db() -> geoip2.database.Reader:
|
|
86
95
|
db_path = Path(f'/tmp/{GEOIP_DB_EDITION}.mmdb')
|
|
87
96
|
db_expire_delay = timedelta(days=config_get_int('core', 'geoip_expire_delay', raise_exception=False, default=30))
|
|
88
97
|
|
|
@@ -100,10 +109,13 @@ def __geoip_db():
|
|
|
100
109
|
return geoip2.database.Reader(str(db_path))
|
|
101
110
|
|
|
102
111
|
|
|
103
|
-
def __get_lat_long(
|
|
112
|
+
def __get_lat_long(
|
|
113
|
+
se: str,
|
|
114
|
+
gi: geoip2.database.Reader
|
|
115
|
+
) -> tuple[Optional[float], Optional[float]]:
|
|
104
116
|
"""
|
|
105
117
|
Get the latitude and longitude on one host using the GeoLite DB
|
|
106
|
-
:param se
|
|
118
|
+
:param se : A hostname or IP.
|
|
107
119
|
:param gi : A Reader object (geoip2 API).
|
|
108
120
|
"""
|
|
109
121
|
try:
|
|
@@ -116,7 +128,11 @@ def __get_lat_long(se, gi):
|
|
|
116
128
|
return None, None
|
|
117
129
|
|
|
118
130
|
|
|
119
|
-
def __get_distance(
|
|
131
|
+
def __get_distance(
|
|
132
|
+
se1: str,
|
|
133
|
+
client_location: 'IPDict',
|
|
134
|
+
ignore_error: bool
|
|
135
|
+
) -> float:
|
|
120
136
|
"""
|
|
121
137
|
Get the distance between 2 host using the GeoLite DB
|
|
122
138
|
:param se1 : A first hostname or IP.
|
|
@@ -133,14 +149,15 @@ def __get_distance(se1, client_location, ignore_error):
|
|
|
133
149
|
gi = __geoip_db()
|
|
134
150
|
|
|
135
151
|
lat1, long1 = __get_lat_long(se1, gi)
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
152
|
+
|
|
153
|
+
lat2 = client_location.get('latitude')
|
|
154
|
+
long2 = client_location.get('longitude')
|
|
155
|
+
|
|
156
|
+
if not (lat2 and long2) and client_location['ip'] is not None:
|
|
140
157
|
lat2, long2 = __get_lat_long(client_location['ip'], gi)
|
|
141
158
|
|
|
142
159
|
if lat1 and lat2:
|
|
143
|
-
long1, lat1, long2, lat2 = map(radians, [long1, lat1, long2, lat2])
|
|
160
|
+
long1, lat1, long2, lat2 = map(radians, [long1, lat1, long2, lat2]) # type: ignore (lat2 and long2 might be None)
|
|
144
161
|
dlon = long2 - long1
|
|
145
162
|
dlat = lat2 - lat1
|
|
146
163
|
cache_val = 6378 * 2 * asin(sqrt(sin(dlat / 2)**2 + cos(lat1) * cos(lat2) * sin(dlon / 2)**2))
|
|
@@ -152,7 +169,7 @@ def __get_distance(se1, client_location, ignore_error):
|
|
|
152
169
|
# One host is on the Moon
|
|
153
170
|
cache_val = 360000
|
|
154
171
|
REGION.set(cache_key, cache_val)
|
|
155
|
-
return cache_val
|
|
172
|
+
return cache_val # type: ignore (cache_val should not be None)
|
|
156
173
|
|
|
157
174
|
|
|
158
175
|
def __download_custom_distance_table() -> None:
|
|
@@ -206,7 +223,7 @@ def __download_custom_distance_table() -> None:
|
|
|
206
223
|
REGION.set(cache_key, distance)
|
|
207
224
|
|
|
208
225
|
|
|
209
|
-
def __get_distance_custom(rse: Union[tuple, str], client_location:
|
|
226
|
+
def __get_distance_custom(rse: Union[tuple, str], client_location: 'IPDict') -> float:
|
|
210
227
|
"""
|
|
211
228
|
Return the distance from a client to a RSE by looking up in custom distance table
|
|
212
229
|
:param rse: RSE name, or tuple containing replica information with RSE name third
|
|
@@ -228,7 +245,11 @@ def __get_distance_custom(rse: Union[tuple, str], client_location: dict) -> floa
|
|
|
228
245
|
return cache_val
|
|
229
246
|
|
|
230
247
|
|
|
231
|
-
def site_selector(
|
|
248
|
+
def site_selector(
|
|
249
|
+
replicas: dict[str, 'ReplicaDict'],
|
|
250
|
+
site: str,
|
|
251
|
+
vo: str
|
|
252
|
+
) -> list[str]:
|
|
232
253
|
"""
|
|
233
254
|
Return a list of replicas located on one site.
|
|
234
255
|
:param replicas : A dict with RSEs as values and replicas as keys (URIs).
|
|
@@ -249,7 +270,11 @@ def site_selector(replicas, site, vo):
|
|
|
249
270
|
return result
|
|
250
271
|
|
|
251
272
|
|
|
252
|
-
def sort_replicas(
|
|
273
|
+
def sort_replicas(
|
|
274
|
+
dictreplica: dict[str, Any],
|
|
275
|
+
client_location: 'IPDict',
|
|
276
|
+
selection: Optional[str] = None
|
|
277
|
+
) -> list[str]:
|
|
253
278
|
"""
|
|
254
279
|
General sorting method for a dictionary of replicas. Returns the List of replicas.
|
|
255
280
|
|
|
@@ -279,19 +304,13 @@ def sort_replicas(dictreplica: dict, client_location: dict, selection: Optional[
|
|
|
279
304
|
replicas = sort_geoip(dictreplica, client_location, ignore_error=config_get_bool('core', 'geoip_ignore_error', raise_exception=False, default=True))
|
|
280
305
|
elif selection == 'custom_table':
|
|
281
306
|
replicas = sort_custom(dictreplica, client_location)
|
|
282
|
-
elif selection == 'closeness':
|
|
283
|
-
replicas = sort_closeness(dictreplica, client_location)
|
|
284
|
-
elif selection == 'dynamic':
|
|
285
|
-
replicas = sort_dynamic(dictreplica, client_location)
|
|
286
|
-
elif selection == 'ranking':
|
|
287
|
-
replicas = sort_ranking(dictreplica, client_location)
|
|
288
307
|
elif selection == 'random':
|
|
289
308
|
replicas = sort_random(dictreplica)
|
|
290
309
|
|
|
291
310
|
return replicas
|
|
292
311
|
|
|
293
312
|
|
|
294
|
-
def sort_random(dictreplica: dict) -> list:
|
|
313
|
+
def sort_random(dictreplica: dict[str, Any]) -> list[str]:
|
|
295
314
|
"""
|
|
296
315
|
Return a list of replicas sorted randomly.
|
|
297
316
|
:param dictreplica: A dict with replicas as keys (URIs).
|
|
@@ -302,7 +321,11 @@ def sort_random(dictreplica: dict) -> list:
|
|
|
302
321
|
return list_replicas
|
|
303
322
|
|
|
304
323
|
|
|
305
|
-
def sort_geoip(
|
|
324
|
+
def sort_geoip(
|
|
325
|
+
dictreplica: dict[str, Any],
|
|
326
|
+
client_location: 'IPDict',
|
|
327
|
+
ignore_error: bool = False
|
|
328
|
+
) -> list[str]:
|
|
306
329
|
"""
|
|
307
330
|
Return a list of replicas sorted by geographical distance to the client IP.
|
|
308
331
|
:param dictreplica: A dict with replicas as keys (URIs).
|
|
@@ -310,19 +333,22 @@ def sort_geoip(dictreplica: dict, client_location: dict, ignore_error: bool = Fa
|
|
|
310
333
|
:param ignore_error: Ignore exception when the GeoLite DB cannot be retrieved
|
|
311
334
|
"""
|
|
312
335
|
|
|
313
|
-
def distance(pfn):
|
|
336
|
+
def distance(pfn: str) -> float:
|
|
314
337
|
url = urlparse(pfn)
|
|
315
338
|
if url.scheme == 'root':
|
|
316
339
|
# handle root proxy urls: root://10.0.0.1//root://192.168.1.1:1094//dpm/....
|
|
317
340
|
sub_url = urlparse(url.path.lstrip('/'))
|
|
318
341
|
if sub_url.scheme and sub_url.hostname:
|
|
319
342
|
url = sub_url
|
|
320
|
-
return __get_distance(url.hostname, client_location, ignore_error)
|
|
343
|
+
return __get_distance(url.hostname, client_location, ignore_error) # type: ignore (hostname might be None)
|
|
321
344
|
|
|
322
345
|
return list(sorted(dictreplica, key=distance))
|
|
323
346
|
|
|
324
347
|
|
|
325
|
-
def sort_custom(
|
|
348
|
+
def sort_custom(
|
|
349
|
+
dictreplica: dict[str, Any],
|
|
350
|
+
client_location: 'IPDict'
|
|
351
|
+
) -> list[str]:
|
|
326
352
|
"""
|
|
327
353
|
Return a list of replicas sorted according to the custom distance table.
|
|
328
354
|
:param dictreplica: A dict with replicas as keys (URIs).
|
|
@@ -334,33 +360,3 @@ def sort_custom(dictreplica: dict, client_location: dict) -> list:
|
|
|
334
360
|
return __get_distance_custom(dictreplica[pfn], client_location)
|
|
335
361
|
|
|
336
362
|
return list(sorted(dictreplica, key=distance))
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
def sort_closeness(dictreplica: dict, client_location: dict) -> list:
|
|
340
|
-
"""
|
|
341
|
-
Return a list of replicas sorted by AGIS closeness. NOT IMPLEMENTED
|
|
342
|
-
:param dictreplica: A dict with replicas as keys (URIs).
|
|
343
|
-
:param client_location: Location dictionary containing {'ip', 'fqdn', 'site', 'latitude', 'longitude'}
|
|
344
|
-
"""
|
|
345
|
-
|
|
346
|
-
return list(dictreplica.keys())
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
def sort_ranking(dictreplica: dict, client_location: dict) -> list:
|
|
350
|
-
"""
|
|
351
|
-
Return a list of replicas sorted by ranking metric. NOT IMPLEMENTED
|
|
352
|
-
:param dictreplica: A dict with replicas as keys (URIs).
|
|
353
|
-
:param client_location: Location dictionary containing {'ip', 'fqdn', 'site', 'latitude', 'longitude'}
|
|
354
|
-
"""
|
|
355
|
-
|
|
356
|
-
return list(dictreplica.keys())
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
def sort_dynamic(dictreplica: dict, client_location: dict) -> list:
|
|
360
|
-
"""
|
|
361
|
-
Return a list of replicas sorted by dynamic network metrics. NOT IMPLEMENTED
|
|
362
|
-
:param dictreplica: A dict with replicas as keys (URIs).
|
|
363
|
-
:param client_location: Location dictionary containing {'ip', 'fqdn', 'site', 'latitude', 'longitude'}
|
|
364
|
-
"""
|
|
365
|
-
|
|
366
|
-
return list(dictreplica.keys())
|
rucio/core/request.py
CHANGED
|
@@ -20,10 +20,8 @@ import math
|
|
|
20
20
|
import random
|
|
21
21
|
import threading
|
|
22
22
|
import traceback
|
|
23
|
-
import uuid
|
|
24
23
|
from abc import ABCMeta, abstractmethod
|
|
25
24
|
from collections import defaultdict, namedtuple
|
|
26
|
-
from collections.abc import Iterable, Iterator, Mapping, Sequence
|
|
27
25
|
from dataclasses import dataclass
|
|
28
26
|
from typing import TYPE_CHECKING, Any, Optional, Union
|
|
29
27
|
|
|
@@ -31,7 +29,6 @@ from sqlalchemy import and_, delete, exists, insert, or_, select, update
|
|
|
31
29
|
from sqlalchemy.exc import IntegrityError
|
|
32
30
|
from sqlalchemy.orm import aliased
|
|
33
31
|
from sqlalchemy.sql.expression import asc, false, func, null, true
|
|
34
|
-
from sqlalchemy.sql.functions import coalesce
|
|
35
32
|
|
|
36
33
|
from rucio.common.config import config_get_bool, config_get_int
|
|
37
34
|
from rucio.common.constants import RseAttr
|
|
@@ -51,6 +48,8 @@ from rucio.db.sqla.util import temp_table_mngr
|
|
|
51
48
|
RequestAndState = namedtuple('RequestAndState', ['request_id', 'request_state'])
|
|
52
49
|
|
|
53
50
|
if TYPE_CHECKING:
|
|
51
|
+
import uuid
|
|
52
|
+
from collections.abc import Iterable, Iterator, Mapping, Sequence
|
|
54
53
|
|
|
55
54
|
from sqlalchemy.engine import Row
|
|
56
55
|
from sqlalchemy.orm import Session
|
|
@@ -298,7 +297,7 @@ def requeue_and_archive(
|
|
|
298
297
|
@METRICS.count_it
|
|
299
298
|
@transactional_session
|
|
300
299
|
def queue_requests(
|
|
301
|
-
requests: Iterable[RequestDict],
|
|
300
|
+
requests: 'Iterable[RequestDict]',
|
|
302
301
|
*,
|
|
303
302
|
session: "Session",
|
|
304
303
|
logger: LoggerFunction = logging.log
|
|
@@ -457,7 +456,7 @@ def list_and_mark_transfer_requests_and_source_replicas(
|
|
|
457
456
|
limit: Optional[int] = None,
|
|
458
457
|
activity: Optional[str] = None,
|
|
459
458
|
older_than: Optional[datetime.datetime] = None,
|
|
460
|
-
rses: Optional[Sequence[str]] = None,
|
|
459
|
+
rses: Optional['Sequence[str]'] = None,
|
|
461
460
|
request_type: Optional[list[RequestType]] = None,
|
|
462
461
|
request_state: Optional[RequestState] = None,
|
|
463
462
|
required_source_rse_attrs: Optional[list[str]] = None,
|
|
@@ -494,8 +493,6 @@ def list_and_mark_transfer_requests_and_source_replicas(
|
|
|
494
493
|
if request_type is None:
|
|
495
494
|
request_type = [RequestType.TRANSFER]
|
|
496
495
|
|
|
497
|
-
now = datetime.datetime.utcnow()
|
|
498
|
-
|
|
499
496
|
sub_requests = select(
|
|
500
497
|
models.Request.id,
|
|
501
498
|
models.Request.request_type,
|
|
@@ -527,7 +524,11 @@ def list_and_mark_transfer_requests_and_source_replicas(
|
|
|
527
524
|
models.ReplicationRule,
|
|
528
525
|
models.Request.rule_id == models.ReplicationRule.id
|
|
529
526
|
).where(
|
|
530
|
-
|
|
527
|
+
or_(models.ReplicationRule.child_rule_id != null(),
|
|
528
|
+
and_(models.ReplicationRule.child_rule_id == null(),
|
|
529
|
+
models.ReplicationRule.expires_at == null()),
|
|
530
|
+
and_(models.ReplicationRule.child_rule_id == null(),
|
|
531
|
+
models.ReplicationRule.expires_at > datetime.datetime.utcnow()))
|
|
531
532
|
).join(
|
|
532
533
|
models.RSE,
|
|
533
534
|
models.RSE.id == models.Request.dest_rse_id
|
|
@@ -1035,7 +1036,7 @@ def transition_request_state(
|
|
|
1035
1036
|
@METRICS.count_it
|
|
1036
1037
|
@transactional_session
|
|
1037
1038
|
def transition_requests_state_if_possible(
|
|
1038
|
-
request_ids: Iterable[str],
|
|
1039
|
+
request_ids: 'Iterable[str]',
|
|
1039
1040
|
new_state: str,
|
|
1040
1041
|
*,
|
|
1041
1042
|
session: "Session",
|
|
@@ -1942,7 +1943,7 @@ class TransferStatsManager:
|
|
|
1942
1943
|
resolution: datetime.timedelta,
|
|
1943
1944
|
start_time: "Optional[datetime.datetime]" = None,
|
|
1944
1945
|
end_time: "Optional[datetime.datetime]" = None
|
|
1945
|
-
) -> Iterator[tuple[datetime.datetime, datetime.datetime]]:
|
|
1946
|
+
) -> 'Iterator[tuple[datetime.datetime, datetime.datetime]]':
|
|
1946
1947
|
"""
|
|
1947
1948
|
Iterates, back in time, over time intervals of length `resolution` which are fully
|
|
1948
1949
|
included within the input interval (start_time, end_time).
|
|
@@ -2065,17 +2066,18 @@ def get_request_stats(
|
|
|
2065
2066
|
activity: Optional[str] = None,
|
|
2066
2067
|
*,
|
|
2067
2068
|
session: "Session"
|
|
2068
|
-
) -> Sequence[
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
]
|
|
2069
|
+
) -> """Sequence[
|
|
2070
|
+
Row[tuple[
|
|
2071
|
+
Optional[InternalAccount],
|
|
2072
|
+
RequestState,
|
|
2073
|
+
uuid.UUID,
|
|
2074
|
+
Optional[uuid.UUID],
|
|
2075
|
+
Optional[str],
|
|
2076
|
+
int,
|
|
2077
|
+
Optional[int]
|
|
2078
|
+
]
|
|
2079
|
+
]
|
|
2080
|
+
]""":
|
|
2079
2081
|
"""
|
|
2080
2082
|
Retrieve statistics about requests by destination, activity and state.
|
|
2081
2083
|
"""
|
|
@@ -2521,7 +2523,7 @@ def release_all_waiting_requests(
|
|
|
2521
2523
|
def list_transfer_limits(
|
|
2522
2524
|
*,
|
|
2523
2525
|
session: "Session",
|
|
2524
|
-
) -> Iterator[dict[str, Any]]:
|
|
2526
|
+
) -> 'Iterator[dict[str, Any]]':
|
|
2525
2527
|
stmt = select(
|
|
2526
2528
|
models.TransferLimit
|
|
2527
2529
|
)
|
|
@@ -2531,7 +2533,7 @@ def list_transfer_limits(
|
|
|
2531
2533
|
|
|
2532
2534
|
|
|
2533
2535
|
def _sync_rse_transfer_limit(
|
|
2534
|
-
limit_id: Union[str, uuid.UUID],
|
|
2536
|
+
limit_id: Union[str, 'uuid.UUID'],
|
|
2535
2537
|
desired_rse_ids: set[str],
|
|
2536
2538
|
*,
|
|
2537
2539
|
session: "Session",
|
|
@@ -2609,7 +2611,7 @@ def set_transfer_limit(
|
|
|
2609
2611
|
waitings: Optional[int] = None,
|
|
2610
2612
|
*,
|
|
2611
2613
|
session: "Session",
|
|
2612
|
-
) -> uuid.UUID:
|
|
2614
|
+
) -> 'uuid.UUID':
|
|
2613
2615
|
"""
|
|
2614
2616
|
Create or update a transfer limit
|
|
2615
2617
|
|
|
@@ -2991,12 +2993,12 @@ def get_source_rse(
|
|
|
2991
2993
|
|
|
2992
2994
|
@stream_session
|
|
2993
2995
|
def list_requests(
|
|
2994
|
-
src_rse_ids: Sequence[str],
|
|
2995
|
-
dst_rse_ids: Sequence[str],
|
|
2996
|
-
states: Optional[Sequence[RequestState]] = None,
|
|
2996
|
+
src_rse_ids: 'Sequence[str]',
|
|
2997
|
+
dst_rse_ids: 'Sequence[str]',
|
|
2998
|
+
states: Optional['Sequence[RequestState]'] = None,
|
|
2997
2999
|
*,
|
|
2998
3000
|
session: "Session"
|
|
2999
|
-
) -> Iterator[models.Request]:
|
|
3001
|
+
) -> 'Iterator[models.Request]':
|
|
3000
3002
|
"""
|
|
3001
3003
|
List all requests in a specific state from a source RSE to a destination RSE.
|
|
3002
3004
|
|
|
@@ -3021,14 +3023,14 @@ def list_requests(
|
|
|
3021
3023
|
|
|
3022
3024
|
@stream_session
|
|
3023
3025
|
def list_requests_history(
|
|
3024
|
-
src_rse_ids: Sequence[str],
|
|
3025
|
-
dst_rse_ids: Sequence[str],
|
|
3026
|
-
states: Optional[Sequence[RequestState]] = None,
|
|
3026
|
+
src_rse_ids: 'Sequence[str]',
|
|
3027
|
+
dst_rse_ids: 'Sequence[str]',
|
|
3028
|
+
states: Optional['Sequence[RequestState]'] = None,
|
|
3027
3029
|
offset: Optional[int] = None,
|
|
3028
3030
|
limit: Optional[int] = None,
|
|
3029
3031
|
*,
|
|
3030
3032
|
session: "Session"
|
|
3031
|
-
) -> Iterator[models.RequestHistory]:
|
|
3033
|
+
) -> 'Iterator[models.RequestHistory]':
|
|
3032
3034
|
"""
|
|
3033
3035
|
List all historical requests in a specific state from a source RSE to a destination RSE.
|
|
3034
3036
|
|