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)