From dcaecb4dad1a5100813a0b1b592582f537f01bf5 Mon Sep 17 00:00:00 2001 From: Bogdan Dobrelya Date: Thu, 8 Jun 2017 13:22:38 +0200 Subject: [PATCH] Install prerequisites for undercloud deploy Address the tech debt introduced in the quickstart-extras undercloud-deploy role. Move installation of the packages into the 'openstack undercloud deploy' prerequisites phase, executed as a separate deployment step. Add new flag --install-kolla, defaults to False. If enabled, adds the openatack-kolla package to the prerequisites. Add release notes for undercloud deploy. Add missing python-heat-agent-ansible prerequisite. Change-Id: I54445b73891ff414acc6d3323aa378243d4d655f Signed-off-by: Bogdan Dobrelya --- ...undercloud-with-heat-789655d324b2727b.yaml | 13 ++++ .../v1/undercloud/test_undercloud_deploy.py | 42 +++++++++++++ tripleoclient/v1/undercloud_deploy.py | 59 +++++++++++++++++++ 3 files changed, 114 insertions(+) create mode 100644 releasenotes/notes/deploy-undercloud-with-heat-789655d324b2727b.yaml diff --git a/releasenotes/notes/deploy-undercloud-with-heat-789655d324b2727b.yaml b/releasenotes/notes/deploy-undercloud-with-heat-789655d324b2727b.yaml new file mode 100644 index 000000000..d10eb7fb2 --- /dev/null +++ b/releasenotes/notes/deploy-undercloud-with-heat-789655d324b2727b.yaml @@ -0,0 +1,13 @@ +--- +features: + - | + EXPERIMENTAL feature to install the undercloud with openstack heat + add support for a containerized undercloud. It checks for prequisites + and installs missing packages then deploys undercloud with heat-all. + + - | + New flag `--install-kolla`, defaults to False. Adds or removes Kolla + packages to/from the list of required packages to be installed by the + ``openstack undercloud deploy`` command. Set it to True, if you want + to build Kolla containers on the undercloud node as the part of your + continuous deployment pipeline. diff --git a/tripleoclient/tests/v1/undercloud/test_undercloud_deploy.py b/tripleoclient/tests/v1/undercloud/test_undercloud_deploy.py index d2d19c6ca..c37a04fd8 100644 --- a/tripleoclient/tests/v1/undercloud/test_undercloud_deploy.py +++ b/tripleoclient/tests/v1/undercloud/test_undercloud_deploy.py @@ -15,6 +15,7 @@ import mock import os +import subprocess from tripleoclient.tests.v1.test_plugin import TestPluginV1 @@ -35,6 +36,8 @@ class TestUndercloudDeploy(TestPluginV1): # Get the command object to test self.cmd = undercloud_deploy.DeployUndercloud(self.app, None) + # Substitute required packages + self.cmd.prerequisites = iter(['foo', 'bar', 'baz']) @mock.patch('os.path.exists') @mock.patch('tripleo_common.utils.passwords.generate_passwords') @@ -83,3 +86,42 @@ class TestUndercloudDeploy(TestPluginV1): mock_dump.assert_called_once_with(expected_dict, mock_open_handle, default_flow_style=False) + + @mock.patch('subprocess.check_call', autospec=True) + def test_install_prerequisites(self, mock_check_call): + mock_check_call.side_effect = [ + True, subprocess.CalledProcessError(1, ''), True, + subprocess.CalledProcessError(1, ''), True] + arglist = ['--install-kolla'] + verifylist = [('install_kolla', True)] + cmd_parser = self.cmd.get_parser('check_parser') + parsed_args = cmd_parser.parse_args(arglist) + self.check_parser(self.cmd, arglist, verifylist) + self.cmd._install_prerequisites(parsed_args.install_kolla) + + mock_check_call.assert_has_calls([ + mock.call(['rpm', '-q', 'foo']), + mock.call(['rpm', '-q', 'bar']), + mock.call(['rpm', '-q', 'baz']), + mock.call(['rpm', '-q', 'openstack-kolla']), + mock.call(['yum', '-y', 'install', 'bar', 'openstack-kolla']) + ]) + + @mock.patch('subprocess.check_call', autospec=True) + def test_fail_prerequisites(self, mock_check_call): + mock_check_call.side_effect = [ + True, subprocess.CalledProcessError(127, ''), True, True] + arglist = [] + verifylist = [] + cmd_parser = self.cmd.get_parser('check_parser') + parsed_args = cmd_parser.parse_args(arglist) + self.check_parser(self.cmd, arglist, verifylist) + try: + self.cmd._install_prerequisites(parsed_args.install_kolla) + except Exception as e: + self.assertTrue('Failed to check for prerequisites: ' + 'bar, the exit status 127' in str(e)) + + mock_check_call.assert_has_calls([ + mock.call(['rpm', '-q', 'foo']), + mock.call(['rpm', '-q', 'bar'])]) diff --git a/tripleoclient/v1/undercloud_deploy.py b/tripleoclient/v1/undercloud_deploy.py index f5546317a..67c2f5daa 100644 --- a/tripleoclient/v1/undercloud_deploy.py +++ b/tripleoclient/v1/undercloud_deploy.py @@ -15,6 +15,7 @@ from __future__ import print_function import argparse +import itertools import logging import netaddr import os @@ -47,17 +48,64 @@ from tripleoclient import heat_launcher from tripleo_common.utils import passwords as password_utils +# TODO(bogdando) rework the list by real requirements for the +# heat-container-image vs heat-native cases +REQUIRED_PACKAGES = iter([ + 'openstack-heat-api', + 'openstack-heat-engine', + 'openstack-heat-monolith', + 'python-heat-agent', + 'python-heat-agent-apply-config', + 'python-heat-agent-hiera', + 'python-heat-agent-puppet', + 'python-heat-agent-docker-cmd', + 'python-heat-agent-json-file', + 'python-heat-agent-ansible', + 'python-ipaddr', + 'python-tripleoclient', + 'docker', + 'openvswitch', + 'openstack-puppet-modules', + 'yum-plugin-priorities', + 'openstack-tripleo-common', + 'openstack-tripleo-heat-templates', + 'deltarpm' +]) + class DeployUndercloud(command.Command): """Deploy Undercloud (experimental feature)""" log = logging.getLogger(__name__ + ".DeployUndercloud") auth_required = False + prerequisites = REQUIRED_PACKAGES def _get_hostname(self): p = subprocess.Popen(["hostname", "-s"], stdout=subprocess.PIPE) return p.communicate()[0].rstrip() + def _install_prerequisites(self, add_kolla): + print('Checking for installed prerequisites ...') + processed = [] + if add_kolla: + self.prerequisites = itertools.chain( + self.prerequisites, ['openstack-kolla']) + + for p in self.prerequisites: + try: + subprocess.check_call(['rpm', '-q', p]) + except subprocess.CalledProcessError as e: + if e.returncode == 1: + processed.append(p) + elif e.returncode != 0: + raise Exception('Failed to check for prerequisites: ' + '%s, the exit status %s' + % (p, e.returncode)) + + if len(processed) > 0: + print('Installing prerequisites ...') + subprocess.check_call(['yum', '-y', 'install'] + processed) + def _lookup_tripleo_server_stackid(self, client, stack_id): server_stack_id = None @@ -415,6 +463,14 @@ class DeployUndercloud(command.Command): dest='keep_running', help=_('Keep the process running on failures for debugging') ) + parser.add_argument( + '--install-kolla', + action='store_true', + dest='install_kolla', + default=False, + help=_('Require Kolla packages to be installed for building' + 'containers from the undercloud node') + ) return parser def take_action(self, parsed_args): @@ -444,6 +500,9 @@ class DeployUndercloud(command.Command): if os.geteuid() != 0: raise exceptions.DeploymentError("Please run as root.") + # Install required packages + self._install_prerequisites(parsed_args.install_kolla) + keystone_pid = self._fork_fake_keystone() # we do this as root to chown config files properly for docker, etc.