Repository: rucio/rucio

Issue:
delete_rule for rule_deleters does not work
Motivation
----------

The conversion of issuer into an object is not done (at least) for the delete_replication_rule :
```
def delete_replication_rule(rule_id, purge_replicas, issuer):
    """
    Deletes a replication rule and all associated locks.

    :param rule_id:  The id of the rule to be deleted
    :param issuer:   The issuing account of this operation
    :raises:         RuleNotFound, AccessDenied
    """
    kwargs = {'rule_id': rule_id, 'purge_replicas': purge_replicas}
    if not has_permission(issuer=issuer, action='del_rule', kwargs=kwargs):
        raise AccessDenied('Account %s can not remove this replication rule.' % (issuer))
    rule.delete_rule(rule_id=rule_id, purge_replicas=purge_replicas, soft=True)
```
It leads to a permission issue when trying to delete a rule.
The other methods need to be checked too




Discussion:
The conversion is done in the permission API, this is correct. The problem here is that sometimes we do comparisons such as:
`if issuer in rse_attr.get('rule_deleters').split(','):`
Which does not work, since the issuer object is looked for in a list of strings. This needs to be adapted to `issuer.external`.
See https://github.com/rucio/rucio/blob/525812b8f83f1069d38ab78aebedb732f21e77ec/lib/rucio/core/permission/atlas.py#L473
There might be other places in the permission code which do that as well.
@hahahannes Can you please have a look in the permission APIs and adapt these lines? (Wherever issuer `in` is used. Thanks!

Resolving patch:
diff --git a/lib/rucio/core/permission/atlas.py b/lib/rucio/core/permission/atlas.py
--- a/lib/rucio/core/permission/atlas.py
+++ b/lib/rucio/core/permission/atlas.py
@@ -352,7 +352,7 @@ def perm_del_identity(issuer, kwargs):
     :returns: True if account is allowed, otherwise False
     """
 
-    return _is_root(issuer) or issuer in kwargs.get('accounts')
+    return _is_root(issuer) or issuer.external in kwargs.get('accounts')
 
 
 def perm_add_did(issuer, kwargs):
@@ -470,7 +470,7 @@ def perm_del_rule(issuer, kwargs):
     for rse in rses:
         rse_attr = list_rse_attributes(rse_id=rse['id'])
         if rse_attr.get('rule_deleters'):
-            if issuer in rse_attr.get('rule_deleters').split(','):
+            if issuer.external in rse_attr.get('rule_deleters').split(','):
                 return True
 
     return False
@@ -580,7 +580,7 @@ def perm_approve_rule(issuer, kwargs):
     for rse in rses:
         rse_attr = list_rse_attributes(rse_id=rse['id'])
         if rse_attr.get('rule_approvers'):
-            if issuer in rse_attr.get('rule_approvers').split(','):
+            if issuer.external in rse_attr.get('rule_approvers').split(','):
                 return True
 
     # LOCALGROUPDISK/LOCALGROUPTAPE admins can approve the rule
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
@@ -326,7 +326,7 @@ def perm_del_identity(issuer, kwargs):
     :returns: True if account is allowed, otherwise False
     """
 
-    return _is_root(issuer) or issuer in kwargs.get('accounts')
+    return _is_root(issuer) or issuer.external in kwargs.get('accounts')
 
 
 def perm_add_did(issuer, kwargs):
diff --git a/lib/rucio/core/permission/generic.py b/lib/rucio/core/permission/generic.py
--- a/lib/rucio/core/permission/generic.py
+++ b/lib/rucio/core/permission/generic.py
@@ -329,7 +329,7 @@ def perm_del_identity(issuer, kwargs):
     :returns: True if account is allowed, otherwise False
     """
 
-    return _is_root(issuer) or issuer in kwargs.get('accounts')
+    return _is_root(issuer) or issuer.external in kwargs.get('accounts')
 
 
 def perm_add_did(issuer, kwargs):


Test patch:
diff --git a/lib/rucio/tests/test_rule.py b/lib/rucio/tests/test_rule.py
--- a/lib/rucio/tests/test_rule.py
+++ b/lib/rucio/tests/test_rule.py
@@ -1153,3 +1153,18 @@ def test_change_rule_lifetime(self):
         get2 = self.rule_client.get_replication_rule(rule_id_1)
 
         assert(get['expires_at'] != get2['expires_at'])
+
+    def test_approve_rule(self):
+        """ REPLICATION RULE (CLIENT): Approve rule"""
+        scope = InternalScope('mock')
+        files = create_files(3, scope, self.rse1_id)
+        dataset = 'dataset_' + str(uuid())
+        add_did(scope, dataset, DIDType.from_sym('DATASET'), self.jdoe)
+        attach_dids(scope, dataset, files, self.jdoe)
+
+        rule_id = add_rule(dids=[{'scope': scope, 'name': dataset}], account=self.jdoe, copies=1, rse_expression=self.rse1, grouping='DATASET', weight='fakeweight', lifetime=150, locked=True, subscription_id=None, ask_approval=True)[0]
+        rule = self.rule_client.get_replication_rule(rule_id)
+        assert_equal(rule['state'], str(RuleState.WAITING_APPROVAL))
+        self.rule_client.approve_replication_rule(rule_id)
+        rule = self.rule_client.get_replication_rule(rule_id)
+        assert_equal(rule['state'], str(RuleState.INJECT))