Refactoring: clean up inspection data handlers

* Avoid using the term "introspection". We need to settle on either
  "inspection" or "introspection", and the Ironic API already uses
  the former.

* Accept (and return) inventory and plugin data separately to reflect
  the Ironic API (single JSON blobs are an Inspector legacy).

* Make sure to mention the container name in error logging.

* Use more readable formatting syntax for building Swift names.

* Do not mock objects with dicts (in unit tests).

* Simplify inventory API tests.

Change-Id: Id8c4bc6d35b9634f5a5ac2b345a8fd7f1dba13c0
This commit is contained in:
Dmitry Tantsur 2023-03-14 16:18:08 +01:00
parent 3dd54a1101
commit e30ba65f94
8 changed files with 148 additions and 197 deletions

View File

@ -1964,8 +1964,7 @@ class NodeInventoryController(rest.RestController):
"""
node = api_utils.check_node_policy_and_retrieve(
'baremetal:node:inventory:get', self.node_ident)
return inspect_utils.get_introspection_data(node,
api.request.context)
return inspect_utils.get_inspection_data(node, api.request.context)
class NodesController(rest.RestController):

View File

@ -17,16 +17,17 @@ from ironic.common.i18n import _
opts = [
cfg.StrOpt('data_backend',
help=_('The storage backend for storing introspection data.'),
choices=[('none', _('introspection data will not be stored')),
('database', _('introspection data stored in an SQL '
'database')),
('swift', _('introspection data stored in Swift'))],
help=_('The storage backend for storing inspection data.'),
choices=[
('none', _('do not store inspection data')),
('database', _('store in the service database')),
('swift', _('store in the Object Storage (swift)')),
],
default='database'),
cfg.StrOpt('swift_data_container',
default='introspection_data_container',
help=_('The Swift introspection data container to store '
'the inventory data.')),
help=_('The Swift container prefix to store the inspection '
'data (separately inventory and plugin data).')),
]

View File

@ -68,101 +68,88 @@ def create_ports_if_not_exist(task, macs=None):
def clean_up_swift_entries(task):
"""Delete swift entries containing introspection data.
"""Delete swift entries containing inspection data.
Delete swift entries related to the node in task.node containing
introspection data. The entries are
inspection data. The entries are
``inspector_data-<task.node.uuid>-inventory`` for hardware inventory and
similar for ``-plugin`` containing the rest of the introspection data.
similar for ``-plugin`` containing the rest of the inspection data.
:param task: A TaskManager instance.
"""
if CONF.inventory.data_backend != 'swift':
return
swift_api = swift.SwiftAPI()
swift_object_name = '%s-%s' % (_OBJECT_NAME_PREFIX, task.node.uuid)
container = CONF.inventory.swift_data_container
inventory_obj_name = swift_object_name + '-inventory'
plugin_obj_name = swift_object_name + '-plugin'
inventory_obj_name = f'{_OBJECT_NAME_PREFIX}-{task.node.uuid}-inventory'
plugin_obj_name = f'{_OBJECT_NAME_PREFIX}-{task.node.uuid}-plugin'
try:
swift_api.delete_object(inventory_obj_name, container)
except swiftclient.exceptions.ClientException as e:
if e.http_status == 404:
# 404 -> entry did not exist - acceptable.
pass
else:
LOG.error("Object %(obj)s related to node %(node)s "
"failed to be deleted with expection: %(e)s",
if e.http_status != 404:
LOG.error("Object %(obj)s in container %(cont)s with inventory "
"for node %(node)s failed to be deleted: %(e)s",
{'obj': inventory_obj_name, 'node': task.node.uuid,
'e': e})
'e': e, 'cont': container})
raise exception.SwiftObjectStillExists(obj=inventory_obj_name,
node=task.node.uuid)
try:
swift_api.delete_object(plugin_obj_name, container)
except swiftclient.exceptions.ClientException as e:
if e.http_status == 404:
# 404 -> entry did not exist - acceptable.
pass
else:
LOG.error("Object %(obj)s related to node %(node)s "
"failed to be deleted with exception: %(e)s",
if e.http_status != 404:
LOG.error("Object %(obj)s in container %(cont)s with plugin data "
"for node %(node)s failed to be deleted: %(e)s",
{'obj': plugin_obj_name, 'node': task.node.uuid,
'e': e})
'e': e, 'cont': container})
raise exception.SwiftObjectStillExists(obj=plugin_obj_name,
node=task.node.uuid)
def store_introspection_data(node, introspection_data, context):
"""Store introspection data.
def store_inspection_data(node, inventory, plugin_data, context):
"""Store inspection data.
Store the introspection data for a node. Either to database
or swift as configured.
Store the inspection data for a node. The storage is either the database
or the Object Storage API (swift/radosgw) as configured.
:param node: the Ironic node that the introspection data is about
:param introspection_data: the data to store
:param node: the Ironic node that the inspection data is about
:param inventory: the inventory to store
:param plugin_data: the plugin data (if any) to store
:param context: an admin context
"""
# If store_data == 'none', do not store the data
store_data = CONF.inventory.data_backend
if store_data == 'none':
LOG.debug('Introspection data storage is disabled, the data will '
'not be saved for node %(node)s', {'node': node.uuid})
LOG.debug('Inspection data storage is disabled, the data will '
'not be saved for node %s', node.uuid)
return
inventory_data = introspection_data.pop("inventory")
plugin_data = introspection_data
if store_data == 'database':
node_inventory.NodeInventory(
context,
node_id=node.id,
inventory_data=inventory_data,
inventory_data=inventory,
plugin_data=plugin_data).create()
LOG.info('Introspection data was stored in database for node '
'%(node)s', {'node': node.uuid})
LOG.info('Inspection data was stored in database for node %s',
node.uuid)
if store_data == 'swift':
swift_object_name = _store_introspection_data_in_swift(
swift_object_name = _store_inspection_data_in_swift(
node_uuid=node.uuid,
inventory_data=inventory_data,
inventory_data=inventory,
plugin_data=plugin_data)
LOG.info('Introspection data was stored for node %(node)s in Swift'
' object %(obj_name)s-inventory and %(obj_name)s-plugin',
LOG.info('Inspection data was stored in Swift for node %(node)s: '
'objects %(obj_name)s-inventory and %(obj_name)s-plugin',
{'node': node.uuid, 'obj_name': swift_object_name})
def _node_inventory_convert(node_inventory):
inventory_data = node_inventory['inventory_data']
plugin_data = node_inventory['plugin_data']
return {"inventory": inventory_data, "plugin_data": plugin_data}
def get_inspection_data(node, context):
"""Get inspection data.
Retrieve the inspection data for a node either from database
or the Object Storage API (swift/radosgw) as configured.
def get_introspection_data(node, context):
"""Get introspection data.
Retrieve the introspection data for a node. Either from database
or swift as configured.
:param node_id: the Ironic node that the required data is about
:param node: the Ironic node that the required data is about
:param context: an admin context
:returns: dictionary with ``inventory`` and ``plugin_data`` fields
:raises: NodeInventoryNotFound if no inventory has been saved
"""
store_data = CONF.inventory.data_backend
if store_data == 'none':
@ -170,58 +157,57 @@ def get_introspection_data(node, context):
if store_data == 'database':
node_inventory = objects.NodeInventory.get_by_node_id(
context, node.id)
return _node_inventory_convert(node_inventory)
return {"inventory": node_inventory.inventory_data,
"plugin_data": node_inventory.plugin_data}
if store_data == 'swift':
try:
node_inventory = _get_introspection_data_from_swift(node.uuid)
return _get_inspection_data_from_swift(node.uuid)
except exception.SwiftObjectNotFoundError:
raise exception.NodeInventoryNotFound(node=node.uuid)
return node_inventory
def _store_introspection_data_in_swift(node_uuid, inventory_data, plugin_data):
"""Uploads introspection data to Swift.
def _store_inspection_data_in_swift(node_uuid, inventory_data, plugin_data):
"""Uploads inspection data to Swift.
:param data: data to store in Swift
:param node_id: ID of the Ironic node that the data came from
:returns: name of the Swift object that the data is stored in
"""
swift_api = swift.SwiftAPI()
swift_object_name = '%s-%s' % (_OBJECT_NAME_PREFIX, node_uuid)
swift_object_name = f'{_OBJECT_NAME_PREFIX}-{node_uuid}'
container = CONF.inventory.swift_data_container
swift_api.create_object_from_data(swift_object_name + '-inventory',
swift_api.create_object_from_data(f'{swift_object_name}-inventory',
inventory_data,
container)
swift_api.create_object_from_data(swift_object_name + '-plugin',
swift_api.create_object_from_data(f'{swift_object_name}-plugin',
plugin_data,
container)
return swift_object_name
def _get_introspection_data_from_swift(node_uuid):
"""Get introspection data from Swift.
def _get_inspection_data_from_swift(node_uuid):
"""Get inspection data from Swift.
:param node_uuid: UUID of the Ironic node that the data came from
:returns: dictionary with ``inventory`` and ``plugin_data`` fields
"""
swift_api = swift.SwiftAPI()
swift_object_name = '%s-%s' % (_OBJECT_NAME_PREFIX, node_uuid)
container = CONF.inventory.swift_data_container
inv_obj = swift_object_name + '-inventory'
plug_obj = swift_object_name + '-plugin'
inv_obj = f'{_OBJECT_NAME_PREFIX}-{node_uuid}-inventory'
plug_obj = f'{_OBJECT_NAME_PREFIX}-{node_uuid}-plugin'
try:
inventory_data = swift_api.get_object(inv_obj, container)
except exception.SwiftOperationError:
LOG.error("Failed to retrieve object %(obj)s from swift",
{'obj': inv_obj})
LOG.error("Failed to retrieve object %(obj)s from container %(cont)s",
{'obj': inv_obj, 'cont': container})
raise exception.SwiftObjectNotFoundError(obj=inv_obj,
container=container,
operation='get')
try:
plugin_data = swift_api.get_object(plug_obj, container)
except exception.SwiftOperationError:
LOG.error("Failed to retrieve object %(obj)s from swift",
{'obj': plug_obj})
LOG.error("Failed to retrieve object %(obj)s from container %(cont)s",
{'obj': plug_obj, 'cont': container})
raise exception.SwiftObjectNotFoundError(obj=plug_obj,
container=container,
operation='get')

