diff --git a/releasenotes/notes/update-converge-916c7682f4d0e9f5.yaml b/releasenotes/notes/update-converge-916c7682f4d0e9f5.yaml new file mode 100644 index 000000000..91e987482 --- /dev/null +++ b/releasenotes/notes/update-converge-916c7682f4d0e9f5.yaml @@ -0,0 +1,6 @@ +--- +upgrade: + - | + For minor updates, an `openstack overcloud update converge` + command has been added and must be run to restore the deployment + plan (remove no-ops of some resources) after a minor update. diff --git a/setup.cfg b/setup.cfg index ba78b3221..eb176013f 100644 --- a/setup.cfg +++ b/setup.cfg @@ -91,6 +91,7 @@ openstack.tripleoclient.v1 = overcloud_support_report_collect = tripleoclient.v1.overcloud_support:ReportExecute overcloud_update_prepare= tripleoclient.v1.overcloud_update:UpdatePrepare overcloud_update_run = tripleoclient.v1.overcloud_update:UpdateRun + overcloud_update_converge= tripleoclient.v1.overcloud_update:UpdateConverge overcloud_upgrade_prepare = tripleoclient.v1.overcloud_upgrade:UpgradePrepare overcloud_upgrade_run = tripleoclient.v1.overcloud_upgrade:UpgradeRun overcloud_upgrade_converge = tripleoclient.v1.overcloud_upgrade:UpgradeConvergeOvercloud diff --git a/tripleoclient/tests/v1/overcloud_update/fakes.py b/tripleoclient/tests/v1/overcloud_update/fakes.py index 45cc69e8b..e8eacc5ef 100644 --- a/tripleoclient/tests/v1/overcloud_update/fakes.py +++ b/tripleoclient/tests/v1/overcloud_update/fakes.py @@ -59,3 +59,15 @@ class TestOvercloudUpdateRun(utils.TestCommand): self.app.client_manager.auth_ref = mock.Mock(auth_token="TOKEN") self.app.client_manager.tripleoclient = FakeClientWrapper() self.app.client_manager.workflow_engine = mock.Mock() + + +class TestOvercloudUpdateConverge(utils.TestCommand): + + def setUp(self): + super(TestOvercloudUpdateConverge, self).setUp() + + self.app.client_manager.auth_ref = mock.Mock(auth_token="TOKEN") + self.app.client_manager.baremetal = mock.Mock() + self.app.client_manager.orchestration = mock.Mock() + self.app.client_manager.tripleoclient = FakeClientWrapper() + self.app.client_manager.workflow_engine = mock.Mock() diff --git a/tripleoclient/tests/v1/overcloud_update/test_overcloud_update.py b/tripleoclient/tests/v1/overcloud_update/test_overcloud_update.py index 9349cf901..70d671bb0 100644 --- a/tripleoclient/tests/v1/overcloud_update/test_overcloud_update.py +++ b/tripleoclient/tests/v1/overcloud_update/test_overcloud_update.py @@ -228,3 +228,41 @@ class TestOvercloudUpdateRun(fakes.TestOvercloudUpdateRun): ] self.assertRaises(ParserException, lambda: self.check_parser( self.cmd, argslist, verifylist)) + + +class TestOvercloudUpdateConverge(fakes.TestOvercloudUpdateConverge): + + def setUp(self): + super(TestOvercloudUpdateConverge, self).setUp() + + # Get the command object to test + app_args = mock.Mock() + app_args.verbose_level = 1 + self.cmd = overcloud_update.UpdateConverge(self.app, app_args) + + @mock.patch('tripleoclient.utils.get_stack') + @mock.patch('tripleoclient.workflows.package_update.update_converge_nodes') + @mock.patch( + 'tripleoclient.v1.overcloud_deploy.DeployOvercloud.take_action') + def test_update_converge(self, deploy_action, converge_workflow, + get_stack): + get_stack.return_value.stack_name = 'cloud' + + argslist = ['--templates', '--stack', 'cloud'] + verifylist = [ + ('stack', 'cloud') + ] + parsed_args = self.check_parser(self.cmd, argslist, verifylist) + + with mock.patch('os.path.exists') as mock_exists, \ + mock.patch('os.path.isfile') as mock_isfile: + mock_exists.return_value = True + mock_isfile.return_value = True + self.cmd.take_action(parsed_args) + assert('/usr/share/openstack-tripleo-heat-templates/' + 'environments/lifecycle/update-converge.yaml' + in parsed_args.environment_files) + deploy_action.assert_called_once_with(parsed_args) + converge_workflow.assert_called_once_with( + self.app.client_manager, container='cloud', + queue_name='update') diff --git a/tripleoclient/v1/overcloud_update.py b/tripleoclient/v1/overcloud_update.py index 03959fc10..4b4671deb 100644 --- a/tripleoclient/v1/overcloud_update.py +++ b/tripleoclient/v1/overcloud_update.py @@ -83,7 +83,7 @@ class UpdatePrepare(DeployOvercloud): # packag_update mistral action parsed_args.update_plan_only = True - # Add the upgrade-prepare.yaml environment to set noops etc + # Add the update-prepare.yaml environment to set noops etc templates_dir = (parsed_args.templates or constants.TRIPLEO_HEAT_TEMPLATES) parsed_args.environment_files = oooutils.prepend_environment( @@ -170,3 +170,36 @@ class UpdateRun(command.Command): constants.MINOR_UPDATE_PLAYBOOKS, package_update, parsed_args.ssh_user) + + +class UpdateConverge(DeployOvercloud): + """Converge the update on Overcloud nodes. + + This restores the plan environment so that normal deployment + workflow is back in place. The action does not perform a Heat + stack update. + """ + + log = logging.getLogger(__name__ + ".UpdateConverge") + + def take_action(self, parsed_args): + self.log.debug("take_action(%s)" % parsed_args) + clients = self.app.client_manager + stack_name = oooutils.get_stack( + clients.orchestration, parsed_args.stack).stack_name + + # Only update plan, do not perform stack update. + parsed_args.update_plan_only = True + + # Add the update-converge.yaml environment to unset noops + templates_dir = (parsed_args.templates or + constants.TRIPLEO_HEAT_TEMPLATES) + parsed_args.environment_files = oooutils.prepend_environment( + parsed_args.environment_files, templates_dir, + constants.UPDATE_CONVERGE_ENV) + + super(UpdateConverge, self).take_action(parsed_args) + package_update.update_converge_nodes( + clients, container=stack_name, queue_name=constants.UPDATE_QUEUE) + print("Update converge on stack {0} complete.".format( + parsed_args.stack)) diff --git a/tripleoclient/workflows/package_update.py b/tripleoclient/workflows/package_update.py index 941ecbbd2..62e7be9df 100644 --- a/tripleoclient/workflows/package_update.py +++ b/tripleoclient/workflows/package_update.py @@ -107,6 +107,27 @@ def update_ansible(clients, **workflow_input): raise RuntimeError('Update failed with: {}'.format(payload)) +def update_converge_nodes(clients, **workflow_input): + workflow_client = clients.workflow_engine + tripleoclients = clients.tripleoclient + + with tripleoclients.messaging_websocket( + workflow_input['queue_name']) as ws: + execution = base.start_workflow( + workflow_client, + 'tripleo.package_update.v1.update_converge_plan', + workflow_input=workflow_input + ) + + for payload in base.wait_for_messages(workflow_client, ws, execution): + assert payload['status'] == "SUCCESS", pprint.pformat(payload) + + if payload['status'] == 'SUCCESS': + print('Success') + else: + raise RuntimeError('Update converge failed: {}'.format(payload)) + + def converge_nodes(clients, **workflow_input): workflow_client = clients.workflow_engine tripleoclients = clients.tripleoclient