Merge "Add ManagementInterface"
This commit is contained in:
commit
6be126ec98
42
ironic/common/boot_devices.py
Normal file
42
ironic/common/boot_devices.py
Normal file
@ -0,0 +1,42 @@
|
||||
# Copyright 2014 Red Hat, Inc.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
|
||||
"""
|
||||
Mapping of boot devices used when requesting the system to boot
|
||||
from an alternate device.
|
||||
|
||||
The options presented were based on the IPMItool chassis
|
||||
bootdev command. You can find the documentation at:
|
||||
http://linux.die.net/man/1/ipmitool
|
||||
|
||||
NOTE: This module does not include all the options from ipmitool because
|
||||
they don't make sense in the limited context of Ironic right now.
|
||||
"""
|
||||
|
||||
PXE = 'pxe'
|
||||
"Boot from PXE boot"
|
||||
|
||||
DISK = 'disk'
|
||||
"Boot from default Hard-drive"
|
||||
|
||||
CDROM = 'cdrom'
|
||||
"Boot from CD/DVD"
|
||||
|
||||
BIOS = 'bios'
|
||||
"Boot into BIOS setup"
|
||||
|
||||
SAFE = 'safe'
|
||||
"Boot from default Hard-drive, request Safe Mode"
|
@ -69,6 +69,14 @@ class BaseDriver(object):
|
||||
May be None, if unsupported by a driver.
|
||||
"""
|
||||
|
||||
management = None
|
||||
"""`Standard` attribute for management related features.
|
||||
|
||||
A reference to an instance of :class:ManagementInterface.
|
||||
May be None, if unsupported by a driver.
|
||||
"""
|
||||
standard_interfaces.append('management')
|
||||
|
||||
vendor = None
|
||||
"""Attribute for accessing any vendor-specific extensions.
|
||||
|
||||
@ -348,3 +356,55 @@ class VendorInterface(object):
|
||||
raise exception.UnsupportedDriverExtension(
|
||||
_('Vendor interface does not support driver vendor_passthru '
|
||||
'method: %s') % method)
|
||||
|
||||
|
||||
@six.add_metaclass(abc.ABCMeta)
|
||||
class ManagementInterface(object):
|
||||
"""Interface for management related actions."""
|
||||
|
||||
# TODO(lucasagomes): The 'node' parameter
|
||||
# needs to be passed to validate() because of the
|
||||
# ConductorManager.validate_driver_interfaces(). Remove it as part of
|
||||
# https://bugs.launchpad.net/ironic/+bug/1312632.
|
||||
@abc.abstractmethod
|
||||
def validate(self, task, node):
|
||||
"""Validate the driver-specific management information.
|
||||
|
||||
:param task: a task from TaskManager.
|
||||
:param node: a single Node to validate.
|
||||
:raises: InvalidParameterValue
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_supported_boot_devices(self):
|
||||
"""Get a list of the supported boot devices.
|
||||
|
||||
:returns: A list with the supported boot devices defined
|
||||
in :mod:`ironic.common.boot_devices`.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def set_boot_device(self, task, device, **kwargs):
|
||||
"""Set the boot device for a node.
|
||||
|
||||
Set the boot device to use on next reboot of the node.
|
||||
|
||||
:param task: a task from TaskManager.
|
||||
:param device: the boot device, one of
|
||||
:mod:`ironic.common.boot_devices`.
|
||||
:param kwargs: extra driver-specific parameters.
|
||||
:raises: InvalidParameterValue if an invalid boot device is
|
||||
specified.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_boot_device(self, task):
|
||||
"""Get the current boot device for a node.
|
||||
|
||||
Provides the current boot device of the node. Be aware that not
|
||||
all drivers support this.
|
||||
|
||||
:param task: a task from TaskManager.
|
||||
:returns: the boot device, one of :mod:`ironic.common.boot_devices`
|
||||
or None if it is unknown.
|
||||
"""
|
||||
|
@ -42,6 +42,7 @@ class FakeDriver(base.BaseDriver):
|
||||
'second_method': self.b}
|
||||
self.vendor = utils.MixinVendorInterface(self.mapping)
|
||||
self.console = fake.FakeConsole()
|
||||
self.management = fake.FakeManagement()
|
||||
|
||||
|
||||
class FakeIPMIToolDriver(base.BaseDriver):
|
||||
|
@ -24,6 +24,7 @@ functionality between a power interface and a deploy interface, when both rely
|
||||
on seprate vendor_passthru methods.
|
||||
"""
|
||||
|
||||
from ironic.common import boot_devices
|
||||
from ironic.common import exception
|
||||
from ironic.common import states
|
||||
from ironic.drivers import base
|
||||
@ -143,3 +144,21 @@ class FakeConsole(base.ConsoleInterface):
|
||||
|
||||
def get_console(self, task, node):
|
||||
return {}
|
||||
|
||||
|
||||
class FakeManagement(base.ManagementInterface):
|
||||
"""Example implementation of a simple management interface."""
|
||||
|
||||
def validate(self, task, node):
|
||||
return True
|
||||
|
||||
def get_supported_boot_devices(self):
|
||||
return [boot_devices.PXE]
|
||||
|
||||
def set_boot_device(self, task, device, **kwargs):
|
||||
if device not in self.get_supported_boot_devices():
|
||||
raise exception.InvalidParameterValue(_(
|
||||
"Invalid boot device %s specified.") % device)
|
||||
|
||||
def get_boot_device(self, task):
|
||||
return boot_devices.PXE
|
||||
|
@ -752,6 +752,7 @@ class ManagerTestCase(tests_db_base.DbTestCase):
|
||||
node['uuid'])
|
||||
expected = {'console': {'result': True},
|
||||
'power': {'result': True},
|
||||
'management': {'result': True},
|
||||
'deploy': {'result': True}}
|
||||
self.assertEqual(expected, ret)
|
||||
|
||||
|
@ -17,16 +17,18 @@
|
||||
|
||||
"""Test class for Fake driver."""
|
||||
|
||||
import mock
|
||||
|
||||
from ironic.common import boot_devices
|
||||
from ironic.common import driver_factory
|
||||
from ironic.common import exception
|
||||
from ironic.common import states
|
||||
from ironic.conductor import task_manager
|
||||
from ironic.db import api as db_api
|
||||
from ironic.drivers import base as driver_base
|
||||
from ironic.openstack.common import context
|
||||
from ironic.tests import base
|
||||
from ironic.tests.conductor import utils as mgr_utils
|
||||
from ironic.tests.db import utils as db_utils
|
||||
from ironic.tests.objects import utils as obj_utils
|
||||
|
||||
|
||||
class FakeDriverTestCase(base.TestCase):
|
||||
@ -34,11 +36,13 @@ class FakeDriverTestCase(base.TestCase):
|
||||
def setUp(self):
|
||||
super(FakeDriverTestCase, self).setUp()
|
||||
self.context = context.get_admin_context()
|
||||
self.dbapi = db_api.get_instance()
|
||||
mgr_utils.mock_the_extension_manager()
|
||||
self.driver = driver_factory.get_driver("fake")
|
||||
db_node = db_utils.get_test_node()
|
||||
self.node = self.dbapi.create_node(db_node)
|
||||
self.node = obj_utils.get_test_node(self.context)
|
||||
self.task = mock.Mock(spec=task_manager.TaskManager)
|
||||
self.task.shared = False
|
||||
self.task.node = self.node
|
||||
self.task.driver = self.driver
|
||||
|
||||
def test_driver_interfaces(self):
|
||||
# fake driver implements only 3 out of 5 interfaces
|
||||
@ -50,15 +54,14 @@ class FakeDriverTestCase(base.TestCase):
|
||||
self.assertIsNone(self.driver.rescue)
|
||||
|
||||
def test_power_interface(self):
|
||||
with task_manager.acquire(self.context,
|
||||
[self.node.uuid]) as task:
|
||||
self.driver.power.validate(task, self.node)
|
||||
self.driver.power.get_power_state(task, self.node)
|
||||
self.assertRaises(exception.InvalidParameterValue,
|
||||
self.driver.power.set_power_state,
|
||||
task, self.node, states.NOSTATE)
|
||||
self.driver.power.set_power_state(task, self.node, states.POWER_ON)
|
||||
self.driver.power.reboot(task, self.node)
|
||||
self.driver.power.validate(self.task, self.node)
|
||||
self.driver.power.get_power_state(self.task, self.node)
|
||||
self.assertRaises(exception.InvalidParameterValue,
|
||||
self.driver.power.set_power_state,
|
||||
self.task, self.node, states.NOSTATE)
|
||||
self.driver.power.set_power_state(self.task, self.node,
|
||||
states.POWER_ON)
|
||||
self.driver.power.reboot(self.task, self.node)
|
||||
|
||||
def test_deploy_interface(self):
|
||||
self.driver.deploy.validate(None, self.node)
|
||||
@ -70,3 +73,23 @@ class FakeDriverTestCase(base.TestCase):
|
||||
|
||||
self.driver.deploy.clean_up(None, None)
|
||||
self.driver.deploy.tear_down(None, None)
|
||||
|
||||
def test_management_interface_validate(self):
|
||||
self.driver.management.validate(self.task, self.node)
|
||||
|
||||
def test_management_interface_set_boot_device_good(self):
|
||||
self.driver.management.set_boot_device(self.task, boot_devices.PXE)
|
||||
|
||||
def test_management_interface_set_boot_device_fail(self):
|
||||
self.assertRaises(exception.InvalidParameterValue,
|
||||
self.driver.management.set_boot_device, self.task,
|
||||
'not-supported')
|
||||
|
||||
def test_management_interface_get_supported_boot_devices(self):
|
||||
expected = [boot_devices.PXE]
|
||||
self.assertEqual(expected,
|
||||
self.driver.management.get_supported_boot_devices())
|
||||
|
||||
def test_management_interface_get_boot_device(self):
|
||||
self.assertEqual(boot_devices.PXE,
|
||||
self.driver.management.get_boot_device(self.task))
|
||||
|
Loading…
Reference in New Issue
Block a user