diff --git a/releasenotes/notes/check-boot-action-548e38d17cf1ad96.yaml b/releasenotes/notes/check-boot-action-548e38d17cf1ad96.yaml new file mode 100644 index 000000000..813f88c3b --- /dev/null +++ b/releasenotes/notes/check-boot-action-548e38d17cf1ad96.yaml @@ -0,0 +1,4 @@ +--- +features: + - Adds an action and workflow used to check the status of + the boot images in Glance. diff --git a/setup.cfg b/setup.cfg index 21daafd52..02c840ca4 100644 --- a/setup.cfg +++ b/setup.cfg @@ -95,6 +95,7 @@ mistral.actions = tripleo.swift.tempurl = tripleo_common.actions.swifthelper:SwiftTempUrlAction 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.get_pubkey = tripleo_common.actions.validations:GetPubkeyAction tripleo.validations.enabled = tripleo_common.actions.validations:Enabled tripleo.validations.list_groups = tripleo_common.actions.validations:ListGroupsAction diff --git a/tripleo_common/actions/validations.py b/tripleo_common/actions/validations.py index 9f37ffe7f..38a425575 100644 --- a/tripleo_common/actions/validations.py +++ b/tripleo_common/actions/validations.py @@ -122,3 +122,54 @@ class RunValidationAction(base.TripleOAction): if identity_file: utils.cleanup_identity_file(identity_file) return mistral_workflow_utils.Result(**mistral_result) + + +class CheckBootImagesAction(base.TripleOAction): + """Validate boot images""" + + # TODO(bcrochet): The validation actions are temporary. This logic should + # move to the tripleo-validations project eventually. + def __init__(self, images, + deploy_kernel_name=constants.DEFAULT_DEPLOY_KERNEL_NAME, + deploy_ramdisk_name=constants.DEFAULT_DEPLOY_RAMDISK_NAME): + super(CheckBootImagesAction, self).__init__() + self.images = images + self.deploy_kernel_name = deploy_kernel_name + self.deploy_ramdisk_name = deploy_ramdisk_name + + def run(self): + messages = [] + kernel_id = self._check_for_image(self.deploy_kernel_name, messages) + ramdisk_id = self._check_for_image(self.deploy_ramdisk_name, messages) + + return_value = { + 'kernel_id': kernel_id, + 'ramdisk_id': ramdisk_id, + 'errors': messages, + 'warnings': [] + } + + if messages: + mistral_result = mistral_workflow_utils.Result(error=return_value) + else: + mistral_result = mistral_workflow_utils.Result(data=return_value) + + return mistral_result + + def _check_for_image(self, name, messages): + multiple_message = ("Please make sure there is only one image named " + "'{}' in glance.") + missing_message = ("No image with the name '{}' found - make sure you " + "have uploaded boot images.") + + image_id = None + found_images = [item['id'] for item in self.images + if item['name'] == name] + if len(found_images) > 1: + messages.append(multiple_message.format(name)) + elif len(found_images) == 0: + messages.append(missing_message.format(name)) + else: + image_id = found_images[0] + + return image_id diff --git a/tripleo_common/constants.py b/tripleo_common/constants.py index f0d7dfe53..e53bba8ba 100644 --- a/tripleo_common/constants.py +++ b/tripleo_common/constants.py @@ -112,3 +112,7 @@ DEFAULT_BAREMETAL_API_VERSION = '1.29' # The name of the file which holds the Mistral environment contents for plan # import/export PLAN_ENVIRONMENT = 'plan-environment.yaml' + +DEFAULT_DEPLOY_KERNEL_NAME = 'bm-deploy-kernel' + +DEFAULT_DEPLOY_RAMDISK_NAME = 'bm-deploy-ramdisk' diff --git a/tripleo_common/tests/actions/test_validations.py b/tripleo_common/tests/actions/test_validations.py index b32a19708..4c2b2aa9b 100644 --- a/tripleo_common/tests/actions/test_validations.py +++ b/tripleo_common/tests/actions/test_validations.py @@ -200,3 +200,86 @@ class RunValidationActionTest(base.TestCase): constants.DEFAULT_CONTAINER_NAME) mock_cleanup_identity_file.assert_called_once_with( 'identity_file_path') + + +class TestCheckBootImagesAction(base.TestCase): + def setUp(self): + super(TestCheckBootImagesAction, self).setUp() + self.images = [ + {'id': '67890', 'name': 'ramdisk'}, + {'id': '12345', 'name': 'kernel'}, + ] + + @mock.patch( + 'tripleo_common.actions.validations.CheckBootImagesAction' + '._check_for_image') + def test_run(self, mock_check_for_image): + mock_check_for_image.side_effect = ['12345', '67890'] + expected = mistral_workflow_utils.Result( + data={ + 'kernel_id': '12345', + 'ramdisk_id': '67890', + 'warnings': [], + 'errors': []}) + action_args = { + 'images': self.images, + 'deploy_kernel_name': 'kernel', + 'deploy_ramdisk_name': 'ramdisk' + } + action = validations.CheckBootImagesAction(**action_args) + self.assertEqual(expected, action.run()) + mock_check_for_image.assert_has_calls([ + mock.call('kernel', []), + mock.call('ramdisk', []) + ]) + + def test_check_for_image_success(self): + expected = '12345' + action_args = { + 'images': self.images, + 'deploy_kernel_name': 'kernel', + 'deploy_ramdisk_name': 'ramdisk' + } + + messages = mock.Mock() + action = validations.CheckBootImagesAction(**action_args) + self.assertEqual(expected, action._check_for_image('kernel', messages)) + messages.assert_not_called() + + def test_check_for_image_missing(self): + expected = None + deploy_kernel_name = 'missing' + action_args = { + 'images': self.images, + 'deploy_kernel_name': deploy_kernel_name + } + expected_message = ("No image with the name '%s' found - make sure " + "you have uploaded boot images." + % deploy_kernel_name) + + messages = [] + action = validations.CheckBootImagesAction(**action_args) + self.assertEqual(expected, + action._check_for_image(deploy_kernel_name, messages)) + self.assertEqual(1, len(messages)) + self.assertIn(expected_message, messages) + + def test_check_for_image_too_many(self): + expected = None + deploy_ramdisk_name = 'toomany' + images = list(self.images) + images.append({'id': 'abcde', 'name': deploy_ramdisk_name}) + images.append({'id': '45678', 'name': deploy_ramdisk_name}) + action_args = { + 'images': images, + 'deploy_ramdisk_name': deploy_ramdisk_name + } + expected_message = ("Please make sure there is only one image named " + "'%s' in glance." % deploy_ramdisk_name) + + messages = [] + action = validations.CheckBootImagesAction(**action_args) + self.assertEqual( + expected, action._check_for_image(deploy_ramdisk_name, messages)) + self.assertEqual(1, len(messages)) + self.assertIn(expected_message, messages) diff --git a/workbooks/validations.yaml b/workbooks/validations.yaml index 0f2d54fbf..7793f3748 100644 --- a/workbooks/validations.yaml +++ b/workbooks/validations.yaml @@ -249,3 +249,70 @@ workflows: config_name: copy_ssh_key group: script queue_name: <% $.queue_name %> + + check_boot_images: + input: + - deploy_kernel_name: 'bm-deploy-kernel' + - deploy_ramdisk_name: 'bm-deploy-ramdisk' + - run_validations: true + - queue_name: tripleo + output: + errors: <% $.errors %> + warnings: <% $.warnings %> + kernel_id: <% $.kernel_id %> + ramdisk_id: <% $.ramdisk_id %> + tasks: + check_run_validations: + on-complete: + - get_images: <% $.run_validations %> + - send_message: <% not $.run_validations %> + + get_images: + action: glance.images_list + on-success: check_images + publish: + images: <% task(get_images).result %> + + check_images: + action: tripleo.validations.check_boot_images + input: + images: <% $.images %> + deploy_kernel_name: <% $.deploy_kernel_name %> + deploy_ramdisk_name: <% $.deploy_ramdisk_name %> + on-success: send_message + on-error: fail_check_images + publish: + kernel_id: <% task(check_images).result.kernel_id %> + ramdisk_id: <% task(check_images).result.ramdisk_id %> + warnings: <% task(check_images).result.warnings %> + errors: <% task(check_images).result.errors %> + publish-on-error: + kernel_id: <% task(check_images).result.kernel_id %> + ramdisk_id: <% task(check_images).result.ramdisk_id %> + warnings: <% task(check_images).result.warnings %> + errors: <% task(check_images).result.errors %> + + fail_check_images: + on-success: send_message + publish: + status: FAILED + message: <% task(check_images).result %> + + send_message: + action: zaqar.queue_post + retry: count=5 delay=1 + input: + queue_name: <% $.queue_name %> + messages: + body: + type: tripleo.validations.v1.check_boot_images + payload: + status: <% $.get('status', 'SUCCESS') %> + message: <% $.get('message', '') %> + execution: <% execution() %> + kernel_id: <% $.kernel_id %> + ramdisk_id: <% $.ramdisk_id %> + errors: <% $.errors %> + warnings: <% $.warnings %> + on-success: + - fail: <% $.get('status') = "FAILED" %>