Repository: rucio/rucio

Issue:
Internal server error when declaring bad replicas on non-existent RSEs
Motivation
----------

```
>>> c.declare_bad_file_replicas(['fsf://fds/tmp/test.2b27ab27-7f4a-4cc1-bca7-1fe257ef0b40'], 'test')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/dcameron/dev/rucio-client-venv/lib/python3.6/site-packages/rucio/client/replicaclient.py", line 63, in declare_bad_file_replicas
    raise exc_cls(exc_msg)
rucio.common.exception.RucioException: An unknown exception occurred.
Details: no error information passed (http status code: 500 ('internal_server_error', 'server_error', '/o\\', '✗'))
```

This is because the call to `replica.declare_bad_file_replicas()` [in the API](https://github.com/rucio/rucio/blob/master/lib/rucio/api/replica.py#L81) returns a dictionary like `{'unknown': [u'fsf://fds/tmp/test.2b27ab27-7f4a-4cc1-bca7-1fe257ef0b40']}`

Then it tries to resolve the RSE ID `unknown` to an RSE name, and this crashes because it's not a valid UUID.

I saw this problem in the unit tests for fixes for issue #3395 


Modification
------------

Probably the best solution is to validate rse_ids in the core rse code.

Internal server error when declaring bad replicas on non-existent RSEs
Motivation
----------

```
>>> c.declare_bad_file_replicas(['fsf://fds/tmp/test.2b27ab27-7f4a-4cc1-bca7-1fe257ef0b40'], 'test')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/dcameron/dev/rucio-client-venv/lib/python3.6/site-packages/rucio/client/replicaclient.py", line 63, in declare_bad_file_replicas
    raise exc_cls(exc_msg)
rucio.common.exception.RucioException: An unknown exception occurred.
Details: no error information passed (http status code: 500 ('internal_server_error', 'server_error', '/o\\', '✗'))
```

This is because the call to `replica.declare_bad_file_replicas()` [in the API](https://github.com/rucio/rucio/blob/master/lib/rucio/api/replica.py#L81) returns a dictionary like `{'unknown': [u'fsf://fds/tmp/test.2b27ab27-7f4a-4cc1-bca7-1fe257ef0b40']}`

Then it tries to resolve the RSE ID `unknown` to an RSE name, and this crashes because it's not a valid UUID.

I saw this problem in the unit tests for fixes for issue #3395 


Modification
------------

Probably the best solution is to validate rse_ids in the core rse code.



Discussion:

Resolving patch:
diff --git a/lib/rucio/core/replica.py b/lib/rucio/core/replica.py
--- a/lib/rucio/core/replica.py
+++ b/lib/rucio/core/replica.py
@@ -411,7 +411,7 @@ def declare_bad_file_replicas(pfns, reason, issuer, status=BadFilesStatus.BAD, s
     scheme, files_to_declare, unknown_replicas = get_pfn_to_rse(pfns, vo=issuer.vo, session=session)
     for rse_id in files_to_declare:
         notdeclared = __declare_bad_file_replicas(files_to_declare[rse_id], rse_id, reason, issuer, status=status, scheme=scheme, session=session)
-        if notdeclared != []:
+        if notdeclared:
             unknown_replicas[rse_id] = notdeclared
     return unknown_replicas
 
diff --git a/lib/rucio/web/rest/flaskapi/v1/replica.py b/lib/rucio/web/rest/flaskapi/v1/replica.py
--- a/lib/rucio/web/rest/flaskapi/v1/replica.py
+++ b/lib/rucio/web/rest/flaskapi/v1/replica.py
@@ -571,6 +571,7 @@ def post(self):
         :status 201: Created.
         :status 400: Cannot decode json parameter list.
         :status 401: Invalid auth token.
+        :status 404: RSE not found.
         :status 404: Replica not found.
         :status 500: Internal Error.
         :returns: A list of not successfully declared files.
@@ -592,6 +593,8 @@ def post(self):
             not_declared_files = declare_bad_file_replicas(pfns=pfns, reason=reason, issuer=request.environ.get('issuer'), vo=request.environ.get('vo'))
         except AccessDenied as error:
             return generate_http_error_flask(401, 'AccessDenied', error.args[0])
+        except RSENotFound as error:
+            return generate_http_error_flask(404, 'RSENotFound', error.args[0])
         except ReplicaNotFound as error:
             return generate_http_error_flask(404, 'ReplicaNotFound', error.args[0])
         except RucioException as error:
diff --git a/lib/rucio/web/rest/webpy/v1/replica.py b/lib/rucio/web/rest/webpy/v1/replica.py
--- a/lib/rucio/web/rest/webpy/v1/replica.py
+++ b/lib/rucio/web/rest/webpy/v1/replica.py
@@ -578,6 +578,8 @@ def POST(self):
             not_declared_files = declare_bad_file_replicas(pfns=pfns, reason=reason, issuer=ctx.env.get('issuer'), vo=ctx.env.get('vo'))
         except AccessDenied as error:
             raise generate_http_error(401, 'AccessDenied', error.args[0])
+        except RSENotFound as error:
+            raise generate_http_error(404, 'RSENotFound', error.args[0])
         except ReplicaNotFound as error:
             raise generate_http_error(404, 'ReplicaNotFound', error.args[0])
         except RucioException as error:


Test patch: