From 10e665a148efec0cf75bd5dd07decf23a36a52e0 Mon Sep 17 00:00:00 2001
From: Huanxuan Ao <huanxuan.ao@easystack.cn>
Date: Mon, 15 Aug 2016 19:03:50 +0800
Subject: [PATCH] Error handling of multi REST API calls for "snapshot set"
 command

Support multi REST API calls error handling for
"snapshot set" command follow the rule in
doc/source/command-errors.rst. Also add a unit
test for testing the error handling

Change-Id: I0c6214271bc54a25b051c0a62438c3344c8b51d7
---
 .../tests/unit/volume/v2/test_snapshot.py     | 49 +++++++++++++++++++
 openstackclient/volume/v1/snapshot.py         | 25 ++++++++--
 openstackclient/volume/v2/snapshot.py         | 35 ++++++++++---
 3 files changed, 99 insertions(+), 10 deletions(-)

diff --git a/openstackclient/tests/unit/volume/v2/test_snapshot.py b/openstackclient/tests/unit/volume/v2/test_snapshot.py
index 333d8d7248..d355662d8b 100644
--- a/openstackclient/tests/unit/volume/v2/test_snapshot.py
+++ b/openstackclient/tests/unit/volume/v2/test_snapshot.py
@@ -376,6 +376,55 @@ class TestSnapshotSet(TestSnapshot):
             self.snapshot.id, "error")
         self.assertIsNone(result)
 
+    def test_volume_set_state_failed(self):
+        self.snapshots_mock.reset_state.side_effect = exceptions.CommandError()
+        arglist = [
+            '--state', 'error',
+            self.snapshot.id
+        ]
+        verifylist = [
+            ('state', 'error'),
+            ('snapshot', self.snapshot.id)
+        ]
+
+        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+        try:
+            self.cmd.take_action(parsed_args)
+            self.fail('CommandError should be raised.')
+        except exceptions.CommandError as e:
+            self.assertEqual('One or more of the set operations failed',
+                             str(e))
+        self.snapshots_mock.reset_state.assert_called_once_with(
+            self.snapshot.id, 'error')
+
+    def test_volume_set_name_and_state_failed(self):
+        self.snapshots_mock.reset_state.side_effect = exceptions.CommandError()
+        arglist = [
+            '--state', 'error',
+            "--name", "new_snapshot",
+            self.snapshot.id
+        ]
+        verifylist = [
+            ('state', 'error'),
+            ("name", "new_snapshot"),
+            ('snapshot', self.snapshot.id)
+        ]
+
+        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+        try:
+            self.cmd.take_action(parsed_args)
+            self.fail('CommandError should be raised.')
+        except exceptions.CommandError as e:
+            self.assertEqual('One or more of the set operations failed',
+                             str(e))
+        kwargs = {
+            "name": "new_snapshot",
+        }
+        self.snapshots_mock.update.assert_called_once_with(
+            self.snapshot.id, **kwargs)
+        self.snapshots_mock.reset_state.assert_called_once_with(
+            self.snapshot.id, 'error')
+
 
 class TestSnapshotShow(TestSnapshot):
 
diff --git a/openstackclient/volume/v1/snapshot.py b/openstackclient/volume/v1/snapshot.py
index bb3a1fc354..f8fa7c954b 100644
--- a/openstackclient/volume/v1/snapshot.py
+++ b/openstackclient/volume/v1/snapshot.py
@@ -16,15 +16,20 @@
 """Volume v1 Snapshot action implementations"""
 
 import copy
+import logging
 
 from osc_lib.cli import parseractions
 from osc_lib.command import command
+from osc_lib import exceptions
 from osc_lib import utils
 import six
 
 from openstackclient.i18n import _
 
 
+LOG = logging.getLogger(__name__)
+
+
 class CreateSnapshot(command.ShowOne):
     """Create new snapshot"""
 
@@ -199,17 +204,31 @@ class SetSnapshot(command.Command):
         snapshot = utils.find_resource(volume_client.volume_snapshots,
                                        parsed_args.snapshot)
 
+        result = 0
         if parsed_args.property:
-            volume_client.volume_snapshots.set_metadata(snapshot.id,
-                                                        parsed_args.property)
+            try:
+                volume_client.volume_snapshots.set_metadata(
+                    snapshot.id, parsed_args.property)
+            except Exception as e:
+                LOG.error(_("Failed to set snapshot property: %s"), e)
+                result += 1
 
         kwargs = {}
         if parsed_args.name:
             kwargs['display_name'] = parsed_args.name
         if parsed_args.description:
             kwargs['display_description'] = parsed_args.description
+        if kwargs:
+            try:
+                snapshot.update(**kwargs)
+            except Exception as e:
+                LOG.error(_("Failed to update snapshot display name "
+                          "or display description: %s"), e)
+                result += 1
 
-        snapshot.update(**kwargs)
+        if result > 0:
+            raise exceptions.CommandError(_("One or more of the "
+                                          "set operations failed"))
 
 
 class ShowSnapshot(command.ShowOne):
diff --git a/openstackclient/volume/v2/snapshot.py b/openstackclient/volume/v2/snapshot.py
index 8304a5eb46..0d82655108 100644
--- a/openstackclient/volume/v2/snapshot.py
+++ b/openstackclient/volume/v2/snapshot.py
@@ -240,19 +240,40 @@ class SetSnapshot(command.Command):
         snapshot = utils.find_resource(volume_client.volume_snapshots,
                                        parsed_args.snapshot)
 
+        result = 0
+        if parsed_args.property:
+            try:
+                volume_client.volume_snapshots.set_metadata(
+                    snapshot.id, parsed_args.property)
+            except Exception as e:
+                LOG.error(_("Failed to set snapshot property: %s"), e)
+                result += 1
+
+        if parsed_args.state:
+            try:
+                volume_client.volume_snapshots.reset_state(
+                    snapshot.id, parsed_args.state)
+            except Exception as e:
+                LOG.error(_("Failed to set snapshot state: %s"), e)
+                result += 1
+
         kwargs = {}
         if parsed_args.name:
             kwargs['name'] = parsed_args.name
         if parsed_args.description:
             kwargs['description'] = parsed_args.description
+        if kwargs:
+            try:
+                volume_client.volume_snapshots.update(
+                    snapshot.id, **kwargs)
+            except Exception as e:
+                LOG.error(_("Failed to update snapshot name "
+                          "or description: %s"), e)
+                result += 1
 
-        if parsed_args.property:
-            volume_client.volume_snapshots.set_metadata(snapshot.id,
-                                                        parsed_args.property)
-        if parsed_args.state:
-            volume_client.volume_snapshots.reset_state(snapshot.id,
-                                                       parsed_args.state)
-        volume_client.volume_snapshots.update(snapshot.id, **kwargs)
+        if result > 0:
+            raise exceptions.CommandError(_("One or more of the "
+                                          "set operations failed"))
 
 
 class ShowSnapshot(command.ShowOne):