Moving admin actions to extension

Begins to address LP bug 821145

Change-Id: I2799a8d70a167dda6d56f8fab2fc121fa2365a8a
This commit is contained in:
Brian Waldon
2011-09-20 01:59:05 -04:00
parent ef22c0054c
commit 5f7356be10
12 changed files with 321 additions and 367 deletions

View File

@@ -115,17 +115,8 @@ class APIRouter(base_wsgi.Router):
if FLAGS.allow_admin_api:
LOG.debug(_("Including admin operations in API."))
server_members['pause'] = 'POST'
server_members['unpause'] = 'POST'
server_members['diagnostics'] = 'GET'
server_members['actions'] = 'GET'
server_members['suspend'] = 'POST'
server_members['resume'] = 'POST'
server_members['rescue'] = 'POST'
server_members['migrate'] = 'POST'
server_members['unrescue'] = 'POST'
server_members['reset_network'] = 'POST'
server_members['inject_network_info'] = 'POST'
mapper.resource("user", "users",
controller=users.create_resource(),

View File

@@ -0,0 +1,204 @@
# Copyright 2011 Openstack, LLC.
#
# 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.
"""The rescue mode extension."""
import traceback
import webob
from webob import exc
from nova import compute
from nova import exception
from nova import flags
from nova import log as logging
from nova import utils
from nova.api.openstack import extensions
from nova.api.openstack import faults
from nova.scheduler import api as scheduler_api
FLAGS = flags.FLAGS
LOG = logging.getLogger("nova.api.openstack.contrib.admin_actions")
class Admin_actions(extensions.ExtensionDescriptor):
"""Adds a set of admin-only actions to servers"""
def __init__(self):
super(Admin_actions, self).__init__()
self.compute_api = compute.API()
@extensions.admin_only
@exception.novaclient_converter
@scheduler_api.redirect_handler
def _pause(self, input_dict, req, id):
"""Permit Admins to pause the server"""
ctxt = req.environ['nova.context']
try:
self.compute_api.pause(ctxt, id)
except Exception:
readable = traceback.format_exc()
LOG.exception(_("Compute.api::pause %s"), readable)
raise exc.HTTPUnprocessableEntity()
return webob.Response(status_int=202)
@extensions.admin_only
@exception.novaclient_converter
@scheduler_api.redirect_handler
def _unpause(self, input_dict, req, id):
"""Permit Admins to unpause the server"""
ctxt = req.environ['nova.context']
try:
self.compute_api.unpause(ctxt, id)
except Exception:
readable = traceback.format_exc()
LOG.exception(_("Compute.api::unpause %s"), readable)
raise exc.HTTPUnprocessableEntity()
return webob.Response(status_int=202)
@extensions.admin_only
@exception.novaclient_converter
@scheduler_api.redirect_handler
def _suspend(self, input_dict, req, id):
"""Permit admins to suspend the server"""
context = req.environ['nova.context']
try:
self.compute_api.suspend(context, id)
except Exception:
readable = traceback.format_exc()
LOG.exception(_("compute.api::suspend %s"), readable)
raise exc.HTTPUnprocessableEntity()
return webob.Response(status_int=202)
@extensions.admin_only
@exception.novaclient_converter
@scheduler_api.redirect_handler
def _resume(self, input_dict, req, id):
"""Permit admins to resume the server from suspend"""
context = req.environ['nova.context']
try:
self.compute_api.resume(context, id)
except Exception:
readable = traceback.format_exc()
LOG.exception(_("compute.api::resume %s"), readable)
raise exc.HTTPUnprocessableEntity()
return webob.Response(status_int=202)
@extensions.admin_only
@exception.novaclient_converter
@scheduler_api.redirect_handler
def _migrate(self, input_dict, req, id):
"""Permit admins to migrate a server to a new host"""
try:
self.compute_api.resize(req.environ['nova.context'], id)
except Exception, e:
LOG.exception(_("Error in migrate %s"), e)
raise exc.HTTPBadRequest()
return webob.Response(status_int=202)
@extensions.admin_only
@exception.novaclient_converter
@scheduler_api.redirect_handler
def _reset_network(self, input_dict, req, id):
"""Permit admins to reset networking on an server"""
context = req.environ['nova.context']
try:
self.compute_api.reset_network(context, id)
except Exception:
readable = traceback.format_exc()
LOG.exception(_("Compute.api::reset_network %s"), readable)
raise exc.HTTPUnprocessableEntity()
return webob.Response(status_int=202)
@extensions.admin_only
@exception.novaclient_converter
@scheduler_api.redirect_handler
def _inject_network_info(self, input_dict, req, id):
"""Permit admins to inject network info into a server"""
context = req.environ['nova.context']
try:
self.compute_api.inject_network_info(context, id)
except Exception:
readable = traceback.format_exc()
LOG.exception(_("Compute.api::inject_network_info %s"), readable)
raise exc.HTTPUnprocessableEntity()
return webob.Response(status_int=202)
@extensions.admin_only
@exception.novaclient_converter
@scheduler_api.redirect_handler
def _lock(self, input_dict, req, id):
"""Permit admins to lock a server"""
context = req.environ['nova.context']
try:
self.compute_api.lock(context, id)
except Exception:
readable = traceback.format_exc()
LOG.exception(_("Compute.api::lock %s"), readable)
raise exc.HTTPUnprocessableEntity()
return webob.Response(status_int=202)
@extensions.admin_only
@exception.novaclient_converter
@scheduler_api.redirect_handler
def _unlock(self, input_dict, req, id):
"""Permit admins to lock a server"""
context = req.environ['nova.context']
try:
self.compute_api.unlock(context, id)
except Exception:
readable = traceback.format_exc()
LOG.exception(_("Compute.api::unlock %s"), readable)
raise exc.HTTPUnprocessableEntity()
return webob.Response(status_int=202)
def get_name(self):
return "AdminActions"
def get_alias(self):
return "os-admin-actions"
def get_description(self):
return "Adds admin-only server actions: pause, unpause, " + \
"suspend, resume, migrate, resetNetwork, " +\
"injectNetworkInfo, lock and unlock"
def get_namespace(self):
return "http://docs.openstack.org/ext/admin-actions/api/v1.1"
def get_updated(self):
return "2011-09-20T00:00:00+00:00"
def get_actions(self):
actions = [
extensions.ActionExtension("servers", "pause", self._pause),
extensions.ActionExtension("servers", "unpause", self._unpause),
extensions.ActionExtension("servers", "suspend", self._suspend),
extensions.ActionExtension("servers", "resume", self._resume),
extensions.ActionExtension("servers", "migrate", self._migrate),
extensions.ActionExtension("servers",
"resetNetwork",
self._reset_network),
extensions.ActionExtension("servers",
"injectNetworkInfo",
self._inject_network_info),
extensions.ActionExtension("servers", "lock", self._lock),
extensions.ActionExtension("servers", "unlock", self._unlock),
]
return actions

View File

@@ -1,30 +0,0 @@
# Copyright (c) 2011 Openstack, LLC.
# All Rights Reserved.
#
# 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.
"""Decorator for limiting extensions that should be admin-only."""
from functools import wraps
from nova import flags
FLAGS = flags.FLAGS
def admin_only(fnc):
@wraps(fnc)
def _wrapped(self, *args, **kwargs):
if FLAGS.allow_admin_api:
return fnc(self, *args, **kwargs)
return []
_wrapped.func_name = fnc.func_name
return _wrapped

View File

@@ -24,7 +24,6 @@ from nova import log as logging
from nova.api.openstack import common
from nova.api.openstack import extensions
from nova.api.openstack import faults
from nova.api.openstack.contrib import admin_only
from nova.scheduler import api as scheduler_api
@@ -105,12 +104,15 @@ class HostController(object):
raise webob.exc.HTTPBadRequest(explanation=e.msg)
return {"host": host, "power_action": result}
@extensions.admin_only
def startup(self, req, id):
return self._host_power_action(req, host=id, action="startup")
@extensions.admin_only
def shutdown(self, req, id):
return self._host_power_action(req, host=id, action="shutdown")
@extensions.admin_only
def reboot(self, req, id):
return self._host_power_action(req, host=id, action="reboot")
@@ -131,7 +133,6 @@ class Hosts(extensions.ExtensionDescriptor):
def get_updated(self):
return "2011-06-29T00:00:00+00:00"
@admin_only.admin_only
def get_resources(self):
resources = [extensions.ResourceExtension('os-hosts',
HostController(), collection_actions={'update': 'PUT'},

View File

@@ -29,23 +29,13 @@ FLAGS = flags.FLAGS
LOG = logging.getLogger("nova.api.contrib.rescue")
def wrap_errors(fn):
""""Ensure errors are not passed along."""
def wrapped(*args):
try:
return fn(*args)
except Exception, e:
return faults.Fault(exc.HTTPInternalServerError())
return wrapped
class Rescue(exts.ExtensionDescriptor):
"""The Rescue controller for the OpenStack API."""
def __init__(self):
super(Rescue, self).__init__()
self.compute_api = compute.API()
@wrap_errors
@exts.wrap_errors
def _rescue(self, input_dict, req, instance_id):
"""Rescue an instance."""
context = req.environ["nova.context"]
@@ -57,7 +47,7 @@ class Rescue(exts.ExtensionDescriptor):
return {'adminPass': password}
@wrap_errors
@exts.wrap_errors
def _unrescue(self, input_dict, req, instance_id):
"""Unrescue an instance."""
context = req.environ["nova.context"]

View File

@@ -16,14 +16,16 @@
# License for the specific language governing permissions and limitations
# under the License.
import functools
import imp
import inspect
import os
import sys
from lxml import etree
import routes
import webob.dec
import webob.exc
from lxml import etree
from nova import exception
from nova import flags
@@ -36,7 +38,7 @@ from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
LOG = logging.getLogger('extensions')
LOG = logging.getLogger('nova.api.openstack.extensions')
FLAGS = flags.FLAGS
@@ -523,3 +525,23 @@ class ExtensionsXMLSerializer(wsgi.XMLDictSerializer):
"""Convert the xml object to an xml string."""
return etree.tostring(root, encoding='UTF-8')
def admin_only(fnc):
@functools.wraps(fnc)
def _wrapped(self, *args, **kwargs):
if FLAGS.allow_admin_api:
return fnc(self, *args, **kwargs)
return faults.Fault(webob.exc.HTTPNotFound())
_wrapped.func_name = fnc.func_name
return _wrapped
def wrap_errors(fn):
""""Ensure errors are not passed along."""
def wrapped(*args):
try:
return fn(*args)
except Exception, e:
return faults.Fault(webob.exc.HTTPInternalServerError())
return wrapped

View File

@@ -18,7 +18,6 @@ import base64
import os
import traceback
from novaclient import exceptions as novaclient_exceptions
from lxml import etree
from webob import exc
import webob
@@ -59,19 +58,6 @@ class ConvertedException(exc.WSGIHTTPException):
super(ConvertedException, self).__init__()
def novaclient_exception_converter(f):
"""Convert novaclient ClientException HTTP codes to webob exceptions.
Has to be the outer-most decorator.
"""
def new_f(*args, **kwargs):
try:
ret = f(*args, **kwargs)
return ret
except novaclient_exceptions.ClientException, e:
raise ConvertedException(e.code, e.message, e.details)
return new_f
class Controller(object):
""" The Server API base controller class for the OpenStack API """
@@ -354,7 +340,7 @@ class Controller(object):
expl = _('Userdata content cannot be decoded')
raise exc.HTTPBadRequest(explanation=expl)
@novaclient_exception_converter
@exception.novaclient_converter
@scheduler_api.redirect_handler
def show(self, req, id):
""" Returns server details by server id """
@@ -580,7 +566,7 @@ class Controller(object):
def _update(self, context, req, id, inst_dict):
return exc.HTTPNotImplemented()
@novaclient_exception_converter
@exception.novaclient_converter
@scheduler_api.redirect_handler
def action(self, req, id, body):
"""Multi-purpose method used to take actions on a server"""
@@ -719,41 +705,7 @@ class Controller(object):
raise exc.HTTPUnprocessableEntity()
return webob.Response(status_int=202)
@novaclient_exception_converter
@scheduler_api.redirect_handler
def lock(self, req, id):
"""
lock the instance with id
admin only operation
"""
context = req.environ['nova.context']
try:
self.compute_api.lock(context, id)
except Exception:
readable = traceback.format_exc()
LOG.exception(_("Compute.api::lock %s"), readable)
raise exc.HTTPUnprocessableEntity()
return webob.Response(status_int=202)
@novaclient_exception_converter
@scheduler_api.redirect_handler
def unlock(self, req, id):
"""
unlock the instance with id
admin only operation
"""
context = req.environ['nova.context']
try:
self.compute_api.unlock(context, id)
except Exception:
readable = traceback.format_exc()
LOG.exception(_("Compute.api::unlock %s"), readable)
raise exc.HTTPUnprocessableEntity()
return webob.Response(status_int=202)
@novaclient_exception_converter
@exception.novaclient_converter
@scheduler_api.redirect_handler
def get_lock(self, req, id):
"""
@@ -769,133 +721,7 @@ class Controller(object):
raise exc.HTTPUnprocessableEntity()
return webob.Response(status_int=202)
@novaclient_exception_converter
@scheduler_api.redirect_handler
def reset_network(self, req, id):
"""
Reset networking on an instance (admin only).
"""
context = req.environ['nova.context']
try:
self.compute_api.reset_network(context, id)
except Exception:
readable = traceback.format_exc()
LOG.exception(_("Compute.api::reset_network %s"), readable)
raise exc.HTTPUnprocessableEntity()
return webob.Response(status_int=202)
@novaclient_exception_converter
@scheduler_api.redirect_handler
def inject_network_info(self, req, id):
"""
Inject network info for an instance (admin only).
"""
context = req.environ['nova.context']
try:
self.compute_api.inject_network_info(context, id)
except Exception:
readable = traceback.format_exc()
LOG.exception(_("Compute.api::inject_network_info %s"), readable)
raise exc.HTTPUnprocessableEntity()
return webob.Response(status_int=202)
@novaclient_exception_converter
@scheduler_api.redirect_handler
def pause(self, req, id):
""" Permit Admins to Pause the server. """
ctxt = req.environ['nova.context']
try:
self.compute_api.pause(ctxt, id)
except Exception:
readable = traceback.format_exc()
LOG.exception(_("Compute.api::pause %s"), readable)
raise exc.HTTPUnprocessableEntity()
return webob.Response(status_int=202)
@novaclient_exception_converter
@scheduler_api.redirect_handler
def unpause(self, req, id):
""" Permit Admins to Unpause the server. """
ctxt = req.environ['nova.context']
try:
self.compute_api.unpause(ctxt, id)
except Exception:
readable = traceback.format_exc()
LOG.exception(_("Compute.api::unpause %s"), readable)
raise exc.HTTPUnprocessableEntity()
return webob.Response(status_int=202)
@novaclient_exception_converter
@scheduler_api.redirect_handler
def suspend(self, req, id):
"""permit admins to suspend the server"""
context = req.environ['nova.context']
try:
self.compute_api.suspend(context, id)
except Exception:
readable = traceback.format_exc()
LOG.exception(_("compute.api::suspend %s"), readable)
raise exc.HTTPUnprocessableEntity()
return webob.Response(status_int=202)
@novaclient_exception_converter
@scheduler_api.redirect_handler
def resume(self, req, id):
"""permit admins to resume the server from suspend"""
context = req.environ['nova.context']
try:
self.compute_api.resume(context, id)
except Exception:
readable = traceback.format_exc()
LOG.exception(_("compute.api::resume %s"), readable)
raise exc.HTTPUnprocessableEntity()
return webob.Response(status_int=202)
@novaclient_exception_converter
@scheduler_api.redirect_handler
def migrate(self, req, id):
try:
self.compute_api.resize(req.environ['nova.context'], id)
except Exception, e:
LOG.exception(_("Error in migrate %s"), e)
raise exc.HTTPBadRequest()
return webob.Response(status_int=202)
@novaclient_exception_converter
@scheduler_api.redirect_handler
def rescue(self, req, id, body={}):
"""Permit users to rescue the server."""
context = req.environ["nova.context"]
try:
if 'rescue' in body and body['rescue'] and \
'adminPass' in body['rescue']:
password = body['rescue']['adminPass']
else:
password = utils.generate_password(FLAGS.password_length)
self.compute_api.rescue(context, id, rescue_password=password)
except Exception:
readable = traceback.format_exc()
LOG.exception(_("compute.api::rescue %s"), readable)
raise exc.HTTPUnprocessableEntity()
return {'adminPass': password}
@novaclient_exception_converter
@scheduler_api.redirect_handler
def unrescue(self, req, id):
"""Permit users to unrescue the server."""
context = req.environ["nova.context"]
try:
self.compute_api.unrescue(context, id)
except Exception:
readable = traceback.format_exc()
LOG.exception(_("compute.api::unrescue %s"), readable)
raise exc.HTTPUnprocessableEntity()
return webob.Response(status_int=202)
@novaclient_exception_converter
@exception.novaclient_converter
@scheduler_api.redirect_handler
def get_ajax_console(self, req, id):
"""Returns a url to an instance's ajaxterm console."""
@@ -906,7 +732,7 @@ class Controller(object):
raise exc.HTTPNotFound()
return webob.Response(status_int=202)
@novaclient_exception_converter
@exception.novaclient_converter
@scheduler_api.redirect_handler
def get_vnc_console(self, req, id):
"""Returns a url to an instance's ajaxterm console."""
@@ -917,7 +743,7 @@ class Controller(object):
raise exc.HTTPNotFound()
return webob.Response(status_int=202)
@novaclient_exception_converter
@exception.novaclient_converter
@scheduler_api.redirect_handler
def diagnostics(self, req, id):
"""Permit Admins to retrieve server diagnostics."""
@@ -960,7 +786,7 @@ class Controller(object):
class ControllerV10(Controller):
"""v1.0 OpenStack API controller"""
@novaclient_exception_converter
@exception.novaclient_converter
@scheduler_api.redirect_handler
def delete(self, req, id):
""" Destroys a server """
@@ -1047,7 +873,7 @@ class ControllerV10(Controller):
class ControllerV11(Controller):
"""v1.1 OpenStack API controller"""
@novaclient_exception_converter
@exception.novaclient_converter
@scheduler_api.redirect_handler
def delete(self, req, id):
""" Destroys a server """

View File

@@ -27,11 +27,26 @@ SHOULD include dedicated exception logging.
from functools import wraps
import sys
from novaclient import exceptions as novaclient_exceptions
from nova import log as logging
LOG = logging.getLogger('nova.exception')
def novaclient_converter(f):
"""Convert novaclient ClientException HTTP codes to webob exceptions.
Has to be the outer-most decorator.
"""
def new_f(*args, **kwargs):
try:
ret = f(*args, **kwargs)
return ret
except novaclient_exceptions.ClientException, e:
raise ConvertedException(e.code, e.message, e.details)
return new_f
class ProcessExecutionError(IOError):
def __init__(self, stdout=None, stderr=None, exit_code=None, cmd=None,
description=None):

View File

@@ -0,0 +1,64 @@
# Copyright 2011 OpenStack LLC.
#
# 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 json
import webob
from nova import compute
from nova import flags
from nova import test
from nova.tests.api.openstack import fakes
FLAGS = flags.FLAGS
def fake_compute_api(cls, req, id):
return True
class AdminActionsTest(test.TestCase):
_actions = ('pause', 'unpause', 'suspend', 'resume', 'migrate',
'resetNetwork', 'injectNetworkInfo', 'lock', 'unlock')
_methods = ('pause', 'unpause', 'suspend', 'resume', 'resize',
'reset_network', 'inject_network_info', 'lock', 'unlock')
def setUp(self):
super(AdminActionsTest, self).setUp()
self.flags(allow_admin_api=True)
for _method in self._methods:
self.stubs.Set(compute.API, _method, fake_compute_api)
def test_admin_api_enabled(self):
app = fakes.wsgi_app()
for _action in self._actions:
req = webob.Request.blank('/v1.1/fake/servers/1/action')
req.method = 'POST'
req.body = json.dumps({_action: None})
req.content_type = 'application/json'
res = req.get_response(app)
self.assertEqual(res.status_int, 202)
def test_admin_api_disabled(self):
FLAGS.allow_admin_api = False
app = fakes.wsgi_app()
for _action in self._actions:
req = webob.Request.blank('/v1.1/fake/servers/1/action')
req.method = 'POST'
req.body = json.dumps({_action: None})
req.content_type = 'application/json'
res = req.get_response(app)
self.assertEqual(res.status_int, 404)

View File

@@ -85,6 +85,7 @@ class ExtensionControllerTest(test.TestCase):
ext_path = os.path.join(os.path.dirname(__file__), "extensions")
self.flags(osapi_extensions_path=ext_path)
self.ext_list = [
"AdminActions",
"Createserverext",
"DeferredDelete",
"DiskConfig",

View File

@@ -299,23 +299,6 @@ class ServerActionsTest(test.TestCase):
res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 400)
def test_migrate_server(self):
"""This is basically the same as resize, only we provide the `migrate`
attribute in the body's dict.
"""
req = self.webreq('/1/migrate', 'POST')
self.resize_called = False
def resize_mock(*args):
self.resize_called = True
self.stubs.Set(nova.compute.api.API, 'resize', resize_mock)
res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 202)
self.assertEqual(self.resize_called, True)
def test_create_backup(self):
"""The happy path for creating backups"""
self.flags(allow_admin_api=True)

View File

@@ -261,10 +261,6 @@ class ServersTest(test.TestCase):
instance_addresses)
self.stubs.Set(nova.db.api, 'instance_get_floating_address',
instance_addresses)
self.stubs.Set(nova.compute.API, 'pause', fake_compute_api)
self.stubs.Set(nova.compute.API, 'unpause', fake_compute_api)
self.stubs.Set(nova.compute.API, 'suspend', fake_compute_api)
self.stubs.Set(nova.compute.API, 'resume', fake_compute_api)
self.stubs.Set(nova.compute.API, "get_diagnostics", fake_compute_api)
self.stubs.Set(nova.compute.API, "get_actions", fake_compute_api)
@@ -2700,55 +2696,6 @@ class ServersTest(test.TestCase):
self.assertEqual(s['imageId'], 10)
self.assertEqual(s['flavorId'], 1)
def test_server_pause(self):
self.flags(allow_admin_api=True)
req = webob.Request.blank('/v1.0/servers/1/pause')
req.method = 'POST'
req.content_type = 'application/json'
res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 202)
def test_server_unpause(self):
self.flags(allow_admin_api=True)
req = webob.Request.blank('/v1.0/servers/1/unpause')
req.method = 'POST'
req.content_type = 'application/json'
res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 202)
def test_server_suspend(self):
self.flags(allow_admin_api=True)
req = webob.Request.blank('/v1.0/servers/1/suspend')
req.method = 'POST'
req.content_type = 'application/json'
res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 202)
def test_server_resume(self):
self.flags(allow_admin_api=True)
req = webob.Request.blank('/v1.0/servers/1/resume')
req.method = 'POST'
req.content_type = 'application/json'
res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 202)
def test_server_reset_network(self):
self.flags(allow_admin_api=True)
req = webob.Request.blank('/v1.0/servers/1/reset_network')
req.method = 'POST'
req.content_type = 'application/json'
res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 202)
def test_server_inject_network_info(self):
self.flags(allow_admin_api=True)
req = webob.Request.blank(
'/v1.0/servers/1/inject_network_info')
req.method = 'POST'
req.content_type = 'application/json'
res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 202)
def test_server_diagnostics(self):
self.flags(allow_admin_api=False)
req = webob.Request.blank("/v1.0/servers/1/diagnostics")
@@ -2779,66 +2726,6 @@ class ServersTest(test.TestCase):
self.assertEqual(res.status, '202 Accepted')
self.assertEqual(self.server_delete_called, True)
def test_rescue_generates_password(self):
self.flags(allow_admin_api=True)
self.called = False
def rescue_mock(*args, **kwargs):
self.called = True
self.stubs.Set(nova.compute.api.API, 'rescue', rescue_mock)
req = webob.Request.blank('/v1.0/servers/1/rescue')
req.method = 'POST'
req.content_type = 'application/json'
res = req.get_response(fakes.wsgi_app())
self.assertEqual(self.called, True)
self.assertEqual(res.status_int, 200)
res_body = json.loads(res.body)
self.assertTrue('adminPass' in res_body)
self.assertEqual(FLAGS.password_length, len(res_body['adminPass']))
def test_rescue_with_preset_password(self):
self.flags(allow_admin_api=True)
self.called = False
def rescue_mock(*args, **kwargs):
self.called = True
self.stubs.Set(nova.compute.api.API, 'rescue', rescue_mock)
req = webob.Request.blank('/v1.0/servers/1/rescue')
req.method = 'POST'
body = {"rescue": {"adminPass": "AABBCC112233"}}
req.body = json.dumps(body)
req.content_type = 'application/json'
res = req.get_response(fakes.wsgi_app())
self.assertEqual(self.called, True)
self.assertEqual(res.status_int, 200)
res_body = json.loads(res.body)
self.assertTrue('adminPass' in res_body)
self.assertEqual('AABBCC112233', res_body['adminPass'])
def test_rescue_raises_handled(self):
self.flags(allow_admin_api=True)
body = {}
def rescue_mock(*args, **kwargs):
raise Exception('Who cares?')
self.stubs.Set(nova.compute.api.API, 'rescue', rescue_mock)
req = webob.Request.blank('/v1.0/servers/1/rescue')
req.method = 'POST'
req.content_type = 'application/json'
res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 422)
def test_delete_server_instance_v1_1(self):
req = webob.Request.blank('/v1.1/fake/servers/1')
req.method = 'DELETE'