Add 'deleted' status check in _poll_for_status

When use command '--poll' to show progress, if the object's staus change
into 'deleted' for some reason, it will lead a endless loop.Becasue there
is no check about 'deleted' status.

For example, when use 'image-create --poll' to create a vm's snapshoot,
if glance's quota is small than the snapshoot, the image will be deleted.

Change-Id: I028e3064b3371f87873d74494c39255775a2c818
Closes-bug:#1470047
This commit is contained in:
wangxiyuan 2015-07-01 15:26:10 +08:00
parent 40a4070f28
commit ba79073d7b
4 changed files with 42 additions and 0 deletions

View File

@ -93,6 +93,11 @@ class VersionNotFoundForAPIMethod(Exception):
return self.msg_fmt % {"vers": self.version, "method": self.method} return self.msg_fmt % {"vers": self.version, "method": self.method}
class InstanceInDeletedState(Exception):
"""Instance is in the deleted state."""
pass
class ClientException(Exception): class ClientException(Exception):
""" """
The base exception class for all exceptions this library raises. The base exception class for all exceptions this library raises.

View File

@ -665,6 +665,8 @@ class FakeHTTPClient(base_client.HTTPClient):
elif action == 'createImage': elif action == 'createImage':
assert set(body[action].keys()) == set(['name', 'metadata']) assert set(body[action].keys()) == set(['name', 'metadata'])
_headers = dict(location="http://blah/images/456") _headers = dict(location="http://blah/images/456")
if body[action]['name'] == 'mysnapshot_deleted':
_headers = dict(location="http://blah/images/457")
elif action == 'os-getConsoleOutput': elif action == 'os-getConsoleOutput':
assert list(body[action]) == ['length'] assert list(body[action]) == ['length']
return (202, {}, {'output': 'foo'}) return (202, {}, {'output': 'foo'})
@ -1035,6 +1037,16 @@ class FakeHTTPClient(base_client.HTTPClient):
"status": "SAVING", "status": "SAVING",
"progress": 80, "progress": 80,
"links": {}, "links": {},
},
{
"id": 3,
"name": "My Server Backup Deleted",
"serverId": 1234,
"updated": "2010-10-10T12:00:00Z",
"created": "2010-08-10T12:00:00Z",
"status": "DELETED",
"fault": {'message': 'Image has been deleted.'},
"links": {},
} }
]}) ]})
@ -1047,6 +1059,9 @@ class FakeHTTPClient(base_client.HTTPClient):
def get_images_456(self, **kw): def get_images_456(self, **kw):
return (200, {}, {'image': self.get_images_detail()[2]['images'][1]}) return (200, {}, {'image': self.get_images_detail()[2]['images'][1]})
def get_images_457(self, **kw):
return (200, {}, {'image': self.get_images_detail()[2]['images'][2]})
def get_images_3e861307_73a6_4d1f_8d68_f68b03223032(self): def get_images_3e861307_73a6_4d1f_8d68_f68b03223032(self):
raise exceptions.NotFound('404') raise exceptions.NotFound('404')

View File

@ -813,6 +813,24 @@ class ShellTest(utils.TestCase):
self.assertIn('My Server Backup', output) self.assertIn('My Server Backup', output)
self.assertIn('SAVING', output) self.assertIn('SAVING', output)
@mock.patch('novaclient.v2.shell._poll_for_status')
def test_create_image_with_poll(self, poll_method):
self.run_command(
'image-create sample-server mysnapshot --poll')
self.assert_called_anytime(
'POST', '/servers/1234/action',
{'createImage': {'name': 'mysnapshot', 'metadata': {}}},
)
self.assertEqual(1, poll_method.call_count)
poll_method.assert_has_calls(
[mock.call(self.shell.cs.images.get, '456', 'snapshotting',
['active'])])
def test_create_image_with_poll_to_check_image_state_deleted(self):
self.assertRaises(
exceptions.InstanceInDeletedState, self.run_command,
'image-create sample-server mysnapshot_deleted --poll')
def test_image_delete(self): def test_image_delete(self):
self.run_command('image-delete 1') self.run_command('image-delete 1')
self.assert_called('DELETE', '/images/1') self.assert_called('DELETE', '/images/1')

View File

@ -583,6 +583,10 @@ def _poll_for_status(poll_fn, obj_id, action, final_ok_states,
if not silent: if not silent:
print(_("\nError %s server") % action) print(_("\nError %s server") % action)
raise exceptions.InstanceInErrorState(obj.fault['message']) raise exceptions.InstanceInErrorState(obj.fault['message'])
elif status == "deleted":
if not silent:
print(_("\nDeleted %s server") % action)
raise exceptions.InstanceInDeletedState(obj.fault['message'])
if not silent: if not silent:
print_progress(progress) print_progress(progress)