Implement check flavors as a custom action
Adds a custom action to check the flavors passed against the defined flavors. Change-Id: Ia0751ec4c63692ceda97d3845edcde1c26f9a3a8 Partial-Bug: #1638697
This commit is contained in:
parent
bc99748ff0
commit
c33b81aa31
@ -0,0 +1,4 @@
|
||||
---
|
||||
features:
|
||||
- Adds an action and workflow used to check the status of
|
||||
the defined and passed flavors in Nova.
|
@ -96,6 +96,7 @@ mistral.actions =
|
||||
tripleo.templates.process = tripleo_common.actions.templates:ProcessTemplatesAction
|
||||
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.get_pubkey = tripleo_common.actions.validations:GetPubkeyAction
|
||||
tripleo.validations.enabled = tripleo_common.actions.validations:Enabled
|
||||
tripleo.validations.list_groups = tripleo_common.actions.validations:ListGroupsAction
|
||||
|
@ -173,3 +173,70 @@ class CheckBootImagesAction(base.TripleOAction):
|
||||
image_id = found_images[0]
|
||||
|
||||
return image_id
|
||||
|
||||
|
||||
class CheckFlavorsAction(base.TripleOAction):
|
||||
"""Validate and collect nova flavors in use.
|
||||
|
||||
Ensure that selected flavors (--ROLE-flavor) are valid in nova.
|
||||
Issue a warning if local boot is not set for a flavor.
|
||||
"""
|
||||
|
||||
# TODO(bcrochet): The validation actions are temporary. This logic should
|
||||
# move to the tripleo-validations project eventually.
|
||||
def __init__(self, flavors, roles_info):
|
||||
super(CheckFlavorsAction, self).__init__()
|
||||
self.flavors = flavors
|
||||
self.roles_info = roles_info
|
||||
|
||||
def run(self):
|
||||
"""Validate and collect nova flavors in use.
|
||||
|
||||
Ensure that selected flavors (--ROLE-flavor) are valid in nova.
|
||||
Issue a warning if local boot is not set for a flavor.
|
||||
|
||||
:returns: dictionary flavor name -> (flavor object, scale)
|
||||
"""
|
||||
flavors = {f['name']: f for f in self.flavors}
|
||||
result = {}
|
||||
warnings = []
|
||||
errors = []
|
||||
|
||||
message = "Flavor '{1}' provided for the role '{0}', does not exist"
|
||||
|
||||
for target, (flavor_name, scale) in self.roles_info.items():
|
||||
if flavor_name is None or not scale:
|
||||
continue
|
||||
|
||||
old_flavor_name, old_scale = result.get(flavor_name, (None, None))
|
||||
|
||||
if old_flavor_name:
|
||||
result[flavor_name] = (old_flavor_name, old_scale + scale)
|
||||
else:
|
||||
flavor = flavors.get(flavor_name)
|
||||
|
||||
if flavor:
|
||||
if flavor.get('capabilities:boot_option', '') == 'netboot':
|
||||
warnings.append(
|
||||
'Flavor %s "capabilities:boot_option" is set to '
|
||||
'"netboot". Nodes will PXE boot from the ironic '
|
||||
'conductor instead of using a local bootloader. '
|
||||
'Make sure that enough nodes are marked with the '
|
||||
'"boot_option" capability set to "netboot".'
|
||||
% flavor_name)
|
||||
|
||||
result[flavor_name] = (flavor, scale)
|
||||
else:
|
||||
errors.append(message.format(target, flavor_name))
|
||||
|
||||
return_value = {
|
||||
'flavors': result,
|
||||
'errors': errors,
|
||||
'warnings': warnings,
|
||||
}
|
||||
if errors:
|
||||
mistral_result = {'error': return_value}
|
||||
else:
|
||||
mistral_result = {'data': return_value}
|
||||
|
||||
return mistral_workflow_utils.Result(**mistral_result)
|
||||
|
@ -283,3 +283,100 @@ class TestCheckBootImagesAction(base.TestCase):
|
||||
expected, action._check_for_image(deploy_ramdisk_name, messages))
|
||||
self.assertEqual(1, len(messages))
|
||||
self.assertIn(expected_message, messages)
|
||||
|
||||
|
||||
class TestCheckFlavorsAction(base.TestCase):
|
||||
def setUp(self):
|
||||
super(TestCheckFlavorsAction, self).setUp()
|
||||
self.flavors = [
|
||||
{'name': 'flavor1', 'capabilities:boot_option': 'local'},
|
||||
{'name': 'flavor2', 'capabilities:boot_option': 'netboot'},
|
||||
{'name': 'flavor3'}
|
||||
]
|
||||
|
||||
def test_run_success(self):
|
||||
roles_info = {
|
||||
'role1': ('flavor1', 1),
|
||||
}
|
||||
|
||||
expected = mistral_workflow_utils.Result(
|
||||
data={
|
||||
'flavors': {
|
||||
'flavor1': (
|
||||
{
|
||||
'name': 'flavor1',
|
||||
'capabilities:boot_option': 'local'
|
||||
}, 1)
|
||||
},
|
||||
'warnings': [],
|
||||
'errors': [],
|
||||
}
|
||||
)
|
||||
|
||||
action_args = {
|
||||
'flavors': self.flavors,
|
||||
'roles_info': roles_info
|
||||
}
|
||||
action = validations.CheckFlavorsAction(**action_args)
|
||||
self.assertEqual(expected, action.run())
|
||||
|
||||
def test_run_boot_option_is_netboot(self):
|
||||
roles_info = {
|
||||
'role2': ('flavor2', 1),
|
||||
'role3': ('flavor3', 1),
|
||||
}
|
||||
|
||||
expected = mistral_workflow_utils.Result(
|
||||
data={
|
||||
'flavors': {
|
||||
'flavor2': (
|
||||
{
|
||||
'name': 'flavor2',
|
||||
'capabilities:boot_option': 'netboot'
|
||||
}, 1),
|
||||
'flavor3': (
|
||||
{
|
||||
'name': 'flavor3',
|
||||
}, 1),
|
||||
},
|
||||
'warnings': [
|
||||
('Flavor %s "capabilities:boot_option" is set to '
|
||||
'"netboot". Nodes will PXE boot from the ironic '
|
||||
'conductor instead of using a local bootloader. Make '
|
||||
'sure that enough nodes are marked with the '
|
||||
'"boot_option" capability set to "netboot".' % 'flavor2')
|
||||
],
|
||||
'errors': []
|
||||
}
|
||||
)
|
||||
|
||||
action_args = {
|
||||
'flavors': self.flavors,
|
||||
'roles_info': roles_info
|
||||
}
|
||||
action = validations.CheckFlavorsAction(**action_args)
|
||||
result = action.run()
|
||||
self.assertEqual(expected, result)
|
||||
|
||||
def test_run_flavor_does_not_exist(self):
|
||||
roles_info = {
|
||||
'role4': ('does_not_exist', 1),
|
||||
}
|
||||
|
||||
expected = mistral_workflow_utils.Result(
|
||||
error={
|
||||
'errors': [
|
||||
"Flavor '%s' provided for the role '%s', does not "
|
||||
"exist" % ('does_not_exist', 'role4')
|
||||
],
|
||||
'warnings': [],
|
||||
'flavors': {},
|
||||
}
|
||||
)
|
||||
|
||||
action_args = {
|
||||
'flavors': self.flavors,
|
||||
'roles_info': roles_info
|
||||
}
|
||||
action = validations.CheckFlavorsAction(**action_args)
|
||||
self.assertEqual(expected, action.run())
|
||||
|
@ -316,3 +316,65 @@ workflows:
|
||||
warnings: <% $.warnings %>
|
||||
on-success:
|
||||
- fail: <% $.get('status') = "FAILED" %>
|
||||
|
||||
collect_flavors:
|
||||
input:
|
||||
- roles_info: {}
|
||||
- run_validations: true
|
||||
- queue_name: tripleo
|
||||
output:
|
||||
errors: <% $.errors %>
|
||||
warnings: <% $.warnings %>
|
||||
flavors: <% $.flavors %>
|
||||
|
||||
tasks:
|
||||
check_run_validations:
|
||||
on-complete:
|
||||
- get_flavors: <% $.run_validations %>
|
||||
- send_message: <% not $.run_validations %>
|
||||
|
||||
get_flavors:
|
||||
action: nova.flavors_list
|
||||
on-success: check_flavors
|
||||
publish:
|
||||
nova_flavors: <% task(get_flavors).result %>
|
||||
|
||||
check_flavors:
|
||||
action: tripleo.validations.check_flavors
|
||||
input:
|
||||
flavors: <% $.nova_flavors %>
|
||||
roles_info: <% $.roles_info %>
|
||||
on-success: send_message
|
||||
on-error: fail_check_flavors
|
||||
publish:
|
||||
flavors: <% task(check_flavors).result.flavors %>
|
||||
errors: <% task(check_flavors).result.errors %>
|
||||
warnings: <% task(check_flavors).result.warnings %>
|
||||
publish-on-error:
|
||||
flavors: {}
|
||||
errors: <% task(check_flavors).result.errors %>
|
||||
warnings: <% task(check_flavors).result.warnings %>
|
||||
|
||||
fail_check_flavors:
|
||||
on-success: send_message
|
||||
publish:
|
||||
status: FAILED
|
||||
message: <% task(check_flavors).result %>
|
||||
|
||||
send_message:
|
||||
action: zaqar.queue_post
|
||||
retry: count=5 delay=1
|
||||
input:
|
||||
queue_name: <% $.queue_name %>
|
||||
messages:
|
||||
body:
|
||||
type: tripleo.validations.v1.collect_flavors
|
||||
payload:
|
||||
status: <% $.get('status', 'SUCCESS') %>
|
||||
message: <% $.get('message', '') %>
|
||||
execution: <% execution() %>
|
||||
flavors: <% $.flavors %>
|
||||
errors: <% $.errors %>
|
||||
warnings: <% $.warnings %>
|
||||
on-success:
|
||||
- fail: <% $.get('status') = "FAILED" %>
|
||||
|
Loading…
x
Reference in New Issue
Block a user