Repository: rucio/rucio
Issue: Dark Reaper does not work with Python 3

Motivation
----------

```
Traceback (most recent call last):
  File "/usr/lib64/python3.6/threading.py", line 916, in _bootstrap_inner
    self.run()
  File "/usr/lib64/python3.6/threading.py", line 864, in run
    self._target(*self._args, **self._kwargs)
  File "/usr/local/lib/python3.6/site-packages/rucio/daemons/reaper/dark_reaper.py", line 84, in reaper
    hash_executable = hashlib.sha256(sys.argv[0] + ''.join(rses)).hexdigest()
TypeError: Unicode-objects must be encoded before hashing
```

```
Traceback (most recent call last):
  File "/usr/local/lib/python3.6/site-packages/rucio/daemons/reaper/dark_reaper.py", line 114, in reaper
    operation='delete', scheme=scheme).values()[0])
TypeError: 'dict_values' object does not support indexing
```

Modification
------------

Port to Python 3.

Changed files:
lib/rucio/daemons/reaper/dark_reaper.py

diff --git a/lib/rucio/daemons/reaper/dark_reaper.py b/lib/rucio/daemons/reaper/dark_reaper.py
index 34ea698bc..34748961c 100644
--- a/lib/rucio/daemons/reaper/dark_reaper.py
+++ b/lib/rucio/daemons/reaper/dark_reaper.py
@@ -1,5 +1,5 @@
 # -*- coding: utf-8 -*-
-# Copyright 2016-2020 CERN
+# Copyright 2016-2021 CERN
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -23,7 +23,7 @@
 # - Brandon White <bjwhite@fnal.gov>, 2019
 # - Patrick Austin <patrick.austin@stfc.ac.uk>, 2020
 # - Benedikt Ziemons <benedikt.ziemons@cern.ch>, 2020
-# - Dimitrios Christidis <dimitrios.christidis@cern.ch>, 2020
+# - Dimitrios Christidis <dimitrios.christidis@cern.ch>, 2020-2021
 
 '''
 Dark Reaper is a daemon to manage quarantined file deletion.
@@ -83,7 +83,7 @@ def reaper(rses=[], worker_number=0, total_workers=1, chunk_size=100, once=False
     thread = threading.current_thread()
     hostname = socket.gethostname()
     executable = ' '.join(sys.argv)
-    hash_executable = hashlib.sha256(sys.argv[0] + ''.join(rses)).hexdigest()
+    hash_executable = hashlib.sha256((sys.argv[0] + ''.join(rses)).encode()).hexdigest()
     sanity_check(executable=None, hostname=hostname)
 
     while not GRACEFUL_STOP.is_set():
@@ -111,9 +111,12 @@ def reaper(rses=[], worker_number=0, total_workers=1, chunk_size=100, once=False
                         if replica['scope']:
                             scope = replica['scope'].external
                         try:
-                            pfn = str(rsemgr.lfns2pfns(rse_settings=rse_info,
-                                                       lfns=[{'scope': scope, 'name': replica['name'], 'path': replica['path']}],
-                                                       operation='delete', scheme=scheme).values()[0])
+                            pfn = str(list(rsemgr.lfns2pfns(rse_settings=rse_info,
+                                                            lfns=[{'scope': scope,
+                                                                   'name': replica['name'],
+                                                                   'path': replica['path']}],
+                                                            operation='delete',
+                                                            scheme=scheme).values())[0])
                             logging.info('Dark Reaper %s-%s: Deletion ATTEMPT of %s:%s as %s on %s', worker_number, total_workers, scope, replica['name'], pfn, rse)
                             start = time.time()
                             prot.delete(pfn)