You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

248 lines
9.1 KiB

10 months ago
import functools
import itertools
import json
import os
import shutil
import tarfile
from datetime import datetime
from leapp.cli.commands import command_utils
from leapp.cli.commands.config import get_config
from leapp.exceptions import CommandError
from leapp.repository.scan import find_and_scan_repositories
from leapp.utils import audit
from leapp.utils.audit import get_checkpoints, get_connection, get_messages
from leapp.utils.output import report_unsupported
from leapp.utils.report import fetch_upgrade_report_messages, generate_report_file
def disable_database_sync():
def disable_db_sync_decorator(f):
@functools.wraps(f)
def wrapper(*args, **kwargs):
saved = os.environ.get('LEAPP_DEVEL_DATABASE_SYNC_OFF', None)
try:
os.environ['LEAPP_DEVEL_DATABASE_SYNC_OFF'] = '1'
return f(*args, **kwargs)
finally:
os.environ.pop('LEAPP_DEVEL_DATABASE_SYNC_OFF')
if saved:
os.environ['LEAPP_DEVEL_DATABASE_SYNC_OFF'] = saved
return wrapper
if not os.environ.get('LEAPP_DATABASE_FORCE_SYNC_ON', None):
audit.create_connection = disable_db_sync_decorator(audit.create_connection)
def restore_leapp_env_vars(context):
"""
Restores leapp environment variables from the `IPUConfig` message.
"""
messages = get_messages(('IPUConfig',), context)
leapp_env_vars = json.loads((messages or [{}])[0].get('message', {}).get('data', '{}')).get('leapp_env_vars', {})
for entry in leapp_env_vars:
os.environ[entry['name']] = entry['value']
def archive_logfiles():
""" Archive log files from a previous run of Leapp """
cfg = get_config()
if not os.path.isdir(cfg.get('files_to_archive', 'dir')):
os.makedirs(cfg.get('files_to_archive', 'dir'))
files_to_archive = [os.path.join(cfg.get('files_to_archive', 'dir'), f)
for f in cfg.get('files_to_archive', 'files').split(',')
if os.path.isfile(os.path.join(cfg.get('files_to_archive', 'dir'), f))]
if not os.path.isdir(cfg.get('archive', 'dir')):
os.makedirs(cfg.get('archive', 'dir'))
if files_to_archive:
if os.path.isdir(cfg.get('debug', 'dir')):
files_to_archive.append(cfg.get('debug', 'dir'))
now = datetime.now().strftime('%Y%m%d%H%M%S')
archive_file = os.path.join(cfg.get('archive', 'dir'), 'leapp-{}-logs.tar.gz'.format(now))
with tarfile.open(archive_file, "w:gz") as tar:
for file_to_add in files_to_archive:
tar.add(file_to_add)
if os.path.isdir(file_to_add):
shutil.rmtree(file_to_add, ignore_errors=True)
try:
os.remove(file_to_add)
except OSError:
pass
# leapp_db is not in files_to_archive to not have it removed
if os.path.isfile(cfg.get('database', 'path')):
tar.add(cfg.get('database', 'path'))
def load_repositories_from(name, repo_path, manager=None):
if get_config().has_option('repositories', name):
repo_path = get_config().get('repositories', name)
return find_and_scan_repositories(repo_path, manager=manager)
def load_repositories():
manager = load_repositories_from('repo_path', '/etc/leapp/repo.d/', manager=None)
manager.load()
return manager
def fetch_last_upgrade_context(use_context=None):
"""
:return: Context of the last execution
"""
with get_connection(None) as db:
if use_context:
cursor = db.execute(
"SELECT context, stamp, configuration FROM execution WHERE context = ?", (use_context,))
else:
cursor = db.execute(
"SELECT context, stamp, configuration FROM execution WHERE kind = 'upgrade' ORDER BY id DESC LIMIT 1")
row = cursor.fetchone()
if row:
return row[0], json.loads(row[2])
return None, {}
def fetch_all_upgrade_contexts():
"""
:return: All upgrade execution contexts
"""
with get_connection(None) as db:
cursor = db.execute(
"SELECT context, stamp, configuration FROM execution WHERE kind = 'upgrade' ORDER BY id DESC")
row = cursor.fetchall()
if row:
return row
return None
def get_last_phase(context):
checkpoints = get_checkpoints(context=context)
if checkpoints:
return checkpoints[-1]['phase']
return None
def check_env_and_conf(env_var, conf_var, configuration):
"""
Checks whether the given environment variable or the given configuration value are set to '1'
"""
return os.getenv(env_var, '0') == '1' or configuration.get(conf_var, '0') == '1'
def generate_report_files(context, report_schema):
"""
Generates all report files for specific leapp run (txt and json format)
"""
cfg = get_config()
report_txt, report_json = [os.path.join(cfg.get('report', 'dir'),
'leapp-report.{}'.format(f)) for f in ['txt', 'json']]
# fetch all report messages as a list of dicts
messages = fetch_upgrade_report_messages(context)
generate_report_file(messages, context, report_txt, report_schema)
generate_report_file(messages, context, report_json, report_schema)
def get_cfg_files(section, cfg, must_exist=True):
"""
Provide files from particular config section
"""
files = []
for file_ in cfg.get(section, 'files').split(','):
file_path = os.path.join(cfg.get(section, 'dir'), file_)
if not must_exist or must_exist and os.path.isfile(file_path):
files.append(file_path)
return files
def warn_if_unsupported(configuration):
env = os.environ
if env.get('LEAPP_UNSUPPORTED', '0') == '1':
devel_vars = {k: env[k] for k in env if k.startswith('LEAPP_DEVEL_')}
report_unsupported(devel_vars, configuration["whitelist_experimental"])
def handle_output_level(args):
"""
Set environment variables following command line arguments.
"""
os.environ['LEAPP_DEBUG'] = '1' if args.debug else os.getenv('LEAPP_DEBUG', '0')
if os.environ['LEAPP_DEBUG'] == '1' or args.verbose:
os.environ['LEAPP_VERBOSE'] = '1'
else:
os.environ['LEAPP_VERBOSE'] = os.getenv('LEAPP_VERBOSE', '0')
# NOTE(ivasilev) Please make sure you are not calling prepare_configuration after first reboot.
# If called as leapp upgrade --resume this will happily crash in target version container for
# the latest supported release because of target_version discovery attempt.
def prepare_configuration(args):
"""Returns a configuration dict object while setting a few env vars as a side-effect"""
if args.whitelist_experimental:
args.whitelist_experimental = list(itertools.chain(*[i.split(',') for i in args.whitelist_experimental]))
os.environ['LEAPP_EXPERIMENTAL'] = '1'
else:
os.environ['LEAPP_EXPERIMENTAL'] = '0'
os.environ['LEAPP_UNSUPPORTED'] = '0' if os.getenv('LEAPP_UNSUPPORTED', '0') == '0' else '1'
if args.no_rhsm:
os.environ['LEAPP_NO_RHSM'] = '1'
elif os.getenv('LEAPP_NO_RHSM') != '1':
os.environ['LEAPP_NO_RHSM'] = os.getenv('LEAPP_DEVEL_SKIP_RHSM', '0')
if args.no_insights_register:
os.environ['LEAPP_NO_INSIGHTS_REGISTER'] = '1'
if args.enablerepo:
os.environ['LEAPP_ENABLE_REPOS'] = ','.join(args.enablerepo)
if os.environ.get('LEAPP_NO_RHSM', '0') == '1' or args.no_rhsm_facts:
os.environ['LEAPP_NO_RHSM_FACTS'] = '1'
if args.channel:
os.environ['LEAPP_TARGET_PRODUCT_CHANNEL'] = args.channel
if args.iso:
os.environ['LEAPP_TARGET_ISO'] = args.iso
target_iso_path = os.environ.get('LEAPP_TARGET_ISO')
if target_iso_path:
# Make sure we convert rel paths into abs ones while we know what CWD is
os.environ['LEAPP_TARGET_ISO'] = os.path.abspath(target_iso_path)
if args.nogpgcheck:
os.environ['LEAPP_NOGPGCHECK'] = '1'
# Check upgrade path and fail early if it's unsupported
target_version, flavor = command_utils.vet_upgrade_path(args)
os.environ['LEAPP_UPGRADE_PATH_TARGET_RELEASE'] = target_version
os.environ['LEAPP_UPGRADE_PATH_FLAVOUR'] = flavor
current_version = command_utils.get_os_release_version_id('/etc/os-release')
os.environ['LEAPP_IPU_IN_PROGRESS'] = '{source}to{target}'.format(
source=command_utils.get_major_version(current_version),
target=command_utils.get_major_version(target_version)
)
configuration = {
'debug': os.getenv('LEAPP_DEBUG', '0'),
'verbose': os.getenv('LEAPP_VERBOSE', '0'),
'whitelist_experimental': args.whitelist_experimental or (),
}
return configuration
def process_whitelist_experimental(repositories, workflow, configuration, logger=None):
for actor_name in configuration.get('whitelist_experimental', ()):
actor = repositories.lookup_actor(actor_name)
if actor:
workflow.whitelist_experimental_actor(actor)
else:
msg = 'No such Actor: {}'.format(actor_name)
if logger:
logger.error(msg)
raise CommandError(msg)