Create dummy interfaces for use with hardware types

A new module is created containing "noop" implementations of all
interfaces we consider optional. These can be used as default
implementation for hardware types that don't support a particular
interface or just don't want it enabled by default.

Partial-Bug: #1524745
Change-Id: I2abe2ff5449ac2671020f309b27c4e738fa017b5
This commit is contained in:
Dmitry Tantsur 2016-11-04 17:43:17 +01:00
parent 565a0ed6b9
commit 7591dcedfb
3 changed files with 148 additions and 0 deletions

View File

@ -0,0 +1,67 @@
# Copyright 2016 Red Hat, Inc.
#
# 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.
"""
Dummy interface implementations for use as defaults with optional interfaces.
Note that unlike fake implementatios, these do not pass validation and raise
exceptions for user-accessible actions.
"""
from ironic.common import exception
from ironic.drivers import base
def _fail(iface, task, *args, **kwargs):
# TODO(dtanstur): support hardware types
driver = task.node.driver
raise exception.UnsupportedDriverExtension(
driver=driver, extension=iface.interface_type)
class FailMixin(object):
"""Mixin to add to an interface to make it fail validation."""
def get_properties(self):
return {}
validate = _fail
class NoConsole(FailMixin, base.ConsoleInterface):
"""Console interface implementation that raises errors on all requests."""
stop_console = get_console = start_console = _fail
class NoRescue(FailMixin, base.RescueInterface):
"""Rescue interface implementation that raises errors on all requests."""
rescue = unrescue = _fail
class NoVendor(FailMixin, base.VendorInterface):
"""Vendor interface implementation that raises errors on all requests."""
def driver_validate(self, method, **kwargs):
raise exception.UnsupportedDriverExtension(
driver=type(self).__name__, extension=self.interface_type)
class NoInspect(FailMixin, base.InspectInterface):
"""Inspect interface implementation that raises errors on all requests."""
inspect_hardware = _fail
class NoRAID(FailMixin, base.RAIDInterface):
"""RAID interface implementation that raises errors on all requests."""
create_configuration = delete_configuration = _fail

View File

@ -0,0 +1,66 @@
# Copyright 2016 Red Hat, Inc.
#
# 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 mock
import stevedore
from ironic.common import exception
from ironic.drivers.modules import noop
from ironic.tests import base
# TODO(dtantsur): move to ironic.common.driver_factory
def hardware_interface_extension_manager(interface):
"""Get a Stevedore extension manager for given hardware interface."""
return stevedore.extension.ExtensionManager(
'ironic.hardware.interfaces.%s' % interface,
invoke_on_load=True)
class NoInterfacesTestCase(base.TestCase):
iface_types = ['console', 'inspect', 'raid', 'rescue', 'vendor']
task = mock.Mock(node=mock.Mock(driver='pxe_foobar', spec=['driver']),
spec=['node'])
def test_console(self):
for method in ('start_console', 'stop_console', 'get_console'):
self.assertRaises(exception.UnsupportedDriverExtension,
getattr(noop.NoConsole(), method),
self.task)
def test_rescue(self):
for method in ('rescue', 'unrescue'):
self.assertRaises(exception.UnsupportedDriverExtension,
getattr(noop.NoRescue(), method),
self.task)
def test_vendor(self):
self.assertRaises(exception.UnsupportedDriverExtension,
noop.NoVendor().validate,
self.task, 'method')
self.assertRaises(exception.UnsupportedDriverExtension,
noop.NoVendor().driver_validate,
'method')
def test_inspect(self):
self.assertRaises(exception.UnsupportedDriverExtension,
noop.NoInspect().inspect_hardware, self.task)
def test_load_by_name(self):
for iface_type in self.iface_types:
mgr = hardware_interface_extension_manager(iface_type)
inst = mgr['no-%s' % iface_type].obj
self.assertEqual({}, inst.get_properties())
self.assertRaises(exception.UnsupportedDriverExtension,
inst.validate, self.task)

View File

@ -97,11 +97,26 @@ ironic.drivers =
pxe_iscsi_cimc = ironic.drivers.pxe:PXEAndCIMCDriver
pxe_agent_cimc = ironic.drivers.agent:AgentAndCIMCDriver
ironic.hardware.interfaces.console =
no-console = ironic.drivers.modules.noop:NoConsole
ironic.hardware.interfaces.inspect =
no-inspect = ironic.drivers.modules.noop:NoInspect
ironic.hardware.interfaces.network =
flat = ironic.drivers.modules.network.flat:FlatNetwork
noop = ironic.drivers.modules.network.noop:NoopNetwork
neutron = ironic.drivers.modules.network.neutron:NeutronNetwork
ironic.hardware.interfaces.raid =
no-raid = ironic.drivers.modules.noop:NoRAID
ironic.hardware.interfaces.rescue =
no-rescue = ironic.drivers.modules.noop:NoRescue
ironic.hardware.interfaces.vendor =
no-vendor = ironic.drivers.modules.noop:NoVendor
ironic.database.migration_backend =
sqlalchemy = ironic.db.sqlalchemy.migration