Repository: rucio/rucio

Issue:
Confused states of BadFilesStatus and ReplicaStatuss
Motivation
----------

The original add_bad_dids function confused these two enums, but it worked perhaps because the names were similar enough. The SQLAlchemy upgrade exposed this mistake.

Modification
------------

Use the right code in the right place



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
@@ -34,7 +34,7 @@
 # - Luc Goossens <luc.goossens@cern.ch>, 2020
 # - Eli Chadwick <eli.chadwick@stfc.ac.uk>, 2020
 # - Patrick Austin <patrick.austin@stfc.ac.uk>, 2020
-# - Eric Vaandering <ewv@fnal.gov>, 2020
+# - Eric Vaandering <ewv@fnal.gov>, 2020-2021
 # - Benedikt Ziemons <benedikt.ziemons@cern.ch>, 2020
 
 from __future__ import print_function
@@ -403,7 +403,7 @@ def __declare_bad_file_replicas(pfns, rse_id, reason, issuer, status=BadFilesSta
 
 
 @transactional_session
-def add_bad_dids(dids, rse_id, reason, issuer, state=ReplicaState.BAD, session=None):
+def add_bad_dids(dids, rse_id, reason, issuer, state=BadFilesStatus.BAD, session=None):
     """
     Declare a list of bad replicas.
 
@@ -411,11 +411,11 @@ def add_bad_dids(dids, rse_id, reason, issuer, state=ReplicaState.BAD, session=N
     :param rse_id: The RSE id.
     :param reason: The reason of the loss.
     :param issuer: The issuer account.
-    :param state: ReplicaState.BAD
+    :param state: BadFilesStatus.BAD
     :param session: The database session in use.
     """
     unknown_replicas = []
-    replicas = []
+    replicas_for_update = []
 
     for did in dids:
         scope = InternalScope(did['scope'], vo=issuer.vo)
@@ -423,7 +423,7 @@ def add_bad_dids(dids, rse_id, reason, issuer, state=ReplicaState.BAD, session=N
         replica_exists, _scope, _name, already_declared, size = __exists_replicas(rse_id, scope, name, path=None,
                                                                                   session=session)
         if replica_exists and not already_declared:
-            replicas.append({'scope': scope, 'name': name, 'rse_id': rse_id, 'state': ReplicaState.BAD})
+            replicas_for_update.append({'scope': scope, 'name': name, 'rse_id': rse_id, 'state': ReplicaState.BAD})
             new_bad_replica = models.BadReplicas(scope=scope, name=name, rse_id=rse_id, reason=reason, state=state,
                                                  account=issuer, bytes=size)
             new_bad_replica.save(session=session, flush=False)
@@ -435,9 +435,9 @@ def add_bad_dids(dids, rse_id, reason, issuer, state=ReplicaState.BAD, session=N
             else:
                 unknown_replicas.append('%s:%s %s' % (did['scope'], name, 'Unknown replica'))
 
-    if str(state) == str(ReplicaState.BAD):
+    if state == BadFilesStatus.BAD:
         try:
-            update_replicas_states(replicas, session=session)
+            update_replicas_states(replicas_for_update, session=session)
         except exception.UnsupportedOperation:
             raise exception.ReplicaNotFound("One or several replicas don't exist.")
 
diff --git a/lib/rucio/web/rest/flaskapi/v1/replicas.py b/lib/rucio/web/rest/flaskapi/v1/replicas.py
--- a/lib/rucio/web/rest/flaskapi/v1/replicas.py
+++ b/lib/rucio/web/rest/flaskapi/v1/replicas.py
@@ -32,8 +32,6 @@
 
 from flask import Flask, Blueprint, Response, request
 from flask.views import MethodView
-from six import string_types
-
 from rucio.api.replica import (add_replicas, list_replicas, list_dataset_replicas,
                                list_dataset_replicas_bulk, delete_replicas,
                                get_did_from_pfns, update_replicas_states,
@@ -50,9 +48,11 @@
                                     InvalidObject, ScopeNotFound)
 from rucio.common.utils import parse_response, APIEncoder, render_json_list
 from rucio.core.replica_sorter import sort_replicas
-from rucio.db.sqla.constants import BadFilesStatus, ReplicaState
-from rucio.web.rest.flaskapi.v1.common import check_accept_header_wrapper_flask, try_stream, parse_scope_name, request_auth_env, response_headers
+from rucio.db.sqla.constants import BadFilesStatus
+from rucio.web.rest.flaskapi.v1.common import (check_accept_header_wrapper_flask, try_stream, parse_scope_name,
+                                               request_auth_env, response_headers)
 from rucio.web.rest.utils import generate_http_error_flask
+from six import string_types
 
 try:
     from urllib import unquote
@@ -967,7 +967,7 @@ def post(self):
                 rse = params['rse']
             if 'reason' in params:
                 reason = params['reason']
-            state = ReplicaState.BAD
+            state = BadFilesStatus.BAD
             if 'expires_at' in params and params['expires_at']:
                 expires_at = datetime.strptime(params['expires_at'], "%Y-%m-%dT%H:%M:%S.%f")
             not_declared_files = add_bad_dids(dids=dids, rse=rse, issuer=request.environ.get('issuer'), state=state,
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
@@ -33,9 +33,6 @@
 from traceback import format_exc
 from xml.sax.saxutils import escape
 
-from six import string_types
-from web import application, ctx, Created, data, header, InternalError, loadhook, OK, unloadhook
-
 from rucio.api.replica import (add_replicas, list_replicas, list_dataset_replicas, list_dataset_replicas_bulk,
                                delete_replicas, list_dataset_replicas_vp,
                                get_did_from_pfns, update_replicas_states,
@@ -53,9 +50,11 @@
 from rucio.common.schema import insert_scope_name
 from rucio.common.utils import parse_response, APIEncoder, render_json_list
 from rucio.core.replica_sorter import sort_replicas
-from rucio.db.sqla.constants import BadFilesStatus, ReplicaState
+from rucio.db.sqla.constants import BadFilesStatus
 from rucio.web.rest.common import rucio_loadhook, rucio_unloadhook, RucioController, check_accept_header_wrapper
 from rucio.web.rest.utils import generate_http_error
+from six import string_types
+from web import application, ctx, Created, data, header, InternalError, loadhook, OK, unloadhook
 
 try:
     from urllib import unquote
@@ -932,7 +931,7 @@ def POST(self):
                 rse = params['rse']
             if 'reason' in params:
                 reason = params['reason']
-            state = ReplicaState.BAD
+            state = BadFilesStatus.BAD
             if 'expires_at' in params and params['expires_at']:
                 expires_at = datetime.strptime(params['expires_at'], "%Y-%m-%dT%H:%M:%S.%f")
             not_declared_files = add_bad_dids(dids=dids, rse=rse, issuer=ctx.env.get('issuer'), state=state,


Test patch: