#!/usr/bin/python # # Copyright (c) 2017 OpenStack Foundation # All Rights Reserved. # # 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. from __future__ import absolute_import from __future__ import division from __future__ import print_function from ansible.module_utils.basic import AnsibleModule from copy import deepcopy from fnmatch import fnmatch import os import re ANSIBLE_METADATA = {'metadata_version': '1.1', 'status': ['preview'], 'supported_by': 'community'} DOCUMENTATION = ''' --- module: rhsm_repository short_description: Manage RHSM repositories using the subscription-manager command description: - Manage(List/Enable/Disable) RHSM repositories to the Red Hat Subscription Management entitlement platform using the C(subscription-manager) command. version_added: '2.5' author: Giovanni Sciortino (@giovannisciortino) notes: - In order to manage RHSM repositories the system must be already registered to RHSM manually or using the ansible module redhat_subscription. - One option between name and list must be defined, both options in the same task must not be defined. requirements: - subscription-manager options: state: description: - If state is equal to present or disabled, indicates the desired repository state. choices: [present, enabled, absent, disabled] required: True default: "present" name: description: - The ID of repositories to enable. - To operate on several repositories this can accept a comma separated list or a YAML list. required: True ''' EXAMPLES = ''' - name: Enable a RHSM repository rhsm_repository: name: rhel-7-server-rpms - name: Disable all Red Hat repositories rhsm_repository: name: '*' state: disabled - name: Enable all repositories starting with rhel-6-server rhsm_repository: name: rhel-6-server* state: enabled - name: Disable all repositories except rhel-7-server-rpms rhsm_repository: name: "{{ item }}" state: disabled with_items: "{{ rhsm_repository.repositories | map(attribute='id') | difference(['rhel-7-server-rpms']) }}" ''' RETURN = ''' repositories: description: - The list of Red Hat repositories with their states. - When this module is used to change the repositories states, this list contains the updated states after the changes. returned: success type: list ''' def run_subscription_manager(module, arguments): # Execute subuscription-manager with arguments and manage common errors rhsm_bin = module.get_bin_path('subscription-manager') if not rhsm_bin: module.fail_json(msg='The executable file subscription-manager was ' + 'not found in PATH') rc, out, err = module.run_command("%s %s" % (rhsm_bin, " ".join(arguments))) if rc == 1 and (err == 'The password you typed is invalid.\nPlease try ' + 'again.\n' or os.getuid() != 0): module.fail_json(msg='The executable file subscription-manager must ' + 'be run using root privileges') elif rc == 0 and (out == 'This system has no repositories available ' + 'through subscriptions.\n'): module.fail_json(msg='This system has no repositories available ' + 'through subscriptions') elif rc == 1: module.fail_json(msg='subscription-manager failed with the ' + 'following error: %s' % err) else: return rc, out, err def get_repository_list(module, list_parameter): # Generate RHSM repository list and return a list of dict if list_parameter == 'list_enabled': rhsm_arguments = ['repos', '--list-enabled'] elif list_parameter == 'list_disabled': rhsm_arguments = ['repos', '--list-disabled'] elif list_parameter == 'list': rhsm_arguments = ['repos', '--list'] rc, out, err = run_subscription_manager(module, rhsm_arguments) skip_lines = [ '+----------------------------------------------------------+', ' Available Repositories in /etc/yum.repos.d/redhat.repo' ] repo_id_re_str = r'Repo ID: (.*)' repo_name_re_str = r'Repo Name: (.*)' repo_url_re_str = r'Repo URL: (.*)' repo_enabled_re_str = r'Enabled: (.*)' repo_id = '' repo_name = '' repo_url = '' repo_enabled = '' repo_result = [] for line in out.split('\n'): if line in skip_lines: continue repo_id_re = re.match(repo_id_re_str, line) if repo_id_re: repo_id = repo_id_re.group(1) continue repo_name_re = re.match(repo_name_re_str, line) if repo_name_re: repo_name = repo_name_re.group(1) continue repo_url_re = re.match(repo_url_re_str, line) if repo_url_re: repo_url = repo_url_re.group(1) continue repo_enabled_re = re.match(repo_enabled_re_str, line) if repo_enabled_re: repo_enabled = repo_enabled_re.group(1) repo = { "id": repo_id, "name": repo_name, "url": repo_url, "enabled": True if repo_enabled == '1' else False } repo_result.append(repo) return repo_result def repository_modify(module, state, name): name = set(name) current_repo_list = get_repository_list(module, 'list') updated_repo_list = deepcopy(current_repo_list) matched_existing_repo = {} for repoid in name: matched_existing_repo[repoid] = [] for idx, repo in enumerate(current_repo_list): if fnmatch(repo['id'], repoid): matched_existing_repo[repoid].append(repo) # Update current_repo_list to return it as result variable if state == 'enabled': updated_repo_list[idx]['enabled'] = True else: updated_repo_list[idx]['enabled'] = False changed = False results = [] diff_before = "" diff_after = "" rhsm_arguments = ['repos'] for repoid in matched_existing_repo: if len(matched_existing_repo[repoid]) == 0: results.append("%s is not a valid repository ID" % repoid) module.fail_json(results=results, msg="%s is not a valid repository ID" % repoid) for repo in matched_existing_repo[repoid]: if state in ['disabled', 'absent']: if repo['enabled']: changed = True diff_before += "Repository '%s' is enabled" % repo['id'] diff_after += "Repository '%s' is disabled" % repo['id'] results.append( "Repository '%s' is disabled for this system" % repo['id']) rhsm_arguments += ['--disable', repo['id']] elif state in ['enabled', 'present']: if not repo['enabled']: changed = True diff_before += "Repository '%s' is disabled" % repo['id'] diff_after += "Repository '%s' is enabled" % repo['id'] results.append( "Repository '%s' is enabled for this system" % repo['id']) rhsm_arguments += ['--enable', repo['id']] diff = {'before': diff_before, 'after': diff_after, 'before_header': "RHSM repositories", 'after_header': "RHSM repositories"} if not module.check_mode: rc, out, err = run_subscription_manager(module, rhsm_arguments) results = out.split('\n') module.exit_json(results=results, changed=changed, repositories=updated_repo_list, diff=diff) def main(): module = AnsibleModule( argument_spec=dict( name=dict(type='list', required=True), state=dict(choices=['enabled', 'present', 'disabled', 'absent'], default='enabled'), ), supports_check_mode=True, ) name = module.params['name'] state = module.params['state'] repository_modify(module, state, name) if __name__ == '__main__': main()