Merge "Refactor node's and driver's vendor passthru to a common place"
This commit is contained in:
commit
95b71efa06
@ -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):
|
||||
|
@ -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):
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user