2020-03-09 10:11:07 +01:00
|
|
|
#!/usr/bin/python
|
2021-08-08 10:40:22 +02:00
|
|
|
# -*- coding: utf-8 -*-
|
2020-03-09 10:11:07 +01:00
|
|
|
|
2022-08-05 12:28:29 +02:00
|
|
|
# Copyright (c) 2017, Giovanni Sciortino (@giovannisciortino)
|
|
|
|
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
|
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
2020-03-09 10:11:07 +01:00
|
|
|
|
|
|
|
from __future__ import absolute_import, division, print_function
|
|
|
|
__metaclass__ = type
|
|
|
|
|
|
|
|
DOCUMENTATION = '''
|
|
|
|
---
|
|
|
|
module: rhsm_repository
|
|
|
|
short_description: Manage RHSM repositories using the subscription-manager command
|
|
|
|
description:
|
|
|
|
- Manage (Enable/Disable) RHSM repositories to the Red Hat Subscription
|
|
|
|
Management entitlement platform using the C(subscription-manager) command.
|
|
|
|
author: Giovanni Sciortino (@giovannisciortino)
|
|
|
|
notes:
|
|
|
|
- In order to manage RHSM repositories the system must be already registered
|
2023-06-15 15:48:51 +02:00
|
|
|
to RHSM manually or using the Ansible M(community.general.redhat_subscription) module.
|
2023-03-22 13:15:32 +01:00
|
|
|
- It is possible to interact with C(subscription-manager) only as root,
|
|
|
|
so root permissions are required to successfully run this module.
|
2020-03-09 10:11:07 +01:00
|
|
|
|
|
|
|
requirements:
|
|
|
|
- subscription-manager
|
2023-02-20 17:30:26 +01:00
|
|
|
extends_documentation_fragment:
|
|
|
|
- community.general.attributes
|
|
|
|
attributes:
|
|
|
|
check_mode:
|
|
|
|
support: full
|
|
|
|
diff_mode:
|
|
|
|
support: full
|
2020-03-09 10:11:07 +01:00
|
|
|
options:
|
|
|
|
state:
|
|
|
|
description:
|
|
|
|
- If state is equal to present or disabled, indicates the desired
|
|
|
|
repository state.
|
2023-06-11 10:38:09 +02:00
|
|
|
- |
|
|
|
|
Please note that V(present) and V(absent) are deprecated, and will be
|
|
|
|
removed in community.general 10.0.0; please use V(enabled) and
|
|
|
|
V(disabled) instead.
|
2020-03-09 10:11:07 +01:00
|
|
|
choices: [present, enabled, absent, disabled]
|
2020-06-26 15:17:11 +02:00
|
|
|
default: "enabled"
|
|
|
|
type: str
|
2020-03-09 10:11:07 +01:00
|
|
|
name:
|
|
|
|
description:
|
|
|
|
- The ID of repositories to enable.
|
|
|
|
- To operate on several repositories this can accept a comma separated
|
|
|
|
list or a YAML list.
|
2022-08-24 19:59:13 +02:00
|
|
|
required: true
|
2020-06-26 15:17:11 +02:00
|
|
|
type: list
|
|
|
|
elements: str
|
2020-03-09 10:11:07 +01:00
|
|
|
purge:
|
|
|
|
description:
|
2023-06-15 15:48:51 +02:00
|
|
|
- Disable all currently enabled repositories that are not not specified in O(name).
|
|
|
|
Only set this to V(true) if passing in a list of repositories to the O(name) field.
|
2020-03-09 10:11:07 +01:00
|
|
|
Using this with C(loop) will most likely not have the desired result.
|
|
|
|
type: bool
|
2022-08-24 19:59:13 +02:00
|
|
|
default: false
|
2020-03-09 10:11:07 +01:00
|
|
|
'''
|
|
|
|
|
|
|
|
EXAMPLES = '''
|
|
|
|
- name: Enable a RHSM repository
|
2020-07-13 21:50:31 +02:00
|
|
|
community.general.rhsm_repository:
|
2020-03-09 10:11:07 +01:00
|
|
|
name: rhel-7-server-rpms
|
|
|
|
|
|
|
|
- name: Disable all RHSM repositories
|
2020-07-13 21:50:31 +02:00
|
|
|
community.general.rhsm_repository:
|
2020-03-09 10:11:07 +01:00
|
|
|
name: '*'
|
|
|
|
state: disabled
|
|
|
|
|
|
|
|
- name: Enable all repositories starting with rhel-6-server
|
2020-07-13 21:50:31 +02:00
|
|
|
community.general.rhsm_repository:
|
2020-03-09 10:11:07 +01:00
|
|
|
name: rhel-6-server*
|
|
|
|
state: enabled
|
|
|
|
|
|
|
|
- name: Disable all repositories except rhel-7-server-rpms
|
2020-07-13 21:50:31 +02:00
|
|
|
community.general.rhsm_repository:
|
2020-03-09 10:11:07 +01:00
|
|
|
name: rhel-7-server-rpms
|
2022-09-06 20:42:17 +02:00
|
|
|
purge: true
|
2020-03-09 10:11:07 +01:00
|
|
|
'''
|
|
|
|
|
|
|
|
RETURN = '''
|
|
|
|
repositories:
|
|
|
|
description:
|
|
|
|
- The list of RHSM repositories with their states.
|
|
|
|
- When this module is used to change the repository states, this list contains the updated states after the changes.
|
|
|
|
returned: success
|
|
|
|
type: list
|
|
|
|
'''
|
|
|
|
|
|
|
|
import os
|
|
|
|
from fnmatch import fnmatch
|
|
|
|
from copy import deepcopy
|
|
|
|
from ansible.module_utils.basic import AnsibleModule
|
|
|
|
|
|
|
|
|
2023-07-02 21:44:53 +02:00
|
|
|
class Rhsm(object):
|
|
|
|
def __init__(self, module):
|
|
|
|
self.module = module
|
|
|
|
self.rhsm_bin = self.module.get_bin_path('subscription-manager', required=True)
|
|
|
|
self.rhsm_kwargs = {
|
|
|
|
'environ_update': dict(LANG='C', LC_ALL='C', LC_MESSAGES='C'),
|
|
|
|
'expand_user_and_vars': False,
|
|
|
|
'use_unsafe_shell': False,
|
|
|
|
}
|
|
|
|
|
|
|
|
def run_repos(self, arguments):
|
|
|
|
"""
|
|
|
|
Execute `subscription-manager repos` with arguments and manage common errors
|
|
|
|
"""
|
|
|
|
rc, out, err = self.module.run_command(
|
|
|
|
[self.rhsm_bin, 'repos'] + arguments,
|
|
|
|
**self.rhsm_kwargs
|
|
|
|
)
|
|
|
|
|
|
|
|
if rc == 0 and out == 'This system has no repositories available through subscriptions.\n':
|
|
|
|
self.module.fail_json(msg='This system has no repositories available through subscriptions')
|
|
|
|
elif rc == 1:
|
|
|
|
self.module.fail_json(msg='subscription-manager failed with the following error: %s' % err)
|
|
|
|
else:
|
|
|
|
return rc, out, err
|
|
|
|
|
|
|
|
def list_repositories(self):
|
|
|
|
"""
|
|
|
|
Generate RHSM repository list and return a list of dict
|
|
|
|
"""
|
|
|
|
rc, out, err = self.run_repos(['--list'])
|
|
|
|
|
|
|
|
repo_id = ''
|
|
|
|
repo_name = ''
|
|
|
|
repo_url = ''
|
|
|
|
repo_enabled = ''
|
|
|
|
|
|
|
|
repo_result = []
|
|
|
|
for line in out.splitlines():
|
2023-07-15 12:57:54 +02:00
|
|
|
# ignore lines that are:
|
|
|
|
# - empty
|
|
|
|
# - "+---------[...]" -- i.e. header
|
|
|
|
# - " Available Repositories [...]" -- i.e. header
|
|
|
|
if line == '' or line[0] == '+' or line[0] == ' ':
|
2023-07-02 21:44:53 +02:00
|
|
|
continue
|
|
|
|
|
2023-07-15 12:57:54 +02:00
|
|
|
if line.startswith('Repo ID: '):
|
|
|
|
repo_id = line[9:].lstrip()
|
2023-07-02 21:44:53 +02:00
|
|
|
continue
|
|
|
|
|
2023-07-15 12:57:54 +02:00
|
|
|
if line.startswith('Repo Name: '):
|
|
|
|
repo_name = line[11:].lstrip()
|
2023-07-02 21:44:53 +02:00
|
|
|
continue
|
|
|
|
|
2023-07-15 12:57:54 +02:00
|
|
|
if line.startswith('Repo URL: '):
|
|
|
|
repo_url = line[10:].lstrip()
|
2023-07-02 21:44:53 +02:00
|
|
|
continue
|
|
|
|
|
2023-07-15 12:57:54 +02:00
|
|
|
if line.startswith('Enabled: '):
|
|
|
|
repo_enabled = line[9:].lstrip()
|
2023-07-02 21:44:53 +02:00
|
|
|
|
|
|
|
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, rhsm, state, name, purge=False):
|
2020-03-09 10:11:07 +01:00
|
|
|
name = set(name)
|
2023-07-02 21:44:53 +02:00
|
|
|
current_repo_list = rhsm.list_repositories()
|
2020-03-09 10:11:07 +01:00
|
|
|
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
|
|
|
|
updated_repo_list[idx]['enabled'] = True if state == 'enabled' else False
|
|
|
|
|
|
|
|
changed = False
|
|
|
|
results = []
|
|
|
|
diff_before = ""
|
|
|
|
diff_after = ""
|
2023-07-02 21:44:53 +02:00
|
|
|
rhsm_arguments = []
|
2020-03-09 10:11:07 +01:00
|
|
|
|
|
|
|
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 for this system\n" % repo['id']
|
|
|
|
diff_after += "Repository '%s' is disabled for this system\n" % 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 for this system\n" % repo['id']
|
|
|
|
diff_after += "Repository '%s' is enabled for this system\n" % repo['id']
|
|
|
|
results.append("Repository '%s' is enabled for this system" % repo['id'])
|
|
|
|
rhsm_arguments += ['--enable', repo['id']]
|
|
|
|
|
|
|
|
# Disable all enabled repos on the system that are not in the task and not
|
|
|
|
# marked as disabled by the task
|
|
|
|
if purge:
|
|
|
|
enabled_repo_ids = set(repo['id'] for repo in updated_repo_list if repo['enabled'])
|
|
|
|
matched_repoids_set = set(matched_existing_repo.keys())
|
|
|
|
difference = enabled_repo_ids.difference(matched_repoids_set)
|
|
|
|
if len(difference) > 0:
|
|
|
|
for repoid in difference:
|
|
|
|
changed = True
|
|
|
|
diff_before.join("Repository '{repoid}'' is enabled for this system\n".format(repoid=repoid))
|
|
|
|
diff_after.join("Repository '{repoid}' is disabled for this system\n".format(repoid=repoid))
|
|
|
|
results.append("Repository '{repoid}' is disabled for this system".format(repoid=repoid))
|
|
|
|
rhsm_arguments.extend(['--disable', repoid])
|
2023-06-20 07:13:47 +02:00
|
|
|
for updated_repo in updated_repo_list:
|
|
|
|
if updated_repo['id'] in difference:
|
|
|
|
updated_repo['enabled'] = False
|
2020-03-09 10:11:07 +01:00
|
|
|
|
|
|
|
diff = {'before': diff_before,
|
|
|
|
'after': diff_after,
|
|
|
|
'before_header': "RHSM repositories",
|
|
|
|
'after_header': "RHSM repositories"}
|
|
|
|
|
2020-06-11 10:00:48 +02:00
|
|
|
if not module.check_mode and changed:
|
2023-07-02 21:44:53 +02:00
|
|
|
rc, out, err = rhsm.run_repos(rhsm_arguments)
|
2020-03-09 10:11:07 +01:00
|
|
|
results = out.splitlines()
|
|
|
|
module.exit_json(results=results, changed=changed, repositories=updated_repo_list, diff=diff)
|
|
|
|
|
|
|
|
|
|
|
|
def main():
|
|
|
|
module = AnsibleModule(
|
|
|
|
argument_spec=dict(
|
2020-06-26 15:17:11 +02:00
|
|
|
name=dict(type='list', elements='str', required=True),
|
2020-03-09 10:11:07 +01:00
|
|
|
state=dict(choices=['enabled', 'disabled', 'present', 'absent'], default='enabled'),
|
|
|
|
purge=dict(type='bool', default=False),
|
|
|
|
),
|
|
|
|
supports_check_mode=True,
|
|
|
|
)
|
2023-03-22 13:15:32 +01:00
|
|
|
|
|
|
|
if os.getuid() != 0:
|
|
|
|
module.fail_json(
|
|
|
|
msg="Interacting with subscription-manager requires root permissions ('become: true')"
|
|
|
|
)
|
|
|
|
|
2023-07-02 21:44:53 +02:00
|
|
|
rhsm = Rhsm(module)
|
|
|
|
|
2020-03-09 10:11:07 +01:00
|
|
|
name = module.params['name']
|
|
|
|
state = module.params['state']
|
|
|
|
purge = module.params['purge']
|
|
|
|
|
2023-06-11 10:38:09 +02:00
|
|
|
if state in ['present', 'absent']:
|
|
|
|
replacement = 'enabled' if state == 'present' else 'disabled'
|
|
|
|
module.deprecate(
|
|
|
|
'state=%s is deprecated; please use state=%s instead' % (state, replacement),
|
|
|
|
version='10.0.0',
|
|
|
|
collection_name='community.general',
|
|
|
|
)
|
|
|
|
|
2023-07-02 21:44:53 +02:00
|
|
|
repository_modify(module, rhsm, state, name, purge)
|
2020-03-09 10:11:07 +01:00
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
main()
|