Repository: rucio/rucio

Issue:
Exception not catched for PostgreSQL when attaching DIDs twice.
Motivation
----------
While running the test of this [PR](https://github.com/rucio/rucio/pull/1546), I encountered an exception only with PostgreSQL as database, that is not catched. It raised after tryting to attach a dataset to a container twice. 
```
rucio add-container mock:container
rucio add-dataset mock:dataset
rucio attach mock:container mock:dataset
rucio attach mock:container mock:dataset

ERROR	An unknown exception occurred.
Details: [u'(psycopg2.IntegrityError) duplicate key value violates unique constraint "CONTENTS_PK"\nDETAIL:  Key (scope, name, child_scope, child_name)=(mock, co, mock, da) already exists.\n']
```
With other databases a DuplicateContent gets thrown.

Modification
------------
I would add it to the pattern matching of the IntegrityError [here](https://github.com/rucio/rucio/blob/master/lib/rucio/core/did.py#L458)



Discussion:

Resolving patch:
diff --git a/lib/rucio/core/did.py b/lib/rucio/core/did.py
--- a/lib/rucio/core/did.py
+++ b/lib/rucio/core/did.py
@@ -457,7 +457,8 @@ def __add_collections_to_container(scope, name, collections, account, session):
             raise exception.DataIdentifierNotFound("Data identifier not found")
         elif match('.*IntegrityError.*ORA-00001: unique constraint .*CONTENTS_PK.*violated.*', error.args[0]) \
                 or match('.*IntegrityError.*1062.*Duplicate entry .*for key.*PRIMARY.*', error.args[0]) \
-                or match('.*columns scope, name, child_scope, child_name are not unique.*', error.args[0]):
+                or match('.*columns scope, name, child_scope, child_name are not unique.*', error.args[0]) \
+                or match('.*IntegrityError.*duplicate key value violates unique constraint.*', error.args[0]):
             raise exception.DuplicateContent(error.args)
         raise exception.RucioException(error.args)
 


Test patch:
diff --git a/lib/rucio/tests/test_bin_rucio.py b/lib/rucio/tests/test_bin_rucio.py
--- a/lib/rucio/tests/test_bin_rucio.py
+++ b/lib/rucio/tests/test_bin_rucio.py
@@ -770,6 +770,25 @@ def test_attach_file_twice(self):
         print(err)
         nose.tools.assert_not_equal(re.search("The file already exists", err), None)
 
+    def test_attach_dataset_twice(self):
+        """ CLIENT(USER): Rucio attach a dataset twice """
+        container = 'container_%s' % generate_uuid()
+        dataset = 'dataset_%s' % generate_uuid()
+        self.did_client.add_container(scope=self.user, name=container)
+        self.did_client.add_dataset(scope=self.user, name=dataset)
+
+        # Attach dataset to container
+        cmd = 'rucio attach {0}:{1} {0}:{2}'.format(self.user, container, dataset)
+        exitcode, out, err = execute(cmd)
+
+        # Attach again
+        cmd = 'rucio attach {0}:{1} {0}:{2}'.format(self.user, container, dataset)
+        print(self.marker + cmd)
+        exitcode, out, err = execute(cmd)
+        print(out)
+        print(err)
+        nose.tools.assert_not_equal(re.search("Data identifier already added to the destination content", err), None)
+
     def test_detach_non_existing_file(self):
         """CLIENT(USER): Rucio detach a non existing file"""
         tmp_file1 = file_generator()