Merge "Add ManagementInterface"

This commit is contained in:
Jenkins 2014-04-30 03:33:45 +00:00 committed by Gerrit Code Review
commit 6be126ec98
6 changed files with 160 additions and 14 deletions

View 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"

View File

@ -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.
"""

View File

@ -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):

View File

@ -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

View File

@ -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)

View File

@ -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))