Repository: rucio/rucio

Issue:
Add add-exception command in the CLI
Motivation
----------
A CLI command to add a new exception is missing and need to be added






Discussion:

Resolving patch:
diff --git a/lib/rucio/client/lifetimeclient.py b/lib/rucio/client/lifetimeclient.py
--- a/lib/rucio/client/lifetimeclient.py
+++ b/lib/rucio/client/lifetimeclient.py
@@ -1,4 +1,5 @@
-# Copyright 2017-2018 CERN for the benefit of the ATLAS collaboration.
+# -*- coding: utf-8 -*-
+# Copyright 2017-2022 CERN
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -13,10 +14,13 @@
 # limitations under the License.
 #
 # Authors:
-# - Cedric Serfon <cedric.serfon@cern.ch>, 2017
-# - Vincent Garonne <vgaronne@gmail.com>, 2018
+# - Cedric Serfon <cedric.serfon@cern.ch>, 2017-2022
+# - Vincent Garonne <vincent.garonne@cern.ch>, 2018
+# - Joaquín Bogado <jbogado@linti.unlp.edu.ar>, 2018
 # - Martin Barisits <martin.barisits@cern.ch>, 2018
 # - Andrew Lister <andrew.lister@stfc.ac.uk>, 2019
+# - David Población Criado <david.poblacion.criado@cern.ch>, 2021
+# - Igor Mandrichenko <igorvm@gmail.com>, 2021
 
 from __future__ import print_function
 
@@ -73,9 +77,7 @@ def add_exception(self, dids, account, pattern, comments, expires_at):
         path = self.LIFETIME_BASEURL + '/'
         url = build_url(choice(self.list_hosts), path=path)
         data = {'dids': dids, 'account': account, 'pattern': pattern, 'comments': comments, 'expires_at': expires_at}
-        print(render_json(**data))
         result = self._send_request(url, type_='POST', data=render_json(**data))
-        print(result.text)
         if result.status_code == codes.created:
             return loads(result.text)
         exc_cls, exc_msg = self._get_exception(headers=result.headers, status_code=result.status_code, data=result.content)


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
@@ -20,7 +20,7 @@
 # - Thomas Beermann <thomas.beermann@cern.ch>, 2012-2021
 # - Joaquín Bogado <jbogado@linti.unlp.edu.ar>, 2014-2018
 # - Cheng-Hsi Chao <cheng-hsi.chao@cern.ch>, 2014
-# - Cedric Serfon <cedric.serfon@cern.ch>, 2015
+# - Cedric Serfon <cedric.serfon@cern.ch>, 2015-2022
 # - Martin Barisits <martin.barisits@cern.ch>, 2015-2022
 # - Frank Berghaus <frank.berghaus@cern.ch>, 2017-2018
 # - Tobias Wegner <twegner@cern.ch>, 2018
@@ -76,8 +76,7 @@ def conf_vo(self):
                 # Client-only test, only use config with no DB config
                 self.vo = {'vo': get_long_vo()}
             try:
-                remove(get_tmp_dir()
-                       + '/.rucio_root@%s/auth_token_for_account_root' % self.vo['vo'])
+                remove(get_tmp_dir() + '/.rucio_root@%s/auth_token_for_account_root' % self.vo['vo'])
             except OSError as error:
                 if error.args[0] != 2:
                     raise error
@@ -2172,3 +2171,39 @@ def test_rucio_create_rule_with_0_copies(self):
         print(out)
         assert exitcode != 0
         assert "The number of copies for a replication rule should be greater than 0." in err
+
+    def test_add_lifetime_exception(self):
+        """ CLIENT(USER): Rucio submission of lifetime exception """
+        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)
+        filename = get_tmp_dir() + 'lifetime_exception.txt'
+        with open(filename, 'w') as file_:
+            file_.write('%s:%s\n' % (self.user, dataset))
+
+        # Try adding an exception
+        cmd = 'rucio add-lifetime-exception --inputfile %s --reason "%s" --expiration %s' % (filename, 'Needed for analysis', '2015-10-30')
+        print(cmd)
+        exitcode, out, err = execute(cmd)
+        print(exitcode, out, err)
+        assert exitcode == 0
+        assert "Nothing to submit" in err
+
+        with open(filename, 'w') as file_:
+            file_.write('%s:%s\n' % (self.user, dataset))
+            file_.write('%s:%s' % (self.user, container))
+
+        # Try adding an exception
+        cmd = 'rucio add-lifetime-exception --inputfile %s --reason "%s" --expiration %s' % (filename, 'Needed for analysis', '2015-10-30')
+        print(cmd)
+        exitcode, out, err = execute(cmd)
+        print(exitcode, out, err)
+        assert exitcode == 1
+        assert "One or more DIDs are containers" in err
+
+        try:
+            remove(filename)
+        except OSError as e:
+            if e.args[0] != 2:
+                raise e