View File

@ -299,15 +299,17 @@ def _check_status(task):
_inspection_error_handler(task, error)
elif status.is_finished:
_clean_up(task)
store_data = CONF.inventory.data_backend
if store_data == 'none':
LOG.debug('Introspection data storage is disabled, the data will '
'not be saved for node %(node)s', {'node': node.uuid})
if CONF.inventory.data_backend == 'none':
LOG.debug('Inspection data storage is disabled, the data will '
'not be saved for node %s', node.uuid)
return
introspection_data = inspector_client.get_introspection_data(
node.uuid, processed=True)
inspect_utils.store_introspection_data(node, introspection_data,
task.context)
# TODO(dtantsur): having no inventory is an abnormal state, handle it.
inventory = introspection_data.pop('inventory', {})
inspect_utils.store_inspection_data(node, inventory,
introspection_data,
task.context)
def _clean_up(task):

View File

@ -7927,20 +7927,15 @@ class TestNodeInventory(test_api_base.BaseApiTest):
self.node = obj_utils.create_test_node(
self.context,
provision_state=states.AVAILABLE, name='node-81')
self.node.save()
self.node.obj_reset_changes()
CONF.set_override('data_backend', 'database', group='inventory')
def _add_inventory(self):
self.inventory = objects.NodeInventory(
node_id=self.node.id, inventory_data=self.fake_inventory_data,
plugin_data=self.fake_plugin_data)
self.inventory.create()
def test_get_old_version(self):
@mock.patch.object(inspect_utils, 'get_inspection_data', autospec=True)
def test_get_old_version(self, mock_get):
ret = self.get_json('/nodes/%s/inventory' % self.node.uuid,
headers={api_base.Version.string: "1.80"},
expect_errors=True)
self.assertEqual(http_client.NOT_FOUND, ret.status_code)
mock_get.assert_not_called()
def test_get_inventory_no_inventory(self):
ret = self.get_json('/nodes/%s/inventory' % self.node.uuid,
@ -7949,33 +7944,10 @@ class TestNodeInventory(test_api_base.BaseApiTest):
self.assertEqual(http_client.NOT_FOUND, ret.status_code)
def test_get_inventory(self):
self._add_inventory()
CONF.set_override('data_backend', 'database',
group='inventory')
ret = self.get_json('/nodes/%s/inventory' % self.node.uuid,
headers={api_base.Version.string: self.version})
self.assertEqual({'inventory': self.fake_inventory_data,
'plugin_data': self.fake_plugin_data}, ret)
@mock.patch.object(inspect_utils, 'get_introspection_data',
autospec=True)
def test_get_inventory_exception(self, mock_get_data):
CONF.set_override('data_backend', 'database',
group='inventory')
mock_get_data.side_effect = [
exception.NodeInventoryNotFound]
ret = self.get_json('/nodes/%s/inventory' % self.node.uuid,
headers={api_base.Version.string: self.version},
expect_errors=True)
self.assertEqual(http_client.NOT_FOUND, ret.status_int)
@mock.patch.object(inspect_utils, '_get_introspection_data_from_swift',
autospec=True)
def test_get_inventory_swift(self, mock_get_data):
CONF.set_override('data_backend', 'swift',
group='inventory')
mock_get_data.return_value = {"inventory": self.fake_inventory_data,
"plugin_data": self.fake_plugin_data}
obj_utils.create_test_inventory(
self.context, self.node,
inventory_data=self.fake_inventory_data,
plugin_data=self.fake_plugin_data)
ret = self.get_json('/nodes/%s/inventory' % self.node.uuid,
headers={api_base.Version.string: self.version})
self.assertEqual({'inventory': self.fake_inventory_data,

View File

@ -505,22 +505,24 @@ class CheckStatusTestCase(BaseTestCase):
self.task)
self.driver.boot.clean_up_ramdisk.assert_called_once_with(self.task)
@mock.patch.object(inspect_utils, 'store_introspection_data',
autospec=True)
@mock.patch.object(inspect_utils, 'store_inspection_data', autospec=True)
def test_status_ok_store_inventory(self, mock_store_data, mock_client):
mock_get = mock_client.return_value.get_introspection
mock_get.return_value = mock.Mock(is_finished=True,
error=None,
spec=['is_finished', 'error'])
fake_introspection_data = {
"inventory": {"cpu": "amd"}, "disks": [{"name": "/dev/vda"}]}
fake_inventory = {"cpu": "amd"}
fake_plugin_data = {"disks": [{"name": "/dev/vda"}]}
fake_introspection_data = dict(fake_plugin_data,
inventory=fake_inventory)
mock_get_data = mock_client.return_value.get_introspection_data
mock_get_data.return_value = fake_introspection_data
inspector._check_status(self.task)
mock_get.assert_called_once_with(self.node.uuid)
mock_get_data.assert_called_once_with(self.node.uuid, processed=True)
mock_store_data.assert_called_once_with(self.node,
fake_introspection_data,
fake_inventory,
fake_plugin_data,
self.task.context)
def test_status_ok_store_inventory_nostore(self, mock_client):

View File

@ -103,7 +103,7 @@ class SwiftCleanUp(db_base.DbTestCase):
@mock.patch.object(swift, 'SwiftAPI', autospec=True)
def test_clean_up_swift_entries(self, swift_api_mock):
CONF.set_override('data_backend', 'swift', group='inventory')
container = 'introspection_data'
container = 'inspection_data'
CONF.set_override('swift_data_container', container, group='inventory')
swift_obj_mock = swift_api_mock.return_value
with task_manager.acquire(self.context, self.node.uuid,
@ -117,7 +117,7 @@ class SwiftCleanUp(db_base.DbTestCase):
@mock.patch.object(swift, 'SwiftAPI', autospec=True)
def test_clean_up_swift_entries_with_404_exception(self, swift_api_mock):
CONF.set_override('data_backend', 'swift', group='inventory')
container = 'introspection_data'
container = 'inspection_data'
CONF.set_override('swift_data_container', container, group='inventory')
swift_obj_mock = swift_api_mock.return_value
with task_manager.acquire(self.context, self.node.uuid,
@ -132,7 +132,7 @@ class SwiftCleanUp(db_base.DbTestCase):
@mock.patch.object(swift, 'SwiftAPI', autospec=True)
def test_clean_up_swift_entries_with_fail_exception(self, swift_api_mock):
CONF.set_override('data_backend', 'swift', group='inventory')
container = 'introspection_data'
container = 'inspection_data'
CONF.set_override('swift_data_container', container, group='inventory')
swift_obj_mock = swift_api_mock.return_value
with task_manager.acquire(self.context, self.node.uuid,
@ -148,7 +148,7 @@ class SwiftCleanUp(db_base.DbTestCase):
@mock.patch.object(swift, 'SwiftAPI', autospec=True)
def test_clean_up_swift_entries_with_fail_exceptions(self, swift_api_mock):
CONF.set_override('data_backend', 'swift', group='inventory')
container = 'introspection_data'
container = 'inspection_data'
CONF.set_override('swift_data_container', container, group='inventory')
swift_obj_mock = swift_api_mock.return_value
with task_manager.acquire(self.context, self.node.uuid,
@ -171,115 +171,93 @@ class IntrospectionDataStorageFunctionsTestCase(db_base.DbTestCase):
super(IntrospectionDataStorageFunctionsTestCase, self).setUp()
self.node = obj_utils.create_test_node(self.context)
def test_store_introspection_data_db(self):
CONF.set_override('data_backend', 'database',
group='inventory')
fake_introspection_data = {'inventory': self.fake_inventory_data,
**self.fake_plugin_data}
def test_store_inspection_data_db(self):
CONF.set_override('data_backend', 'database', group='inventory')
fake_context = ironic_context.RequestContext()
utils.store_introspection_data(self.node, fake_introspection_data,
fake_context)
utils.store_inspection_data(self.node, self.fake_inventory_data,
self.fake_plugin_data, fake_context)
stored = objects.NodeInventory.get_by_node_id(self.context,
self.node.id)
self.assertEqual(self.fake_inventory_data, stored["inventory_data"])
self.assertEqual(self.fake_plugin_data, stored["plugin_data"])
@mock.patch.object(utils, '_store_introspection_data_in_swift',
@mock.patch.object(utils, '_store_inspection_data_in_swift',
autospec=True)
def test_store_introspection_data_swift(self, mock_store_data):
def test_store_inspection_data_swift(self, mock_store_data):
CONF.set_override('data_backend', 'swift', group='inventory')
CONF.set_override(
'swift_data_container', 'introspection_data',
'swift_data_container', 'inspection_data',
group='inventory')
fake_introspection_data = {
"inventory": self.fake_inventory_data, **self.fake_plugin_data}
fake_context = ironic_context.RequestContext()
utils.store_introspection_data(self.node, fake_introspection_data,
fake_context)
utils.store_inspection_data(self.node, self.fake_inventory_data,
self.fake_plugin_data, fake_context)
mock_store_data.assert_called_once_with(
self.node.uuid, inventory_data=self.fake_inventory_data,
plugin_data=self.fake_plugin_data)
def test_store_introspection_data_nostore(self):
def test_store_inspection_data_nostore(self):
CONF.set_override('data_backend', 'none', group='inventory')
fake_introspection_data = {
"inventory": self.fake_inventory_data, **self.fake_plugin_data}
fake_context = ironic_context.RequestContext()
ret = utils.store_introspection_data(self.node,
fake_introspection_data,
fake_context)
self.assertIsNone(ret)
utils.store_inspection_data(self.node, self.fake_inventory_data,
self.fake_plugin_data, fake_context)
self.assertRaises(exception.NodeInventoryNotFound,
objects.NodeInventory.get_by_node_id,
self.context, self.node.id)
def test__node_inventory_convert(self):
required_output = {"inventory": self.fake_inventory_data,
"plugin_data": self.fake_plugin_data}
input_given = {}
input_given["inventory_data"] = self.fake_inventory_data
input_given["plugin_data"] = self.fake_plugin_data
input_given["booom"] = "boom"
ret = utils._node_inventory_convert(input_given)
self.assertEqual(required_output, ret)
@mock.patch.object(utils, '_node_inventory_convert', autospec=True)
@mock.patch.object(objects, 'NodeInventory', spec_set=True, autospec=True)
def test_get_introspection_data_db(self, mock_inventory, mock_convert):
CONF.set_override('data_backend', 'database',
group='inventory')
fake_introspection_data = {'inventory': self.fake_inventory_data,
'plugin_data': self.fake_plugin_data}
def test_get_inspection_data_db(self):
CONF.set_override('data_backend', 'database', group='inventory')
obj_utils.create_test_inventory(
self.context, self.node,
inventory_data=self.fake_inventory_data,
plugin_data=self.fake_plugin_data)
fake_context = ironic_context.RequestContext()
mock_inventory.get_by_node_id.return_value = fake_introspection_data
utils.get_introspection_data(self.node, fake_context)
mock_convert.assert_called_once_with(fake_introspection_data)
ret = utils.get_inspection_data(self.node, fake_context)
fake_inspection_data = {'inventory': self.fake_inventory_data,
'plugin_data': self.fake_plugin_data}
self.assertEqual(ret, fake_inspection_data)
@mock.patch.object(objects, 'NodeInventory', spec_set=True, autospec=True)
def test_get_introspection_data_db_exception(self, mock_inventory):
CONF.set_override('data_backend', 'database',
group='inventory')
def test_get_inspection_data_db_exception(self):
CONF.set_override('data_backend', 'database', group='inventory')
fake_context = ironic_context.RequestContext()
mock_inventory.get_by_node_id.side_effect = [
exception.NodeInventoryNotFound(self.node.uuid)]
self.assertRaises(
exception.NodeInventoryNotFound, utils.get_introspection_data,
exception.NodeInventoryNotFound, utils.get_inspection_data,
self.node, fake_context)
@mock.patch.object(utils, '_get_introspection_data_from_swift',
autospec=True)
def test_get_introspection_data_swift(self, mock_get_data):
@mock.patch.object(utils, '_get_inspection_data_from_swift', autospec=True)
def test_get_inspection_data_swift(self, mock_get_data):
CONF.set_override('data_backend', 'swift', group='inventory')
CONF.set_override(
'swift_data_container', 'introspection_data',
'swift_data_container', 'inspection_data',
group='inventory')
fake_context = ironic_context.RequestContext()
utils.get_introspection_data(self.node, fake_context)
mock_get_data.assert_called_once_with(
self.node.uuid)
ret = utils.get_inspection_data(self.node, fake_context)
mock_get_data.assert_called_once_with(self.node.uuid)
self.assertEqual(mock_get_data.return_value, ret)
@mock.patch.object(utils, '_get_introspection_data_from_swift',
autospec=True)
def test_get_introspection_data_swift_exception(self, mock_get_data):
@mock.patch.object(utils, '_get_inspection_data_from_swift', autospec=True)
def test_get_inspection_data_swift_exception(self, mock_get_data):
CONF.set_override('data_backend', 'swift', group='inventory')
CONF.set_override(
'swift_data_container', 'introspection_data',
'swift_data_container', 'inspection_data',
group='inventory')
fake_context = ironic_context.RequestContext()
mock_get_data.side_effect = exception.SwiftObjectNotFoundError()
self.assertRaises(
exception.NodeInventoryNotFound, utils.get_introspection_data,
exception.NodeInventoryNotFound, utils.get_inspection_data,
self.node, fake_context)
def test_get_introspection_data_nostore(self):
def test_get_inspection_data_nostore(self):
CONF.set_override('data_backend', 'none', group='inventory')
fake_context = ironic_context.RequestContext()
self.assertRaises(
exception.NodeInventoryNotFound, utils.get_introspection_data,
exception.NodeInventoryNotFound, utils.get_inspection_data,
self.node, fake_context)
@mock.patch.object(swift, 'SwiftAPI', autospec=True)
def test__store_introspection_data_in_swift(self, swift_api_mock):
container = 'introspection_data'
def test__store_inspection_data_in_swift(self, swift_api_mock):
container = 'inspection_data'
CONF.set_override('swift_data_container', container, group='inventory')
utils._store_introspection_data_in_swift(
utils._store_inspection_data_in_swift(
self.node.uuid, self.fake_inventory_data, self.fake_plugin_data)
swift_obj_mock = swift_api_mock.return_value
object_name = 'inspector_data-' + str(self.node.uuid)
@ -290,23 +268,22 @@ class IntrospectionDataStorageFunctionsTestCase(db_base.DbTestCase):
container)])
@mock.patch.object(swift, 'SwiftAPI', autospec=True)
def test__get_introspection_data_from_swift(self, swift_api_mock):
container = 'introspection_data'
def test__get_inspection_data_from_swift(self, swift_api_mock):
container = 'inspection_data'
CONF.set_override('swift_data_container', container, group='inventory')
swift_obj_mock = swift_api_mock.return_value
swift_obj_mock.get_object.side_effect = [
self.fake_inventory_data,
self.fake_plugin_data
]
ret = utils._get_introspection_data_from_swift(self.node.uuid)
ret = utils._get_inspection_data_from_swift(self.node.uuid)
req_ret = {"inventory": self.fake_inventory_data,
"plugin_data": self.fake_plugin_data}
self.assertEqual(req_ret, ret)
@mock.patch.object(swift, 'SwiftAPI', autospec=True)
def test__get_introspection_data_from_swift_exception(self,
swift_api_mock):
container = 'introspection_data'
def test__get_inspection_data_from_swift_exception(self, swift_api_mock):
container = 'inspection_data'
CONF.set_override('swift_data_container', container, group='inventory')
swift_obj_mock = swift_api_mock.return_value
swift_obj_mock.get_object.side_effect = [
@ -314,5 +291,5 @@ class IntrospectionDataStorageFunctionsTestCase(db_base.DbTestCase):
self.fake_plugin_data
]
self.assertRaises(exception.SwiftObjectNotFoundError,
utils._get_introspection_data_from_swift,
utils._get_inspection_data_from_swift,
self.node.uuid)

View File

@ -380,3 +380,15 @@ class SchemasTestMixIn(object):
"for %s, schema key %s has invalid %s "
"field %s" % (payload, schema_key, resource,
key))
def create_test_inventory(ctxt, node, **kw):
"""Create and return a test node inventory object."""
inv = objects.NodeInventory(ctxt)
if not isinstance(node, str):
node = node.id
kw['node_id'] = node
for key, value in kw.items():
setattr(inv, key, value)
inv.create()
return inv