Repository: rucio/rucio

Issue:
RSE existence check should consider deleted flag
Motivation
----------
I am not sure if I found a bug in the RSE deletion in core.rse.del_rse() or if it is more a session problem.
I tried this test but it did not work.
```python
from rucio.core.rse import add_rse, del_rse, rse_exists
rse_name = 'TEST'                                                                                                                                                                                                                                       
add_rse(rse_name)                                                                                                                                                                                                                                                     
del_rse(rse_name)                                                                                                                                                                                                                                                     
rse_exists(rse_name) # -> True
```
Same happens with this. I suspect it relates to the way sqlalchemy handles the deletion and relationships.
```python
from rucio.db.sqla import session,models
rse_name = 'TEST2'                                                                                                                                                                                                                                       
db_session = session.get_session()
models.RSE(rse=rse_name).save(session=db_session)
db_session.query(models.RSE).filter_by(rse=rse_name).count() # -> 1
rse = db_session.query(models.RSE).filter_by(rse=rse_name).one()
# This deletion is used in core.rse.del_rse()
rse.delete(session=db_session)
db_session.commit()
db_session.query(models.RSE).filter_by(rse=rse_name).count() # -> 1
```
Strangely the deletion works when using the API and a RSENotFound error gets raised in a second deletion. But if I try to get the RSE usage, the request does not raise a RSENotFound which it should because it is querying the RSE to get the ID.
```
DELETE /rses/TEST -> 200
DELETE /rses/TEST -> 404
GET /rses/TEST/usage -> 200
```

Modification
------------
The deletion works as expected if I use the [sqlalchemy bulk deletion](https://docs.sqlalchemy.org/en/latest/orm/query.html#sqlalchemy.orm.query.Query.delete) with the corresponding ON DELETE CASCADE added to the model definitions of RSEUsage, RSEAttrAssociation, RSEProtocols, etc.
```python
from rucio.db.sqla import session,models
rse_name = 'TEST3'                                                                                                                                                                                                                                       
db_session = session.get_session()
models.RSE(rse=rse_name).save(session=db_session)
db_session.query(models.RSE).filter_by(rse=rse_name).count() # -> 1
db_session.query(models.RSE).filter_by(rse=rse_name).delete(synchronize_session=False)
db_session.query(models.RSE).filter_by(rse=rse_name).count() # -> 0
```
```
DELETE /rses/TEST -> 200
DELETE /rses/TEST -> 404
GET /rses/TEST/usage -> 404
```


Discussion:
we never delete RSE. It's on purpose a soft deletion with the deleted column instead...
Ah alright, thanks.
but ´rse_exists(rse_name) # -> True´ should give back `False` instead if the flag is deleted.

Resolving patch:
diff --git a/lib/rucio/core/rse.py b/lib/rucio/core/rse.py
--- a/lib/rucio/core/rse.py
+++ b/lib/rucio/core/rse.py
@@ -116,14 +116,14 @@ def add_rse(rse, deterministic=True, volatile=False, city=None, region_code=None
 @read_session
 def rse_exists(rse, session=None):
     """
-    Checks to see if RSE exists. This procedure does not check its status.
+    Checks to see if RSE exists.
 
     :param rse: Name of the rse.
     :param session: The database session in use.
 
     :returns: True if found, otherwise false.
     """
-    return True if session.query(models.RSE).filter_by(rse=rse).first() else False
+    return True if session.query(models.RSE).filter_by(rse=rse, deleted=False).first() else False
 
 
 @read_session


Test patch:
diff --git a/lib/rucio/tests/test_rse.py b/lib/rucio/tests/test_rse.py
--- a/lib/rucio/tests/test_rse.py
+++ b/lib/rucio/tests/test_rse.py
@@ -93,6 +93,7 @@ def test_create_and_check_for_rse(self):
         with assert_raises(Duplicate):
             add_rse(rse_name)
         del_rse(rse_name)
+        assert_equal(rse_exists(rse_name), False)
 
     def test_list_rses(self):
         """ RSE (CORE): Test the listing of all RSEs """