Add raid.apply_configuration deploy step
For compatibility with out-of-band RAID deploy steps, we need to have one apply_configuration step, not a create/delete pair. Change-Id: I55bbed96673c9fa247cafdac9a3ade3a6ff3f38d Story: #2006963
This commit is contained in:
parent
6035771676
commit
c0502649ba
ironic_python_agent
@ -70,6 +70,8 @@ class DeployExtension(base.BaseAgentExtension):
|
|||||||
msg = 'Malformed deploy_step, no "step" key: %s' % step
|
msg = 'Malformed deploy_step, no "step" key: %s' % step
|
||||||
LOG.error(msg)
|
LOG.error(msg)
|
||||||
raise ValueError(msg)
|
raise ValueError(msg)
|
||||||
|
|
||||||
|
kwargs.update(step.get('args') or {})
|
||||||
try:
|
try:
|
||||||
result = hardware.dispatch_to_managers(step['step'], node, ports,
|
result = hardware.dispatch_to_managers(step['step'], node, ports,
|
||||||
**kwargs)
|
**kwargs)
|
||||||
|
@ -55,6 +55,21 @@ NODE = None
|
|||||||
|
|
||||||
SUPPORTED_SOFTWARE_RAID_LEVELS = frozenset(['0', '1', '1+0', '5', '6'])
|
SUPPORTED_SOFTWARE_RAID_LEVELS = frozenset(['0', '1', '1+0', '5', '6'])
|
||||||
|
|
||||||
|
RAID_APPLY_CONFIGURATION_ARGSINFO = {
|
||||||
|
"raid_config": {
|
||||||
|
"description": "The RAID configuration to apply.",
|
||||||
|
"required": True,
|
||||||
|
},
|
||||||
|
"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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def _get_device_info(dev, devclass, field):
|
def _get_device_info(dev, devclass, field):
|
||||||
"""Get the device info according to device class and field."""
|
"""Get the device info according to device class and field."""
|
||||||
@ -738,6 +753,7 @@ class HardwareManager(object, metaclass=abc.ABCMeta):
|
|||||||
'reboot_requested': Whether the agent should request Ironic reboots
|
'reboot_requested': Whether the agent should request Ironic reboots
|
||||||
the node via the power driver after the
|
the node via the power driver after the
|
||||||
operation completes.
|
operation completes.
|
||||||
|
'argsinfo': arguments specification.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1537,19 +1553,29 @@ class GenericHardwareManager(HardwareManager):
|
|||||||
def get_deploy_steps(self, node, ports):
|
def get_deploy_steps(self, node, ports):
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
'step': 'delete_configuration',
|
'step': 'apply_configuration',
|
||||||
'priority': 0,
|
|
||||||
'interface': 'raid',
|
|
||||||
'reboot_requested': False,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'step': 'create_configuration',
|
|
||||||
'priority': 0,
|
'priority': 0,
|
||||||
'interface': 'raid',
|
'interface': 'raid',
|
||||||
'reboot_requested': False,
|
'reboot_requested': False,
|
||||||
|
'argsinfo': RAID_APPLY_CONFIGURATION_ARGSINFO,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
def apply_configuration(self, node, ports, raid_config,
|
||||||
|
delete_existing=True):
|
||||||
|
"""Apply RAID configuration.
|
||||||
|
|
||||||
|
:param node: A dictionary of the node object.
|
||||||
|
:param ports: A list of dictionaries containing information
|
||||||
|
of ports for the node.
|
||||||
|
:param raid_config: The configuration to apply.
|
||||||
|
:param delete_existing: Whether to delete the existing configuration.
|
||||||
|
"""
|
||||||
|
self.validate_configuration(raid_config, node)
|
||||||
|
if delete_existing:
|
||||||
|
self.delete_configuration(node, ports)
|
||||||
|
self._do_create_configuration(node, ports, raid_config)
|
||||||
|
|
||||||
def create_configuration(self, node, ports):
|
def create_configuration(self, node, ports):
|
||||||
"""Create a RAID configuration.
|
"""Create a RAID configuration.
|
||||||
|
|
||||||
@ -1565,18 +1591,20 @@ class GenericHardwareManager(HardwareManager):
|
|||||||
valid or if there was an error when creating the RAID
|
valid or if there was an error when creating the RAID
|
||||||
devices.
|
devices.
|
||||||
"""
|
"""
|
||||||
|
raid_config = node.get('target_raid_config', {})
|
||||||
|
if not raid_config:
|
||||||
|
LOG.debug("No target_raid_config found")
|
||||||
|
return {}
|
||||||
|
|
||||||
|
return self._do_create_configuration(node, ports, raid_config)
|
||||||
|
|
||||||
|
def _do_create_configuration(self, node, ports, raid_config):
|
||||||
# incr starts to 1
|
# incr starts to 1
|
||||||
# It means md0 is on the partition 1, md1 on 2...
|
# It means md0 is on the partition 1, md1 on 2...
|
||||||
# incr could be incremented if we ever decide, for example to create
|
# incr could be incremented if we ever decide, for example to create
|
||||||
# some additional partitions here (boot partitions)
|
# some additional partitions here (boot partitions)
|
||||||
incr = 1
|
incr = 1
|
||||||
|
|
||||||
raid_config = node.get('target_raid_config', {})
|
|
||||||
if not raid_config:
|
|
||||||
LOG.debug("No target_raid_config found")
|
|
||||||
return {}
|
|
||||||
|
|
||||||
# No 'software' controller: do nothing. If 'controller' is
|
# No 'software' controller: do nothing. If 'controller' is
|
||||||
# set to 'software' on only one of the drives, the validation
|
# set to 'software' on only one of the drives, the validation
|
||||||
# code will catch it.
|
# code will catch it.
|
||||||
|
@ -163,6 +163,34 @@ class TestDeployExtension(base.IronicAgentTest):
|
|||||||
self.assertEqual(expected_result, async_result.command_result)
|
self.assertEqual(expected_result, async_result.command_result)
|
||||||
mock_cache_node.assert_called_once_with(self.node)
|
mock_cache_node.assert_called_once_with(self.node)
|
||||||
|
|
||||||
|
@mock.patch('ironic_python_agent.hardware.dispatch_to_managers',
|
||||||
|
autospec=True)
|
||||||
|
@mock.patch('ironic_python_agent.hardware.check_versions',
|
||||||
|
autospec=True)
|
||||||
|
def test_execute_deploy_step_with_args(self, mock_version, mock_dispatch,
|
||||||
|
mock_cache_node):
|
||||||
|
result = 'deployed'
|
||||||
|
mock_dispatch.return_value = result
|
||||||
|
|
||||||
|
step = self.step['GenericHardwareManager'][0]
|
||||||
|
step['args'] = {'foo': 'bar'}
|
||||||
|
expected_result = {
|
||||||
|
'deploy_step': step,
|
||||||
|
'deploy_result': result
|
||||||
|
}
|
||||||
|
async_result = self.agent_extension.execute_deploy_step(
|
||||||
|
step=self.step['GenericHardwareManager'][0],
|
||||||
|
node=self.node, ports=self.ports,
|
||||||
|
deploy_version=self.version)
|
||||||
|
async_result.join()
|
||||||
|
|
||||||
|
mock_version.assert_called_once_with(self.version)
|
||||||
|
mock_dispatch.assert_called_once_with(
|
||||||
|
self.step['GenericHardwareManager'][0]['step'],
|
||||||
|
self.node, self.ports, foo='bar')
|
||||||
|
self.assertEqual(expected_result, async_result.command_result)
|
||||||
|
mock_cache_node.assert_called_once_with(self.node)
|
||||||
|
|
||||||
@mock.patch('ironic_python_agent.hardware.dispatch_to_managers',
|
@mock.patch('ironic_python_agent.hardware.dispatch_to_managers',
|
||||||
autospec=True)
|
autospec=True)
|
||||||
@mock.patch('ironic_python_agent.hardware.check_versions',
|
@mock.patch('ironic_python_agent.hardware.check_versions',
|
||||||
|
Loading…
x
Reference in New Issue
Block a user