Repository: rucio/rucio
Issue: Traceback when declaring bad replicas and unable to identify the RSE

Motivation
----------

```python
>>> import rucio.api.replica
>>> replicas = rucio.api.replica.declare_bad_file_replicas(pfns=['davs://dcgftp.usatlas.bnl.gov:443/pnfs/usatlas.bnl.gov/BNLT0D1/rucio/mc16_13TeV/22/6d/log.27574092._000437.job.log.tgz.1'], reason='Decommissioning CA-UVIC-CLOUD_DATADISK', issuer='ddmadmin')
Traceback (most recent call last):
  File "/usr/local/lib64/python3.6/site-packages/sqlalchemy/engine/base.py", line 1700, in _execute_context
    dialect, self, conn, execution_options, *args, **kw
  File "/usr/local/lib64/python3.6/site-packages/sqlalchemy/engine/default.py", line 1080, in _init_compiled
    for key in compiled_params
  File "/usr/local/lib64/python3.6/site-packages/sqlalchemy/engine/default.py", line 1080, in <dictcomp>
    for key in compiled_params
  File "/usr/local/lib64/python3.6/site-packages/sqlalchemy/sql/type_api.py", line 1374, in process
    return impl_processor(process_param(value, dialect))
  File "/usr/local/lib/python3.6/site-packages/rucio/db/sqla/types.py", line 69, in process_bind_param
    return uuid.UUID(value).bytes
  File "/usr/lib64/python3.6/uuid.py", line 140, in __init__
    raise ValueError('badly formed hexadecimal UUID string')
ValueError: badly formed hexadecimal UUID string

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python3.6/site-packages/rucio/api/replica.py", line 98, in declare_bad_file_replicas
    rse = get_rse_name(rse_id=k)
  File "/usr/local/lib/python3.6/site-packages/retrying.py", line 49, in wrapped_f
    return Retrying(*dargs, **dkw).call(f, *args, **kw)
  File "/usr/local/lib/python3.6/site-packages/retrying.py", line 206, in call
    return attempt.get(self._wrap_exception)
  File "/usr/local/lib/python3.6/site-packages/retrying.py", line 247, in get
    six.reraise(self.value[0], self.value[1], self.value[2])
  File "/usr/local/lib/python3.6/site-packages/six.py", line 703, in reraise
    raise value
  File "/usr/local/lib/python3.6/site-packages/retrying.py", line 200, in call
    attempt = Attempt(fn(*args, **kwargs), attempt_number, False)
  File "/usr/local/lib/python3.6/site-packages/rucio/db/sqla/session.py", line 295, in new_funct
    return function(*args, **kwargs)
  File "/usr/local/lib/python3.6/site-packages/rucio/core/rse.py", line 313, in get_rse_name
    result = query.one()[0]
  File "/usr/local/lib64/python3.6/site-packages/sqlalchemy/orm/query.py", line 2808, in one
    return self._iter().one()
  File "/usr/local/lib64/python3.6/site-packages/sqlalchemy/orm/query.py", line 2849, in _iter
    execution_options={"_sa_orm_load_options": self.load_options},
  File "/usr/local/lib64/python3.6/site-packages/sqlalchemy/orm/session.py", line 1689, in execute
    result = conn._execute_20(statement, params or {}, execution_options)
  File "/usr/local/lib64/python3.6/site-packages/sqlalchemy/engine/base.py", line 1611, in _execute_20
    return meth(self, args_10style, kwargs_10style, execution_options)
  File "/usr/local/lib64/python3.6/site-packages/sqlalchemy/sql/elements.py", line 326, in _execute_on_connection
    self, multiparams, params, execution_options
  File "/usr/local/lib64/python3.6/site-packages/sqlalchemy/engine/base.py", line 1488, in _execute_clauseelement
    cache_hit=cache_hit,
  File "/usr/local/lib64/python3.6/site-packages/sqlalchemy/engine/base.py", line 1706, in _execute_context
    e, util.text_type(statement), parameters, None, None
  File "/usr/local/lib64/python3.6/site-packages/sqlalchemy/engine/base.py", line 2024, in _handle_dbapi_exception
    sqlalchemy_exception, with_traceback=exc_info[2], from_=e
  File "/usr/local/lib64/python3.6/site-packages/sqlalchemy/util/compat.py", line 207, in raise_
    raise exception
  File "/usr/local/lib64/python3.6/site-packages/sqlalchemy/engine/base.py", line 1700, in _execute_context
    dialect, self, conn, execution_options, *args, **kw
  File "/usr/local/lib64/python3.6/site-packages/sqlalchemy/engine/default.py", line 1080, in _init_compiled
    for key in compiled_params
  File "/usr/local/lib64/python3.6/site-packages/sqlalchemy/engine/default.py", line 1080, in <dictcomp>
    for key in compiled_params
  File "/usr/local/lib64/python3.6/site-packages/sqlalchemy/sql/type_api.py", line 1374, in process
    return impl_processor(process_param(value, dialect))
  File "/usr/local/lib/python3.6/site-packages/rucio/db/sqla/types.py", line 69, in process_bind_param
    return uuid.UUID(value).bytes
  File "/usr/lib64/python3.6/uuid.py", line 140, in __init__
    raise ValueError('badly formed hexadecimal UUID string')
sqlalchemy.exc.StatementError: (builtins.ValueError) badly formed hexadecimal UUID string
[SQL: SELECT atlas_rucio.rses.rse AS atlas_rucio_rses_rse
FROM atlas_rucio.rses
WHERE atlas_rucio.rses.id = :id_1]
```
```python
>>> import rucio.core.replica
>>> from rucio.common.types import InternalAccount
>>> rucio.core.replica.declare_bad_file_replicas(pfns=['davs://dcgftp.usatlas.bnl.gov:443/pnfs/usatlas.bnl.gov/BNLT0D1/rucio/mc16_13TeV/22/6d/log.27574092._000437.job.log.tgz.1'], reason='Decommissioning CA-UVIC-CLOUD_DATADISK', issuer=InternalAccount('ddmadmin'))
{'unknown': ['davs://dcgftp.usatlas.bnl.gov:443/pnfs/usatlas.bnl.gov/BNLT0D1/rucio/mc16_13TeV/22/6d/log.27574092._000437.job.log.tgz.1']}
```

