Repository: rucio/rucio

Issue:
PFN checking should accept mixed protocols
Motivation
----------

For the add_files_to_datasets() call a list of attachments with pfns can be given to Rucio. In the case that these PFNs have different protocols, the PFN check fails, since the protocol is only initialised once (with the last protocol of the list) and assumes all PFNs have the same protocol.

E.g.: 

`[{'scope': 'panda', 'name': 'panda.0908235529.354928.lib._19050738', 'dids': [{'adler32': '7dd69a5f', 'name': 'panda.0908235529.354928.lib._19050738.18598150846.lib.tgz', 'bytes': 72565480L, 'pfn': 'srm://f-dpm001.grid.sinica.edu.tw:8446/srm/managerv2?SFN=/dpm/grid.sinica.edu.tw/home/atlas/atlasscratchdisk/rucio/panda/23/40/panda.0908235529.354928.lib._19050738.18598150846.lib.tgz', 'meta': {'panda_id': 4478387679, 'guid': '81789F3E-572E-4DFA-BE8B-04667522031E'}, 'scope': 'panda'}, {'adler32': '048f10bf', 'name': 'panda.0908235529.354928.lib._19050738.18598150847.log.tgz', 'bytes': 72614448L, 'pfn': 'davs://f-dpm000.grid.sinica.edu.tw:443/dpm/grid.sinica.edu.tw/home/atlas/atlasscratchdisk/rucio/panda/80/c7/panda.0908235529.354928.lib._19050738.18598150847.log.tgz', 'meta': {'panda_id': 4478387679, 'guid': 'c71d6bf8-d372-437a-b0a8-efeb3dacbfa3'}, 'scope': 'panda'}], 'rse': 'TAIWAN-LCG2_SCRATCHDISK'}]
`

ATLAS JIRA Link: https://its.cern.ch/jira/browse/RUCIO-2890

Modification
------------

PFN check needs to initialise a protocol for each protocol-group of PFNs. 


Discussion:

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
@@ -14,7 +14,7 @@
 #
 # Authors:
 # - Vincent Garonne <vgaronne@gmail.com>, 2016
-# - Martin Barisits <martin.barisits@cern.ch>, 2016-2018
+# - Martin Barisits <martin.barisits@cern.ch>, 2016-2019
 # - Cedric Serfon <cedric.serfon@cern.ch>, 2016-2019
 # - Mario Lassnig <mario.lassnig@cern.ch>, 2018
 # - Hannes Hansen <hannes.jakob.hansen@cern.ch>, 2018-2019
@@ -115,7 +115,7 @@ def has_permission(issuer, action, kwargs):
 
 
 def _is_root(issuer):
-    return issuer.external == 'root'
+    return issuer.external == 'root' or issuer.external == 'ddmadmin'
 
 
 def perm_default(issuer, kwargs):
@@ -448,7 +448,7 @@ def perm_del_rule(issuer, kwargs):
     :param kwargs: List of arguments for the action.
     :returns: True if account is allowed to call the API call, otherwise False
     """
-    if _is_root(issuer) or issuer == 'ddmadmin':
+    if _is_root(issuer):
         return True
     if get_rule(kwargs['rule_id'])['account'] == issuer:
         return True
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
@@ -601,9 +601,12 @@ def perm_add_replicas(issuer, kwargs):
     :param kwargs: List of arguments for the action.
     :returns: True if account is allowed, otherwise False
     """
-    return (_is_root(issuer)
-            or str(kwargs.get('rse', '')).endswith('_Temp')  # NOQA: W503
-            or has_account_attribute(account=issuer, key='admin'))  # NOQA: W503
+
+    is_root = _is_root(issuer)
+    is_temp = str(kwargs.get('rse', '')).endswith('_Temp')
+    is_admin = has_account_attribute(account=issuer, key='admin')
+
+    return is_root or is_temp or is_admin
 
 
 def perm_skip_availability_check(issuer, kwargs):


Test patch:
diff --git a/lib/rucio/tests/test_replica.py b/lib/rucio/tests/test_replica.py
--- a/lib/rucio/tests/test_replica.py
+++ b/lib/rucio/tests/test_replica.py
@@ -439,8 +439,6 @@ def test_replica_no_site(self):
     def test_replica_mixed_protocols(self):
         """ REPLICA (CORE): Test adding replicas with mixed protocol """
 
-        rc = ReplicaClient()
-
         rse = 'APERTURE_%s' % rse_name_generator()
         rse_id = add_rse(rse)
 
@@ -469,12 +467,12 @@ def test_replica_mixed_protocols(self):
         name = 'element_%s' % generate_uuid()
         hstr = hashlib.md5(('%s:%s' % (tmp_scope, name)).encode('utf-8')).hexdigest()
         pfn = 'root://root.aperture.com:1409//test/chamber/mock/%s/%s/%s' % (hstr[0:2], hstr[2:4], name)
-        files.append({'scope': tmp_scope, 'name': name,'bytes': 1234, 'adler32': 'deadbeef', 'pfn': pfn})
+        files.append({'scope': tmp_scope, 'name': name, 'bytes': 1234, 'adler32': 'deadbeef', 'pfn': pfn})
 
         name = 'element_%s' % generate_uuid()
         hstr = hashlib.md5(('%s:%s' % (tmp_scope, name)).encode('utf-8')).hexdigest()
         pfn = 'http://root.aperture.com:1409//test/chamber/mock/%s/%s/%s' % (hstr[0:2], hstr[2:4], name)
-        files.append({'scope': tmp_scope, 'name': name,'bytes': 1234, 'adler32': 'deadbeef', 'pfn': pfn})
+        files.append({'scope': tmp_scope, 'name': name, 'bytes': 1234, 'adler32': 'deadbeef', 'pfn': pfn})
 
         add_replicas(rse_id=rse_id, files=files, account=root)