rucio 37.5.0__py3-none-any.whl → 37.7.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of rucio might be problematic. Click here for more details.
- rucio/cli/bin_legacy/rucio.py +41 -22
- rucio/cli/bin_legacy/rucio_admin.py +1 -1
- rucio/cli/did.py +2 -2
- rucio/cli/rse.py +2 -3
- rucio/cli/rule.py +9 -5
- rucio/cli/subscription.py +1 -1
- rucio/client/baseclient.py +9 -4
- rucio/client/didclient.py +16 -16
- rucio/client/downloadclient.py +16 -15
- rucio/client/exportclient.py +45 -4
- rucio/client/lockclient.py +3 -3
- rucio/client/pingclient.py +35 -4
- rucio/client/replicaclient.py +2 -2
- rucio/client/touchclient.py +3 -2
- rucio/client/uploadclient.py +728 -183
- rucio/common/cache.py +1 -2
- rucio/common/client.py +4 -30
- rucio/common/config.py +27 -3
- rucio/common/constants.py +5 -1
- rucio/common/didtype.py +2 -2
- rucio/common/dumper/__init__.py +1 -1
- rucio/common/pcache.py +20 -25
- rucio/common/plugins.py +12 -19
- rucio/common/policy.py +3 -2
- rucio/common/schema/__init__.py +11 -8
- rucio/common/types.py +7 -5
- rucio/common/utils.py +1 -1
- rucio/core/account.py +2 -1
- rucio/core/account_limit.py +3 -2
- rucio/core/authentication.py +1 -1
- rucio/core/credential.py +1 -1
- rucio/core/did.py +62 -61
- rucio/core/did_meta_plugins/__init__.py +10 -10
- rucio/core/did_meta_plugins/did_column_meta.py +9 -9
- rucio/core/did_meta_plugins/did_meta_plugin_interface.py +3 -3
- rucio/core/did_meta_plugins/elasticsearch_meta.py +7 -7
- rucio/core/did_meta_plugins/json_meta.py +2 -2
- rucio/core/did_meta_plugins/mongo_meta.py +9 -9
- rucio/core/did_meta_plugins/postgres_meta.py +7 -7
- rucio/core/dirac.py +3 -2
- rucio/core/distance.py +2 -1
- rucio/core/exporter.py +3 -2
- rucio/core/importer.py +5 -5
- rucio/core/lifetime_exception.py +2 -2
- rucio/core/lock.py +7 -7
- rucio/core/meta_conventions.py +2 -2
- rucio/core/monitor.py +1 -1
- rucio/core/naming_convention.py +1 -1
- rucio/core/nongrid_trace.py +2 -2
- rucio/core/oidc.py +2 -2
- rucio/core/permission/__init__.py +9 -6
- rucio/core/permission/generic.py +2 -2
- rucio/core/permission/generic_multi_vo.py +2 -2
- rucio/core/replica.py +22 -22
- rucio/core/request.py +2 -2
- rucio/core/rse.py +7 -7
- rucio/core/rule.py +38 -38
- rucio/core/rule_grouping.py +2 -3
- rucio/core/scope.py +1 -1
- rucio/core/trace.py +2 -2
- rucio/core/transfer.py +2 -2
- rucio/core/vo.py +2 -1
- rucio/daemons/atropos/atropos.py +2 -1
- rucio/daemons/auditor/__init__.py +1 -1
- rucio/daemons/automatix/automatix.py +5 -5
- rucio/daemons/badreplicas/minos.py +12 -5
- rucio/daemons/badreplicas/minos_temporary_expiration.py +5 -2
- rucio/daemons/badreplicas/necromancer.py +9 -3
- rucio/daemons/bb8/bb8.py +2 -1
- rucio/daemons/bb8/common.py +1 -1
- rucio/daemons/bb8/nuclei_background_rebalance.py +3 -3
- rucio/daemons/bb8/t2_background_rebalance.py +1 -1
- rucio/daemons/cache/consumer.py +1 -1
- rucio/daemons/conveyor/common.py +3 -3
- rucio/daemons/conveyor/finisher.py +13 -4
- rucio/daemons/conveyor/poller.py +5 -2
- rucio/daemons/conveyor/receiver.py +1 -1
- rucio/daemons/conveyor/submitter.py +2 -1
- rucio/daemons/follower/follower.py +1 -1
- rucio/daemons/hermes/hermes.py +29 -8
- rucio/daemons/judge/cleaner.py +2 -2
- rucio/daemons/judge/evaluator.py +7 -7
- rucio/daemons/judge/injector.py +2 -2
- rucio/daemons/judge/repairer.py +2 -2
- rucio/daemons/reaper/dark_reaper.py +5 -4
- rucio/daemons/reaper/reaper.py +7 -7
- rucio/daemons/replicarecoverer/suspicious_replica_recoverer.py +4 -4
- rucio/daemons/storage/consistency/actions.py +3 -3
- rucio/daemons/tracer/kronos.py +3 -2
- rucio/daemons/transmogrifier/transmogrifier.py +71 -69
- rucio/daemons/undertaker/undertaker.py +8 -7
- rucio/db/sqla/constants.py +4 -3
- rucio/db/sqla/migrate_repo/versions/3082b8cef557_add_naming_convention_table_and_closed_.py +1 -1
- rucio/db/sqla/migrate_repo/versions/4df2c5ddabc0_remove_temporary_dids.py +1 -1
- rucio/db/sqla/migrate_repo/versions/c129ccdb2d5_add_lumiblocknr_to_dids.py +1 -1
- rucio/db/sqla/models.py +3 -3
- rucio/db/sqla/session.py +7 -7
- rucio/db/sqla/util.py +3 -2
- rucio/gateway/account.py +77 -101
- rucio/gateway/account_limit.py +90 -116
- rucio/gateway/authentication.py +9 -8
- rucio/gateway/config.py +11 -10
- rucio/gateway/credential.py +2 -1
- rucio/gateway/did.py +58 -58
- rucio/gateway/dirac.py +3 -2
- rucio/gateway/exporter.py +2 -1
- rucio/gateway/heartbeat.py +3 -2
- rucio/gateway/identity.py +4 -3
- rucio/gateway/importer.py +2 -1
- rucio/gateway/lifetime_exception.py +5 -4
- rucio/gateway/lock.py +6 -5
- rucio/gateway/meta_conventions.py +3 -2
- rucio/gateway/permission.py +2 -1
- rucio/gateway/quarantined_replica.py +2 -1
- rucio/gateway/replica.py +20 -20
- rucio/gateway/request.py +10 -10
- rucio/gateway/rse.py +27 -26
- rucio/gateway/rule.py +12 -11
- rucio/gateway/scope.py +4 -3
- rucio/gateway/subscription.py +7 -6
- rucio/gateway/vo.py +5 -4
- rucio/rse/__init__.py +7 -6
- rucio/rse/protocols/ngarc.py +2 -2
- rucio/rse/protocols/srm.py +1 -1
- rucio/rse/protocols/webdav.py +8 -1
- rucio/rse/rsemanager.py +5 -4
- rucio/rse/translation.py +2 -2
- rucio/tests/common.py +6 -5
- rucio/vcsversion.py +3 -3
- rucio/web/rest/flaskapi/v1/accountlimits.py +5 -5
- rucio/web/rest/flaskapi/v1/accounts.py +20 -20
- rucio/web/rest/flaskapi/v1/archives.py +4 -3
- rucio/web/rest/flaskapi/v1/common.py +5 -4
- rucio/web/rest/flaskapi/v1/dids.py +382 -331
- rucio/web/rest/flaskapi/v1/lifetime_exceptions.py +5 -5
- rucio/web/rest/flaskapi/v1/locks.py +13 -13
- rucio/web/rest/flaskapi/v1/main.py +1 -0
- rucio/web/rest/flaskapi/v1/redirect.py +2 -2
- rucio/web/rest/flaskapi/v1/replicas.py +16 -16
- rucio/web/rest/flaskapi/v1/requests.py +16 -16
- rucio/web/rest/flaskapi/v1/subscriptions.py +7 -7
- {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-abacus-account +8 -1
- {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-abacus-rse +8 -1
- {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-auditor +1 -1
- {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-conveyor-throttler +7 -1
- {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-follower +1 -1
- {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-judge-cleaner +9 -1
- {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-necromancer +7 -1
- {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-replica-recoverer +31 -9
- {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-undertaker +8 -2
- {rucio-37.5.0.dist-info → rucio-37.7.0.dist-info}/METADATA +1 -1
- {rucio-37.5.0.dist-info → rucio-37.7.0.dist-info}/RECORD +202 -202
- {rucio-37.5.0.data → rucio-37.7.0.data}/data/rucio/etc/alembic.ini.template +0 -0
- {rucio-37.5.0.data → rucio-37.7.0.data}/data/rucio/etc/alembic_offline.ini.template +0 -0
- {rucio-37.5.0.data → rucio-37.7.0.data}/data/rucio/etc/globus-config.yml.template +0 -0
- {rucio-37.5.0.data → rucio-37.7.0.data}/data/rucio/etc/ldap.cfg.template +0 -0
- {rucio-37.5.0.data → rucio-37.7.0.data}/data/rucio/etc/mail_templates/rule_approval_request.tmpl +0 -0
- {rucio-37.5.0.data → rucio-37.7.0.data}/data/rucio/etc/mail_templates/rule_approved_admin.tmpl +0 -0
- {rucio-37.5.0.data → rucio-37.7.0.data}/data/rucio/etc/mail_templates/rule_approved_user.tmpl +0 -0
- {rucio-37.5.0.data → rucio-37.7.0.data}/data/rucio/etc/mail_templates/rule_denied_admin.tmpl +0 -0
- {rucio-37.5.0.data → rucio-37.7.0.data}/data/rucio/etc/mail_templates/rule_denied_user.tmpl +0 -0
- {rucio-37.5.0.data → rucio-37.7.0.data}/data/rucio/etc/mail_templates/rule_ok_notification.tmpl +0 -0
- {rucio-37.5.0.data → rucio-37.7.0.data}/data/rucio/etc/rse-accounts.cfg.template +0 -0
- {rucio-37.5.0.data → rucio-37.7.0.data}/data/rucio/etc/rucio.cfg.atlas.client.template +0 -0
- {rucio-37.5.0.data → rucio-37.7.0.data}/data/rucio/etc/rucio.cfg.template +0 -0
- {rucio-37.5.0.data → rucio-37.7.0.data}/data/rucio/etc/rucio_multi_vo.cfg.template +0 -0
- {rucio-37.5.0.data → rucio-37.7.0.data}/data/rucio/requirements.server.txt +0 -0
- {rucio-37.5.0.data → rucio-37.7.0.data}/data/rucio/tools/bootstrap.py +0 -0
- {rucio-37.5.0.data → rucio-37.7.0.data}/data/rucio/tools/merge_rucio_configs.py +0 -0
- {rucio-37.5.0.data → rucio-37.7.0.data}/data/rucio/tools/reset_database.py +0 -0
- {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio +0 -0
- {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-abacus-collection-replica +0 -0
- {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-admin +0 -0
- {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-atropos +0 -0
- {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-automatix +0 -0
- {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-bb8 +0 -0
- {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-cache-client +0 -0
- {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-cache-consumer +0 -0
- {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-conveyor-finisher +0 -0
- {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-conveyor-poller +0 -0
- {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-conveyor-preparer +0 -0
- {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-conveyor-receiver +0 -0
- {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-conveyor-stager +0 -0
- {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-conveyor-submitter +0 -0
- {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-dark-reaper +0 -0
- {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-dumper +0 -0
- {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-hermes +0 -0
- {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-judge-evaluator +0 -0
- {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-judge-injector +0 -0
- {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-judge-repairer +0 -0
- {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-kronos +0 -0
- {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-minos +0 -0
- {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-minos-temporary-expiration +0 -0
- {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-oauth-manager +0 -0
- {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-reaper +0 -0
- {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-rse-decommissioner +0 -0
- {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-storage-consistency-actions +0 -0
- {rucio-37.5.0.data → rucio-37.7.0.data}/scripts/rucio-transmogrifier +0 -0
- {rucio-37.5.0.dist-info → rucio-37.7.0.dist-info}/WHEEL +0 -0
- {rucio-37.5.0.dist-info → rucio-37.7.0.dist-info}/licenses/AUTHORS.rst +0 -0
- {rucio-37.5.0.dist-info → rucio-37.7.0.dist-info}/licenses/LICENSE +0 -0
- {rucio-37.5.0.dist-info → rucio-37.7.0.dist-info}/top_level.txt +0 -0
|
@@ -124,7 +124,7 @@ def __split_rule_select_rses(
|
|
|
124
124
|
weight: int,
|
|
125
125
|
rse_expression: str,
|
|
126
126
|
copies: int,
|
|
127
|
-
|
|
127
|
+
blocklisted_rse_ids: list,
|
|
128
128
|
logger: LoggerFunction,
|
|
129
129
|
) -> tuple[list, bool, bool]:
|
|
130
130
|
"""
|
|
@@ -138,7 +138,7 @@ def __split_rule_select_rses(
|
|
|
138
138
|
:param weight: The weight of the rule.
|
|
139
139
|
:param rse_expression: The RSE expression of the rule.
|
|
140
140
|
:param copies: The number of copies.
|
|
141
|
-
:param
|
|
141
|
+
:param blocklisted_rse_ids: The list of blocklisted rse_ids.
|
|
142
142
|
:param logger: The logger.
|
|
143
143
|
:return: A tuple with list selected_rses, and 2 booleans create_rule, wont_reevaluate.
|
|
144
144
|
"""
|
|
@@ -172,7 +172,7 @@ def __split_rule_select_rses(
|
|
|
172
172
|
copies=copies,
|
|
173
173
|
size=0,
|
|
174
174
|
preferred_rses=preferred_rses,
|
|
175
|
-
blocklist=
|
|
175
|
+
blocklist=blocklisted_rse_ids,
|
|
176
176
|
)
|
|
177
177
|
wont_reevaluate = True
|
|
178
178
|
break
|
|
@@ -184,26 +184,22 @@ def __split_rule_select_rses(
|
|
|
184
184
|
) as error:
|
|
185
185
|
logger(
|
|
186
186
|
logging.WARNING,
|
|
187
|
-
'Problem getting RSEs for subscription "%s" for account %s : %s. %s'
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
'Try including blocklisted sites' if attempt == 0 else 'Skipping rule creation.'
|
|
193
|
-
),
|
|
187
|
+
'Problem getting RSEs for subscription "%s" for account %s : %s. %s',
|
|
188
|
+
subscription_name,
|
|
189
|
+
account,
|
|
190
|
+
str(error),
|
|
191
|
+
'Try including blocklisted sites' if attempt == 0 else 'Skipping rule creation.'
|
|
194
192
|
)
|
|
195
193
|
# Now including the blocklisted sites
|
|
196
|
-
|
|
194
|
+
blocklisted_rse_ids = []
|
|
197
195
|
METRICS.counter(name="addnewrule.errortype.{exception}").labels(exception=str(error.__class__.__name__)).inc()
|
|
198
196
|
wont_reevaluate = True
|
|
199
197
|
except Exception as error:
|
|
200
198
|
logger(
|
|
201
199
|
logging.ERROR,
|
|
202
|
-
"Problem resolving RSE expression %s : %s"
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
str(error),
|
|
206
|
-
)
|
|
200
|
+
"Problem resolving RSE expression %s : %s",
|
|
201
|
+
rse_expression,
|
|
202
|
+
str(error),
|
|
207
203
|
)
|
|
208
204
|
if len(preferred_rses) - len(preferred_unmatched) >= copies:
|
|
209
205
|
create_rule = False
|
|
@@ -242,6 +238,7 @@ def get_subscriptions(logger: LoggerFunction = logging.log) -> list[dict]:
|
|
|
242
238
|
break
|
|
243
239
|
if rule.get("copies") == "*":
|
|
244
240
|
rule["copies"] = len(list_rses_from_expression)
|
|
241
|
+
rule["wildcard"] = True
|
|
245
242
|
overwrite_rules = True
|
|
246
243
|
if skip_sub:
|
|
247
244
|
continue
|
|
@@ -272,7 +269,7 @@ def get_subscriptions(logger: LoggerFunction = logging.log) -> list[dict]:
|
|
|
272
269
|
subscriptions.extend(sub_dict[priority])
|
|
273
270
|
logger(logging.INFO, "%i active subscriptions", len(subscriptions))
|
|
274
271
|
except SubscriptionNotFound as error:
|
|
275
|
-
logger(logging.WARNING, "No subscriptions defined: %s"
|
|
272
|
+
logger(logging.WARNING, "No subscriptions defined: %s", (str(error)))
|
|
276
273
|
return []
|
|
277
274
|
except TypeError as error:
|
|
278
275
|
logger(
|
|
@@ -307,7 +304,7 @@ def __is_matching_subscription(
|
|
|
307
304
|
try:
|
|
308
305
|
filter_string = loads(subscription["filter"])
|
|
309
306
|
except ValueError as error:
|
|
310
|
-
logging.error("%s : Subscription will be skipped"
|
|
307
|
+
logging.error("%s : Subscription will be skipped", error)
|
|
311
308
|
return False
|
|
312
309
|
# Loop over the keys of filter_string for subscription
|
|
313
310
|
for key in filter_string:
|
|
@@ -399,7 +396,7 @@ def select_algorithm(
|
|
|
399
396
|
selected_rses = {}
|
|
400
397
|
for rule_id in rule_ids:
|
|
401
398
|
rule = get_rule(rule_id)
|
|
402
|
-
logging.
|
|
399
|
+
logger(logging.DEBUG, "In select_algorithm, %s", str(rule))
|
|
403
400
|
rse = rule["rse_expression"]
|
|
404
401
|
vo = rule["account"].vo
|
|
405
402
|
if rse_exists(rse, vo=vo):
|
|
@@ -439,7 +436,7 @@ def select_algorithm(
|
|
|
439
436
|
weight=rule.get("weight"),
|
|
440
437
|
rse_expression=rse_expression,
|
|
441
438
|
copies=rule.get('copies'),
|
|
442
|
-
|
|
439
|
+
blocklisted_rse_ids=params['blocklisted_rse_ids'],
|
|
443
440
|
logger=logger,
|
|
444
441
|
)
|
|
445
442
|
dict_selected_rses = {}
|
|
@@ -487,12 +484,13 @@ def run_once(heartbeat_handler: "HeartbeatHandler", bulk: int, **_kwargs) -> boo
|
|
|
487
484
|
|
|
488
485
|
worker_number, total_workers, logger = heartbeat_handler.live()
|
|
489
486
|
stopwatch = Stopwatch()
|
|
490
|
-
|
|
487
|
+
block_listed = {rse['rse']: rse["id"] for rse in list_rses({"availability_write": False})}
|
|
488
|
+
blocklisted_rse_ids = list(block_listed.values())
|
|
491
489
|
identifiers = []
|
|
492
490
|
# List all the active subscriptions
|
|
493
491
|
subscriptions = get_subscriptions(logger=logger)
|
|
494
492
|
|
|
495
|
-
# Loop over all the new
|
|
493
|
+
# Loop over all the new DIDs
|
|
496
494
|
# Get the new DIDs based on the is_new flag
|
|
497
495
|
logger(logging.DEBUG, "Listing new dids")
|
|
498
496
|
for did in list_new_dids(
|
|
@@ -535,6 +533,7 @@ def run_once(heartbeat_handler: "HeartbeatHandler", bulk: int, **_kwargs) -> boo
|
|
|
535
533
|
# Get all the rule and subscription parameters
|
|
536
534
|
rule_dict = __get_rule_dict(rule_dict, subscription)
|
|
537
535
|
weight = rule_dict.get("weight", None)
|
|
536
|
+
ignore_availability = rule_dict.get("ignore_availability", False)
|
|
538
537
|
source_replica_expression = rule_dict.get(
|
|
539
538
|
"source_replica_expression", None
|
|
540
539
|
)
|
|
@@ -551,7 +550,7 @@ def run_once(heartbeat_handler: "HeartbeatHandler", bulk: int, **_kwargs) -> boo
|
|
|
551
550
|
params['rse_expression'] = rule_dict.get("rse_expression")
|
|
552
551
|
params['subscription_id'] = subscription["id"]
|
|
553
552
|
params['subscription_name'] = subscription["name"]
|
|
554
|
-
params['
|
|
553
|
+
params['blocklisted_rse_ids'] = blocklisted_rse_ids
|
|
555
554
|
if rule_dict.get("associated_site_idx", None):
|
|
556
555
|
params["associated_site_idx"] = rule_dict.get(
|
|
557
556
|
"associated_site_idx", None
|
|
@@ -583,7 +582,7 @@ def run_once(heartbeat_handler: "HeartbeatHandler", bulk: int, **_kwargs) -> boo
|
|
|
583
582
|
weight=weight,
|
|
584
583
|
rse_expression=rule_dict.get("rse_expression"),
|
|
585
584
|
copies=copies,
|
|
586
|
-
|
|
585
|
+
blocklisted_rse_ids=blocklisted_rse_ids,
|
|
587
586
|
logger=logger,
|
|
588
587
|
)
|
|
589
588
|
copies = 1
|
|
@@ -595,20 +594,26 @@ def run_once(heartbeat_handler: "HeartbeatHandler", bulk: int, **_kwargs) -> boo
|
|
|
595
594
|
nb_rule = 0
|
|
596
595
|
# Try to create the rule
|
|
597
596
|
logger(logging.DEBUG, 'selected_rses : %s' % selected_rses)
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
source_replica_expression
|
|
603
|
-
|
|
604
|
-
None,
|
|
605
|
-
)
|
|
606
|
-
weight = selected_rses[rse].get("weight", None)
|
|
607
|
-
logger(
|
|
608
|
-
logging.INFO,
|
|
609
|
-
"Will insert one rule for %s:%s on %s"
|
|
610
|
-
% (did["scope"], did["name"], rse),
|
|
597
|
+
for rse in selected_rses:
|
|
598
|
+
if isinstance(selected_rses, dict):
|
|
599
|
+
# selected_rses is a dictionary only when split_rule is True or for chained subscriptions
|
|
600
|
+
source_replica_expression = selected_rses[rse].get(
|
|
601
|
+
"source_replica_expression",
|
|
602
|
+
None,
|
|
611
603
|
)
|
|
604
|
+
weight = selected_rses[rse].get("weight", None)
|
|
605
|
+
logger(
|
|
606
|
+
logging.INFO,
|
|
607
|
+
"Will insert one rule for %s:%s on %s",
|
|
608
|
+
did["scope"], did["name"], rse,
|
|
609
|
+
)
|
|
610
|
+
if rse in block_listed and rule_dict.get("wildcard"):
|
|
611
|
+
if ignore_availability:
|
|
612
|
+
logger(logging.WARNING, "RSE %s is unavailable, but wildcard number of copies is used with ignore_availability option. Creating a rule", rse)
|
|
613
|
+
else:
|
|
614
|
+
logger(logging.INFO, "RSE %s is unavailable and wildcard number of copies is used. Skipping rule creation", rse)
|
|
615
|
+
continue
|
|
616
|
+
try:
|
|
612
617
|
rule_ids = add_rule(
|
|
613
618
|
dids=[
|
|
614
619
|
{
|
|
@@ -627,9 +632,7 @@ def run_once(heartbeat_handler: "HeartbeatHandler", bulk: int, **_kwargs) -> boo
|
|
|
627
632
|
source_replica_expression=source_replica_expression,
|
|
628
633
|
activity=rule_dict.get("activity"),
|
|
629
634
|
purge_replicas=rule_dict.get("purge_replicas", False),
|
|
630
|
-
ignore_availability=
|
|
631
|
-
"ignore_availability", None
|
|
632
|
-
),
|
|
635
|
+
ignore_availability=ignore_availability,
|
|
633
636
|
comment=rule_dict.get("comment"),
|
|
634
637
|
delay_injection=rule_dict.get("delay_injection"),
|
|
635
638
|
)
|
|
@@ -640,41 +643,40 @@ def run_once(heartbeat_handler: "HeartbeatHandler", bulk: int, **_kwargs) -> boo
|
|
|
640
643
|
if split_rule:
|
|
641
644
|
success = True
|
|
642
645
|
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
646
|
+
except (
|
|
647
|
+
InvalidReplicationRule,
|
|
648
|
+
InvalidRuleWeight,
|
|
649
|
+
InvalidRSEExpression,
|
|
650
|
+
StagingAreaRuleRequiresLifetime,
|
|
651
|
+
DuplicateRule,
|
|
652
|
+
) as error:
|
|
653
|
+
# Errors that won't be retried
|
|
654
|
+
success = True
|
|
655
|
+
logger(logging.ERROR, str(error))
|
|
656
|
+
METRICS.counter("addnewrule.errortype.{exception}").labels(exception=str(error.__class__.__name__)).inc()
|
|
657
|
+
except Exception:
|
|
658
|
+
# Errors that will be retried
|
|
659
|
+
METRICS.counter("addnewrule.errortype.{exception}").labels(exception="unknown").inc()
|
|
660
|
+
logger(logging.ERROR, "Unexpected error", exc_info=True)
|
|
661
|
+
|
|
662
|
+
METRICS.counter("addnewrule.done").inc(nb_rule)
|
|
663
|
+
METRICS.counter("addnewrule.activity.{activity}").labels(activity="".join(rule_dict.get("activity").split())).inc(nb_rule)
|
|
664
|
+
success = True
|
|
661
665
|
|
|
662
666
|
did_success = did_success and success
|
|
663
667
|
if not success:
|
|
664
668
|
logger(
|
|
665
669
|
logging.ERROR,
|
|
666
|
-
"Rule for %s:%s on %s cannot be inserted"
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
rule_dict.get("rse_expression"),
|
|
671
|
-
),
|
|
670
|
+
"Rule for %s:%s on %s cannot be inserted",
|
|
671
|
+
did["scope"],
|
|
672
|
+
did["name"],
|
|
673
|
+
rule_dict.get("rse_expression"),
|
|
672
674
|
)
|
|
673
675
|
else:
|
|
674
676
|
logger(
|
|
675
677
|
logging.INFO,
|
|
676
|
-
"%s rule(s) inserted in %f seconds"
|
|
677
|
-
|
|
678
|
+
"%s rule(s) inserted in %f seconds",
|
|
679
|
+
str(nb_rule), time.time() - stime,
|
|
678
680
|
)
|
|
679
681
|
|
|
680
682
|
if did_success:
|
|
@@ -697,7 +699,7 @@ def run_once(heartbeat_handler: "HeartbeatHandler", bulk: int, **_kwargs) -> boo
|
|
|
697
699
|
flag_stopwatch = Stopwatch()
|
|
698
700
|
for identifier in chunks(identifiers, 100):
|
|
699
701
|
set_new_dids(identifier, None)
|
|
700
|
-
logger(logging.DEBUG, "Time to set the new flag : %f"
|
|
702
|
+
logger(logging.DEBUG, "Time to set the new flag : %f", flag_stopwatch.elapsed)
|
|
701
703
|
|
|
702
704
|
stopwatch.stop()
|
|
703
705
|
|
|
@@ -709,9 +711,9 @@ def run_once(heartbeat_handler: "HeartbeatHandler", bulk: int, **_kwargs) -> boo
|
|
|
709
711
|
)
|
|
710
712
|
logger(
|
|
711
713
|
logging.INFO,
|
|
712
|
-
"It took %f seconds to process %i DIDs"
|
|
714
|
+
"It took %f seconds to process %i DIDs", stopwatch.elapsed, len(identifiers),
|
|
713
715
|
)
|
|
714
|
-
logger(logging.DEBUG, "DIDs processed : %s"
|
|
716
|
+
logger(logging.DEBUG, "DIDs processed : %s", str(identifiers))
|
|
715
717
|
METRICS.counter(name="transmogrifier.job.done").inc(1)
|
|
716
718
|
METRICS.timer("job.duration").observe(stopwatch.elapsed)
|
|
717
719
|
must_sleep = True
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
15
|
'''
|
|
16
|
-
Undertaker is a daemon to manage expired
|
|
16
|
+
Undertaker is a daemon to manage expired DID.
|
|
17
17
|
'''
|
|
18
18
|
|
|
19
19
|
import functools
|
|
@@ -29,6 +29,7 @@ from typing import TYPE_CHECKING
|
|
|
29
29
|
from sqlalchemy.exc import DatabaseError
|
|
30
30
|
|
|
31
31
|
import rucio.db.sqla.util
|
|
32
|
+
from rucio.common.constants import DEFAULT_VO
|
|
32
33
|
from rucio.common.exception import DatabaseException, RuleNotFound, UnsupportedOperation
|
|
33
34
|
from rucio.common.logging import setup_logging
|
|
34
35
|
from rucio.common.types import InternalAccount
|
|
@@ -36,7 +37,7 @@ from rucio.common.utils import chunks
|
|
|
36
37
|
from rucio.core.did import delete_dids, list_expired_dids
|
|
37
38
|
from rucio.core.monitor import MetricManager
|
|
38
39
|
from rucio.daemons.common import HeartbeatHandler, run_daemon
|
|
39
|
-
from rucio.db.sqla.constants import MYSQL_LOCK_NOWAIT_REGEX, ORACLE_RESOURCE_BUSY_REGEX, PSQL_LOCK_NOT_AVAILABLE_REGEX
|
|
40
|
+
from rucio.db.sqla.constants import MYSQL_LOCK_NOWAIT_REGEX, ORACLE_RESOURCE_BUSY_REGEX, PSQL_LOCK_NOT_AVAILABLE_REGEX, PSQL_PSYCOPG_LOCK_NOT_AVAILABLE_REGEX
|
|
40
41
|
|
|
41
42
|
if TYPE_CHECKING:
|
|
42
43
|
from types import FrameType
|
|
@@ -51,7 +52,7 @@ DAEMON_NAME = 'undertaker'
|
|
|
51
52
|
|
|
52
53
|
def undertaker(once: bool = False, sleep_time: int = 60, chunk_size: int = 10) -> None:
|
|
53
54
|
"""
|
|
54
|
-
Main loop to select and delete
|
|
55
|
+
Main loop to select and delete DIDs.
|
|
55
56
|
"""
|
|
56
57
|
paused_dids = {} # {(scope, name): datetime}
|
|
57
58
|
run_daemon(
|
|
@@ -72,7 +73,7 @@ def run_once(paused_dids: dict[tuple, datetime], chunk_size: int, heartbeat_hand
|
|
|
72
73
|
worker_number, total_workers, logger = heartbeat_handler.live()
|
|
73
74
|
|
|
74
75
|
try:
|
|
75
|
-
# Refresh paused
|
|
76
|
+
# Refresh paused DIDs
|
|
76
77
|
iter_paused_dids = deepcopy(paused_dids)
|
|
77
78
|
for key in iter_paused_dids:
|
|
78
79
|
if datetime.utcnow() > paused_dids[key]:
|
|
@@ -90,20 +91,20 @@ def run_once(paused_dids: dict[tuple, datetime], chunk_size: int, heartbeat_hand
|
|
|
90
91
|
_, _, logger = heartbeat_handler.live()
|
|
91
92
|
try:
|
|
92
93
|
logger(logging.INFO, 'Receive %s dids to delete', len(chunk))
|
|
93
|
-
delete_dids(dids=chunk, account=InternalAccount('root', vo=
|
|
94
|
+
delete_dids(dids=chunk, account=InternalAccount('root', vo=DEFAULT_VO), expire_rules=True)
|
|
94
95
|
logger(logging.INFO, 'Delete %s dids', len(chunk))
|
|
95
96
|
METRICS.counter(name='undertaker.delete_dids').inc(len(chunk))
|
|
96
97
|
except RuleNotFound as error:
|
|
97
98
|
logger(logging.ERROR, error)
|
|
98
99
|
except (DatabaseException, DatabaseError, UnsupportedOperation) as e:
|
|
99
|
-
if match(ORACLE_RESOURCE_BUSY_REGEX, str(e.args[0])) or match(PSQL_LOCK_NOT_AVAILABLE_REGEX, str(e.args[0])) or match(MYSQL_LOCK_NOWAIT_REGEX, str(e.args[0])):
|
|
100
|
+
if match(ORACLE_RESOURCE_BUSY_REGEX, str(e.args[0])) or match(PSQL_LOCK_NOT_AVAILABLE_REGEX, str(e.args[0])) or match(PSQL_PSYCOPG_LOCK_NOT_AVAILABLE_REGEX, str(e.args[0])) or match(MYSQL_LOCK_NOWAIT_REGEX, str(e.args[0])):
|
|
100
101
|
for did in chunk:
|
|
101
102
|
paused_dids[(did['scope'], did['name'])] = datetime.utcnow() + timedelta(seconds=randint(600, 2400)) # noqa: S311
|
|
102
103
|
METRICS.counter('delete_dids.exceptions.{exception}').labels(exception='LocksDetected').inc()
|
|
103
104
|
logger(logging.WARNING, 'Locks detected for chunk')
|
|
104
105
|
else:
|
|
105
106
|
logger(logging.ERROR, 'Got database error %s.', str(e))
|
|
106
|
-
except:
|
|
107
|
+
except Exception:
|
|
107
108
|
logging.critical(traceback.format_exc())
|
|
108
109
|
|
|
109
110
|
|
rucio/db/sqla/constants.py
CHANGED
|
@@ -26,6 +26,7 @@ ORACLE_DEADLOCK_DETECTED_REGEX = r".*ORA-00060.*"
|
|
|
26
26
|
ORACLE_RESOURCE_BUSY_REGEX = r".*ORA-00054.*"
|
|
27
27
|
ORACLE_UNIQUE_CONSTRAINT_VIOLATED_REGEX = r".*ORA-00001.*"
|
|
28
28
|
PSQL_LOCK_NOT_AVAILABLE_REGEX = r".*55P03.*"
|
|
29
|
+
PSQL_PSYCOPG_LOCK_NOT_AVAILABLE_REGEX = r".*psycopg.errors.LockNotAvailable.*"
|
|
29
30
|
MYSQL_LOCK_NOWAIT_REGEX = r".*3572.*"
|
|
30
31
|
MYSQL_LOCK_WAIT_TIMEOUT_EXCEEDED = "ERROR 1205 (HY000)"
|
|
31
32
|
|
|
@@ -196,9 +197,9 @@ class SubscriptionState(Enum):
|
|
|
196
197
|
BROKEN = 'B'
|
|
197
198
|
|
|
198
199
|
|
|
199
|
-
#class TransferLimitDirection(Enum):
|
|
200
|
-
#
|
|
201
|
-
#
|
|
200
|
+
# class TransferLimitDirection(Enum):
|
|
201
|
+
# SOURCE = 'S'
|
|
202
|
+
# DESTINATION = 'D'
|
|
202
203
|
|
|
203
204
|
|
|
204
205
|
class DatabaseOperationType(Enum):
|
rucio/db/sqla/models.py
CHANGED
|
@@ -29,7 +29,7 @@ from sqlalchemy.types import LargeBinary
|
|
|
29
29
|
# and it must be renamed to avoid conflicts with the policy package schema modules
|
|
30
30
|
from rucio.common import schema as common_schema
|
|
31
31
|
from rucio.common import utils
|
|
32
|
-
from rucio.common.constants import TransferLimitDirection
|
|
32
|
+
from rucio.common.constants import DEFAULT_VO, TransferLimitDirection
|
|
33
33
|
from rucio.common.types import InternalAccount, InternalScope # noqa: TCH001 (types are needed by SQLAlchemy)
|
|
34
34
|
from rucio.db.sqla.constants import (
|
|
35
35
|
AccountStatus,
|
|
@@ -563,7 +563,7 @@ class DeletedDataIdentifier(BASE, ModelBase):
|
|
|
563
563
|
|
|
564
564
|
|
|
565
565
|
class UpdatedDID(BASE, ModelBase):
|
|
566
|
-
"""Represents the recently updated
|
|
566
|
+
"""Represents the recently updated DIDs"""
|
|
567
567
|
__tablename__ = 'updated_dids'
|
|
568
568
|
id: Mapped[str] = mapped_column(GUID(), default=utils.generate_uuid)
|
|
569
569
|
scope: Mapped[InternalScope] = mapped_column(InternalScopeString(common_schema.get_schema_value('SCOPE_LENGTH')))
|
|
@@ -776,7 +776,7 @@ class RSE(BASE, SoftModelBase):
|
|
|
776
776
|
__tablename__ = 'rses'
|
|
777
777
|
id: Mapped[str] = mapped_column(GUID(), default=utils.generate_uuid)
|
|
778
778
|
rse: Mapped[str] = mapped_column(String(255))
|
|
779
|
-
vo: Mapped[str] = mapped_column(String(3), nullable=False, server_default=
|
|
779
|
+
vo: Mapped[str] = mapped_column(String(3), nullable=False, server_default=DEFAULT_VO)
|
|
780
780
|
rse_type: Mapped[RSEType] = mapped_column(Enum(RSEType, name='RSES_TYPE_CHK',
|
|
781
781
|
create_constraint=True,
|
|
782
782
|
values_callable=lambda obj: [e.value for e in obj]),
|
rucio/db/sqla/session.py
CHANGED
|
@@ -54,7 +54,7 @@ if TYPE_CHECKING:
|
|
|
54
54
|
try:
|
|
55
55
|
main_script = os.path.basename(sys.argv[0])
|
|
56
56
|
CURRENT_COMPONENT = main_script.split('-')[1]
|
|
57
|
-
except:
|
|
57
|
+
except Exception:
|
|
58
58
|
CURRENT_COMPONENT = None
|
|
59
59
|
|
|
60
60
|
DATABASE_SECTION = 'database'
|
|
@@ -63,7 +63,7 @@ try:
|
|
|
63
63
|
sql_connection = config_get('%s-database' % CURRENT_COMPONENT, 'default', check_config_table=False).strip()
|
|
64
64
|
if sql_connection and len(sql_connection):
|
|
65
65
|
DATABASE_SECTION = '%s-database' % CURRENT_COMPONENT
|
|
66
|
-
except:
|
|
66
|
+
except Exception:
|
|
67
67
|
pass
|
|
68
68
|
|
|
69
69
|
DEFAULT_SCHEMA_NAME = config_get(DATABASE_SECTION, 'schema',
|
|
@@ -221,7 +221,7 @@ def get_engine() -> 'Engine':
|
|
|
221
221
|
for param, param_type in config_params:
|
|
222
222
|
try:
|
|
223
223
|
params[param] = param_type(config_get(DATABASE_SECTION, param, check_config_table=False))
|
|
224
|
-
except:
|
|
224
|
+
except Exception:
|
|
225
225
|
pass
|
|
226
226
|
_ENGINE = create_engine(sql_connection, **params)
|
|
227
227
|
if 'mysql' in sql_connection:
|
|
@@ -406,7 +406,7 @@ def read_session(function: "Callable[P, R]"):
|
|
|
406
406
|
except DatabaseError as error:
|
|
407
407
|
session.rollback() # type: ignore
|
|
408
408
|
raise DatabaseException(str(error))
|
|
409
|
-
except:
|
|
409
|
+
except Exception:
|
|
410
410
|
session.rollback() # type: ignore
|
|
411
411
|
raise
|
|
412
412
|
finally:
|
|
@@ -451,7 +451,7 @@ def stream_session(function: "Callable[P, R]"):
|
|
|
451
451
|
except DatabaseError as error:
|
|
452
452
|
session.rollback() # type: ignore
|
|
453
453
|
raise DatabaseException(str(error))
|
|
454
|
-
except:
|
|
454
|
+
except Exception:
|
|
455
455
|
session.rollback() # type: ignore
|
|
456
456
|
raise
|
|
457
457
|
finally:
|
|
@@ -460,7 +460,7 @@ def stream_session(function: "Callable[P, R]"):
|
|
|
460
460
|
try:
|
|
461
461
|
for row in function(*args, session=session, **kwargs):
|
|
462
462
|
yield row
|
|
463
|
-
except:
|
|
463
|
+
except Exception:
|
|
464
464
|
raise
|
|
465
465
|
return _update_session_wrapper(new_funct, function)
|
|
466
466
|
|
|
@@ -491,7 +491,7 @@ def transactional_session(function: "Callable[P, R]") -> 'Callable':
|
|
|
491
491
|
except DatabaseError as error:
|
|
492
492
|
session.rollback() # type: ignore
|
|
493
493
|
raise DatabaseException(str(error))
|
|
494
|
-
except:
|
|
494
|
+
except Exception:
|
|
495
495
|
session.rollback() # type: ignore
|
|
496
496
|
raise
|
|
497
497
|
finally:
|
rucio/db/sqla/util.py
CHANGED
|
@@ -33,6 +33,7 @@ from sqlalchemy.sql.expression import select, text
|
|
|
33
33
|
from rucio import alembicrevision
|
|
34
34
|
from rucio.common.cache import MemcacheRegion
|
|
35
35
|
from rucio.common.config import config_get, config_get_list
|
|
36
|
+
from rucio.common.constants import DEFAULT_VO
|
|
36
37
|
from rucio.common.schema import get_schema_value
|
|
37
38
|
from rucio.common.types import InternalAccount, LoggerFunction
|
|
38
39
|
from rucio.common.utils import generate_uuid
|
|
@@ -136,7 +137,7 @@ def create_base_vo() -> None:
|
|
|
136
137
|
|
|
137
138
|
session_scoped = get_session()
|
|
138
139
|
|
|
139
|
-
vo = models.VO(vo=
|
|
140
|
+
vo = models.VO(vo=DEFAULT_VO, description='Default base VO', email='N/A')
|
|
140
141
|
with session_scoped() as s:
|
|
141
142
|
with s.begin():
|
|
142
143
|
s.add_all([vo])
|
|
@@ -172,7 +173,7 @@ def create_root_account() -> None:
|
|
|
172
173
|
else:
|
|
173
174
|
access = 'root'
|
|
174
175
|
|
|
175
|
-
account = models.Account(account=InternalAccount(access,
|
|
176
|
+
account = models.Account(account=InternalAccount(access, DEFAULT_VO), account_type=AccountType.SERVICE, status=AccountStatus.ACTIVE)
|
|
176
177
|
|
|
177
178
|
salt = urandom(255)
|
|
178
179
|
salted_password = salt + up_pwd.encode()
|