Merge "Refactor node's and driver's vendor passthru to a common place"

This commit is contained in:
Jenkins 2015-06-19 14:58:10 +00:00 committed by Gerrit Code Review
commit 95b71efa06
4 changed files with 89 additions and 27 deletions

View File

@ -20,9 +20,9 @@ from wsme import types as wtypes
from ironic.api.controllers import base
from ironic.api.controllers import link
from ironic.api.controllers.v1 import utils as api_utils
from ironic.api import expose
from ironic.common import exception
from ironic.common.i18n import _
# Property information for drivers:
@ -142,19 +142,9 @@ class DriverPassthruController(rest.RestController):
implementation.
:param data: body of data to supply to the specified method.
"""
if not method:
raise wsme.exc.ClientSideError(_("Method not specified"))
if data is None:
data = {}
http_method = pecan.request.method.upper()
topic = pecan.request.rpcapi.get_topic_for_driver(driver_name)
response = pecan.request.rpcapi.driver_vendor_passthru(
pecan.request.context, driver_name, method,
http_method, data, topic=topic)
status_code = 202 if response['async'] else 200
return wsme.api.Response(response['return'], status_code=status_code)
return api_utils.vendor_passthru(driver_name, method, topic, data=data,
driver_passthru=True)
class DriversController(rest.RestController):

View File

@ -709,20 +709,8 @@ class NodeVendorPassthruController(rest.RestController):
# Raise an exception if node is not found
rpc_node = api_utils.get_rpc_node(node_ident)
topic = pecan.request.rpcapi.get_topic_for(rpc_node)
# Raise an exception if method is not specified
if not method:
raise wsme.exc.ClientSideError(_("Method not specified"))
if data is None:
data = {}
http_method = pecan.request.method.upper()
response = pecan.request.rpcapi.vendor_passthru(
pecan.request.context, rpc_node.uuid, method,
http_method, data, topic)
status_code = 202 if response['async'] else 200
return wsme.api.Response(response['return'], status_code=status_code)
return api_utils.vendor_passthru(rpc_node.uuid, method, topic,
data=data)
class NodeMaintenanceController(rest.RestController):

View File

@ -105,3 +105,39 @@ def is_valid_node_name(name):
:returns: True if the name is valid, False otherwise.
"""
return utils.is_hostname_safe(name) and (not uuidutils.is_uuid_like(name))
def vendor_passthru(ident, method, topic, data=None, driver_passthru=False):
"""Call a vendor passthru API extension.
Call the vendor passthru API extension and process the method response
to set the right return code for methods that are asynchronous or
synchronous; Attach the return value to the response object if it's
being served statically.
:param ident: The resource identification. For node's vendor passthru
this is the node's UUID, for driver's vendor passthru this is the
driver's name.
:param method: The vendor method name.
:param topic: The RPC topic.
:param data: The data passed to the vendor method. Defaults to None.
:param driver_passthru: Boolean value. Whether this is a node or
driver vendor passthru. Defaults to False.
:returns: A WSME response object to be returned by the API.
"""
if not method:
raise wsme.exc.ClientSideError(_("Method not specified"))
if data is None:
data = {}
http_method = pecan.request.method.upper()
params = (pecan.request.context, ident, method, http_method, data, topic)
if driver_passthru:
response = pecan.request.rpcapi.driver_vendor_passthru(*params)
else:
response = pecan.request.rpcapi.vendor_passthru(*params)
status_code = 202 if response['async'] else 200
return wsme.api.Response(response['return'], status_code=status_code)

View File

@ -154,3 +154,51 @@ class TestNodeIdent(base.TestCase):
self.assertRaises(exception.NodeNotFound,
utils.get_rpc_node,
self.valid_name)
class TestVendorPassthru(base.TestCase):
def test_method_not_specified(self):
self.assertRaises(wsme.exc.ClientSideError,
utils.vendor_passthru, 'fake-ident',
None, 'fake-topic', data='fake-data')
@mock.patch.object(pecan, 'request',
spec_set=['method', 'context', 'rpcapi'])
def _vendor_passthru(self, mock_request, async=True,
driver_passthru=False):
return_value = {'return': 'SpongeBob', 'async': async}
mock_request.method = 'post'
mock_request.context = 'fake-context'
passthru_mock = None
if driver_passthru:
passthru_mock = mock_request.rpcapi.driver_vendor_passthru
else:
passthru_mock = mock_request.rpcapi.vendor_passthru
passthru_mock.return_value = return_value
response = utils.vendor_passthru('fake-ident', 'squarepants',
'fake-topic', data='fake-data',
driver_passthru=driver_passthru)
passthru_mock.assert_called_once_with(
'fake-context', 'fake-ident', 'squarepants', 'POST',
'fake-data', 'fake-topic')
self.assertIsInstance(response, wsme.api.Response)
self.assertEqual('SpongeBob', response.obj)
self.assertEqual(response.return_type, wsme.types.Unset)
sc = 202 if async else 200
self.assertEqual(sc, response.status_code)
def test_vendor_passthru_async(self):
self._vendor_passthru()
def test_vendor_passthru_sync(self):
self._vendor_passthru(async=False)
def test_driver_vendor_passthru_async(self):
self._vendor_passthru(driver_passthru=True)
def test_driver_vendor_passthru_sync(self):
self._vendor_passthru(async=False, driver_passthru=True)