diff --git a/doc/api_samples/all_extensions/extensions-get-resp.json b/doc/api_samples/all_extensions/extensions-get-resp.json index c95789a642a8..a46a48fc1449 100644 --- a/doc/api_samples/all_extensions/extensions-get-resp.json +++ b/doc/api_samples/all_extensions/extensions-get-resp.json @@ -512,6 +512,14 @@ "namespace": "http://docs.openstack.org/compute/ext/rescue/api/v1.1", "updated": "2011-08-18T00:00:00+00:00" }, + { + "alias": "os-extended-rescue-with-image", + "description": "Rescue instance with the image specified.", + "links": [], + "name": "ExtendedRescueWithImage", + "namespace": "http://docs.openstack.org/compute/ext/extended_rescue_with_image/api/v2", + "updated": "2014-03-05T00:00:00+00:00" + }, { "alias": "os-security-group-default-rules", "description": "Default rules for security group support.", diff --git a/doc/api_samples/all_extensions/extensions-get-resp.xml b/doc/api_samples/all_extensions/extensions-get-resp.xml index 5683362ffbbe..167f799500c8 100644 --- a/doc/api_samples/all_extensions/extensions-get-resp.xml +++ b/doc/api_samples/all_extensions/extensions-get-resp.xml @@ -212,6 +212,9 @@ Instance rescue mode. + + Rescue instance with the image specified. + Default rules for security group support. diff --git a/doc/api_samples/os-extended-rescue-with-image/server-get-resp-rescue.json b/doc/api_samples/os-extended-rescue-with-image/server-get-resp-rescue.json new file mode 100644 index 000000000000..d08191977e23 --- /dev/null +++ b/doc/api_samples/os-extended-rescue-with-image/server-get-resp-rescue.json @@ -0,0 +1,53 @@ +{ + "server": { + "accessIPv4": "", + "accessIPv6": "", + "addresses": { + "private": [ + { + "addr": "192.168.0.3", + "version": 4 + } + ] + }, + "created": "2012-09-19T09:22:27Z", + "flavor": { + "id": "1", + "links": [ + { + "href": "http://openstack.example.com/openstack/flavors/1", + "rel": "bookmark" + } + ] + }, + "hostId": "c02c15d17499304e9893d9fc41c415f5096f8aa880bc651cac092650", + "id": "7e21a264-6cc1-4d90-b7b5-f9f49cec3a85", + "image": { + "id": "70a599e0-31e7-49b7-b260-868f441e862b", + "links": [ + { + "href": "http://openstack.example.com/openstack/images/70a599e0-31e7-49b7-b260-868f441e862b", + "rel": "bookmark" + } + ] + }, + "links": [ + { + "href": "http://openstack.example.com/v2/openstack/servers/7e21a264-6cc1-4d90-b7b5-f9f49cec3a85", + "rel": "self" + }, + { + "href": "http://openstack.example.com/openstack/servers/7e21a264-6cc1-4d90-b7b5-f9f49cec3a85", + "rel": "bookmark" + } + ], + "metadata": { + "My Server Name": "Apache1" + }, + "name": "new-server-test", + "status": "RESCUE", + "tenant_id": "openstack", + "updated": "2012-09-19T09:22:27Z", + "user_id": "fake" + } +} \ No newline at end of file diff --git a/doc/api_samples/os-extended-rescue-with-image/server-get-resp-rescue.xml b/doc/api_samples/os-extended-rescue-with-image/server-get-resp-rescue.xml new file mode 100644 index 000000000000..b0da738c4cc7 --- /dev/null +++ b/doc/api_samples/os-extended-rescue-with-image/server-get-resp-rescue.xml @@ -0,0 +1,19 @@ + + + + + + + + + + Apache1 + + + + + + + + + \ No newline at end of file diff --git a/doc/api_samples/os-extended-rescue-with-image/server-post-req.json b/doc/api_samples/os-extended-rescue-with-image/server-post-req.json new file mode 100644 index 000000000000..d88eb4122223 --- /dev/null +++ b/doc/api_samples/os-extended-rescue-with-image/server-post-req.json @@ -0,0 +1,16 @@ +{ + "server" : { + "name" : "new-server-test", + "imageRef" : "http://openstack.example.com/openstack/images/70a599e0-31e7-49b7-b260-868f441e862b", + "flavorRef" : "http://openstack.example.com/openstack/flavors/1", + "metadata" : { + "My Server Name" : "Apache1" + }, + "personality" : [ + { + "path" : "/etc/banner.txt", + "contents" : "ICAgICAgDQoiQSBjbG91ZCBkb2VzIG5vdCBrbm93IHdoeSBpdCBtb3ZlcyBpbiBqdXN0IHN1Y2ggYSBkaXJlY3Rpb24gYW5kIGF0IHN1Y2ggYSBzcGVlZC4uLkl0IGZlZWxzIGFuIGltcHVsc2lvbi4uLnRoaXMgaXMgdGhlIHBsYWNlIHRvIGdvIG5vdy4gQnV0IHRoZSBza3kga25vd3MgdGhlIHJlYXNvbnMgYW5kIHRoZSBwYXR0ZXJucyBiZWhpbmQgYWxsIGNsb3VkcywgYW5kIHlvdSB3aWxsIGtub3csIHRvbywgd2hlbiB5b3UgbGlmdCB5b3Vyc2VsZiBoaWdoIGVub3VnaCB0byBzZWUgYmV5b25kIGhvcml6b25zLiINCg0KLVJpY2hhcmQgQmFjaA==" + } + ] + } +} \ No newline at end of file diff --git a/doc/api_samples/os-extended-rescue-with-image/server-post-req.xml b/doc/api_samples/os-extended-rescue-with-image/server-post-req.xml new file mode 100644 index 000000000000..0a3c8bb5303d --- /dev/null +++ b/doc/api_samples/os-extended-rescue-with-image/server-post-req.xml @@ -0,0 +1,19 @@ + + + + Apache1 + + + + ICAgICAgDQoiQSBjbG91ZCBkb2VzIG5vdCBrbm93IHdoeSBp + dCBtb3ZlcyBpbiBqdXN0IHN1Y2ggYSBkaXJlY3Rpb24gYW5k + IGF0IHN1Y2ggYSBzcGVlZC4uLkl0IGZlZWxzIGFuIGltcHVs + c2lvbi4uLnRoaXMgaXMgdGhlIHBsYWNlIHRvIGdvIG5vdy4g + QnV0IHRoZSBza3kga25vd3MgdGhlIHJlYXNvbnMgYW5kIHRo + ZSBwYXR0ZXJucyBiZWhpbmQgYWxsIGNsb3VkcywgYW5kIHlv + dSB3aWxsIGtub3csIHRvbywgd2hlbiB5b3UgbGlmdCB5b3Vy + c2VsZiBoaWdoIGVub3VnaCB0byBzZWUgYmV5b25kIGhvcml6 + b25zLiINCg0KLVJpY2hhcmQgQmFjaA== + + + \ No newline at end of file diff --git a/doc/api_samples/os-extended-rescue-with-image/server-post-resp.json b/doc/api_samples/os-extended-rescue-with-image/server-post-resp.json new file mode 100644 index 000000000000..d9114225a2bf --- /dev/null +++ b/doc/api_samples/os-extended-rescue-with-image/server-post-resp.json @@ -0,0 +1,16 @@ +{ + "server": { + "adminPass": "xjDVAYHmc34s", + "id": "784f5005-bec9-4c22-8c42-5a7dcba88d82", + "links": [ + { + "href": "http://openstack.example.com/v2/openstack/servers/784f5005-bec9-4c22-8c42-5a7dcba88d82", + "rel": "self" + }, + { + "href": "http://openstack.example.com/openstack/servers/784f5005-bec9-4c22-8c42-5a7dcba88d82", + "rel": "bookmark" + } + ] + } +} \ No newline at end of file diff --git a/doc/api_samples/os-extended-rescue-with-image/server-post-resp.xml b/doc/api_samples/os-extended-rescue-with-image/server-post-resp.xml new file mode 100644 index 000000000000..3a31871ba9af --- /dev/null +++ b/doc/api_samples/os-extended-rescue-with-image/server-post-resp.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/doc/api_samples/os-extended-rescue-with-image/server-rescue-req.json b/doc/api_samples/os-extended-rescue-with-image/server-rescue-req.json new file mode 100644 index 000000000000..1cfab5287283 --- /dev/null +++ b/doc/api_samples/os-extended-rescue-with-image/server-rescue-req.json @@ -0,0 +1,6 @@ +{ + "rescue": { + "adminPass": "MySecretPass", + "rescue_image_ref": "70a599e0-31e7-49b7-b260-868f441e862b" + } +} \ No newline at end of file diff --git a/doc/api_samples/os-extended-rescue-with-image/server-rescue-req.xml b/doc/api_samples/os-extended-rescue-with-image/server-rescue-req.xml new file mode 100644 index 000000000000..737263372937 --- /dev/null +++ b/doc/api_samples/os-extended-rescue-with-image/server-rescue-req.xml @@ -0,0 +1,3 @@ + + \ No newline at end of file diff --git a/doc/api_samples/os-extended-rescue-with-image/server-rescue.json b/doc/api_samples/os-extended-rescue-with-image/server-rescue.json new file mode 100644 index 000000000000..6cd942395fea --- /dev/null +++ b/doc/api_samples/os-extended-rescue-with-image/server-rescue.json @@ -0,0 +1,3 @@ +{ + "adminPass": "MySecretPass" +} \ No newline at end of file diff --git a/doc/api_samples/os-extended-rescue-with-image/server-rescue.xml b/doc/api_samples/os-extended-rescue-with-image/server-rescue.xml new file mode 100644 index 000000000000..582388670248 --- /dev/null +++ b/doc/api_samples/os-extended-rescue-with-image/server-rescue.xml @@ -0,0 +1,2 @@ + +MySecretPass \ No newline at end of file diff --git a/nova/api/openstack/compute/contrib/extended_rescue_with_image.py b/nova/api/openstack/compute/contrib/extended_rescue_with_image.py new file mode 100644 index 000000000000..fbcc4aa31024 --- /dev/null +++ b/nova/api/openstack/compute/contrib/extended_rescue_with_image.py @@ -0,0 +1,25 @@ +# Copyright 2014 OpenStack Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from nova.api.openstack import extensions as exts + + +class Extended_rescue_with_image(exts.ExtensionDescriptor): + """Allow the user to specify the image to use for rescue.""" + + name = "ExtendedRescueWithImage" + alias = "os-extended-rescue-with-image" + namespace = ("http://docs.openstack.org/compute/ext/" + "extended_rescue_with_image/api/v2") + updated = "2014-01-04T00:00:00+00:00" diff --git a/nova/api/openstack/compute/contrib/rescue.py b/nova/api/openstack/compute/contrib/rescue.py index fde79bdc5892..3dc495f22bc0 100644 --- a/nova/api/openstack/compute/contrib/rescue.py +++ b/nova/api/openstack/compute/contrib/rescue.py @@ -32,9 +32,10 @@ authorize = exts.extension_authorizer('compute', 'rescue') class RescueController(wsgi.Controller): - def __init__(self, *args, **kwargs): + def __init__(self, ext_mgr, *args, **kwargs): super(RescueController, self).__init__(*args, **kwargs) self.compute_api = compute.API() + self.ext_mgr = ext_mgr def _get_instance(self, context, instance_id, want_objects=False): try: @@ -57,8 +58,12 @@ class RescueController(wsgi.Controller): instance = self._get_instance(context, id, want_objects=True) try: + rescue_image_ref = None + if self.ext_mgr.is_loaded("os-extended-rescue-with-image"): + if body['rescue'] and 'rescue_image_ref' in body['rescue']: + rescue_image_ref = body['rescue']['rescue_image_ref'] 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: @@ -105,6 +110,6 @@ class Rescue(exts.ExtensionDescriptor): updated = "2011-08-18T00:00:00+00:00" def get_controller_extensions(self): - controller = RescueController() + controller = RescueController(self.ext_mgr) extension = exts.ControllerExtension(self, 'servers', controller) return [extension] diff --git a/nova/tests/api/openstack/compute/contrib/test_extended_rescue_with_image.py b/nova/tests/api/openstack/compute/contrib/test_extended_rescue_with_image.py new file mode 100644 index 000000000000..8e97e5a5d50f --- /dev/null +++ b/nova/tests/api/openstack/compute/contrib/test_extended_rescue_with_image.py @@ -0,0 +1,58 @@ +# Copyright 2014 OpenStack Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import mock +from oslo.config import cfg + +from nova.api.openstack.compute.contrib import rescue +from nova.api.openstack import extensions +from nova import compute +import nova.context as context +from nova import test + +CONF = cfg.CONF +CONF.import_opt('password_length', 'nova.utils') + + +class FakeRequest(object): + def __init__(self, context): + self.environ = {"nova.context": context} + + +class ExtendedRescueWithImageTest(test.NoDBTestCase): + def setUp(self): + super(ExtendedRescueWithImageTest, self).setUp() + ext_mgr = extensions.ExtensionManager() + ext_mgr.extensions = {'os-extended-rescue-with-image': 'fake'} + self.controller = rescue.RescueController(ext_mgr) + + @mock.patch.object(compute.api.API, "rescue") + def _make_rescue_request_with_image_ref(self, body, mock_rescue): + instance = "instance" + self.controller._get_instance = mock.Mock(return_value=instance) + fake_context = context.RequestContext('fake', 'fake') + req = FakeRequest(fake_context) + + self.controller._rescue(req, "id", body) + rescue_image_ref = body["rescue"].get("rescue_image_ref") + mock_rescue.assert_called_with(mock.ANY, mock.ANY, + rescue_password=mock.ANY, rescue_image_ref=rescue_image_ref) + + def test_rescue_with_image_specified(self): + body = dict(rescue={"rescue_image_ref": "image-ref"}) + self._make_rescue_request_with_image_ref(body) + + def test_rescue_without_image_specified(self): + body = dict(rescue={}) + self._make_rescue_request_with_image_ref(body) diff --git a/nova/tests/api/openstack/compute/contrib/test_rescue.py b/nova/tests/api/openstack/compute/contrib/test_rescue.py index affd5f17de7c..c533a1d56d18 100644 --- a/nova/tests/api/openstack/compute/contrib/test_rescue.py +++ b/nova/tests/api/openstack/compute/contrib/test_rescue.py @@ -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 @@ -53,7 +54,7 @@ class RescueTest(test.NoDBTestCase): def test_rescue_from_locked_server(self): def fake_rescue_from_locked_server(self, context, - instance, rescue_password=None): + instance, rescue_password=None, rescue_image_ref=None): raise exception.InstanceIsLocked(instance_uuid=instance['uuid']) self.stubs.Set(compute.api.API, diff --git a/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.json.tpl b/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.json.tpl index 70992ba2522b..1756e3295a94 100644 --- a/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.json.tpl +++ b/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.json.tpl @@ -504,6 +504,14 @@ "namespace": "http://docs.openstack.org/compute/ext/rescue/api/v1.1", "updated": "%(timestamp)s" }, + { + "alias": "os-extended-rescue-with-image", + "description": "%(text)s", + "links": [], + "name": "ExtendedRescueWithImage", + "namespace": "http://docs.openstack.org/compute/ext/extended_rescue_with_image/api/v2", + "updated": "%(timestamp)s" + }, { "alias": "os-security-group-default-rules", "description": "%(text)s", diff --git a/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.xml.tpl b/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.xml.tpl index f4be29ae3081..d5cde20df5ee 100644 --- a/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.xml.tpl +++ b/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.xml.tpl @@ -180,6 +180,9 @@ %(text)s + + %(text)s + %(text)s diff --git a/nova/tests/integrated/api_samples/os-extended-rescue-with-image/server-get-resp-rescue.json.tpl b/nova/tests/integrated/api_samples/os-extended-rescue-with-image/server-get-resp-rescue.json.tpl new file mode 100755 index 000000000000..011ed6396edb --- /dev/null +++ b/nova/tests/integrated/api_samples/os-extended-rescue-with-image/server-get-resp-rescue.json.tpl @@ -0,0 +1,53 @@ +{ + "server": { + "accessIPv4": "", + "accessIPv6": "", + "addresses": { + "private": [ + { + "addr": "%(ip)s", + "version": 4 + } + ] + }, + "created": "%(timestamp)s", + "flavor": { + "id": "1", + "links": [ + { + "href": "%(host)s/openstack/flavors/1", + "rel": "bookmark" + } + ] + }, + "hostId": "%(hostid)s", + "id": "%(id)s", + "image": { + "id": "%(uuid)s", + "links": [ + { + "href": "%(host)s/openstack/images/%(uuid)s", + "rel": "bookmark" + } + ] + }, + "links": [ + { + "href": "%(host)s/v2/openstack/servers/%(id)s", + "rel": "self" + }, + { + "href": "%(host)s/openstack/servers/%(id)s", + "rel": "bookmark" + } + ], + "metadata": { + "My Server Name": "Apache1" + }, + "name": "new-server-test", + "status": "%(status)s", + "tenant_id": "openstack", + "updated": "%(timestamp)s", + "user_id": "fake" + } +} diff --git a/nova/tests/integrated/api_samples/os-extended-rescue-with-image/server-get-resp-rescue.xml.tpl b/nova/tests/integrated/api_samples/os-extended-rescue-with-image/server-get-resp-rescue.xml.tpl new file mode 100755 index 000000000000..d1d9b7c2cb7e --- /dev/null +++ b/nova/tests/integrated/api_samples/os-extended-rescue-with-image/server-get-resp-rescue.xml.tpl @@ -0,0 +1,19 @@ + + + + + + + + + + Apache1 + + + + + + + + + \ No newline at end of file diff --git a/nova/tests/integrated/api_samples/os-extended-rescue-with-image/server-post-req.json.tpl b/nova/tests/integrated/api_samples/os-extended-rescue-with-image/server-post-req.json.tpl new file mode 100755 index 000000000000..d3916d1aa68a --- /dev/null +++ b/nova/tests/integrated/api_samples/os-extended-rescue-with-image/server-post-req.json.tpl @@ -0,0 +1,16 @@ +{ + "server" : { + "name" : "new-server-test", + "imageRef" : "%(host)s/openstack/images/%(image_id)s", + "flavorRef" : "%(host)s/openstack/flavors/1", + "metadata" : { + "My Server Name" : "Apache1" + }, + "personality" : [ + { + "path" : "/etc/banner.txt", + "contents" : "ICAgICAgDQoiQSBjbG91ZCBkb2VzIG5vdCBrbm93IHdoeSBpdCBtb3ZlcyBpbiBqdXN0IHN1Y2ggYSBkaXJlY3Rpb24gYW5kIGF0IHN1Y2ggYSBzcGVlZC4uLkl0IGZlZWxzIGFuIGltcHVsc2lvbi4uLnRoaXMgaXMgdGhlIHBsYWNlIHRvIGdvIG5vdy4gQnV0IHRoZSBza3kga25vd3MgdGhlIHJlYXNvbnMgYW5kIHRoZSBwYXR0ZXJucyBiZWhpbmQgYWxsIGNsb3VkcywgYW5kIHlvdSB3aWxsIGtub3csIHRvbywgd2hlbiB5b3UgbGlmdCB5b3Vyc2VsZiBoaWdoIGVub3VnaCB0byBzZWUgYmV5b25kIGhvcml6b25zLiINCg0KLVJpY2hhcmQgQmFjaA==" + } + ] + } +} diff --git a/nova/tests/integrated/api_samples/os-extended-rescue-with-image/server-post-req.xml.tpl b/nova/tests/integrated/api_samples/os-extended-rescue-with-image/server-post-req.xml.tpl new file mode 100755 index 000000000000..f92614984242 --- /dev/null +++ b/nova/tests/integrated/api_samples/os-extended-rescue-with-image/server-post-req.xml.tpl @@ -0,0 +1,19 @@ + + + + Apache1 + + + + ICAgICAgDQoiQSBjbG91ZCBkb2VzIG5vdCBrbm93IHdoeSBp + dCBtb3ZlcyBpbiBqdXN0IHN1Y2ggYSBkaXJlY3Rpb24gYW5k + IGF0IHN1Y2ggYSBzcGVlZC4uLkl0IGZlZWxzIGFuIGltcHVs + c2lvbi4uLnRoaXMgaXMgdGhlIHBsYWNlIHRvIGdvIG5vdy4g + QnV0IHRoZSBza3kga25vd3MgdGhlIHJlYXNvbnMgYW5kIHRo + ZSBwYXR0ZXJucyBiZWhpbmQgYWxsIGNsb3VkcywgYW5kIHlv + dSB3aWxsIGtub3csIHRvbywgd2hlbiB5b3UgbGlmdCB5b3Vy + c2VsZiBoaWdoIGVub3VnaCB0byBzZWUgYmV5b25kIGhvcml6 + b25zLiINCg0KLVJpY2hhcmQgQmFjaA== + + + diff --git a/nova/tests/integrated/api_samples/os-extended-rescue-with-image/server-post-resp.json.tpl b/nova/tests/integrated/api_samples/os-extended-rescue-with-image/server-post-resp.json.tpl new file mode 100755 index 000000000000..d5f030c8730b --- /dev/null +++ b/nova/tests/integrated/api_samples/os-extended-rescue-with-image/server-post-resp.json.tpl @@ -0,0 +1,16 @@ +{ + "server": { + "adminPass": "%(password)s", + "id": "%(id)s", + "links": [ + { + "href": "%(host)s/v2/openstack/servers/%(uuid)s", + "rel": "self" + }, + { + "href": "%(host)s/openstack/servers/%(uuid)s", + "rel": "bookmark" + } + ] + } +} diff --git a/nova/tests/integrated/api_samples/os-extended-rescue-with-image/server-post-resp.xml.tpl b/nova/tests/integrated/api_samples/os-extended-rescue-with-image/server-post-resp.xml.tpl new file mode 100755 index 000000000000..3bb13e69bd6d --- /dev/null +++ b/nova/tests/integrated/api_samples/os-extended-rescue-with-image/server-post-resp.xml.tpl @@ -0,0 +1,6 @@ + + + + + + diff --git a/nova/tests/integrated/api_samples/os-extended-rescue-with-image/server-rescue-req.json.tpl b/nova/tests/integrated/api_samples/os-extended-rescue-with-image/server-rescue-req.json.tpl new file mode 100755 index 000000000000..0f2e751fcf6d --- /dev/null +++ b/nova/tests/integrated/api_samples/os-extended-rescue-with-image/server-rescue-req.json.tpl @@ -0,0 +1,6 @@ +{ + "rescue": { + "adminPass": "%(password)s", + "rescue_image_ref" : "%(rescue_image_ref)s" + } +} \ No newline at end of file diff --git a/nova/tests/integrated/api_samples/os-extended-rescue-with-image/server-rescue-req.xml.tpl b/nova/tests/integrated/api_samples/os-extended-rescue-with-image/server-rescue-req.xml.tpl new file mode 100755 index 000000000000..75666d81a274 --- /dev/null +++ b/nova/tests/integrated/api_samples/os-extended-rescue-with-image/server-rescue-req.xml.tpl @@ -0,0 +1,3 @@ + + \ No newline at end of file diff --git a/nova/tests/integrated/api_samples/os-extended-rescue-with-image/server-rescue.json.tpl b/nova/tests/integrated/api_samples/os-extended-rescue-with-image/server-rescue.json.tpl new file mode 100755 index 000000000000..1922e4db1bdd --- /dev/null +++ b/nova/tests/integrated/api_samples/os-extended-rescue-with-image/server-rescue.json.tpl @@ -0,0 +1,3 @@ +{ + "adminPass": "%(password)s" +} \ No newline at end of file diff --git a/nova/tests/integrated/api_samples/os-extended-rescue-with-image/server-rescue.xml.tpl b/nova/tests/integrated/api_samples/os-extended-rescue-with-image/server-rescue.xml.tpl new file mode 100755 index 000000000000..b3b95fdde4aa --- /dev/null +++ b/nova/tests/integrated/api_samples/os-extended-rescue-with-image/server-rescue.xml.tpl @@ -0,0 +1,2 @@ + +%(password)s \ No newline at end of file diff --git a/nova/tests/integrated/test_api_samples.py b/nova/tests/integrated/test_api_samples.py index 5d498d47daad..55ca91ee4f4c 100644 --- a/nova/tests/integrated/test_api_samples.py +++ b/nova/tests/integrated/test_api_samples.py @@ -1174,6 +1174,46 @@ class RescueXmlTest(RescueJsonTest): ctype = 'xml' +class ExtendedRescueWithImageJsonTest(ServersSampleBase): + extension_name = ("nova.api.openstack.compute.contrib" + ".extended_rescue_with_image.Extended_rescue_with_image") + + def _get_flags(self): + f = super(ExtendedRescueWithImageJsonTest, self)._get_flags() + f['osapi_compute_extension'] = CONF.osapi_compute_extension[:] + # ExtendedRescueWithImage extension also needs Rescue to be loaded. + f['osapi_compute_extension'].append( + 'nova.api.openstack.compute.contrib.rescue.Rescue') + return f + + def _rescue(self, uuid): + req_subs = { + 'password': 'MySecretPass', + 'rescue_image_ref': fake.get_valid_image_id() + } + response = self._do_post('servers/%s/action' % uuid, + 'server-rescue-req', req_subs) + self._verify_response('server-rescue', req_subs, response, 200) + + def test_server_rescue(self): + uuid = self._post_server() + + self._rescue(uuid) + + # 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) + + +class ExtendedRescueWithImageXmlTest(ExtendedRescueWithImageJsonTest): + ctype = 'xml' + + class ShelveJsonTest(ServersSampleBase): extension_name = "nova.api.openstack.compute.contrib.shelve.Shelve"