It’s `rucio.core.rse.get_rse_name('unknown')` which raises an unhandled exception (the API layer expects `RSENotFound`).

https://github.com/rucio/rucio/blob/80f8c5a96e06abb80e3e6c854b89298f16be6270/lib/rucio/api/replica.py#L96-L101

Modification
------------

Maybe `rucio.core.rse.get_rse_name()` should handle an `rse_id` argument which is not a valid UUID?


Changed files:
lib/rucio/api/replica.py

diff --git a/lib/rucio/api/replica.py b/lib/rucio/api/replica.py
index 8fc851116..2ac5952cd 100644
--- a/lib/rucio/api/replica.py
+++ b/lib/rucio/api/replica.py
@@ -15,7 +15,7 @@
 #
 # Authors:
 # - Vincent Garonne <vincent.garonne@cern.ch>, 2013-2016
-# - Cedric Serfon <cedric.serfon@cern.ch>, 2014-2021
+# - Cedric Serfon <cedric.serfon@cern.ch>, 2014-2022
 # - Thomas Beermann <thomas.beermann@cern.ch>, 2014
 # - Mario Lassnig <mario.lassnig@cern.ch>, 2017-2019
 # - Hannes Hansen <hannes.jakob.hansen@cern.ch>, 2018-2019
@@ -32,6 +32,7 @@
 # - Joel Dierkes <joel.dierkes@cern.ch>, 2021-2022
 # - Christoph Ames <christoph.ames@physik.uni-muenchen.de>, 2021
 
+import uuid
 import datetime
 
 from rucio.api import permission
@@ -112,12 +113,16 @@ def declare_bad_file_replicas(pfns, reason, issuer, vo='def', session=None):
             pfn['scope'] = InternalScope(pfn['scope'], vo=vo)
     replicas = replica.declare_bad_file_replicas(pfns=pfns, reason=reason, issuer=issuer, status=BadFilesStatus.BAD, session=session)
 
-    for k in list(replicas):
+    for rse_id in list(replicas):
         try:
-            rse = get_rse_name(rse_id=k, session=session)
-            replicas[rse] = replicas.pop(k)
+            uuid.UUID(rse_id)
+            rse = get_rse_name(rse_id=rse_id, session=session)
+            replicas[rse] = replicas.pop(rse_id)
         except exception.RSENotFound:
             pass
+        except ValueError:
+            if rse_id == 'unknown':
+                replicas['unknown'] = replicas.pop(rse_id)
     return replicas