python-tripleoclient/tripleoclient/v1/undercloud.py

260 lines
9.3 KiB
Python

# Copyright 2015 Red Hat, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
"""Plugin action implementation"""
import argparse
import logging
import os
import subprocess
import sys
from openstackclient.i18n import _
from oslo_config import cfg
from tripleoclient import command
from tripleoclient import constants
from tripleoclient import exceptions
from tripleoclient import utils
from tripleoclient.v1 import undercloud_config
UNDERCLOUD_FAILURE_MESSAGE = """
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
An error has occured while deploying the Undercloud.
See the previous output for details about what went wrong.
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
"""
UNDERCLOUD_COMPLETION_MESSAGE = """
##########################################################
The Undercloud has been successfully installed.
Useful files:
Password file is at {0}
The stackrc file is at {1}
Use these files to interact with OpenStack services, and
ensure they are secured.
##########################################################
"""
UNDERCLOUD_UPGRADE_COMPLETION_MESSAGE = """
##########################################################
The Undercloud has been successfully upgraded.
Useful files:
Password file is at {0}
The stackrc file is at {1}
Use these files to interact with OpenStack services, and
ensure they are secured.
##########################################################
"""
class InstallUndercloud(command.Command):
"""Install and setup the undercloud"""
auth_required = False
log = logging.getLogger(__name__ + ".InstallUndercloud")
osloconfig = cfg.CONF
def get_parser(self, prog_name):
parser = argparse.ArgumentParser(
description=self.get_description(),
prog=prog_name,
add_help=False
)
parser.add_argument('--force-stack-update',
dest='force_stack_update',
action='store_true',
default=False,
help=_("Do a virtual update of the ephemeral "
"heat stack. New or failed deployments "
"always have the stack_action=CREATE. This "
"option enforces stack_action=UPDATE."),
)
parser.add_argument(
'--no-validations',
dest='no_validations',
action='store_true',
default=False,
help=_("Do not perform undercloud configuration validations"),
)
parser.add_argument(
'--inflight-validations',
dest='inflight',
action='store_true',
default=False,
help=_('Activate in-flight validations during the deploy. '
'In-flight validations provide a robust way to ensure '
'deployed services are running right after their '
'activation. Defaults to False.')
)
parser.add_argument(
'--dry-run',
dest='dry_run',
action='store_true',
default=False,
help=_("Print the install command instead of running it"),
)
parser.add_argument('-y', '--yes', default=False,
action='store_true',
help=_("Skip yes/no prompt (assume yes)."))
parser.add_argument(
'--disable-container-prepare',
action='store_true',
default=False,
help=_('Disable the container preparation actions to prevent '
'container tags from being updated and new containers '
'from being fetched. If you skip this but do not have '
'the container parameters configured, the deployment '
'action may fail.')
)
return parser
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()
no_validations = parsed_args.dry_run or parsed_args.no_validations
inflight = not parsed_args.dry_run and parsed_args.inflight
cmd = undercloud_config.prepare_undercloud_deploy(
no_validations=no_validations,
verbose_level=self.app_args.verbose_level,
force_stack_update=parsed_args.force_stack_update,
dry_run=parsed_args.dry_run,
inflight=inflight,
disable_container_prepare=parsed_args.disable_container_prepare)
self.log.warning("Running: %s" % ' '.join(cmd))
if not parsed_args.dry_run:
try:
subprocess.check_call(cmd)
self.log.warning(UNDERCLOUD_COMPLETION_MESSAGE.format(
os.path.join(
constants.UNDERCLOUD_OUTPUT_DIR,
'tripleo-undercloud-passwords.yaml'
),
'~/stackrc'
))
except Exception as e:
self.log.error(UNDERCLOUD_FAILURE_MESSAGE)
self.log.error(e)
raise exceptions.DeploymentError(e)
class UpgradeUndercloud(InstallUndercloud):
"""Upgrade undercloud"""
auth_required = False
log = logging.getLogger(__name__ + ".UpgradeUndercloud")
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):
"""Necessary packages to be updated before undercloud upgrade."""
if not packages:
return
cmd = ['sudo', 'dnf', 'upgrade', '-y'] + packages
if not dry_run:
self.log.warning("Updating necessary packages: {}".format(
" ".join(packages)))
output = utils.run_command(cmd, name="Update extra packages")
self.log.warning("{}".format(output))
else:
self.log.warning("Would update necessary packages: {}".format(
" ".join(cmd)))
def _run_upgrade(self, parsed_args):
cmd = undercloud_config.\
prepare_undercloud_deploy(
upgrade=True,
yes=parsed_args.yes,
no_validations=parsed_args.
no_validations,
verbose_level=self.app_args.verbose_level,
force_stack_update=parsed_args.force_stack_update)
self.log.warning("Running: %s" % ' '.join(cmd))
try:
subprocess.check_call(cmd)
self.log.warning(
UNDERCLOUD_UPGRADE_COMPLETION_MESSAGE.format(
os.path.join(
constants.UNDERCLOUD_OUTPUT_DIR,
'tripleo-undercloud-passwords.yaml'
),
'~/stackrc'))
except Exception as e:
self.log.error(UNDERCLOUD_FAILURE_MESSAGE)
self.log.error(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)
if (not parsed_args.yes
and not utils.prompt_user_for_confirmation(
constants.UPGRADE_PROMPT, self.log)):
raise exceptions.UndercloudUpgradeNotConfirmed(
constants.UPGRADE_NO)
utils.ensure_run_as_normal_user()
if not parsed_args.skip_package_updates:
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)
if not parsed_args.dry_run:
self._run_upgrade(parsed_args)