Use undercloud upgrade to update all required pkgs

Rather than require the end user to manually update packages prior to
kicking off the undercloud process we can do it ourselves by
implementing a flag to skip the update and invoking the upgrade after
the packages have been updated.

Change-Id: Idda6387922adeb182afd11cb0d692d1fcceff9a8
Related-Bug: #1869776
(cherry picked from commit 7d1b738910)
This commit is contained in:
Alex Schultz 2020-04-09 13:46:36 -06:00
parent 3b52fa2cf1
commit 55c99266c9
3 changed files with 127 additions and 65 deletions

View File

@ -170,6 +170,7 @@ EXPORT_PASSWORD_EXCLUDE_PATTERNS = [
# Package that need to be to the latest before undercloud # Package that need to be to the latest before undercloud
# update/update/ffwd. # update/update/ffwd.
UNDERCLOUD_EXTRA_PACKAGES = [ UNDERCLOUD_EXTRA_PACKAGES = [
"openstack-tripleo-common",
"openstack-tripleo-heat-templates", "openstack-tripleo-heat-templates",
"openstack-tripleo-validations", "openstack-tripleo-validations",
"tripleo-ansible" "tripleo-ansible"

View File

@ -17,6 +17,7 @@ import fixtures
import json import json
import mock import mock
import os import os
import sys
from jinja2 import Template from jinja2 import Template
@ -563,6 +564,7 @@ class TestUndercloudUpgrade(TestPluginV1):
app_args.verbose_level = 1 app_args.verbose_level = 1
self.cmd = undercloud.UpgradeUndercloud(self.app, app_args) self.cmd = undercloud.UpgradeUndercloud(self.app, app_args)
@mock.patch.object(sys, 'executable', 'python2')
# TODO(cjeanner) drop once we have proper oslo.privsep # TODO(cjeanner) drop once we have proper oslo.privsep
@mock.patch('getpass.getuser', return_value='stack') @mock.patch('getpass.getuser', return_value='stack')
@mock.patch('shutil.copy') @mock.patch('shutil.copy')
@ -582,12 +584,64 @@ class TestUndercloudUpgrade(TestPluginV1):
self.cmd.take_action(parsed_args) self.cmd.take_action(parsed_args)
mock_run_command.assert_called_with( mock_run_command.assert_called_with(
['sudo', 'yum', 'upgrade', '-y', ['sudo', 'yum', 'upgrade', '-y',
'python2-tripleoclient',
'openstack-tripleo-common',
'openstack-tripleo-heat-templates', 'openstack-tripleo-heat-templates',
'openstack-tripleo-validations', 'openstack-tripleo-validations',
'tripleo-ansible'], 'tripleo-ansible'],
name='Update extra packages' name='Update extra packages'
) )
mock_subprocess.assert_called_with([
'openstack', 'undercloud', 'upgrade', '--skip-package-updates',
'--no-validations'])
@mock.patch.object(sys, 'executable', 'python3')
# TODO(cjeanner) drop once we have proper oslo.privsep
@mock.patch('os.geteuid', return_value=1001)
@mock.patch('getpass.getuser', return_value='stack')
@mock.patch('shutil.copy')
@mock.patch('os.mkdir')
@mock.patch('tripleoclient.utils.write_env_file', autospec=True)
@mock.patch('subprocess.check_call', autospec=True)
@mock.patch('tripleoclient.utils.run_command', autospec=True)
def test_undercloud_upgrade_all_opts(self, mock_run_command,
mock_subprocess,
mock_wr,
mock_os, mock_copy, mock_user,
mock_getuid):
arglist = ['--force-stack-update', '--no-validations',
'--inflight-validations', '--dry-run', '--yes']
verifylist = []
self.cmd.app_args.verbose_level = 2
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
# DisplayCommandBase.take_action() returns two tuples
self.cmd.take_action(parsed_args)
mock_run_command.assert_not_called()
mock_subprocess.assert_called_with([
'openstack', 'undercloud', 'upgrade', '--skip-package-updates',
'--force-stack-update', '--no-validations',
'--inflight-validations', '--dry-run', '--yes', '--debug'])
# TODO(cjeanner) drop once we have proper oslo.privsep
@mock.patch('os.geteuid', return_value=1001)
@mock.patch('getpass.getuser', return_value='stack')
@mock.patch('shutil.copy')
@mock.patch('os.mkdir')
@mock.patch('tripleoclient.utils.write_env_file', autospec=True)
@mock.patch('subprocess.check_call', autospec=True)
@mock.patch('tripleoclient.utils.run_command', autospec=True)
def test_undercloud_upgrade_no_pkgs(self, mock_run_command,
mock_subprocess,
mock_wr,
mock_os, mock_copy, mock_user,
mock_getuid):
arglist = ['--no-validations', '--skip-package-updates']
verifylist = []
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
# DisplayCommandBase.take_action() returns two tuples
self.cmd.take_action(parsed_args)
mock_subprocess.assert_called_with( mock_subprocess.assert_called_with(
['sudo', '--preserve-env', 'openstack', 'tripleo', 'deploy', ['sudo', '--preserve-env', 'openstack', 'tripleo', 'deploy',
'--standalone', '--standalone-role', 'Undercloud', '--stack', '--standalone', '--standalone-role', 'Undercloud', '--stack',
@ -648,21 +702,13 @@ class TestUndercloudUpgrade(TestPluginV1):
mock_subprocess, mock_subprocess,
mock_wr, mock_os, mock_wr, mock_os,
mock_copy, mock_user): mock_copy, mock_user):
arglist = ['--no-validations'] arglist = ['--no-validations', '--skip-package-updates']
verifylist = [] verifylist = []
parsed_args = self.check_parser(self.cmd, arglist, verifylist) parsed_args = self.check_parser(self.cmd, arglist, verifylist)
# DisplayCommandBase.take_action() returns two tuples # DisplayCommandBase.take_action() returns two tuples
self.cmd.take_action(parsed_args) self.cmd.take_action(parsed_args)
mock_run_command.assert_called_with(
['sudo', 'yum', 'upgrade', '-y',
'openstack-tripleo-heat-templates',
'openstack-tripleo-validations',
'tripleo-ansible'],
name='Update extra packages'
)
mock_subprocess.assert_called_with( mock_subprocess.assert_called_with(
['sudo', '--preserve-env', 'openstack', 'tripleo', 'deploy', ['sudo', '--preserve-env', 'openstack', 'tripleo', 'deploy',
'--standalone', '--standalone-role', 'Undercloud', '--stack', '--standalone', '--standalone-role', 'Undercloud', '--stack',
@ -722,21 +768,13 @@ class TestUndercloudUpgrade(TestPluginV1):
mock_subprocess, mock_subprocess,
mock_wr, mock_os, mock_wr, mock_os,
mock_copy, mock_user): mock_copy, mock_user):
arglist = ['--no-validations'] arglist = ['--no-validations', '--skip-package-updates']
verifylist = [] verifylist = []
parsed_args = self.check_parser(self.cmd, arglist, verifylist) parsed_args = self.check_parser(self.cmd, arglist, verifylist)
# DisplayCommandBase.take_action() returns two tuples # DisplayCommandBase.take_action() returns two tuples
self.cmd.take_action(parsed_args) self.cmd.take_action(parsed_args)
mock_run_command.assert_called_with(
['sudo', 'yum', 'upgrade', '-y',
'openstack-tripleo-heat-templates',
'openstack-tripleo-validations',
'tripleo-ansible'],
name='Update extra packages'
)
mock_subprocess.assert_called_with( mock_subprocess.assert_called_with(
['sudo', '--preserve-env', 'openstack', 'tripleo', 'deploy', ['sudo', '--preserve-env', 'openstack', 'tripleo', 'deploy',
'--standalone', '--standalone-role', 'Undercloud', '--stack', '--standalone', '--standalone-role', 'Undercloud', '--stack',
@ -795,22 +833,14 @@ class TestUndercloudUpgrade(TestPluginV1):
def test_undercloud_upgrade_with_heat_and_yes(self, mock_run_command, def test_undercloud_upgrade_with_heat_and_yes(self, mock_run_command,
mock_subprocess, mock_subprocess,
mock_wr, mock_os, mock_wr, mock_os,
mock_user, mock_copy): mock_copy, mock_user):
arglist = ['--no-validations', '-y'] arglist = ['--no-validations', '-y', '--skip-package-updates']
verifylist = [] verifylist = []
parsed_args = self.check_parser(self.cmd, arglist, verifylist) parsed_args = self.check_parser(self.cmd, arglist, verifylist)
# DisplayCommandBase.take_action() returns two tuples # DisplayCommandBase.take_action() returns two tuples
self.cmd.take_action(parsed_args) self.cmd.take_action(parsed_args)
mock_run_command.assert_called_with(
['sudo', 'yum', 'upgrade', '-y',
'openstack-tripleo-heat-templates',
'openstack-tripleo-validations',
'tripleo-ansible'],
name='Update extra packages'
)
mock_subprocess.assert_called_with( mock_subprocess.assert_called_with(
['sudo', '--preserve-env', 'openstack', 'tripleo', 'deploy', ['sudo', '--preserve-env', 'openstack', 'tripleo', 'deploy',
'--standalone', '--standalone-role', 'Undercloud', '--stack', '--standalone', '--standalone-role', 'Undercloud', '--stack',
@ -871,7 +901,7 @@ class TestUndercloudUpgrade(TestPluginV1):
mock_subprocess, mock_subprocess,
mock_wr, mock_os, mock_wr, mock_os,
mock_copy, mock_user): mock_copy, mock_user):
arglist = ['--no-validations'] arglist = ['--no-validations', '--skip-package-updates']
verifylist = [] verifylist = []
parsed_args = self.check_parser(self.cmd, arglist, verifylist) parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@ -881,14 +911,6 @@ class TestUndercloudUpgrade(TestPluginV1):
self.cmd.take_action(parsed_args) self.cmd.take_action(parsed_args)
self.cmd.app_args.verbose_level = old_verbose self.cmd.app_args.verbose_level = old_verbose
mock_run_command.assert_called_with(
['sudo', 'yum', 'upgrade', '-y',
'openstack-tripleo-heat-templates',
'openstack-tripleo-validations',
'tripleo-ansible'],
name='Update extra packages'
)
mock_subprocess.assert_called_with( mock_subprocess.assert_called_with(
['sudo', '--preserve-env', 'openstack', 'tripleo', 'deploy', ['sudo', '--preserve-env', 'openstack', 'tripleo', 'deploy',
'--standalone', '--standalone-role', 'Undercloud', '--stack', '--standalone', '--standalone-role', 'Undercloud', '--stack',

View File

@ -19,6 +19,7 @@ import argparse
import logging import logging
import os import os
import subprocess import subprocess
import sys
from openstackclient.i18n import _ from openstackclient.i18n import _
@ -165,41 +166,55 @@ class UpgradeUndercloud(InstallUndercloud):
log = logging.getLogger(__name__ + ".UpgradeUndercloud") log = logging.getLogger(__name__ + ".UpgradeUndercloud")
osloconfig = cfg.CONF osloconfig = cfg.CONF
def get_parser(self, prog_name):
parser = super(UpgradeUndercloud, self).get_parser(prog_name)
parser.add_argument('--skip-package-updates',
dest='skip_package_updates',
action='store_true',
default=False,
help=_("Flag to skip the package update when "
"performing upgrades and updates"),
)
return parser
def _update_extra_packages(self, packages=[], dry_run=False): def _update_extra_packages(self, packages=[], dry_run=False):
"""Necessary packages to be updated before undercloud upgrade.""" """Necessary packages to be updated before undercloud upgrade."""
cmd = [] if not packages:
if packages: return
cmd = ['sudo', 'yum', 'upgrade', '-y'] + packages cmd = ['sudo', 'yum', 'upgrade', '-y'] + packages
if cmd:
if not dry_run: if not dry_run:
self.log.warning( self.log.warning("Updating necessary packages: {}".format(
"Updating necessary packages: {}\n{}".format( " ".join(packages)))
" ".join(packages),
("Note that tripleoclient and tripleo-common "
"still need to be updated manually.")
),
)
output = utils.run_command(cmd, name="Update extra packages") output = utils.run_command(cmd, name="Update extra packages")
self.log.warning("{}".format(output)) self.log.warning("{}".format(output))
else: else:
self.log.warning( self.log.warning("Would update necessary packages: {}".format(
"Would update necessary packages: {}".format(" ".join(cmd)) " ".join(cmd)))
)
def take_action(self, parsed_args): def _invoke_self(self, parsed_args):
# Fetch configuration used to add logging to a file cmd = ['openstack', 'undercloud', 'upgrade', '--skip-package-updates']
utils.load_config(self.osloconfig, constants.UNDERCLOUD_CONF_PATH) opts = {'force_stack_update': '--force-stack-update',
utils.configure_logging(self.log, self.app_args.verbose_level, 'no_validations': '--no-validations',
self.osloconfig['undercloud_log_file']) 'inflight': '--inflight-validations',
self.log.debug("take action(%s)" % parsed_args) 'dry_run': '--dry-run',
'yes': '--yes'}
utils.ensure_run_as_normal_user() args = vars(parsed_args)
for k, v in opts.items():
self._update_extra_packages(constants.UNDERCLOUD_EXTRA_PACKAGES, if args[k]:
parsed_args.dry_run) cmd.append(v)
# handle --debug
if self.app_args.verbose_level > 1:
cmd.append('--debug')
try:
subprocess.check_call(cmd)
except Exception as e:
self.log.error(e)
raise exceptions.DeploymentError(e)
def _run_upgrade(self, parsed_args):
cmd = undercloud_config.\ cmd = undercloud_config.\
prepare_undercloud_deploy( prepare_undercloud_deploy(
upgrade=True, upgrade=True,
@ -224,3 +239,27 @@ class UpgradeUndercloud(InstallUndercloud):
self.log.error(UNDERCLOUD_FAILURE_MESSAGE) self.log.error(UNDERCLOUD_FAILURE_MESSAGE)
self.log.error(e) self.log.error(e)
raise exceptions.DeploymentError(e) raise exceptions.DeploymentError(e)
def take_action(self, parsed_args):
# Fetch configuration used to add logging to a file
utils.load_config(self.osloconfig, constants.UNDERCLOUD_CONF_PATH)
utils.configure_logging(self.log, self.app_args.verbose_level,
self.osloconfig['undercloud_log_file'])
self.log.debug("take action(%s)" % parsed_args)
utils.ensure_run_as_normal_user()
if not parsed_args.skip_package_updates:
print("executable is {}".format(sys.executable))
if ('python3' in sys.executable):
pyver = '3'
else:
pyver = '2'
client_pkgs = [
"python{}-tripleoclient".format(pyver),
]
pkgs = client_pkgs + constants.UNDERCLOUD_EXTRA_PACKAGES
self._update_extra_packages(pkgs, parsed_args.dry_run)
self._invoke_self(parsed_args)
else:
self._run_upgrade(parsed_args)