Implement check ironic boot configuration as a custom action
Add a custom action and workflow for checking the configuration of the available Ironic nodes. Change-Id: I74d1c242d0d06c5aff8f6d3533399745d6d8d9f3 Partial-Bug: #1638697
This commit is contained in:
parent
c33b81aa31
commit
f6f1ac9838
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
features:
|
||||
- Adds an action and workflow used to check the ironic boot
|
||||
configuration.
|
|
@ -97,6 +97,7 @@ mistral.actions =
|
|||
tripleo.templates.upload = tripleo_common.actions.templates:UploadTemplatesAction
|
||||
tripleo.validations.check_boot_images = tripleo_common.actions.validations:CheckBootImagesAction
|
||||
tripleo.validations.check_flavors = tripleo_common.actions.validations:CheckFlavorsAction
|
||||
tripleo.validations.check_node_boot_configuration = tripleo_common.actions.validations:CheckNodeBootConfigurationAction
|
||||
tripleo.validations.get_pubkey = tripleo_common.actions.validations:GetPubkeyAction
|
||||
tripleo.validations.enabled = tripleo_common.actions.validations:Enabled
|
||||
tripleo.validations.list_groups = tripleo_common.actions.validations:ListGroupsAction
|
||||
|
|
|
@ -18,6 +18,7 @@ from oslo_concurrency.processutils import ProcessExecutionError
|
|||
|
||||
from tripleo_common.actions import base
|
||||
from tripleo_common import constants
|
||||
from tripleo_common.utils import nodes as nodeutils
|
||||
from tripleo_common.utils import passwords as password_utils
|
||||
from tripleo_common.utils import validations as utils
|
||||
|
||||
|
@ -240,3 +241,57 @@ class CheckFlavorsAction(base.TripleOAction):
|
|||
mistral_result = {'data': return_value}
|
||||
|
||||
return mistral_workflow_utils.Result(**mistral_result)
|
||||
|
||||
|
||||
class CheckNodeBootConfigurationAction(base.TripleOAction):
|
||||
"""Check the boot configuration of the baremetal nodes"""
|
||||
|
||||
# TODO(bcrochet): The validation actions are temporary. This logic should
|
||||
# move to the tripleo-validations project eventually.
|
||||
def __init__(self, node, kernel_id, ramdisk_id):
|
||||
super(CheckNodeBootConfigurationAction, self).__init__()
|
||||
|
||||
self.node = node
|
||||
self.kernel_id = kernel_id
|
||||
self.ramdisk_id = ramdisk_id
|
||||
|
||||
def run(self):
|
||||
warnings = []
|
||||
errors = []
|
||||
message = ("Node {uuid} has an incorrectly configured "
|
||||
"{property}. Expected \"{expected}\" but got "
|
||||
"\"{actual}\".")
|
||||
if self.node['driver_info'].get('deploy_ramdisk') != self.ramdisk_id:
|
||||
errors.append(message.format(
|
||||
uuid=self.node['uuid'],
|
||||
property='driver_info/deploy_ramdisk',
|
||||
expected=self.ramdisk_id,
|
||||
actual=self.node['driver_info'].get('deploy_ramdisk')
|
||||
))
|
||||
if self.node['driver_info'].get('deploy_kernel') != self.kernel_id:
|
||||
errors.append(message.format(
|
||||
uuid=self.node['uuid'],
|
||||
property='driver_info/deploy_kernel',
|
||||
expected=self.kernel_id,
|
||||
actual=self.node['driver_info'].get('deploy_kernel')
|
||||
))
|
||||
capabilities = nodeutils.capabilities_to_dict(
|
||||
self.node['properties'].get('capabilities', ''))
|
||||
if capabilities.get('boot_option') != 'local':
|
||||
boot_option_message = ("Node {uuid} is not configured to use "
|
||||
"boot_option:local in capabilities. It "
|
||||
"will not be used for deployment with "
|
||||
"flavors that require boot_option:local.")
|
||||
|
||||
warnings.append(boot_option_message.format(uuid=self.node['uuid']))
|
||||
|
||||
return_value = {
|
||||
'errors': errors,
|
||||
'warnings': warnings
|
||||
}
|
||||
if errors:
|
||||
mistral_result = {'error': return_value}
|
||||
else:
|
||||
mistral_result = {'data': return_value}
|
||||
|
||||
return mistral_workflow_utils.Result(**mistral_result)
|
||||
|
|
|
@ -380,3 +380,78 @@ class TestCheckFlavorsAction(base.TestCase):
|
|||
}
|
||||
action = validations.CheckFlavorsAction(**action_args)
|
||||
self.assertEqual(expected, action.run())
|
||||
|
||||
|
||||
class TestCheckNodeBootConfigurationAction(base.TestCase):
|
||||
def setUp(self):
|
||||
super(TestCheckNodeBootConfigurationAction, self).setUp()
|
||||
self.kernel_id = '12345'
|
||||
self.ramdisk_id = '67890'
|
||||
self.node = {
|
||||
'uuid': '100f2cf6-06de-480e-a73e-6fdf6c9962b7',
|
||||
'driver_info': {
|
||||
'deploy_kernel': '12345',
|
||||
'deploy_ramdisk': '67890',
|
||||
},
|
||||
'properties': {
|
||||
'capabilities': 'boot_option:local',
|
||||
}
|
||||
}
|
||||
|
||||
def test_run_success(self):
|
||||
expected = mistral_workflow_utils.Result(
|
||||
data={'errors': [], 'warnings': []}
|
||||
)
|
||||
|
||||
action_args = {
|
||||
'node': self.node,
|
||||
'kernel_id': self.kernel_id,
|
||||
'ramdisk_id': self.ramdisk_id,
|
||||
}
|
||||
action = validations.CheckNodeBootConfigurationAction(**action_args)
|
||||
self.assertEqual(expected, action.run())
|
||||
|
||||
def test_run_invalid_ramdisk(self):
|
||||
expected = mistral_workflow_utils.Result(
|
||||
error={
|
||||
'errors': [
|
||||
'Node 100f2cf6-06de-480e-a73e-6fdf6c9962b7 has an '
|
||||
'incorrectly configured driver_info/deploy_ramdisk. '
|
||||
'Expected "67890" but got "98760".'
|
||||
],
|
||||
'warnings': []})
|
||||
|
||||
node = self.node.copy()
|
||||
node['driver_info']['deploy_ramdisk'] = '98760'
|
||||
action_args = {
|
||||
'node': node,
|
||||
'kernel_id': self.kernel_id,
|
||||
'ramdisk_id': self.ramdisk_id,
|
||||
}
|
||||
action = validations.CheckNodeBootConfigurationAction(**action_args)
|
||||
self.assertEqual(expected, action.run())
|
||||
|
||||
def test_no_boot_option_local(self):
|
||||
expected = mistral_workflow_utils.Result(
|
||||
data={
|
||||
'errors': [],
|
||||
'warnings': [
|
||||
'Node 100f2cf6-06de-480e-a73e-6fdf6c9962b7 is not '
|
||||
'configured to use boot_option:local in capabilities. '
|
||||
'It will not be used for deployment with flavors that '
|
||||
'require boot_option:local.'
|
||||
]
|
||||
}
|
||||
)
|
||||
|
||||
node = self.node.copy()
|
||||
node['properties']['capabilities'] = 'boot_option:not_local'
|
||||
|
||||
action_args = {
|
||||
'node': node,
|
||||
'kernel_id': self.kernel_id,
|
||||
'ramdisk_id': self.ramdisk_id,
|
||||
}
|
||||
|
||||
action = validations.CheckNodeBootConfigurationAction(**action_args)
|
||||
self.assertEqual(expected, action.run())
|
||||
|
|
|
@ -378,3 +378,74 @@ workflows:
|
|||
warnings: <% $.warnings %>
|
||||
on-success:
|
||||
- fail: <% $.get('status') = "FAILED" %>
|
||||
|
||||
check_ironic_boot_configuration:
|
||||
input:
|
||||
- kernel_id: null
|
||||
- ramdisk_id: null
|
||||
- run_validations: true
|
||||
- queue_name: tripleo
|
||||
output:
|
||||
errors: <% $.errors %>
|
||||
warnings: <% $.warnings %>
|
||||
|
||||
tasks:
|
||||
check_run_validations:
|
||||
on-complete:
|
||||
- get_ironic_nodes: <% $.run_validations %>
|
||||
- send_message: <% not $.run_validations %>
|
||||
|
||||
get_ironic_nodes:
|
||||
action: ironic.node_list
|
||||
on-success: check_node_boot_configuration
|
||||
on-error: failed_get_ironic_nodes
|
||||
input:
|
||||
maintenance: false
|
||||
detail: true
|
||||
publish:
|
||||
nodes: <% task(get_ironic_nodes).result %>
|
||||
|
||||
failed_get_ironic_nodes:
|
||||
on-success: send_message
|
||||
publish:
|
||||
status: FAILED
|
||||
message: <% task(get_ironic_nodes).result %>
|
||||
|
||||
check_node_boot_configuration:
|
||||
action: tripleo.validations.check_node_boot_configuration
|
||||
input:
|
||||
node: <% $.node %>
|
||||
kernel_id: <% $.kernel_id %>
|
||||
ramdisk_id: <% $.ramdisk_id %>
|
||||
with-items: node in <% $.nodes %>
|
||||
on-success: send_message
|
||||
on-error: fail_check_node_boot_configuration
|
||||
publish:
|
||||
errors: <% task(check_node_boot_configuration).result.errors.flatten() %>
|
||||
warnings: <% task(check_node_boot_configuration).result.warnings.flatten() %>
|
||||
publish-on-error:
|
||||
errors: <% task(check_node_boot_configuration).result.errors.flatten() %>
|
||||
warnings: <% task(check_node_boot_configuration).result.warnings.flatten() %>
|
||||
|
||||
fail_check_node_boot_configuration:
|
||||
on-success: send_message
|
||||
publish:
|
||||
status: FAILED
|
||||
message: <% task(check_node_boot_configuration).result %>
|
||||
|
||||
send_message:
|
||||
action: zaqar.queue_post
|
||||
retry: count=5 delay=1
|
||||
input:
|
||||
queue_name: <% $.queue_name %>
|
||||
messages:
|
||||
body:
|
||||
type: tripleo.validations.v1.check_ironic_boot_configuration
|
||||
payload:
|
||||
status: <% $.get('status', 'SUCCESS') %>
|
||||
message: <% $.get('message', '') %>
|
||||
execution: <% execution() %>
|
||||
errors: <% $.errors %>
|
||||
warnings: <% $.warnings %>
|
||||
on-success:
|
||||
- fail: <% $.get('status') = "FAILED" %>
|
||||
|
|
Loading…
Reference in New Issue