summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ironic/drivers/base.py86
-rw-r--r--ironic/tests/unit/drivers/test_base.py66
2 files changed, 146 insertions, 6 deletions
diff --git a/ironic/drivers/base.py b/ironic/drivers/base.py
index 513ba7113..44175fdba 100644
--- a/ironic/drivers/base.py
+++ b/ironic/drivers/base.py
@@ -38,6 +38,41 @@ LOG = logging.getLogger(__name__)
RAID_CONFIG_SCHEMA = os.path.join(os.path.dirname(__file__),
'raid_config_schema.json')
+RAID_APPLY_CONFIGURATION_ARGSINFO = {
+ "raid_config": {
+ "description": "The RAID configuration to apply.",
+ "required": True,
+ },
+ "create_root_volume": {
+ "description": (
+ "Setting this to 'False' indicates not to create root "
+ "volume that is specified in 'raid_config'. Default "
+ "value is 'True'."
+ ),
+ "required": False,
+ },
+ "create_nonroot_volumes": {
+ "description": (
+ "Setting this to 'False' indicates not to create "
+ "non-root volumes (all except the root volume) in "
+ "'raid_config'. Default value is 'True'."
+ ),
+ "required": False,
+ },
+ "delete_existing": {
+ "description": (
+ "Setting this to 'True' indicates to delete existing RAID "
+ "configuration prior to creating the new configuration. "
+ "Default value is 'True'."
+ ),
+ "required": False,
+ }
+}
+"""
+This may be used as the deploy_step argsinfo argument for RAID interfaces
+implementing an apply_configuration deploy step.
+"""
+
class BareDriver(object):
"""A bare driver object which will have interfaces attached later.
@@ -1120,10 +1155,47 @@ class RAIDInterface(BaseInterface):
"""
raid.validate_configuration(raid_config, self.raid_schema)
+ # NOTE(mgoddard): This is not marked as a deploy step, because it requires
+ # the create_configuration method to support use during deployment, which
+ # might not be true for all implementations. Subclasses wishing to expose
+ # an apply_configuration deploy step should implement this method with a
+ # deploy_step decorator. The RAID_APPLY_CONFIGURATION_ARGSINFO variable may
+ # be used for the deploy_step argsinfo argument. The create_configuration
+ # method must also accept a delete_existing argument.
+ def apply_configuration(self, task, raid_config, create_root_volume=True,
+ create_nonroot_volumes=True,
+ delete_existing=True):
+ """Applies RAID configuration on the given node.
+
+ :param task: A TaskManager instance.
+ :param raid_config: The RAID configuration to apply.
+ :param create_root_volume: Setting this to False indicates
+ not to create root volume that is specified in raid_config.
+ Default value is True.
+ :param create_nonroot_volumes: Setting this to False indicates
+ not to create non-root volumes (all except the root volume) in
+ raid_config. Default value is True.
+ :param delete_existing: Setting this to True indicates to delete RAID
+ configuration prior to creating the new configuration.
+ :raises: InvalidParameterValue, if the RAID configuration is invalid.
+ :returns: states.DEPLOYWAIT if RAID configuration is in progress
+ asynchronously or None if it is complete.
+ """
+ self.validate_raid_config(task, raid_config)
+ node = task.node
+ node.target_raid_config = raid_config
+ node.save()
+ return self.create_configuration(
+ task,
+ create_root_volume=create_root_volume,
+ create_nonroot_volumes=create_nonroot_volumes,
+ delete_existing=delete_existing)
+
@abc.abstractmethod
def create_configuration(self, task,
create_root_volume=True,
- create_nonroot_volumes=True):
+ create_nonroot_volumes=True,
+ delete_existing=True):
"""Creates RAID configuration on the given node.
This method creates a RAID configuration on the given node.
@@ -1143,8 +1215,11 @@ class RAIDInterface(BaseInterface):
:param create_nonroot_volumes: Setting this to False indicates
not to create non-root volumes (all except the root volume) in the
node's target_raid_config. Default value is True.
- :returns: states.CLEANWAIT if RAID configuration is in progress
- asynchronously or None if it is complete.
+ :param delete_existing: Setting this to True indicates to delete RAID
+ configuration prior to creating the new configuration.
+ :returns: states.CLEANWAIT (cleaning) or states.DEPLOYWAIT (deployment)
+ if RAID configuration is in progress asynchronously, or None if it
+ is complete.
"""
@abc.abstractmethod
@@ -1156,8 +1231,9 @@ class RAIDInterface(BaseInterface):
cleared by the implementation.
:param task: A TaskManager instance.
- :returns: states.CLEANWAIT if deletion is in progress
- asynchronously or None if it is complete.
+ :returns: states.CLEANWAIT (cleaning) or states.DEPLOYWAIT (deployment)
+ if deletion is in progress asynchronously, or None if it is
+ complete.
"""
def get_logical_disk_properties(self):
diff --git a/ironic/tests/unit/drivers/test_base.py b/ironic/tests/unit/drivers/test_base.py
index 786178403..1cf00fc10 100644
--- a/ironic/tests/unit/drivers/test_base.py
+++ b/ironic/tests/unit/drivers/test_base.py
@@ -19,6 +19,7 @@ import mock
from ironic.common import exception
from ironic.common import raid
+from ironic.common import states
from ironic.drivers import base as driver_base
from ironic.drivers.modules import fake
from ironic.tests import base
@@ -574,7 +575,8 @@ class MyRAIDInterface(driver_base.RAIDInterface):
def create_configuration(self, task,
create_root_volume=True,
- create_nonroot_volumes=True):
+ create_nonroot_volumes=True,
+ delete_existing=True):
pass
def delete_configuration(self, task):
@@ -626,6 +628,68 @@ class RAIDInterfaceTestCase(base.TestCase):
raid_interface.get_logical_disk_properties()
get_properties_mock.assert_called_once_with(raid_schema)
+ @mock.patch.object(MyRAIDInterface, 'create_configuration', autospec=True)
+ @mock.patch.object(MyRAIDInterface, 'validate_raid_config',
+ autospec=True)
+ def test_apply_configuration(self, mock_validate, mock_create):
+ raid_interface = MyRAIDInterface()
+ node_mock = mock.MagicMock(target_raid_config=None)
+ task_mock = mock.MagicMock(node=node_mock)
+ mock_create.return_value = states.DEPLOYWAIT
+ raid_config = 'some_raid_config'
+
+ result = raid_interface.apply_configuration(task_mock, raid_config)
+
+ self.assertEqual(states.DEPLOYWAIT, result)
+ mock_validate.assert_called_once_with(raid_interface, task_mock,
+ raid_config)
+ mock_create.assert_called_once_with(raid_interface, task_mock,
+ create_root_volume=True,
+ create_nonroot_volumes=True,
+ delete_existing=True)
+ self.assertEqual(raid_config, node_mock.target_raid_config)
+
+ @mock.patch.object(MyRAIDInterface, 'create_configuration', autospec=True)
+ @mock.patch.object(MyRAIDInterface, 'validate_raid_config',
+ autospec=True)
+ def test_apply_configuration_delete_existing(self, mock_validate,
+ mock_create):
+ raid_interface = MyRAIDInterface()
+ node_mock = mock.MagicMock(target_raid_config=None)
+ task_mock = mock.MagicMock(node=node_mock)
+ mock_create.return_value = states.DEPLOYWAIT
+ raid_config = 'some_raid_config'
+
+ result = raid_interface.apply_configuration(task_mock, raid_config,
+ delete_existing=True)
+
+ self.assertEqual(states.DEPLOYWAIT, result)
+ mock_validate.assert_called_once_with(raid_interface, task_mock,
+ raid_config)
+ mock_create.assert_called_once_with(raid_interface, task_mock,
+ create_root_volume=True,
+ create_nonroot_volumes=True,
+ delete_existing=True)
+ self.assertEqual(raid_config, node_mock.target_raid_config)
+
+ @mock.patch.object(MyRAIDInterface, 'create_configuration', autospec=True)
+ @mock.patch.object(MyRAIDInterface, 'validate_raid_config',
+ autospec=True)
+ def test_apply_configuration_invalid(self, mock_validate, mock_create):
+ raid_interface = MyRAIDInterface()
+ node_mock = mock.MagicMock(target_raid_config=None)
+ task_mock = mock.MagicMock(node=node_mock)
+ mock_validate.side_effect = exception.InvalidParameterValue('bad')
+ raid_config = 'some_raid_config'
+
+ self.assertRaises(exception.InvalidParameterValue,
+ raid_interface.apply_configuration, task_mock,
+ raid_config)
+ mock_validate.assert_called_once_with(raid_interface, task_mock,
+ raid_config)
+ self.assertFalse(mock_create.called)
+ self.assertIsNone(node_mock.target_raid_config)
+
class TestDeployInterface(base.TestCase):
@mock.patch.object(driver_base.LOG, 'warning', autospec=True)