From 7708b21bb7aa24119c6de0515bd7e8bf9f6e69ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ely=C3=A9zer=20Mendes=20Rezende?= Date: Tue, 7 Apr 2015 17:15:20 -0300 Subject: [PATCH] Refactor repository management Create tasks to enable and disable repositories. Also drop manage_repos in favor of enable_repos task. The Satellite repo utilities was moved to the enable_satellite_repos task and disabling beaker repos was moved into its own task, the disable_beaker_repos task. Also add tasks to work with custom repositories files. The new tasks are create_custom_repos, delete_custom_repos and manage_custom_repos. The first will create custom repositories files and the second will remove them. The latter can enable or disable a custom repo depending on the boolean value specified for the matching repository name. Add two modules: repository and utils. This is the first step on organizing better the code base. The utils module will have utilities tasks to help creating tasks like distro_info and update_packages tasks. On the other hand repository module have tasks specific to managing repositories. --- automation_tools/__init__.py | 123 ++------------------------ automation_tools/repository.py | 157 +++++++++++++++++++++++++++++++++ automation_tools/utils.py | 81 +++++++++++++++++ fabfile.py | 20 +++-- 4 files changed, 262 insertions(+), 119 deletions(-) create mode 100644 automation_tools/repository.py create mode 100644 automation_tools/utils.py diff --git a/automation_tools/__init__.py b/automation_tools/__init__.py index 307a36603..b3a7b37a8 100644 --- a/automation_tools/__init__.py +++ b/automation_tools/__init__.py @@ -13,6 +13,8 @@ from re import search from urlparse import urlsplit +from automation_tools.repository import enable_satellite_repos +from automation_tools.utils import distro_info, update_packages from fabric.api import cd, env, execute, get, local, put, run if sys.version_info[0] is 2: from urlparse import urljoin # (import-error) pylint:disable=F0401 @@ -650,45 +652,6 @@ def install_prerequisites(): manage_daemon('start', 'ntpd', warn_only=True) -def manage_repos(cdn=False): - """Enables only required RHEL repos for Satellite 6.""" - - if isinstance(cdn, str): - cdn = (cdn.lower() == 'true') - - # Clean up system if Beaker-based - result = run('which yum-config-manager', warn_only=True) - if result.succeeded: - run('yum-config-manager --disable "beaker*"') - else: - run('mv /etc/yum.repos.d/beaker-* ~/', warn_only=True) - run('rm -rf /var/cache/yum*') - - # Disable yum plugin for sub-man - run('sed -i -e "s/^enabled.*/enabled=0/" ' - '/etc/yum/pluginconf.d/subscription-manager.conf') - # And disable all repos for now - run('subscription-manager repos --disable "*"') - - os_version = distro_info()[1] - # If installing from CDN, use the real product - if cdn is True: - run( - 'subscription-manager repos --enable ' - '"rhel-{0}-server-satellite-6.0-rpms"'.format(os_version) - ) - # Enable 'base' OS rpms - run('subscription-manager repos --enable "rhel-{0}-server-rpms"'.format( - os_version)) - # Enable SCL - run('subscription-manager repos --enable "rhel-server-rhscl-{0}-rpms"' - ''.format(os_version)) - run('yum repolist') - - # Update packages - update_packages(warn_only=True) - - def upstream_install( admin_password=None, sam=False, run_katello_installer=True): """Task to install Foreman nightly using katello-deploy script""" @@ -1003,7 +966,13 @@ def product_install(distribution, create_vm=False, certificate_url=None, execute(install_prerequisites, host=host) execute(setenforce, selinux_mode, host=host) - execute(manage_repos, cdn=distribution.endswith('cdn'), host=host) + execute( + enable_satellite_repos, + cdn=distribution.endswith('cdn'), + host=host + ) + execute(update_packages, warn_only=True) + # execute returns a dictionary mapping host strings to the given task's # return value installer_options.update(execute( @@ -1136,61 +1105,6 @@ def create_personal_git_repo(name, private=False): local('rm -rf {0}'.format(repo_name)) -def distro_info(): - """Task which figures out the distro information based on the - /etc/redhat-release file - - A `(distro, major_version)` tuple is returned if called as a function. For - RHEL X.Y.Z it will return ('rhel', X). For Fedora X it will return - ('fedora', X). Be aware that the major_version is an integer. - - """ - # Create/manage host cache - cache = env.get('distro_info_cache') - host = env['host'] - if cache is None: - cache = env['distro_info_cache'] = {} - - if host not in cache: - # Grab the information and store on cache - release_info = run('cat /etc/redhat-release', quiet=True) - if release_info.failed: - print('Failed to read /etc/redhat-release file') - sys.exit(1) - - # Discover the distro - if release_info.startswith('Red Hat Enterprise Linux'): - distro = 'rhel' - elif release_info.startswith('Fedora'): - distro = 'fedora' - else: - distro = None - - # Discover the version - match = search(r' ([0-9.]+) ', release_info) - if match is not None: - parts = match.group(1).split('.') - # extract the major version - major_version = int(parts[0]) - # extract the minor version - if len(parts) > 1: - minor_version = int(parts[1]) - else: - minor_version = None - else: - major_version = minor_version = None - - if distro is None or major_version is None: - print('Was not possible to fetch distro information') - sys.exit(1) - - cache[host] = distro, major_version, minor_version - - distro, major_version, minor_version = cache[host] - print('{0} {1} {2}'.format(distro, major_version, minor_version)) - return distro, major_version, minor_version - - def performance_tuning(running_on_vm=True): """Task which tunes up the Satellite 6 performance @@ -1498,25 +1412,6 @@ def run_errata(): # Run `-downgrade` if you want to revert to the old packages -def update_packages(*args, **kwargs): - """Updates all system packages or only ones specified by `args` - - Use this if you want to simply update all packages or some on system. - Possibly useful for when doing upgrades, etc. - - """ - if len(args) > 0: - arguments = ' '.join(args) - else: - arguments = '' - - run( - 'yum update -y {0}'.format(arguments), - quiet=kwargs.get('quiet', False), - warn_only=kwargs.get('warn_only', False), - ) - - # ============================================================================= # Utility tasks # ============================================================================= diff --git a/automation_tools/repository.py b/automation_tools/repository.py new file mode 100644 index 000000000..629f71d4b --- /dev/null +++ b/automation_tools/repository.py @@ -0,0 +1,157 @@ +"""Taks for managing repositories""" +from __future__ import print_function + +import sys + +from automation_tools.utils import distro_info +from fabric.api import put, run + +if sys.version_info[0] == 2: + from StringIO import StringIO # pylint:disable=import-error +else: + from io import StringIO + + +def disable_repos(*args): + """Disable repos passed as ``args`` using ``subscription-manager repos + --disable``. + + For example:: + + disable_repos('repo1', 'repo2') + + Will run the command ``subscription-manager repos --disable repo1 repo2``. + + + """ + run('subscription-manager repos --disable {0}' + .format(' '.join(['"{0}"'.format(repo) for repo in args]))) + + +def delete_custom_repos(**args): + """Delete repos files on ``/etc/yum.repos.d``. + + All files that match ``.repo`` will be deleted. Be aware that + this task can delete repository files created by ``subscription-manager`` + and other tools. But will raise ``ValueError`` if the repository name is + ``redhat``. + + :raise: ``ValueError`` if repository name is 'redhat'. + + """ + for name in args: + name = name.rstrip('.repo') + if name == 'redhat': + raise ValueError('This task will not delete redhat.repo file.') + run('rm -f /etc/yum.repos.d/{0}.repo'.format(name), warn_only=True) + + +def enable_repos(*args, **kwargs): + """Enable repos passed as ``args`` using ``subscription-manager repos + --enable``. + + For example:: + + enable_repos('repo1', 'repo2') + + Will run the command ``subscription-manager repos --enable repo1 repo2``. + + """ + run('subscription-manager repos --enable {0}' + .format(' '.join(['"{0}"'.format(repo) for repo in args]))) + + +def create_custom_repos(**kwargs): + """Create custom repofiles. + + Each ``kwargs`` item will result in one repository file created. Where the + key is the repository filename and repository name, and the value is the + repository URL. + + For example:: + + create_custom_repo(custom_repo='http://repourl.domain.com/path') + + Will create a repository file named ``custom_repo.repo`` with the following + contents:: + + [custom_repo] + name=custom_repo + baseurl=http://repourl.domain.com/path + enabled=1 + gpgcheck=0 + + """ + for name, url in kwargs.items(): + repo_file = StringIO() + repo_file.write( + '[{name}]\n' + 'name={name}\n' + 'baseurl={url}\n' + 'enabled=1\n' + 'gpgcheck=0\n' + .format(name=name, url=url) + ) + put(local_path=repo_file, + remote_path='/etc/yum.repos.d/{0}.repo'.format(name)) + repo_file.close() + + +def enable_satellite_repos(cdn=False, disable_enabled=True): + """Enable repositories required to install Satellite 6 + + If ``disable_enabled`` is ``True``, then this task will first disable any + already enabled repository, including beaker ones. + + """ + if isinstance(cdn, str): + cdn = (cdn.lower() == 'true') + if isinstance(disable_enabled, str): + disable_enabled = (disable_enabled.lower() == 'true') + + if disable_enabled is True: + disable_beaker_repos() + disable_repos('*') + + repos = [ + 'rhel-{0}-server-rpms', + 'rhel-server-rhscl-{0}-rpms', + ] + + if cdn is True: + repos.append('rhel-{0}-server-satellite-6.0-rpms') + + enable_repos(*[repo.format(distro_info()[1]) for repo in repos]) + + run('yum repolist') + + +def disable_beaker_repos(): + """Disable beaker repositories + + If yum-config-manager is available this task will disable the repos, if not + it will move the beaker repo files to the running user home directory + + """ + # Clean up system if Beaker-based + result = run('which yum-config-manager', warn_only=True) + if result.succeeded: + run('yum-config-manager --disable "beaker*"') + else: + run('mv /etc/yum.repos.d/beaker-* ~/', warn_only=True) + run('rm -rf /var/cache/yum*') + + +def manage_custom_repos(**kwargs): + """Enable or disable custom repositories. + + The keyword key is the repository filename and the boolean value indicates + if it should enable if ``True`` or disable if ``False``. + + """ + for name, enable in kwargs.items(): + repo_file = '/etc/yum.repos.d/{0}.repo'.format(name) + run('sed -i -e "s/^enabled=.*/enabled={0}/" {1}'.format( + 1 if enable is True else 0, + repo_file + )) diff --git a/automation_tools/utils.py b/automation_tools/utils.py new file mode 100644 index 000000000..a936f50a1 --- /dev/null +++ b/automation_tools/utils.py @@ -0,0 +1,81 @@ +"""Utilities tasks and functions""" +from __future__ import print_function + +import re +import sys + +from fabric.api import env, run + + +def distro_info(): + """Task which figures out the distro information based on the + /etc/redhat-release file + + A ``(distro, major_version)`` tuple is returned if called as a function. + For RHEL X.Y.Z it will return ``('rhel', X)``. For Fedora X it will return + ``('fedora', X)``. Be aware that the major_version is an integer. + + """ + # Create/manage host cache + cache = env.get('distro_info_cache') + host = env['host'] + if cache is None: + cache = env['distro_info_cache'] = {} + + if host not in cache: + # Grab the information and store on cache + release_info = run('cat /etc/redhat-release', quiet=True) + if release_info.failed: + print('Failed to read /etc/redhat-release file') + sys.exit(1) + + # Discover the distro + if release_info.startswith('Red Hat Enterprise Linux'): + distro = 'rhel' + elif release_info.startswith('Fedora'): + distro = 'fedora' + else: + distro = None + + # Discover the version + match = re.search(r' ([0-9.]+) ', release_info) + if match is not None: + parts = match.group(1).split('.') + # extract the major version + major_version = int(parts[0]) + # extract the minor version + if len(parts) > 1: + minor_version = int(parts[1]) + else: + minor_version = None + else: + major_version = minor_version = None + + if distro is None or major_version is None: + print('Was not possible to fetch distro information') + sys.exit(1) + + cache[host] = distro, major_version, minor_version + + distro, major_version, minor_version = cache[host] + print('{0} {1} {2}'.format(distro, major_version, minor_version)) + return distro, major_version, minor_version + + +def update_packages(*args, **kwargs): + """Updates all system packages or only ones specified by `args` + + Use this if you want to simply update all packages or some on system. + Possibly useful for when doing upgrades, etc. + + """ + if len(args) > 0: + arguments = ' '.join(args) + else: + arguments = '' + + run( + 'yum update -y {0}'.format(arguments), + quiet=kwargs.get('quiet', False), + warn_only=kwargs.get('warn_only', False), + ) diff --git a/fabfile.py b/fabfile.py index bb5e1f347..07d8a6640 100644 --- a/fabfile.py +++ b/fabfile.py @@ -1,11 +1,10 @@ """Module which publish all automation-tools tasks""" -from automation_tools import ( +from automation_tools import ( # flake8: noqa add_repo, cdn_install, clean_rhsm, client_registration_test, create_personal_git_repo, - distro_info, downstream_install, errata_upgrade, fix_hostname, @@ -15,7 +14,6 @@ install_prerequisites, iso_download, iso_install, - manage_repos, partition_disk, performance_tuning, product_install, @@ -33,10 +31,22 @@ subscribe, unsubscribe, update_basic_packages, - update_packages, upstream_install, vm_create, vm_destroy, vm_list, vm_list_base, -) # flake8: noqa +) +from automation_tools.repository import ( + create_custom_repos, + delete_custom_repos, + disable_beaker_repos, + disable_repos, + enable_repos, + enable_satellite_repos, + manage_custom_repos, +) +from automation_tools.utils import ( + distro_info, + update_packages +)