Add the initial skeleton of the agent inspect interface
No real inspection is done: it only accepts data and returns success. Common code has been extracted from the existing inspector-based implementation. Change-Id: I7462bb2e0449fb1098fe59e394b5c583fea89bac
This commit is contained in:
parent
349b1f7c41
commit
6efa2119e4
@ -115,6 +115,7 @@ def continue_inspection(task, inventory, plugin_data):
|
||||
node = task.node
|
||||
LOG.debug('Inventory for node %(node)s: %(data)s',
|
||||
{'node': node.uuid, 'data': inventory})
|
||||
plugin_data = plugin_data or {}
|
||||
|
||||
try:
|
||||
result = task.driver.inspect.continue_inspection(
|
||||
|
@ -17,6 +17,19 @@ from oslo_config import cfg
|
||||
from ironic.common.i18n import _
|
||||
from ironic.conf import auth
|
||||
|
||||
|
||||
VALID_ADD_PORTS_VALUES = {
|
||||
'all': _('all MAC addresses'),
|
||||
'active': _('MAC addresses of NIC\'s with IP addresses'),
|
||||
'pxe': _('only the MAC address of the PXE NIC'),
|
||||
'disabled': _('do not create any ports'),
|
||||
}
|
||||
VALID_KEEP_PORTS_VALUES = {
|
||||
'all': _('keep even ports with MAC\'s not present in the inventory'),
|
||||
'present': _('keep only ports with MAC\'s present in the inventory'),
|
||||
'added': _('keep only ports determined by the add_ports option'),
|
||||
}
|
||||
|
||||
opts = [
|
||||
cfg.IntOpt('status_check_period', default=60,
|
||||
help=_('period (in seconds) to check status of nodes '
|
||||
|
@ -58,7 +58,7 @@ class GenericHardware(hardware_type.AbstractHardwareType):
|
||||
"""List of supported inspect interfaces."""
|
||||
# Inspector support should be the default if it's enabled by an
|
||||
# operator (implying that the service is installed).
|
||||
return [inspector.Inspector, noop.NoInspect]
|
||||
return [inspector.Inspector, inspector.AgentInspect, noop.NoInspect]
|
||||
|
||||
@property
|
||||
def supported_network_interfaces(self):
|
||||
|
@ -18,7 +18,6 @@ of FUJITSU PRIMERGY servers, and above servers.
|
||||
|
||||
from ironic.drivers import generic
|
||||
from ironic.drivers.modules import agent
|
||||
from ironic.drivers.modules import inspector
|
||||
from ironic.drivers.modules import ipmitool
|
||||
from ironic.drivers.modules import ipxe
|
||||
from ironic.drivers.modules.irmc import bios
|
||||
@ -61,8 +60,7 @@ class IRMCHardware(generic.GenericHardware):
|
||||
@property
|
||||
def supported_inspect_interfaces(self):
|
||||
"""List of supported inspect interfaces."""
|
||||
return [inspect.IRMCInspect, inspector.Inspector,
|
||||
noop.NoInspect]
|
||||
return [inspect.IRMCInspect] + super().supported_inspect_interfaces
|
||||
|
||||
@property
|
||||
def supported_management_interfaces(self):
|
||||
|
@ -10,6 +10,7 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from ironic.drivers.modules.inspector.agent import AgentInspect
|
||||
from ironic.drivers.modules.inspector.interface import Inspector
|
||||
|
||||
__all__ = ['Inspector']
|
||||
__all__ = ['AgentInspect', 'Inspector']
|
||||
|
83
ironic/drivers/modules/inspector/agent.py
Normal file
83
ironic/drivers/modules/inspector/agent.py
Normal file
@ -0,0 +1,83 @@
|
||||
# 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.
|
||||
|
||||
"""
|
||||
In-band inspection implementation.
|
||||
"""
|
||||
|
||||
from oslo_log import log as logging
|
||||
|
||||
from ironic.common import boot_devices
|
||||
from ironic.common.i18n import _
|
||||
from ironic.common import states
|
||||
from ironic.conductor import utils as cond_utils
|
||||
from ironic.drivers.modules import deploy_utils
|
||||
from ironic.drivers.modules import inspect_utils
|
||||
from ironic.drivers.modules.inspector import interface as common
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class AgentInspect(common.Common):
|
||||
"""In-band inspection."""
|
||||
|
||||
def _start_managed_inspection(self, task):
|
||||
"""Start inspection managed by ironic."""
|
||||
ep = deploy_utils.get_ironic_api_url().rstrip('/')
|
||||
if ep.endswith('/v1'):
|
||||
ep = f'{ep}/continue_inspection'
|
||||
else:
|
||||
ep = f'{ep}/v1/continue_inspection'
|
||||
|
||||
common.prepare_managed_inspection(task, ep)
|
||||
cond_utils.node_power_action(task, states.POWER_ON)
|
||||
|
||||
def _start_unmanaged_inspection(self, task):
|
||||
"""Start unmanaged inspection."""
|
||||
try:
|
||||
cond_utils.node_power_action(task, states.POWER_OFF)
|
||||
# Only network boot is supported for unmanaged inspection.
|
||||
cond_utils.node_set_boot_device(task, boot_devices.PXE,
|
||||
persistent=False)
|
||||
cond_utils.node_power_action(task, states.POWER_ON)
|
||||
except Exception as exc:
|
||||
LOG.exception('Unable to start unmanaged inspection for node '
|
||||
'%(uuid)s: %(err)s',
|
||||
{'uuid': task.node.uuid, 'err': exc})
|
||||
error = _('unable to start inspection: %s') % exc
|
||||
common.inspection_error_handler(task, error, raise_exc=True,
|
||||
clean_up=False)
|
||||
|
||||
def abort(self, task):
|
||||
"""Abort hardware inspection.
|
||||
|
||||
:param task: a task from TaskManager.
|
||||
"""
|
||||
error = _("By request, the inspection operation has been aborted")
|
||||
inspect_utils.clear_lookup_addresses(task.node)
|
||||
common.inspection_error_handler(task, error, raise_exc=False,
|
||||
clean_up=True)
|
||||
|
||||
def continue_inspection(self, task, inventory, plugin_data):
|
||||
"""Continue in-band hardware inspection.
|
||||
|
||||
This implementation simply defers to ironic-inspector. It only exists
|
||||
to simplify the transition to Ironic-native in-band inspection.
|
||||
|
||||
:param task: a task from TaskManager.
|
||||
:param inventory: hardware inventory from the node.
|
||||
:param plugin_data: optional plugin-specific data.
|
||||
"""
|
||||
# TODO(dtantsur): migrate the whole pipeline from ironic-inspector
|
||||
LOG.error('Meaningful inspection is not implemented yet in the "agent"'
|
||||
' inspect interface')
|
||||
common.clean_up(task, finish=False)
|
@ -62,7 +62,7 @@ def _get_callback_endpoint(client):
|
||||
parts.query, parts.fragment))
|
||||
|
||||
|
||||
def _tear_down_managed_boot(task):
|
||||
def tear_down_managed_boot(task):
|
||||
errors = []
|
||||
|
||||
ironic_manages_boot = utils.pop_node_nested_field(
|
||||
@ -94,9 +94,9 @@ def _tear_down_managed_boot(task):
|
||||
return errors
|
||||
|
||||
|
||||
def _inspection_error_handler(task, error, raise_exc=False, clean_up=True):
|
||||
def inspection_error_handler(task, error, raise_exc=False, clean_up=True):
|
||||
if clean_up:
|
||||
_tear_down_managed_boot(task)
|
||||
tear_down_managed_boot(task)
|
||||
|
||||
task.node.last_error = error
|
||||
if raise_exc:
|
||||
@ -106,7 +106,7 @@ def _inspection_error_handler(task, error, raise_exc=False, clean_up=True):
|
||||
task.process_event('fail')
|
||||
|
||||
|
||||
def _ironic_manages_boot(task, raise_exc=False):
|
||||
def ironic_manages_boot(task, raise_exc=False):
|
||||
"""Whether ironic should manage boot for this node."""
|
||||
try:
|
||||
task.driver.boot.validate_inspection(task)
|
||||
@ -137,32 +137,21 @@ def _ironic_manages_boot(task, raise_exc=False):
|
||||
return True
|
||||
|
||||
|
||||
def _start_managed_inspection(task):
|
||||
"""Start inspection managed by ironic."""
|
||||
try:
|
||||
cli = client.get_client(task.context)
|
||||
endpoint = _get_callback_endpoint(cli)
|
||||
params = dict(
|
||||
utils.parse_kernel_params(CONF.inspector.extra_kernel_params),
|
||||
**{'ipa-inspection-callback-url': endpoint})
|
||||
if utils.fast_track_enabled(task.node):
|
||||
params['ipa-api-url'] = deploy_utils.get_ironic_api_url()
|
||||
def prepare_managed_inspection(task, endpoint):
|
||||
"""Prepare the boot interface for managed inspection."""
|
||||
params = dict(
|
||||
utils.parse_kernel_params(CONF.inspector.extra_kernel_params),
|
||||
**{'ipa-inspection-callback-url': endpoint})
|
||||
if utils.fast_track_enabled(task.node):
|
||||
params['ipa-api-url'] = deploy_utils.get_ironic_api_url()
|
||||
|
||||
cond_utils.node_power_action(task, states.POWER_OFF)
|
||||
with cond_utils.power_state_for_network_configuration(task):
|
||||
task.driver.network.add_inspection_network(task)
|
||||
task.driver.boot.prepare_ramdisk(task, ramdisk_params=params)
|
||||
cli.start_introspection(task.node.uuid, manage_boot=False)
|
||||
cond_utils.node_power_action(task, states.POWER_ON)
|
||||
except Exception as exc:
|
||||
LOG.exception('Unable to start managed inspection for node %(uuid)s: '
|
||||
'%(err)s', {'uuid': task.node.uuid, 'err': exc})
|
||||
error = _('unable to start inspection: %s') % exc
|
||||
_inspection_error_handler(task, error, raise_exc=True)
|
||||
cond_utils.node_power_action(task, states.POWER_OFF)
|
||||
with cond_utils.power_state_for_network_configuration(task):
|
||||
task.driver.network.add_inspection_network(task)
|
||||
task.driver.boot.prepare_ramdisk(task, ramdisk_params=params)
|
||||
|
||||
|
||||
class Inspector(base.InspectInterface):
|
||||
"""In-band inspection via ironic-inspector project."""
|
||||
class Common(base.InspectInterface):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
@ -189,7 +178,7 @@ class Inspector(base.InspectInterface):
|
||||
"""
|
||||
utils.parse_kernel_params(CONF.inspector.extra_kernel_params)
|
||||
if CONF.inspector.require_managed_boot:
|
||||
_ironic_manages_boot(task, raise_exc=True)
|
||||
ironic_manages_boot(task, raise_exc=True)
|
||||
|
||||
def inspect_hardware(self, task):
|
||||
"""Inspect hardware to obtain the hardware properties.
|
||||
@ -207,12 +196,11 @@ class Inspector(base.InspectInterface):
|
||||
LOG.debug('Pre-creating ports prior to inspection not supported'
|
||||
' on node %s.', task.node.uuid)
|
||||
|
||||
ironic_manages_boot = _ironic_manages_boot(
|
||||
manage_boot = ironic_manages_boot(
|
||||
task, raise_exc=CONF.inspector.require_managed_boot)
|
||||
|
||||
utils.set_node_nested_field(task.node, 'driver_internal_info',
|
||||
_IRONIC_MANAGES_BOOT,
|
||||
ironic_manages_boot)
|
||||
_IRONIC_MANAGES_BOOT, manage_boot)
|
||||
# Make this interface work with the Ironic own /continue_inspection
|
||||
# endpoint to simplify migration to the new in-band inspection
|
||||
# implementation.
|
||||
@ -222,18 +210,40 @@ class Inspector(base.InspectInterface):
|
||||
LOG.debug('Starting inspection for node %(uuid)s using '
|
||||
'ironic-inspector, booting is managed by %(project)s',
|
||||
{'uuid': task.node.uuid,
|
||||
'project': 'ironic' if ironic_manages_boot
|
||||
else 'ironic-inspector'})
|
||||
'project': 'ironic' if manage_boot else 'ironic-inspector'})
|
||||
|
||||
if ironic_manages_boot:
|
||||
_start_managed_inspection(task)
|
||||
if manage_boot:
|
||||
try:
|
||||
self._start_managed_inspection(task)
|
||||
except Exception as exc:
|
||||
LOG.exception('Unable to start managed inspection for node '
|
||||
'%(uuid)s: %(err)s',
|
||||
{'uuid': task.node.uuid, 'err': exc})
|
||||
error = _('unable to start inspection: %s') % exc
|
||||
inspection_error_handler(task, error, raise_exc=True)
|
||||
else:
|
||||
# NOTE(dtantsur): spawning a short-living green thread so that
|
||||
# we can release a lock as soon as possible and allow
|
||||
# ironic-inspector to operate on the node.
|
||||
eventlet.spawn_n(_start_inspection, task.node.uuid, task.context)
|
||||
self._start_unmanaged_inspection(task)
|
||||
return states.INSPECTWAIT
|
||||
|
||||
|
||||
class Inspector(Common):
|
||||
"""In-band inspection via ironic-inspector project."""
|
||||
|
||||
def _start_managed_inspection(self, task):
|
||||
"""Start inspection managed by ironic."""
|
||||
cli = client.get_client(task.context)
|
||||
endpoint = _get_callback_endpoint(cli)
|
||||
prepare_managed_inspection(task, endpoint)
|
||||
cli.start_introspection(task.node.uuid, manage_boot=False)
|
||||
cond_utils.node_power_action(task, states.POWER_ON)
|
||||
|
||||
def _start_unmanaged_inspection(self, task):
|
||||
"""Call to inspector to start inspection."""
|
||||
# NOTE(dtantsur): spawning a short-living green thread so that
|
||||
# we can release a lock as soon as possible and allow
|
||||
# ironic-inspector to operate on the node.
|
||||
eventlet.spawn_n(_start_inspection, task.node.uuid, task.context)
|
||||
|
||||
def abort(self, task):
|
||||
"""Abort hardware inspection.
|
||||
|
||||
@ -253,7 +263,8 @@ class Inspector(base.InspectInterface):
|
||||
)
|
||||
def _periodic_check_result(self, task, manager, context):
|
||||
"""Periodic task checking results of inspection."""
|
||||
_check_status(task)
|
||||
if isinstance(task.driver.inspect, self.__class__):
|
||||
_check_status(task)
|
||||
|
||||
def continue_inspection(self, task, inventory, plugin_data=None):
|
||||
"""Continue in-band hardware inspection.
|
||||
@ -288,7 +299,7 @@ def _start_inspection(node_uuid, context):
|
||||
with task_manager.acquire(context, node_uuid,
|
||||
purpose=lock_purpose) as task:
|
||||
error = _('Failed to start inspection: %s') % exc
|
||||
_inspection_error_handler(task, error)
|
||||
inspection_error_handler(task, error)
|
||||
else:
|
||||
LOG.info('Node %s was sent to inspection to ironic-inspector',
|
||||
node_uuid)
|
||||
@ -330,9 +341,9 @@ def _check_status(task):
|
||||
LOG.error('Inspection failed for node %(uuid)s with error: %(err)s',
|
||||
{'uuid': node.uuid, 'err': status.error})
|
||||
error = _('ironic-inspector inspection failed: %s') % status.error
|
||||
_inspection_error_handler(task, error)
|
||||
inspection_error_handler(task, error)
|
||||
elif status.is_finished:
|
||||
_clean_up(task)
|
||||
clean_up(task)
|
||||
if CONF.inventory.data_backend == 'none':
|
||||
LOG.debug('Inspection data storage is disabled, the data will '
|
||||
'not be saved for node %s', node.uuid)
|
||||
@ -346,15 +357,15 @@ def _check_status(task):
|
||||
task.context)
|
||||
|
||||
|
||||
def _clean_up(task):
|
||||
errors = _tear_down_managed_boot(task)
|
||||
def clean_up(task, finish=True):
|
||||
errors = tear_down_managed_boot(task)
|
||||
if errors:
|
||||
errors = ', '.join(errors)
|
||||
LOG.error('Inspection clean up failed for node %(uuid)s: %(err)s',
|
||||
{'uuid': task.node.uuid, 'err': errors})
|
||||
msg = _('Inspection clean up failed: %s') % errors
|
||||
_inspection_error_handler(task, msg, raise_exc=False, clean_up=False)
|
||||
else:
|
||||
inspection_error_handler(task, msg, raise_exc=False, clean_up=False)
|
||||
elif finish:
|
||||
LOG.info('Inspection finished successfully for node %s',
|
||||
task.node.uuid)
|
||||
task.process_event('done')
|
||||
|
@ -15,7 +15,6 @@
|
||||
|
||||
from ironic.drivers import generic
|
||||
from ironic.drivers.modules import agent
|
||||
from ironic.drivers.modules import inspector
|
||||
from ironic.drivers.modules import ipxe
|
||||
from ironic.drivers.modules import noop
|
||||
from ironic.drivers.modules import noop_mgmt
|
||||
@ -50,8 +49,8 @@ class RedfishHardware(generic.GenericHardware):
|
||||
@property
|
||||
def supported_inspect_interfaces(self):
|
||||
"""List of supported power interfaces."""
|
||||
return [redfish_inspect.RedfishInspect, inspector.Inspector,
|
||||
noop.NoInspect]
|
||||
return ([redfish_inspect.RedfishInspect]
|
||||
+ super().supported_inspect_interfaces)
|
||||
|
||||
@property
|
||||
def supported_boot_interfaces(self):
|
||||
|
124
ironic/tests/unit/drivers/modules/inspector/test_agent.py
Normal file
124
ironic/tests/unit/drivers/modules/inspector/test_agent.py
Normal file
@ -0,0 +1,124 @@
|
||||
# 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 unittest import mock
|
||||
|
||||
from ironic.common import boot_devices
|
||||
from ironic.common import exception
|
||||
from ironic.common import states
|
||||
from ironic.conductor import task_manager
|
||||
from ironic.conf import CONF
|
||||
from ironic.drivers.modules import deploy_utils
|
||||
from ironic.drivers.modules import inspect_utils
|
||||
from ironic.drivers.modules.inspector import agent as inspector
|
||||
from ironic.drivers.modules.inspector import interface as common
|
||||
from ironic.tests.unit.db import base as db_base
|
||||
from ironic.tests.unit.objects import utils as obj_utils
|
||||
|
||||
|
||||
@mock.patch.object(inspect_utils, 'create_ports_if_not_exist', autospec=True)
|
||||
class InspectHardwareTestCase(db_base.DbTestCase):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.node = obj_utils.create_test_node(self.context,
|
||||
inspect_interface='agent')
|
||||
self.iface = inspector.AgentInspect()
|
||||
self.task = mock.MagicMock(spec=task_manager.TaskManager)
|
||||
self.task.context = self.context
|
||||
self.task.shared = False
|
||||
self.task.node = self.node
|
||||
self.task.driver = mock.Mock(
|
||||
spec=['boot', 'network', 'inspect', 'power', 'management'],
|
||||
inspect=self.iface)
|
||||
self.driver = self.task.driver
|
||||
|
||||
def test_unmanaged_ok(self, mock_create_ports_if_not_exist):
|
||||
self.driver.boot.validate_inspection.side_effect = (
|
||||
exception.UnsupportedDriverExtension(''))
|
||||
self.assertEqual(states.INSPECTWAIT,
|
||||
self.iface.inspect_hardware(self.task))
|
||||
mock_create_ports_if_not_exist.assert_called_once_with(self.task)
|
||||
self.assertFalse(self.driver.boot.prepare_ramdisk.called)
|
||||
self.assertFalse(self.driver.network.add_inspection_network.called)
|
||||
self.driver.management.set_boot_device.assert_called_once_with(
|
||||
self.task, device=boot_devices.PXE, persistent=False)
|
||||
self.driver.power.set_power_state.assert_has_calls([
|
||||
mock.call(self.task, states.POWER_OFF, timeout=None),
|
||||
mock.call(self.task, states.POWER_ON, timeout=None),
|
||||
])
|
||||
self.assertFalse(self.driver.network.remove_inspection_network.called)
|
||||
self.assertFalse(self.driver.boot.clean_up_ramdisk.called)
|
||||
|
||||
@mock.patch.object(deploy_utils, 'get_ironic_api_url', autospec=True)
|
||||
def test_managed_ok(self, mock_get_url, mock_create_ports_if_not_exist):
|
||||
endpoint = 'http://192.169.0.42:6385/v1'
|
||||
mock_get_url.return_value = endpoint
|
||||
self.assertEqual(states.INSPECTWAIT,
|
||||
self.iface.inspect_hardware(self.task))
|
||||
self.driver.boot.prepare_ramdisk.assert_called_once_with(
|
||||
self.task, ramdisk_params={
|
||||
'ipa-inspection-callback-url':
|
||||
f'{endpoint}/continue_inspection',
|
||||
})
|
||||
self.driver.network.add_inspection_network.assert_called_once_with(
|
||||
self.task)
|
||||
self.driver.power.set_power_state.assert_has_calls([
|
||||
mock.call(self.task, states.POWER_OFF, timeout=None),
|
||||
mock.call(self.task, states.POWER_ON, timeout=None),
|
||||
])
|
||||
self.assertFalse(self.driver.network.remove_inspection_network.called)
|
||||
self.assertFalse(self.driver.boot.clean_up_ramdisk.called)
|
||||
|
||||
@mock.patch.object(deploy_utils, 'get_ironic_api_url', autospec=True)
|
||||
def test_managed_unversion_url(self, mock_get_url,
|
||||
mock_create_ports_if_not_exist):
|
||||
endpoint = 'http://192.169.0.42:6385/'
|
||||
mock_get_url.return_value = endpoint
|
||||
self.assertEqual(states.INSPECTWAIT,
|
||||
self.iface.inspect_hardware(self.task))
|
||||
mock_create_ports_if_not_exist.assert_called_once_with(self.task)
|
||||
self.driver.boot.prepare_ramdisk.assert_called_once_with(
|
||||
self.task, ramdisk_params={
|
||||
'ipa-inspection-callback-url':
|
||||
f'{endpoint}v1/continue_inspection',
|
||||
})
|
||||
self.driver.network.add_inspection_network.assert_called_once_with(
|
||||
self.task)
|
||||
self.driver.power.set_power_state.assert_has_calls([
|
||||
mock.call(self.task, states.POWER_OFF, timeout=None),
|
||||
mock.call(self.task, states.POWER_ON, timeout=None),
|
||||
])
|
||||
self.assertFalse(self.driver.network.remove_inspection_network.called)
|
||||
self.assertFalse(self.driver.boot.clean_up_ramdisk.called)
|
||||
|
||||
|
||||
@mock.patch.object(common, 'tear_down_managed_boot', autospec=True)
|
||||
class ContinueInspectionTestCase(db_base.DbTestCase):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
CONF.set_override('enabled_inspect_interfaces',
|
||||
['agent', 'no-inspect'])
|
||||
self.node = obj_utils.create_test_node(
|
||||
self.context,
|
||||
inspect_interface='agent',
|
||||
provision_state=states.INSPECTING)
|
||||
self.iface = inspector.AgentInspect()
|
||||
|
||||
def test(self, mock_tear_down):
|
||||
mock_tear_down.return_value = None
|
||||
with task_manager.acquire(self.context, self.node.id) as task:
|
||||
result = self.iface.continue_inspection(
|
||||
task, mock.sentinel.inventory, mock.sentinel.plugin_data)
|
||||
mock_tear_down.assert_called_once_with(task)
|
||||
self.assertEqual(states.INSPECTING, task.node.provision_state)
|
||||
|
||||
self.assertIsNone(result)
|
@ -94,6 +94,7 @@ ironic.hardware.interfaces.deploy =
|
||||
ramdisk = ironic.drivers.modules.ramdisk:RamdiskDeploy
|
||||
|
||||
ironic.hardware.interfaces.inspect =
|
||||
agent = ironic.drivers.modules.inspector:AgentInspect
|
||||
fake = ironic.drivers.modules.fake:FakeInspect
|
||||
idrac = ironic.drivers.modules.drac.inspect:DracInspect
|
||||
idrac-redfish = ironic.drivers.modules.drac.inspect:DracRedfishInspect
|
||||
|
Loading…
x
Reference in New Issue
Block a user