Allow user to specify image to use during rescue - V3 API changes

This commit includes the V3 changes.
Making changes in V3 API to take an extra parameter rescue_image_ref
as part of the rescue action API.
If specified, this image_ref will be used to rescue the instance.
If the image is not specified, then the base image ref is used by
default.

Partially Implements: blueprint allow-image-to-be-specified-during-rescue

DocImpact

Change-Id: I7a9d88bf4dfe73879247f5b82a52928fdde76510
This commit is contained in:
Aditi Raveesh 2014-03-05 11:26:36 +05:30
parent d4813b01a3
commit 001f865c3c
7 changed files with 89 additions and 6 deletions

View File

@ -0,0 +1,6 @@
{
"rescue": {
"admin_password": "MySecretPass",
"image_ref": "70a599e0-31e7-49b7-b260-868f441e862b"
}
}

View File

@ -58,9 +58,14 @@ class RescueController(wsgi.Controller):
instance = common.get_instance(self.compute_api, context, id,
want_objects=True)
rescue_image_ref = None
if body['rescue'] and 'image_ref' in body['rescue']:
rescue_image_ref = body['rescue']['image_ref']
try:
self.compute_api.rescue(context, instance,
rescue_password=password)
rescue_password=password,
rescue_image_ref=rescue_image_ref)
except exception.InstanceIsLocked as e:
raise exc.HTTPConflict(explanation=e.format_message())
except exception.InstanceInvalidState as state_error:

View File

@ -22,6 +22,7 @@ rescue = {
'type': ['object', 'null'],
'properties': {
'admin_password': parameter_types.admin_password,
'image_ref': parameter_types.image_ref,
},
'additionalProperties': False,
},

View File

@ -73,3 +73,8 @@ admin_password = {
# and string pattern.
'type': 'string',
}
image_ref = {
'type': 'string',
}

View File

@ -26,7 +26,8 @@ CONF = cfg.CONF
CONF.import_opt('password_length', 'nova.utils')
def rescue(self, context, instance, rescue_password=None):
def rescue(self, context, instance, rescue_password=None,
rescue_image_ref=None):
pass
@ -34,14 +35,15 @@ def unrescue(self, context, instance):
pass
def fake_compute_get(*args, **kwargs):
uuid = '70f6db34-de8d-4fbd-aafb-4065bdfa6114'
return {'id': 1, 'uuid': uuid}
class RescueTest(test.NoDBTestCase):
def setUp(self):
super(RescueTest, self).setUp()
def fake_compute_get(*args, **kwargs):
uuid = '70f6db34-de8d-4fbd-aafb-4065bdfa6114'
return {'id': 1, 'uuid': uuid}
self.stubs.Set(compute.api.API, "get", fake_compute_get)
self.stubs.Set(compute.api.API, "rescue", rescue)
self.stubs.Set(compute.api.API, "unrescue", unrescue)
@ -64,6 +66,44 @@ class RescueTest(test.NoDBTestCase):
resp = req.get_response(self.app)
self.assertEqual(resp.status_int, 409)
@mock.patch('nova.compute.api.API.rescue')
def test_rescue_with_image_specified(self, mock_compute_api_rescue):
instance = fake_compute_get()
body = {"rescue": {"admin_password": "ABC123",
"image_ref": "img-id"}}
req = webob.Request.blank('/v3/servers/test_inst/action')
req.method = "POST"
req.body = jsonutils.dumps(body)
req.headers["content-type"] = "application/json"
resp = req.get_response(self.app)
self.assertEqual(resp.status_int, 202)
resp_json = jsonutils.loads(resp.body)
self.assertEqual("ABC123", resp_json['admin_password'])
mock_compute_api_rescue.assert_called_with(mock.ANY, instance,
rescue_password=u'ABC123',
rescue_image_ref=u'img-id')
@mock.patch('nova.compute.api.API.rescue')
def test_rescue_without_image_specified(self, mock_compute_api_rescue):
instance = fake_compute_get()
body = {"rescue": {"admin_password": "ABC123"}}
req = webob.Request.blank('/v3/servers/test_inst/action')
req.method = "POST"
req.body = jsonutils.dumps(body)
req.headers["content-type"] = "application/json"
resp = req.get_response(self.app)
self.assertEqual(resp.status_int, 202)
resp_json = jsonutils.loads(resp.body)
self.assertEqual("ABC123", resp_json['admin_password'])
mock_compute_api_rescue.assert_called_with(mock.ANY, instance,
rescue_password=u'ABC123',
rescue_image_ref=None)
def test_rescue_with_preset_password(self):
body = {"rescue": {"admin_password": "AABBCC112233"}}
req = webob.Request.blank('/v3/servers/test_inst/action')

View File

@ -0,0 +1,6 @@
{
"rescue": {
"admin_password": "%(password)s",
"image_ref": "%(image_ref)s"
}
}

View File

@ -46,6 +46,26 @@ class RescueJsonTest(test_servers.ServersSampleBase):
self._verify_response('server-get-resp-rescue', subs, response, 200)
def test_server_rescue_with_image_ref_specified(self):
uuid = self._post_server()
req_subs = {
'password': 'MySecretPass',
'image_ref': '2341-Abc'
}
response = self._do_post('servers/%s/action' % uuid,
'server-rescue-req-with-image-ref', req_subs)
self._verify_response('server-rescue', req_subs, response, 202)
# Do a server get to make sure that the 'RESCUE' state is set
response = self._do_get('servers/%s' % uuid)
subs = self._get_regexes()
subs['hostid'] = '[a-f0-9]+'
subs['id'] = uuid
subs['status'] = 'RESCUE'
self._verify_response('server-get-resp-rescue', subs, response, 200)
def test_server_unrescue(self):
uuid = self._post_server()