summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2016-02-09 15:04:07 +0000
committerGerrit Code Review <review@openstack.org>2016-02-09 15:04:08 +0000
commit3da2728ce61aea60a6e8b4a50f10ba861d8e6673 (patch)
treecd346c665e9db17eac06893c54815cc00192415c
parentb0fcc4efdd360dfb5705f3601d2195cf64bc28ab (diff)
parent0d0749d39ffd122387fde6ee5e9b029f93e53459 (diff)
downloadpython-novaclient-3da2728ce61aea60a6e8b4a50f10ba861d8e6673.tar.gz
Merge "Make _poll_for_status more user-friendly"
-rw-r--r--novaclient/exceptions.py12
-rw-r--r--novaclient/tests/unit/v2/test_shell.py90
-rw-r--r--novaclient/v2/shell.py4
3 files changed, 100 insertions, 6 deletions
diff --git a/novaclient/exceptions.py b/novaclient/exceptions.py
index 94591f26..b9bdf114 100644
--- a/novaclient/exceptions.py
+++ b/novaclient/exceptions.py
@@ -77,9 +77,15 @@ class ConnectionRefused(Exception):
return "ConnectionRefused: %s" % repr(self.response)
-class InstanceInErrorState(Exception):
- """Instance is in the error state."""
- pass
+class ResourceInErrorState(Exception):
+ """Resource is in the error state."""
+
+ def __init__(self, obj):
+ msg = "`%s` resource is in the error state" % obj.__class__.__name__
+ fault_msg = getattr(obj, "fault", {}).get("message")
+ if fault_msg:
+ msg += "due to '%s'" % fault_msg
+ self.message = "%s." % msg
class VersionNotFoundForAPIMethod(Exception):
diff --git a/novaclient/tests/unit/v2/test_shell.py b/novaclient/tests/unit/v2/test_shell.py
index c079d9c6..0869a110 100644
--- a/novaclient/tests/unit/v2/test_shell.py
+++ b/novaclient/tests/unit/v2/test_shell.py
@@ -29,6 +29,7 @@ from six.moves import builtins
import novaclient
from novaclient import api_versions
+from novaclient import base
import novaclient.client
from novaclient import exceptions
import novaclient.shell
@@ -758,7 +759,7 @@ class ShellTest(utils.TestCase):
['active'])])
def test_boot_with_poll_to_check_VM_state_error(self):
- self.assertRaises(exceptions.InstanceInErrorState, self.run_command,
+ self.assertRaises(exceptions.ResourceInErrorState, self.run_command,
'boot --flavor 1 --image 1 some-bad-server --poll')
def test_boot_named_flavor(self):
@@ -2789,3 +2790,90 @@ class GetFirstEndpointTest(utils.TestCase):
self.assertRaises(LookupError,
novaclient.v2.shell._get_first_endpoint,
[], "ORD")
+
+
+class PollForStatusTestCase(utils.TestCase):
+ @mock.patch("novaclient.v2.shell.time")
+ def test_simple_usage(self, mock_time):
+ poll_period = 3
+ some_id = "uuuuuuuuuuuiiiiiiiii"
+ updated_objects = (
+ base.Resource(None, info={"not_default_field": "INPROGRESS"}),
+ base.Resource(None, info={"not_default_field": "OK"}))
+ poll_fn = mock.MagicMock(side_effect=updated_objects)
+
+ novaclient.v2.shell._poll_for_status(
+ poll_fn=poll_fn,
+ obj_id=some_id,
+ status_field="not_default_field",
+ final_ok_states=["ok"],
+ poll_period=poll_period,
+ # just want to test printing in separate tests
+ action="some",
+ silent=True,
+ show_progress=False
+ )
+ self.assertEqual([mock.call(poll_period)],
+ mock_time.sleep.call_args_list)
+ self.assertEqual([mock.call(some_id)] * 2, poll_fn.call_args_list)
+
+ @mock.patch("novaclient.v2.shell.sys.stdout")
+ @mock.patch("novaclient.v2.shell.time")
+ def test_print_progress(self, mock_time, mock_stdout):
+ updated_objects = (
+ base.Resource(None, info={"status": "INPROGRESS", "progress": 0}),
+ base.Resource(None, info={"status": "INPROGRESS", "progress": 50}),
+ base.Resource(None, info={"status": "OK", "progress": 100}))
+ poll_fn = mock.MagicMock(side_effect=updated_objects)
+ action = "some"
+
+ novaclient.v2.shell._poll_for_status(
+ poll_fn=poll_fn,
+ obj_id="uuuuuuuuuuuiiiiiiiii",
+ final_ok_states=["ok"],
+ poll_period="3",
+ action=action,
+ show_progress=True,
+ silent=False)
+
+ stdout_arg_list = [
+ mock.call("\n"),
+ mock.call("\rServer %s... 0%% complete" % action),
+ mock.call("\rServer %s... 50%% complete" % action),
+ mock.call("\rServer %s... 100%% complete" % action),
+ mock.call("\nFinished"),
+ mock.call("\n")]
+ self.assertEqual(
+ stdout_arg_list,
+ mock_stdout.write.call_args_list
+ )
+
+ @mock.patch("novaclient.v2.shell.time")
+ def test_error_state(self, mock_time):
+ fault_msg = "Oops"
+ updated_objects = (
+ base.Resource(None, info={"status": "error",
+ "fault": {"message": fault_msg}}),
+ base.Resource(None, info={"status": "error"}))
+ poll_fn = mock.MagicMock(side_effect=updated_objects)
+ action = "some"
+
+ self.assertRaises(exceptions.ResourceInErrorState,
+ novaclient.v2.shell._poll_for_status,
+ poll_fn=poll_fn,
+ obj_id="uuuuuuuuuuuiiiiiiiii",
+ final_ok_states=["ok"],
+ poll_period="3",
+ action=action,
+ show_progress=True,
+ silent=False)
+
+ self.assertRaises(exceptions.ResourceInErrorState,
+ novaclient.v2.shell._poll_for_status,
+ poll_fn=poll_fn,
+ obj_id="uuuuuuuuuuuiiiiiiiii",
+ final_ok_states=["ok"],
+ poll_period="3",
+ action=action,
+ show_progress=True,
+ silent=False)
diff --git a/novaclient/v2/shell.py b/novaclient/v2/shell.py
index 9ff95a51..f16d5903 100644
--- a/novaclient/v2/shell.py
+++ b/novaclient/v2/shell.py
@@ -642,11 +642,11 @@ def _poll_for_status(poll_fn, obj_id, action, final_ok_states,
elif status == "error":
if not silent:
print(_("\nError %s server") % action)
- raise exceptions.InstanceInErrorState(obj.fault['message'])
+ raise exceptions.ResourceInErrorState(obj)
elif status == "deleted":
if not silent:
print(_("\nDeleted %s server") % action)
- raise exceptions.InstanceInDeletedState(obj.fault['message'])
+ raise exceptions.InstanceInDeletedState(obj.fault["message"])
if not silent:
print_progress(progress)