Repository: rucio/rucio

Issue:
Add quote/rule approvers to CMS
Motivation
----------

CMS RSEs will also need these approvals mechanisms


Modification
------------



Bug when a file with no available replicas is declared
Motivation
----------
When a replica has no replicas `AVAILABLE` and one declare one of these replicas as lost, all the requests for the other replicas are canceled but not the one of the file that was declared.








Discussion:

Resolving patch:
diff --git a/lib/rucio/core/permission/cms.py b/lib/rucio/core/permission/cms.py
--- a/lib/rucio/core/permission/cms.py
+++ b/lib/rucio/core/permission/cms.py
@@ -475,6 +475,17 @@ def perm_approve_rule(issuer, kwargs):
     """
     if _is_root(issuer) or has_account_attribute(account=issuer, key='admin'):
         return True
+
+    rule = get_rule(rule_id=kwargs['rule_id'])
+    rses = parse_expression(rule['rse_expression'])
+
+    # Those in rule_approvers can approve the rule
+    for rse in rses:
+        rse_attr = list_rse_attributes(rse_id=rse['id'])
+        rule_approvers = rse_attr.get('rule_approvers', None)
+        if rule_approvers and issuer.external in rule_approvers.split(','):
+            return True
+
     return False
 
 
@@ -760,6 +771,13 @@ def perm_set_local_account_limit(issuer, kwargs):
             admin_in_country.append(kv['key'].partition('-')[2])
     if admin_in_country and list_rse_attributes(rse_id=kwargs['rse_id']).get('country') in admin_in_country:
         return True
+
+    # Those listed as quota approvers can add to quotas
+    rse_attr = list_rse_attributes(rse_id=kwargs['rse_id'])
+    quota_approvers = rse_attr.get('quota_approvers', None)
+    if quota_approvers and issuer.external in quota_approvers.split(','):
+        return True
+
     return False
 
 
@@ -823,6 +841,12 @@ def perm_delete_local_account_limit(issuer, kwargs):
             admin_in_country.append(kv['key'].partition('-')[2])
     if admin_in_country and list_rse_attributes(rse_id=kwargs['rse_id']).get('country') in admin_in_country:
         return True
+
+    rse_attr = list_rse_attributes(rse_id=kwargs['rse_id'])
+    quota_approvers = rse_attr.get('quota_approvers', None)
+    if quota_approvers and issuer.external in quota_approvers.split(','):
+        return True
+
     return False
 
 
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
@@ -14,7 +14,7 @@
 #
 # Authors:
 # - Vincent Garonne <vgaronne@gmail.com>, 2013-2018
-# - Cedric Serfon <cedric.serfon@cern.ch>, 2013-2019
+# - Cedric Serfon <cedric.serfon@cern.ch>, 2013-2020
 # - Ralph Vigne <ralph.vigne@cern.ch>, 2013-2014
 # - Martin Barisits <martin.barisits@cern.ch>, 2013-2019
 # - Mario Lassnig <mario.lassnig@cern.ch>, 2014-2019
@@ -1407,6 +1407,7 @@ def delete_replicas(rse_id, files, ignore_availability=True, session=None):
             filter(or_(*chunk)).\
             delete(synchronize_session=False)
 
+    rowcount = 0
     for chunk in chunks(replica_condition, 10):
         for (scope, name, rid, replica_bytes) in session.query(models.RSEFileAssociation.scope, models.RSEFileAssociation.name, models.RSEFileAssociation.rse_id, models.RSEFileAssociation.bytes).\
                 with_hint(models.RSEFileAssociation, "INDEX(REPLICAS REPLICAS_PK)", 'oracle').filter(models.RSEFileAssociation.rse_id == rse_id).filter(or_(*chunk)):
diff --git a/lib/rucio/vcsversion.py b/lib/rucio/vcsversion.py
--- a/lib/rucio/vcsversion.py
+++ b/lib/rucio/vcsversion.py
@@ -4,8 +4,8 @@
 '''
 VERSION_INFO = {
     'final': True,
-    'version': '1.21.6',
-    'branch_nick': 'patch-0-Release__1_21_6_preparation',
-    'revision_id': '5f9e6db16019ae94518f6d7e591d611ceb925c03',
-    'revno': 9097
+    'version': '1.21.7',
+    'branch_nick': 'patch-0-Release__1_21_7_preparation',
+    'revision_id': '8e7e22354ba4ca5cfbc8ea945dbe8c6707e42c02',
+    'revno': 9122
 }


Test patch: