From ec6496024f45a2aea65fb6506db8809ab33fcfbb Mon Sep 17 00:00:00 2001
From: Felix Fontein <felix@fontein.de>
Date: Mon, 7 Oct 2024 23:37:44 +0200
Subject: [PATCH] Prepare 10.0.0 release (#8921)

* Bump version to 10.0.0, remove deprecated modules and plugins.

* Remove redhat module utils.

* Drop support for ansible-core 2.13 and ansible-core 2.14.
---
 .github/BOTMETA.yml                           |   8 -
 .github/workflows/ansible-test.yml            |  74 +-
 README.md                                     |   2 +-
 changelogs/fragments/removals.yml             |  10 +
 galaxy.yml                                    |   2 +-
 meta/runtime.yml                              |  10 +-
 plugins/callback/hipchat.py                   | 240 ------
 plugins/module_utils/redhat.py                |  76 --
 plugins/modules/consul_acl.py                 | 695 ------------------
 plugins/modules/rhn_channel.py                | 210 ------
 plugins/modules/rhn_register.py               | 465 ------------
 tests/sanity/extra/botmeta.py                 |   1 -
 tests/unit/plugins/modules/rhn_conftest.py    |  35 -
 .../unit/plugins/modules/test_rhn_channel.py  | 147 ----
 .../unit/plugins/modules/test_rhn_register.py | 293 --------
 15 files changed, 30 insertions(+), 2238 deletions(-)
 create mode 100644 changelogs/fragments/removals.yml
 delete mode 100644 plugins/callback/hipchat.py
 delete mode 100644 plugins/module_utils/redhat.py
 delete mode 100644 plugins/modules/consul_acl.py
 delete mode 100644 plugins/modules/rhn_channel.py
 delete mode 100644 plugins/modules/rhn_register.py
 delete mode 100644 tests/unit/plugins/modules/rhn_conftest.py
 delete mode 100644 tests/unit/plugins/modules/test_rhn_channel.py
 delete mode 100644 tests/unit/plugins/modules/test_rhn_register.py

diff --git a/.github/BOTMETA.yml b/.github/BOTMETA.yml
index be0bf6da30..bcf300025f 100644
--- a/.github/BOTMETA.yml
+++ b/.github/BOTMETA.yml
@@ -61,7 +61,6 @@ files:
   $callbacks/elastic.py:
     keywords: apm observability
     maintainers: v1v
-  $callbacks/hipchat.py: {}
   $callbacks/jabber.py: {}
   $callbacks/log_plays.py: {}
   $callbacks/loganalytics.py:
@@ -1161,12 +1160,6 @@ files:
     keywords: kvm libvirt proxmox qemu
     labels: rhevm virt
     maintainers: $team_virt TimothyVandenbrande
-  $modules/rhn_channel.py:
-    labels: rhn_channel
-    maintainers: vincentvdk alikins $team_rhn
-  $modules/rhn_register.py:
-    labels: rhn_register
-    maintainers: jlaska $team_rhn
   $modules/rhsm_release.py:
     maintainers: seandst $team_rhsm
   $modules/rhsm_repository.py:
@@ -1554,7 +1547,6 @@ macros:
   team_oracle: manojmeda mross22 nalsaber
   team_purestorage: bannaych dnix101 genegr lionmax opslounge raekins sdodsley sile16
   team_redfish: mraineri tomasg2012 xmadsen renxulei rajeevkallur bhavya06 jyundt
-  team_rhn: FlossWare alikins barnabycourt vritant
   team_rhsm: cnsnyder ptoscano
   team_scaleway: remyleone abarbare
   team_solaris: bcoca fishman jasperla jpdasma mator scathatheworm troy2914 xen0l
diff --git a/.github/workflows/ansible-test.yml b/.github/workflows/ansible-test.yml
index 89a3006f56..ca06791a38 100644
--- a/.github/workflows/ansible-test.yml
+++ b/.github/workflows/ansible-test.yml
@@ -29,8 +29,6 @@ jobs:
     strategy:
       matrix:
         ansible:
-          - '2.13'
-          - '2.14'
           - '2.15'
     # Ansible-test on various stable branches does not yet work well with cgroups v2.
     # Since ubuntu-latest now uses Ubuntu 22.04, we need to fall back to the ubuntu-20.04
@@ -67,16 +65,8 @@ jobs:
         exclude:
           - ansible: ''
         include:
-          - ansible: '2.13'
+          - ansible: '2.15'
             python: '2.7'
-          - ansible: '2.13'
-            python: '3.8'
-          - ansible: '2.13'
-            python: '2.7'
-          - ansible: '2.13'
-            python: '3.8'
-          - ansible: '2.14'
-            python: '3.9'
           - ansible: '2.15'
             python: '3.5'
           - ansible: '2.15'
@@ -121,57 +111,19 @@ jobs:
         exclude:
           - ansible: ''
         include:
-          # 2.13
-          - ansible: '2.13'
-            docker: fedora35
-            python: ''
-            target: azp/posix/1/
-          - ansible: '2.13'
-            docker: fedora35
-            python: ''
-            target: azp/posix/2/
-          - ansible: '2.13'
-            docker: fedora35
-            python: ''
-            target: azp/posix/3/
-          - ansible: '2.13'
-            docker: opensuse15py2
-            python: ''
-            target: azp/posix/1/
-          - ansible: '2.13'
-            docker: opensuse15py2
-            python: ''
-            target: azp/posix/2/
-          - ansible: '2.13'
-            docker: opensuse15py2
-            python: ''
-            target: azp/posix/3/
-          - ansible: '2.13'
-            docker: alpine3
-            python: ''
-            target: azp/posix/1/
-          - ansible: '2.13'
-            docker: alpine3
-            python: ''
-            target: azp/posix/2/
-          - ansible: '2.13'
-            docker: alpine3
-            python: ''
-            target: azp/posix/3/
-          # 2.14
-          - ansible: '2.14'
-            docker: alpine3
-            python: ''
-            target: azp/posix/1/
-          - ansible: '2.14'
-            docker: alpine3
-            python: ''
-            target: azp/posix/2/
-          - ansible: '2.14'
-            docker: alpine3
-            python: ''
-            target: azp/posix/3/
           # 2.15
+          - ansible: '2.15'
+            docker: alpine3
+            python: ''
+            target: azp/posix/1/
+          - ansible: '2.15'
+            docker: alpine3
+            python: ''
+            target: azp/posix/2/
+          - ansible: '2.15'
+            docker: alpine3
+            python: ''
+            target: azp/posix/3/
           - ansible: '2.15'
             docker: fedora37
             python: ''
diff --git a/README.md b/README.md
index 4edd58edb3..03dad49f39 100644
--- a/README.md
+++ b/README.md
@@ -37,7 +37,7 @@ For more information about communication, see the [Ansible communication guide](
 
 ## Tested with Ansible
 
-Tested with the current ansible-core 2.13, ansible-core 2.14, ansible-core 2.15, ansible-core 2.16, ansible-core 2.17, ansible-core 2.18 releases and the current development version of ansible-core. Ansible-core versions before 2.13.0 are not supported. This includes all ansible-base 2.10 and Ansible 2.9 releases.
+Tested with the current ansible-core 2.15, ansible-core 2.16, ansible-core 2.17, ansible-core 2.18 releases and the current development version of ansible-core. Ansible-core versions before 2.15.0 are not supported. This includes all ansible-base 2.10 and Ansible 2.9 releases.
 
 ## External requirements
 
diff --git a/changelogs/fragments/removals.yml b/changelogs/fragments/removals.yml
new file mode 100644
index 0000000000..1a1f137194
--- /dev/null
+++ b/changelogs/fragments/removals.yml
@@ -0,0 +1,10 @@
+removed_features:
+  - "The hipchat callback plugin has been removed. The hipchat service has been discontinued and the self-hosted variant has been End of Life since 2020 (https://github.com/ansible-collections/community.general/pull/8921)."
+  - "The consul_acl module has been removed. Use community.general.consul_token and/or community.general.consul_policy instead (https://github.com/ansible-collections/community.general/pull/8921)."
+  - "The rhn_channel module has been removed (https://github.com/ansible-collections/community.general/pull/8921)."
+  - "The rhn_register module has been removed (https://github.com/ansible-collections/community.general/pull/8921)."
+  - "The redhat module utils has been removed (https://github.com/ansible-collections/community.general/pull/8921)."
+breaking_changes:
+  - The collection no longer supports ansible-core 2.13 and ansible-core 2.14.
+    While most (or even all) modules and plugins might still work with these versions, they are no longer tested in CI and breakages regarding them will not be fixed
+    (https://github.com/ansible-collections/community.general/pull/8921)."
diff --git a/galaxy.yml b/galaxy.yml
index 5112bdc64f..3af5356d06 100644
--- a/galaxy.yml
+++ b/galaxy.yml
@@ -5,7 +5,7 @@
 
 namespace: community
 name: general
-version: 9.5.0
+version: 10.0.0
 readme: README.md
 authors:
   - Ansible (https://github.com/ansible)
diff --git a/meta/runtime.yml b/meta/runtime.yml
index 5d4ed8cb89..f5adb64712 100644
--- a/meta/runtime.yml
+++ b/meta/runtime.yml
@@ -3,7 +3,7 @@
 # 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
 
-requires_ansible: '>=2.13.0'
+requires_ansible: '>=2.15.0'
 action_groups:
   consul:
     - consul_agent_check
@@ -44,7 +44,7 @@ plugin_routing:
         warning_text: Use the 'default' callback plugin with 'display_skipped_hosts
           = no' option.
     hipchat:
-      deprecation:
+      tombstone:
         removal_version: 10.0.0
         warning_text: The hipchat service has been discontinued and the self-hosted variant has been End of Life since 2020.
     osx_say:
@@ -72,7 +72,7 @@ plugin_routing:
       redirect: infoblox.nios_modules.nios_next_network
   modules:
     consul_acl:
-      deprecation:
+      tombstone:
         removal_version: 10.0.0
         warning_text: Use community.general.consul_token and/or community.general.consul_policy instead.
     hipchat:
@@ -184,12 +184,12 @@ plugin_routing:
         removal_version: 9.0.0
         warning_text: This module relied on the deprecated package pyrax.
     rhn_channel:
-      deprecation:
+      tombstone:
         removal_version: 10.0.0
         warning_text: RHN is EOL, please contact the community.general maintainers
           if still using this; see the module documentation for more details.
     rhn_register:
-      deprecation:
+      tombstone:
         removal_version: 10.0.0
         warning_text: RHN is EOL, please contact the community.general maintainers
           if still using this; see the module documentation for more details.
diff --git a/plugins/callback/hipchat.py b/plugins/callback/hipchat.py
deleted file mode 100644
index bf0d425303..0000000000
--- a/plugins/callback/hipchat.py
+++ /dev/null
@@ -1,240 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2014, Matt Martz <matt@sivel.net>
-# Copyright (c) 2017 Ansible Project
-# 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
-
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-DOCUMENTATION = '''
-    author: Unknown (!UNKNOWN)
-    name: hipchat
-    type: notification
-    requirements:
-      - whitelist in configuration.
-      - prettytable (python lib)
-    short_description: post task events to hipchat
-    description:
-      - This callback plugin sends status updates to a HipChat channel during playbook execution.
-      - Before 2.4 only environment variables were available for configuring this plugin.
-    deprecated:
-      removed_in: 10.0.0
-      why: The hipchat service has been discontinued and the self-hosted variant has been End of Life since 2020.
-      alternative: There is none.
-    options:
-      token:
-        description: HipChat API token for v1 or v2 API.
-        type: str
-        required: true
-        env:
-          - name: HIPCHAT_TOKEN
-        ini:
-          - section: callback_hipchat
-            key: token
-      api_version:
-        description: HipChat API version, v1 or v2.
-        type: str
-        choices:
-          - v1
-          - v2
-        required: false
-        default: v1
-        env:
-          - name: HIPCHAT_API_VERSION
-        ini:
-          - section: callback_hipchat
-            key: api_version
-      room:
-        description: HipChat room to post in.
-        type: str
-        default: ansible
-        env:
-          - name: HIPCHAT_ROOM
-        ini:
-          - section: callback_hipchat
-            key: room
-      from:
-        description:  Name to post as
-        type: str
-        default: ansible
-        env:
-          - name: HIPCHAT_FROM
-        ini:
-          - section: callback_hipchat
-            key: from
-      notify:
-        description: Add notify flag to important messages
-        type: bool
-        default: true
-        env:
-          - name: HIPCHAT_NOTIFY
-        ini:
-          - section: callback_hipchat
-            key: notify
-
-'''
-
-import os
-import json
-
-try:
-    import prettytable
-    HAS_PRETTYTABLE = True
-except ImportError:
-    HAS_PRETTYTABLE = False
-
-from ansible.plugins.callback import CallbackBase
-from ansible.module_utils.six.moves.urllib.parse import urlencode
-from ansible.module_utils.urls import open_url
-
-
-class CallbackModule(CallbackBase):
-    """This is an example ansible callback plugin that sends status
-    updates to a HipChat channel during playbook execution.
-    """
-
-    CALLBACK_VERSION = 2.0
-    CALLBACK_TYPE = 'notification'
-    CALLBACK_NAME = 'community.general.hipchat'
-    CALLBACK_NEEDS_WHITELIST = True
-
-    API_V1_URL = 'https://api.hipchat.com/v1/rooms/message'
-    API_V2_URL = 'https://api.hipchat.com/v2/'
-
-    def __init__(self):
-
-        super(CallbackModule, self).__init__()
-
-        if not HAS_PRETTYTABLE:
-            self.disabled = True
-            self._display.warning('The `prettytable` python module is not installed. '
-                                  'Disabling the HipChat callback plugin.')
-        self.printed_playbook = False
-        self.playbook_name = None
-        self.play = None
-
-    def set_options(self, task_keys=None, var_options=None, direct=None):
-        super(CallbackModule, self).set_options(task_keys=task_keys, var_options=var_options, direct=direct)
-
-        self.token = self.get_option('token')
-        self.api_version = self.get_option('api_version')
-        self.from_name = self.get_option('from')
-        self.allow_notify = self.get_option('notify')
-        self.room = self.get_option('room')
-
-        if self.token is None:
-            self.disabled = True
-            self._display.warning('HipChat token could not be loaded. The HipChat '
-                                  'token can be provided using the `HIPCHAT_TOKEN` '
-                                  'environment variable.')
-
-        # Pick the request handler.
-        if self.api_version == 'v2':
-            self.send_msg = self.send_msg_v2
-        else:
-            self.send_msg = self.send_msg_v1
-
-    def send_msg_v2(self, msg, msg_format='text', color='yellow', notify=False):
-        """Method for sending a message to HipChat"""
-
-        headers = {'Authorization': 'Bearer %s' % self.token, 'Content-Type': 'application/json'}
-
-        body = {}
-        body['room_id'] = self.room
-        body['from'] = self.from_name[:15]  # max length is 15
-        body['message'] = msg
-        body['message_format'] = msg_format
-        body['color'] = color
-        body['notify'] = self.allow_notify and notify
-
-        data = json.dumps(body)
-        url = self.API_V2_URL + "room/{room_id}/notification".format(room_id=self.room)
-        try:
-            response = open_url(url, data=data, headers=headers, method='POST')
-            return response.read()
-        except Exception as ex:
-            self._display.warning('Could not submit message to hipchat: {0}'.format(ex))
-
-    def send_msg_v1(self, msg, msg_format='text', color='yellow', notify=False):
-        """Method for sending a message to HipChat"""
-
-        params = {}
-        params['room_id'] = self.room
-        params['from'] = self.from_name[:15]  # max length is 15
-        params['message'] = msg
-        params['message_format'] = msg_format
-        params['color'] = color
-        params['notify'] = int(self.allow_notify and notify)
-
-        url = ('%s?auth_token=%s' % (self.API_V1_URL, self.token))
-        try:
-            response = open_url(url, data=urlencode(params))
-            return response.read()
-        except Exception as ex:
-            self._display.warning('Could not submit message to hipchat: {0}'.format(ex))
-
-    def v2_playbook_on_play_start(self, play):
-        """Display Playbook and play start messages"""
-
-        self.play = play
-        name = play.name
-        # This block sends information about a playbook when it starts
-        # The playbook object is not immediately available at
-        # playbook_on_start so we grab it via the play
-        #
-        # Displays info about playbook being started by a person on an
-        # inventory, as well as Tags, Skip Tags and Limits
-        if not self.printed_playbook:
-            self.playbook_name, dummy = os.path.splitext(os.path.basename(self.play.playbook.filename))
-            host_list = self.play.playbook.inventory.host_list
-            inventory = os.path.basename(os.path.realpath(host_list))
-            self.send_msg("%s: Playbook initiated by %s against %s" %
-                          (self.playbook_name,
-                           self.play.playbook.remote_user,
-                           inventory), notify=True)
-            self.printed_playbook = True
-            subset = self.play.playbook.inventory._subset
-            skip_tags = self.play.playbook.skip_tags
-            self.send_msg("%s:\nTags: %s\nSkip Tags: %s\nLimit: %s" %
-                          (self.playbook_name,
-                           ', '.join(self.play.playbook.only_tags),
-                           ', '.join(skip_tags) if skip_tags else None,
-                           ', '.join(subset) if subset else subset))
-
-        # This is where we actually say we are starting a play
-        self.send_msg("%s: Starting play: %s" %
-                      (self.playbook_name, name))
-
-    def playbook_on_stats(self, stats):
-        """Display info about playbook statistics"""
-        hosts = sorted(stats.processed.keys())
-
-        t = prettytable.PrettyTable(['Host', 'Ok', 'Changed', 'Unreachable',
-                                     'Failures'])
-
-        failures = False
-        unreachable = False
-
-        for h in hosts:
-            s = stats.summarize(h)
-
-            if s['failures'] > 0:
-                failures = True
-            if s['unreachable'] > 0:
-                unreachable = True
-
-            t.add_row([h] + [s[k] for k in ['ok', 'changed', 'unreachable',
-                                            'failures']])
-
-        self.send_msg("%s: Playbook complete" % self.playbook_name,
-                      notify=True)
-
-        if failures or unreachable:
-            color = 'red'
-            self.send_msg("%s: Failures detected" % self.playbook_name,
-                          color=color, notify=True)
-        else:
-            color = 'green'
-
-        self.send_msg("/code %s:\n%s" % (self.playbook_name, t), color=color)
diff --git a/plugins/module_utils/redhat.py b/plugins/module_utils/redhat.py
deleted file mode 100644
index 321386a0a5..0000000000
--- a/plugins/module_utils/redhat.py
+++ /dev/null
@@ -1,76 +0,0 @@
-# -*- coding: utf-8 -*-
-# This code is part of Ansible, but is an independent component.
-# This particular file snippet, and this file snippet only, is BSD licensed.
-# Modules you write using this snippet, which is embedded dynamically by Ansible
-# still belong to the author of the module, and may assign their own license
-# to the complete work.
-#
-# Copyright (c), James Laska
-#
-# Simplified BSD License (see LICENSES/BSD-2-Clause.txt or https://opensource.org/licenses/BSD-2-Clause)
-# SPDX-License-Identifier: BSD-2-Clause
-
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-
-import os
-import shutil
-import tempfile
-
-from ansible.module_utils.six.moves import configparser
-
-
-class RegistrationBase(object):
-    """
-    DEPRECATION WARNING
-
-    This class is deprecated and will be removed in community.general 10.0.0.
-    There is no replacement for it; please contact the community.general
-    maintainers in case you are using it.
-    """
-
-    def __init__(self, module, username=None, password=None):
-        self.module = module
-        self.username = username
-        self.password = password
-
-    def configure(self):
-        raise NotImplementedError("Must be implemented by a sub-class")
-
-    def enable(self):
-        # Remove any existing redhat.repo
-        redhat_repo = '/etc/yum.repos.d/redhat.repo'
-        if os.path.isfile(redhat_repo):
-            os.unlink(redhat_repo)
-
-    def register(self):
-        raise NotImplementedError("Must be implemented by a sub-class")
-
-    def unregister(self):
-        raise NotImplementedError("Must be implemented by a sub-class")
-
-    def unsubscribe(self):
-        raise NotImplementedError("Must be implemented by a sub-class")
-
-    def update_plugin_conf(self, plugin, enabled=True):
-        plugin_conf = '/etc/yum/pluginconf.d/%s.conf' % plugin
-
-        if os.path.isfile(plugin_conf):
-            tmpfd, tmpfile = tempfile.mkstemp()
-            shutil.copy2(plugin_conf, tmpfile)
-            cfg = configparser.ConfigParser()
-            cfg.read([tmpfile])
-
-            if enabled:
-                cfg.set('main', 'enabled', 1)
-            else:
-                cfg.set('main', 'enabled', 0)
-
-            fd = open(tmpfile, 'w+')
-            cfg.write(fd)
-            fd.close()
-            self.module.atomic_move(tmpfile, plugin_conf)
-
-    def subscribe(self, **kwargs):
-        raise NotImplementedError("Must be implemented by a sub-class")
diff --git a/plugins/modules/consul_acl.py b/plugins/modules/consul_acl.py
deleted file mode 100644
index 2d60af0625..0000000000
--- a/plugins/modules/consul_acl.py
+++ /dev/null
@@ -1,695 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2015, Steve Gargan <steve.gargan@gmail.com>
-# 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
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-
-DOCUMENTATION = '''
-module: consul_acl
-short_description: Manipulate Consul ACL keys and rules
-description:
- - Allows the addition, modification and deletion of ACL keys and associated
-   rules in a consul cluster via the agent. For more details on using and
-   configuring ACLs, see https://www.consul.io/docs/guides/acl.html.
-author:
-  - Steve Gargan (@sgargan)
-  - Colin Nolan (@colin-nolan)
-extends_documentation_fragment:
-  - community.general.attributes
-attributes:
-  check_mode:
-    support: none
-  diff_mode:
-    support: none
-deprecated:
-  removed_in: 10.0.0
-  why: The legacy ACL system was removed from Consul.
-  alternative: Use M(community.general.consul_token) and/or M(community.general.consul_policy) instead.
-options:
-  mgmt_token:
-    description:
-      - a management token is required to manipulate the acl lists
-    required: true
-    type: str
-  state:
-    description:
-      - whether the ACL pair should be present or absent
-    required: false
-    choices: ['present', 'absent']
-    default: present
-    type: str
-  token_type:
-    description:
-      - the type of token that should be created
-    choices: ['client', 'management']
-    default: client
-    type: str
-  name:
-    description:
-      - the name that should be associated with the acl key, this is opaque
-        to Consul
-    required: false
-    type: str
-  token:
-    description:
-      - the token key identifying an ACL rule set. If generated by consul
-        this will be a UUID
-    required: false
-    type: str
-  rules:
-    type: list
-    elements: dict
-    description:
-      - rules that should be associated with a given token
-    required: false
-  host:
-    description:
-      - host of the consul agent defaults to localhost
-    required: false
-    default: localhost
-    type: str
-  port:
-    type: int
-    description:
-      - the port on which the consul agent is running
-    required: false
-    default: 8500
-  scheme:
-    description:
-      - the protocol scheme on which the consul agent is running
-    required: false
-    default: http
-    type: str
-  validate_certs:
-    type: bool
-    description:
-      - whether to verify the tls certificate of the consul agent
-    required: false
-    default: true
-requirements:
-  - python-consul
-  - pyhcl
-  - requests
-'''
-
-EXAMPLES = """
-- name: Create an ACL with rules
-  community.general.consul_acl:
-    host: consul1.example.com
-    mgmt_token: some_management_acl
-    name: Foo access
-    rules:
-      - key: "foo"
-        policy: read
-      - key: "private/foo"
-        policy: deny
-
-- name: Create an ACL with a specific token
-  community.general.consul_acl:
-    host: consul1.example.com
-    mgmt_token: some_management_acl
-    name: Foo access
-    token: my-token
-    rules:
-      - key: "foo"
-        policy: read
-
-- name: Update the rules associated to an ACL token
-  community.general.consul_acl:
-    host: consul1.example.com
-    mgmt_token: some_management_acl
-    name: Foo access
-    token: some_client_token
-    rules:
-      - event: "bbq"
-        policy: write
-      - key: "foo"
-        policy: read
-      - key: "private"
-        policy: deny
-      - keyring: write
-      - node: "hgs4"
-        policy: write
-      - operator: read
-      - query: ""
-        policy: write
-      - service: "consul"
-        policy: write
-      - session: "standup"
-        policy: write
-
-- name: Remove a token
-  community.general.consul_acl:
-    host: consul1.example.com
-    mgmt_token: some_management_acl
-    token: 172bd5c8-9fe9-11e4-b1b0-3c15c2c9fd5e
-    state: absent
-"""
-
-RETURN = """
-token:
-    description: the token associated to the ACL (the ACL's ID)
-    returned: success
-    type: str
-    sample: a2ec332f-04cf-6fba-e8b8-acf62444d3da
-rules:
-    description: the HCL JSON representation of the rules associated to the ACL, in the format described in the
-                 Consul documentation (https://www.consul.io/docs/guides/acl.html#rule-specification).
-    returned: when O(state=present)
-    type: dict
-    sample: {
-        "key": {
-            "foo": {
-                "policy": "write"
-            },
-            "bar": {
-                "policy": "deny"
-            }
-        }
-    }
-operation:
-    description: the operation performed on the ACL
-    returned: changed
-    type: str
-    sample: update
-"""
-
-
-try:
-    import consul
-    python_consul_installed = True
-except ImportError:
-    python_consul_installed = False
-
-try:
-    import hcl
-    pyhcl_installed = True
-except ImportError:
-    pyhcl_installed = False
-
-try:
-    from requests.exceptions import ConnectionError
-    has_requests = True
-except ImportError:
-    has_requests = False
-
-from collections import defaultdict
-from ansible.module_utils.basic import to_text, AnsibleModule
-
-
-RULE_SCOPES = [
-    "agent",
-    "agent_prefix",
-    "event",
-    "event_prefix",
-    "key",
-    "key_prefix",
-    "keyring",
-    "node",
-    "node_prefix",
-    "operator",
-    "query",
-    "query_prefix",
-    "service",
-    "service_prefix",
-    "session",
-    "session_prefix",
-]
-
-MANAGEMENT_PARAMETER_NAME = "mgmt_token"
-HOST_PARAMETER_NAME = "host"
-SCHEME_PARAMETER_NAME = "scheme"
-VALIDATE_CERTS_PARAMETER_NAME = "validate_certs"
-NAME_PARAMETER_NAME = "name"
-PORT_PARAMETER_NAME = "port"
-RULES_PARAMETER_NAME = "rules"
-STATE_PARAMETER_NAME = "state"
-TOKEN_PARAMETER_NAME = "token"
-TOKEN_TYPE_PARAMETER_NAME = "token_type"
-
-PRESENT_STATE_VALUE = "present"
-ABSENT_STATE_VALUE = "absent"
-
-CLIENT_TOKEN_TYPE_VALUE = "client"
-MANAGEMENT_TOKEN_TYPE_VALUE = "management"
-
-REMOVE_OPERATION = "remove"
-UPDATE_OPERATION = "update"
-CREATE_OPERATION = "create"
-
-_POLICY_JSON_PROPERTY = "policy"
-_RULES_JSON_PROPERTY = "Rules"
-_TOKEN_JSON_PROPERTY = "ID"
-_TOKEN_TYPE_JSON_PROPERTY = "Type"
-_NAME_JSON_PROPERTY = "Name"
-_POLICY_YML_PROPERTY = "policy"
-_POLICY_HCL_PROPERTY = "policy"
-
-_ARGUMENT_SPEC = {
-    MANAGEMENT_PARAMETER_NAME: dict(required=True, no_log=True),
-    HOST_PARAMETER_NAME: dict(default='localhost'),
-    SCHEME_PARAMETER_NAME: dict(default='http'),
-    VALIDATE_CERTS_PARAMETER_NAME: dict(type='bool', default=True),
-    NAME_PARAMETER_NAME: dict(),
-    PORT_PARAMETER_NAME: dict(default=8500, type='int'),
-    RULES_PARAMETER_NAME: dict(type='list', elements='dict'),
-    STATE_PARAMETER_NAME: dict(default=PRESENT_STATE_VALUE, choices=[PRESENT_STATE_VALUE, ABSENT_STATE_VALUE]),
-    TOKEN_PARAMETER_NAME: dict(no_log=False),
-    TOKEN_TYPE_PARAMETER_NAME: dict(choices=[CLIENT_TOKEN_TYPE_VALUE, MANAGEMENT_TOKEN_TYPE_VALUE],
-                                    default=CLIENT_TOKEN_TYPE_VALUE)
-}
-
-
-def set_acl(consul_client, configuration):
-    """
-    Sets an ACL based on the given configuration.
-    :param consul_client: the consul client
-    :param configuration: the run configuration
-    :return: the output of setting the ACL
-    """
-    acls_as_json = decode_acls_as_json(consul_client.acl.list())
-    existing_acls_mapped_by_name = {acl.name: acl for acl in acls_as_json if acl.name is not None}
-    existing_acls_mapped_by_token = {acl.token: acl for acl in acls_as_json}
-    if None in existing_acls_mapped_by_token:
-        raise AssertionError("expecting ACL list to be associated to a token: %s" %
-                             existing_acls_mapped_by_token[None])
-
-    if configuration.token is None and configuration.name and configuration.name in existing_acls_mapped_by_name:
-        # No token but name given so can get token from name
-        configuration.token = existing_acls_mapped_by_name[configuration.name].token
-
-    if configuration.token and configuration.token in existing_acls_mapped_by_token:
-        return update_acl(consul_client, configuration)
-    else:
-        if configuration.token in existing_acls_mapped_by_token:
-            raise AssertionError()
-        if configuration.name in existing_acls_mapped_by_name:
-            raise AssertionError()
-        return create_acl(consul_client, configuration)
-
-
-def update_acl(consul_client, configuration):
-    """
-    Updates an ACL.
-    :param consul_client: the consul client
-    :param configuration: the run configuration
-    :return: the output of the update
-    """
-    existing_acl = load_acl_with_token(consul_client, configuration.token)
-    changed = existing_acl.rules != configuration.rules
-
-    if changed:
-        name = configuration.name if configuration.name is not None else existing_acl.name
-        rules_as_hcl = encode_rules_as_hcl_string(configuration.rules)
-        updated_token = consul_client.acl.update(
-            configuration.token, name=name, type=configuration.token_type, rules=rules_as_hcl)
-        if updated_token != configuration.token:
-            raise AssertionError()
-
-    return Output(changed=changed, token=configuration.token, rules=configuration.rules, operation=UPDATE_OPERATION)
-
-
-def create_acl(consul_client, configuration):
-    """
-    Creates an ACL.
-    :param consul_client: the consul client
-    :param configuration: the run configuration
-    :return: the output of the creation
-    """
-    rules_as_hcl = encode_rules_as_hcl_string(configuration.rules) if len(configuration.rules) > 0 else None
-    token = consul_client.acl.create(
-        name=configuration.name, type=configuration.token_type, rules=rules_as_hcl, acl_id=configuration.token)
-    rules = configuration.rules
-    return Output(changed=True, token=token, rules=rules, operation=CREATE_OPERATION)
-
-
-def remove_acl(consul, configuration):
-    """
-    Removes an ACL.
-    :param consul: the consul client
-    :param configuration: the run configuration
-    :return: the output of the removal
-    """
-    token = configuration.token
-    changed = consul.acl.info(token) is not None
-    if changed:
-        consul.acl.destroy(token)
-    return Output(changed=changed, token=token, operation=REMOVE_OPERATION)
-
-
-def load_acl_with_token(consul, token):
-    """
-    Loads the ACL with the given token (token == rule ID).
-    :param consul: the consul client
-    :param token: the ACL "token"/ID (not name)
-    :return: the ACL associated to the given token
-    :exception ConsulACLTokenNotFoundException: raised if the given token does not exist
-    """
-    acl_as_json = consul.acl.info(token)
-    if acl_as_json is None:
-        raise ConsulACLNotFoundException(token)
-    return decode_acl_as_json(acl_as_json)
-
-
-def encode_rules_as_hcl_string(rules):
-    """
-    Converts the given rules into the equivalent HCL (string) representation.
-    :param rules: the rules
-    :return: the equivalent HCL (string) representation of the rules. Will be None if there is no rules (see internal
-    note for justification)
-    """
-    if len(rules) == 0:
-        # Note: empty string is not valid HCL according to `hcl.load` however, the ACL `Rule` property will be an empty
-        # string if there is no rules...
-        return None
-    rules_as_hcl = ""
-    for rule in rules:
-        rules_as_hcl += encode_rule_as_hcl_string(rule)
-    return rules_as_hcl
-
-
-def encode_rule_as_hcl_string(rule):
-    """
-    Converts the given rule into the equivalent HCL (string) representation.
-    :param rule: the rule
-    :return: the equivalent HCL (string) representation of the rule
-    """
-    if rule.pattern is not None:
-        return '%s "%s" {\n  %s = "%s"\n}\n' % (rule.scope, rule.pattern, _POLICY_HCL_PROPERTY, rule.policy)
-    else:
-        return '%s = "%s"\n' % (rule.scope, rule.policy)
-
-
-def decode_rules_as_hcl_string(rules_as_hcl):
-    """
-    Converts the given HCL (string) representation of rules into a list of rule domain models.
-    :param rules_as_hcl: the HCL (string) representation of a collection of rules
-    :return: the equivalent domain model to the given rules
-    """
-    rules_as_hcl = to_text(rules_as_hcl)
-    rules_as_json = hcl.loads(rules_as_hcl)
-    return decode_rules_as_json(rules_as_json)
-
-
-def decode_rules_as_json(rules_as_json):
-    """
-    Converts the given JSON representation of rules into a list of rule domain models.
-    :param rules_as_json: the JSON representation of a collection of rules
-    :return: the equivalent domain model to the given rules
-    """
-    rules = RuleCollection()
-    for scope in rules_as_json:
-        if not isinstance(rules_as_json[scope], dict):
-            rules.add(Rule(scope, rules_as_json[scope]))
-        else:
-            for pattern, policy in rules_as_json[scope].items():
-                rules.add(Rule(scope, policy[_POLICY_JSON_PROPERTY], pattern))
-    return rules
-
-
-def encode_rules_as_json(rules):
-    """
-    Converts the given rules into the equivalent JSON representation according to the documentation:
-    https://www.consul.io/docs/guides/acl.html#rule-specification.
-    :param rules: the rules
-    :return: JSON representation of the given rules
-    """
-    rules_as_json = defaultdict(dict)
-    for rule in rules:
-        if rule.pattern is not None:
-            if rule.pattern in rules_as_json[rule.scope]:
-                raise AssertionError()
-            rules_as_json[rule.scope][rule.pattern] = {
-                _POLICY_JSON_PROPERTY: rule.policy
-            }
-        else:
-            if rule.scope in rules_as_json:
-                raise AssertionError()
-            rules_as_json[rule.scope] = rule.policy
-    return rules_as_json
-
-
-def decode_rules_as_yml(rules_as_yml):
-    """
-    Converts the given YAML representation of rules into a list of rule domain models.
-    :param rules_as_yml: the YAML representation of a collection of rules
-    :return: the equivalent domain model to the given rules
-    """
-    rules = RuleCollection()
-    if rules_as_yml:
-        for rule_as_yml in rules_as_yml:
-            rule_added = False
-            for scope in RULE_SCOPES:
-                if scope in rule_as_yml:
-                    if rule_as_yml[scope] is None:
-                        raise ValueError("Rule for '%s' does not have a value associated to the scope" % scope)
-                    policy = rule_as_yml[_POLICY_YML_PROPERTY] if _POLICY_YML_PROPERTY in rule_as_yml \
-                        else rule_as_yml[scope]
-                    pattern = rule_as_yml[scope] if _POLICY_YML_PROPERTY in rule_as_yml else None
-                    rules.add(Rule(scope, policy, pattern))
-                    rule_added = True
-                    break
-            if not rule_added:
-                raise ValueError("A rule requires one of %s and a policy." % ('/'.join(RULE_SCOPES)))
-    return rules
-
-
-def decode_acl_as_json(acl_as_json):
-    """
-    Converts the given JSON representation of an ACL into the equivalent domain model.
-    :param acl_as_json: the JSON representation of an ACL
-    :return: the equivalent domain model to the given ACL
-    """
-    rules_as_hcl = acl_as_json[_RULES_JSON_PROPERTY]
-    rules = decode_rules_as_hcl_string(acl_as_json[_RULES_JSON_PROPERTY]) if rules_as_hcl.strip() != "" \
-        else RuleCollection()
-    return ACL(
-        rules=rules,
-        token_type=acl_as_json[_TOKEN_TYPE_JSON_PROPERTY],
-        token=acl_as_json[_TOKEN_JSON_PROPERTY],
-        name=acl_as_json[_NAME_JSON_PROPERTY]
-    )
-
-
-def decode_acls_as_json(acls_as_json):
-    """
-    Converts the given JSON representation of ACLs into a list of ACL domain models.
-    :param acls_as_json: the JSON representation of a collection of ACLs
-    :return: list of equivalent domain models for the given ACLs (order not guaranteed to be the same)
-    """
-    return [decode_acl_as_json(acl_as_json) for acl_as_json in acls_as_json]
-
-
-class ConsulACLNotFoundException(Exception):
-    """
-    Exception raised if an ACL with is not found.
-    """
-
-
-class Configuration:
-    """
-    Configuration for this module.
-    """
-
-    def __init__(self, management_token=None, host=None, scheme=None, validate_certs=None, name=None, port=None,
-                 rules=None, state=None, token=None, token_type=None):
-        self.management_token = management_token    # type: str
-        self.host = host    # type: str
-        self.scheme = scheme    # type: str
-        self.validate_certs = validate_certs    # type: bool
-        self.name = name    # type: str
-        self.port = port    # type: int
-        self.rules = rules    # type: RuleCollection
-        self.state = state    # type: str
-        self.token = token    # type: str
-        self.token_type = token_type    # type: str
-
-
-class Output:
-    """
-    Output of an action of this module.
-    """
-
-    def __init__(self, changed=None, token=None, rules=None, operation=None):
-        self.changed = changed  # type: bool
-        self.token = token  # type: str
-        self.rules = rules  # type: RuleCollection
-        self.operation = operation  # type: str
-
-
-class ACL:
-    """
-    Consul ACL. See: https://www.consul.io/docs/guides/acl.html.
-    """
-
-    def __init__(self, rules, token_type, token, name):
-        self.rules = rules
-        self.token_type = token_type
-        self.token = token
-        self.name = name
-
-    def __eq__(self, other):
-        return other \
-            and isinstance(other, self.__class__) \
-            and self.rules == other.rules \
-            and self.token_type == other.token_type \
-            and self.token == other.token \
-            and self.name == other.name
-
-    def __hash__(self):
-        return hash(self.rules) ^ hash(self.token_type) ^ hash(self.token) ^ hash(self.name)
-
-
-class Rule:
-    """
-    ACL rule. See: https://www.consul.io/docs/guides/acl.html#acl-rules-and-scope.
-    """
-
-    def __init__(self, scope, policy, pattern=None):
-        self.scope = scope
-        self.policy = policy
-        self.pattern = pattern
-
-    def __eq__(self, other):
-        return isinstance(other, self.__class__) \
-            and self.scope == other.scope \
-            and self.policy == other.policy \
-            and self.pattern == other.pattern
-
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __hash__(self):
-        return (hash(self.scope) ^ hash(self.policy)) ^ hash(self.pattern)
-
-    def __str__(self):
-        return encode_rule_as_hcl_string(self)
-
-
-class RuleCollection:
-    """
-    Collection of ACL rules, which are part of a Consul ACL.
-    """
-
-    def __init__(self):
-        self._rules = {}
-        for scope in RULE_SCOPES:
-            self._rules[scope] = {}
-
-    def __iter__(self):
-        all_rules = []
-        for scope, pattern_keyed_rules in self._rules.items():
-            for pattern, rule in pattern_keyed_rules.items():
-                all_rules.append(rule)
-        return iter(all_rules)
-
-    def __len__(self):
-        count = 0
-        for scope in RULE_SCOPES:
-            count += len(self._rules[scope])
-        return count
-
-    def __eq__(self, other):
-        return isinstance(other, self.__class__) \
-            and set(self) == set(other)
-
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def __str__(self):
-        return encode_rules_as_hcl_string(self)
-
-    def add(self, rule):
-        """
-        Adds the given rule to this collection.
-        :param rule: model of a rule
-        :raises ValueError: raised if there already exists a rule for a given scope and pattern
-        """
-        if rule.pattern in self._rules[rule.scope]:
-            patten_info = " and pattern '%s'" % rule.pattern if rule.pattern is not None else ""
-            raise ValueError("Duplicate rule for scope '%s'%s" % (rule.scope, patten_info))
-        self._rules[rule.scope][rule.pattern] = rule
-
-
-def get_consul_client(configuration):
-    """
-    Gets a Consul client for the given configuration.
-
-    Does not check if the Consul client can connect.
-    :param configuration: the run configuration
-    :return: Consul client
-    """
-    token = configuration.management_token
-    if token is None:
-        token = configuration.token
-    if token is None:
-        raise AssertionError("Expecting the management token to always be set")
-    return consul.Consul(host=configuration.host, port=configuration.port, scheme=configuration.scheme,
-                         verify=configuration.validate_certs, token=token)
-
-
-def check_dependencies():
-    """
-    Checks that the required dependencies have been imported.
-    :exception ImportError: if it is detected that any of the required dependencies have not been imported
-    """
-    if not python_consul_installed:
-        raise ImportError("python-consul required for this module. "
-                          "See: https://python-consul.readthedocs.io/en/latest/#installation")
-
-    if not pyhcl_installed:
-        raise ImportError("pyhcl required for this module. "
-                          "See: https://pypi.org/project/pyhcl/")
-
-    if not has_requests:
-        raise ImportError("requests required for this module. See https://pypi.org/project/requests/")
-
-
-def main():
-    """
-    Main method.
-    """
-    module = AnsibleModule(_ARGUMENT_SPEC, supports_check_mode=False)
-
-    try:
-        check_dependencies()
-    except ImportError as e:
-        module.fail_json(msg=str(e))
-
-    configuration = Configuration(
-        management_token=module.params.get(MANAGEMENT_PARAMETER_NAME),
-        host=module.params.get(HOST_PARAMETER_NAME),
-        scheme=module.params.get(SCHEME_PARAMETER_NAME),
-        validate_certs=module.params.get(VALIDATE_CERTS_PARAMETER_NAME),
-        name=module.params.get(NAME_PARAMETER_NAME),
-        port=module.params.get(PORT_PARAMETER_NAME),
-        rules=decode_rules_as_yml(module.params.get(RULES_PARAMETER_NAME)),
-        state=module.params.get(STATE_PARAMETER_NAME),
-        token=module.params.get(TOKEN_PARAMETER_NAME),
-        token_type=module.params.get(TOKEN_TYPE_PARAMETER_NAME)
-    )
-    consul_client = get_consul_client(configuration)
-
-    try:
-        if configuration.state == PRESENT_STATE_VALUE:
-            output = set_acl(consul_client, configuration)
-        else:
-            output = remove_acl(consul_client, configuration)
-    except ConnectionError as e:
-        module.fail_json(msg='Could not connect to consul agent at %s:%s, error was %s' % (
-            configuration.host, configuration.port, str(e)))
-        raise
-
-    return_values = dict(changed=output.changed, token=output.token, operation=output.operation)
-    if output.rules is not None:
-        return_values["rules"] = encode_rules_as_json(output.rules)
-    module.exit_json(**return_values)
-
-
-if __name__ == "__main__":
-    main()
diff --git a/plugins/modules/rhn_channel.py b/plugins/modules/rhn_channel.py
deleted file mode 100644
index b69bb0c686..0000000000
--- a/plugins/modules/rhn_channel.py
+++ /dev/null
@@ -1,210 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-# Copyright (c) Vincent Van de Kussen
-# 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
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-DOCUMENTATION = '''
----
-module: rhn_channel
-short_description: Adds or removes Red Hat software channels
-description:
-    - Adds or removes Red Hat software channels.
-author:
-    - Vincent Van der Kussen (@vincentvdk)
-notes:
-    - This module fetches the system id from RHN.
-extends_documentation_fragment:
-    - community.general.attributes
-attributes:
-    check_mode:
-        support: none
-    diff_mode:
-        support: none
-options:
-    name:
-        description:
-            - Name of the software channel.
-        required: true
-        type: str
-    sysname:
-        description:
-            - Name of the system as it is known in RHN/Satellite.
-        required: true
-        type: str
-    state:
-        description:
-            - Whether the channel should be present or not, taking action if the state is different from what is stated.
-        default: present
-        choices: [ present, absent ]
-        type: str
-    url:
-        description:
-            - The full URL to the RHN/Satellite API.
-        required: true
-        type: str
-    user:
-        description:
-            - RHN/Satellite login.
-        required: true
-        type: str
-    password:
-        description:
-            - RHN/Satellite password.
-        aliases: [pwd]
-        required: true
-        type: str
-    validate_certs:
-        description:
-            - If V(false), SSL certificates will not be validated.
-            - This should only set to V(false) when used on self controlled sites
-              using self-signed certificates, and you are absolutely sure that nobody
-              can modify traffic between the module and the site.
-        type: bool
-        default: true
-        version_added: '0.2.0'
-deprecated:
-    removed_in: 10.0.0
-    why: |
-      RHN hosted at redhat.com was discontinued years ago, and Spacewalk 5
-      (which uses RHN) is EOL since 2020, May 31st; while this module could
-      work on Uyuni / SUSE Manager (fork of Spacewalk 5), we have not heard
-      about anyone using it in those setups.
-    alternative: |
-      Contact the community.general maintainers to report the usage of this
-      module, and potentially step up to maintain it.
-'''
-
-EXAMPLES = '''
-- name: Add a Red Hat software channel
-  community.general.rhn_channel:
-    name: rhel-x86_64-server-v2vwin-6
-    sysname: server01
-    url: https://rhn.redhat.com/rpc/api
-    user: rhnuser
-    password: guessme
-  delegate_to: localhost
-'''
-
-import ssl
-from ansible.module_utils.common.text.converters import to_text
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.six.moves import xmlrpc_client
-
-
-def get_systemid(client, session, sysname):
-    systems = client.system.listUserSystems(session)
-    for system in systems:
-        if system.get('name') == sysname:
-            idres = system.get('id')
-            idd = int(idres)
-            return idd
-
-
-def subscribe_channels(channelname, client, session, sysname, sys_id):
-    channels = base_channels(client, session, sys_id)
-    channels.append(channelname)
-    return client.system.setChildChannels(session, sys_id, channels)
-
-
-def unsubscribe_channels(channelname, client, session, sysname, sys_id):
-    channels = base_channels(client, session, sys_id)
-    channels.remove(channelname)
-    return client.system.setChildChannels(session, sys_id, channels)
-
-
-def base_channels(client, session, sys_id):
-    basechan = client.channel.software.listSystemChannels(session, sys_id)
-    try:
-        chans = [item['label'] for item in basechan]
-    except KeyError:
-        chans = [item['channel_label'] for item in basechan]
-    return chans
-
-
-def main():
-
-    module = AnsibleModule(
-        argument_spec=dict(
-            state=dict(type='str', default='present', choices=['present', 'absent']),
-            name=dict(type='str', required=True),
-            sysname=dict(type='str', required=True),
-            url=dict(type='str', required=True),
-            user=dict(type='str', required=True),
-            password=dict(type='str', required=True, aliases=['pwd'], no_log=True),
-            validate_certs=dict(type='bool', default=True),
-        )
-    )
-
-    state = module.params['state']
-    channelname = module.params['name']
-    systname = module.params['sysname']
-    saturl = module.params['url']
-    user = module.params['user']
-    password = module.params['password']
-    validate_certs = module.params['validate_certs']
-
-    ssl_context = None
-    if not validate_certs:
-        try:  # Python 2.7.9 and newer
-            ssl_context = ssl.create_unverified_context()
-        except AttributeError:  # Legacy Python that doesn't verify HTTPS certificates by default
-            ssl_context = ssl._create_unverified_context()
-        else:  # Python 2.7.8 and older
-            ssl._create_default_https_context = ssl._create_unverified_https_context
-
-    # initialize connection
-    if ssl_context:
-        client = xmlrpc_client.ServerProxy(saturl, context=ssl_context)
-    else:
-        client = xmlrpc_client.Server(saturl)
-
-    try:
-        session = client.auth.login(user, password)
-    except Exception as e:
-        module.fail_json(msg="Unable to establish session with Satellite server: %s " % to_text(e))
-
-    if not session:
-        module.fail_json(msg="Failed to establish session with Satellite server.")
-
-    # get systemid
-    try:
-        sys_id = get_systemid(client, session, systname)
-    except Exception as e:
-        module.fail_json(msg="Unable to get system id: %s " % to_text(e))
-
-    if not sys_id:
-        module.fail_json(msg="Failed to get system id.")
-
-    # get channels for system
-    try:
-        chans = base_channels(client, session, sys_id)
-    except Exception as e:
-        module.fail_json(msg="Unable to get channel information: %s " % to_text(e))
-
-    try:
-        if state == 'present':
-            if channelname in chans:
-                module.exit_json(changed=False, msg="Channel %s already exists" % channelname)
-            else:
-                subscribe_channels(channelname, client, session, systname, sys_id)
-                module.exit_json(changed=True, msg="Channel %s added" % channelname)
-
-        if state == 'absent':
-            if channelname not in chans:
-                module.exit_json(changed=False, msg="Not subscribed to channel %s." % channelname)
-            else:
-                unsubscribe_channels(channelname, client, session, systname, sys_id)
-                module.exit_json(changed=True, msg="Channel %s removed" % channelname)
-    except Exception as e:
-        module.fail_json(msg='Unable to %s channel (%s): %s' % ('add' if state == 'present' else 'remove', channelname, to_text(e)))
-    finally:
-        client.auth.logout(session)
-
-
-if __name__ == '__main__':
-    main()
diff --git a/plugins/modules/rhn_register.py b/plugins/modules/rhn_register.py
deleted file mode 100644
index cd1b708e48..0000000000
--- a/plugins/modules/rhn_register.py
+++ /dev/null
@@ -1,465 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-# Copyright (c) James Laska
-# 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
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-DOCUMENTATION = r'''
----
-module: rhn_register
-short_description: Manage Red Hat Network registration using the C(rhnreg_ks) command
-description:
-    - Manage registration to the Red Hat Network.
-author:
-    - James Laska (@jlaska)
-notes:
-    - This is for older Red Hat products. You probably want the M(community.general.redhat_subscription) module instead.
-    - In order to register a system, C(rhnreg_ks) requires either a username and password, or an activationkey.
-requirements:
-    - rhnreg_ks
-    - either libxml2 or lxml
-extends_documentation_fragment:
-    - community.general.attributes
-attributes:
-    check_mode:
-        support: none
-    diff_mode:
-        support: none
-options:
-    state:
-        description:
-          - Whether to register (V(present)), or unregister (V(absent)) a system.
-        type: str
-        choices: [ absent, present ]
-        default: present
-    username:
-        description:
-            - Red Hat Network username.
-        type: str
-    password:
-        description:
-            - Red Hat Network password.
-        type: str
-    server_url:
-        description:
-            - Specify an alternative Red Hat Network server URL.
-            - The default is the current value of C(serverURL) from C(/etc/sysconfig/rhn/up2date).
-        type: str
-    activationkey:
-        description:
-            - Supply an activation key for use with registration.
-        type: str
-    profilename:
-        description:
-            - Supply an profilename for use with registration.
-        type: str
-    force:
-        description:
-            - Force registration, even if system is already registered.
-        type: bool
-        default: false
-        version_added: 2.0.0
-    ca_cert:
-        description:
-            - Supply a custom ssl CA certificate file for use with registration.
-        type: path
-        aliases: [ sslcacert ]
-    systemorgid:
-        description:
-            - Supply an organizational id for use with registration.
-        type: str
-    channels:
-        description:
-            - Optionally specify a list of channels to subscribe to upon successful registration.
-        type: list
-        elements: str
-        default: []
-    enable_eus:
-        description:
-            - If V(false), extended update support will be requested.
-        type: bool
-        default: false
-    nopackages:
-        description:
-            - If V(true), the registered node will not upload its installed packages information to Satellite server.
-        type: bool
-        default: false
-deprecated:
-    removed_in: 10.0.0
-    why: |
-      RHN hosted at redhat.com was discontinued years ago, and Spacewalk 5
-      (which uses RHN) is EOL since 2020, May 31st; while this module could
-      work on Uyuni / SUSE Manager (fork of Spacewalk 5), we have not heard
-      about anyone using it in those setups.
-    alternative: |
-      Contact the community.general maintainers to report the usage of this
-      module, and potentially step up to maintain it.
-'''
-
-EXAMPLES = r'''
-- name: Unregister system from RHN
-  community.general.rhn_register:
-    state: absent
-    username: joe_user
-    password: somepass
-
-- name: Register as user with password and auto-subscribe to available content
-  community.general.rhn_register:
-    state: present
-    username: joe_user
-    password: somepass
-
-- name: Register with activationkey and enable extended update support
-  community.general.rhn_register:
-    state: present
-    activationkey: 1-222333444
-    enable_eus: true
-
-- name: Register with activationkey and set a profilename which may differ from the hostname
-  community.general.rhn_register:
-    state: present
-    activationkey: 1-222333444
-    profilename: host.example.com.custom
-
-- name: Register as user with password against a satellite server
-  community.general.rhn_register:
-    state: present
-    username: joe_user
-    password: somepass
-    server_url: https://xmlrpc.my.satellite/XMLRPC
-
-- name: Register as user with password and enable channels
-  community.general.rhn_register:
-    state: present
-    username: joe_user
-    password: somepass
-    channels: rhel-x86_64-server-6-foo-1,rhel-x86_64-server-6-bar-1
-
-- name: Force-register as user with password to ensure registration is current on server
-  community.general.rhn_register:
-    state: present
-    username: joe_user
-    password: somepass
-    server_url: https://xmlrpc.my.satellite/XMLRPC
-    force: true
-'''
-
-RETURN = r'''
-# Default return values
-'''
-
-import os
-import sys
-
-# Attempt to import rhn client tools
-sys.path.insert(0, '/usr/share/rhn')
-try:
-    import up2date_client
-    import up2date_client.config
-    HAS_UP2DATE_CLIENT = True
-except ImportError:
-    HAS_UP2DATE_CLIENT = False
-
-# INSERT REDHAT SNIPPETS
-from ansible_collections.community.general.plugins.module_utils import redhat
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.six.moves import urllib, xmlrpc_client
-
-
-class Rhn(redhat.RegistrationBase):
-
-    def __init__(self, module=None, username=None, password=None):
-        redhat.RegistrationBase.__init__(self, module, username, password)
-        self.config = self.load_config()
-        self.server = None
-        self.session = None
-
-    def logout(self):
-        if self.session is not None:
-            self.server.auth.logout(self.session)
-
-    def load_config(self):
-        '''
-            Read configuration from /etc/sysconfig/rhn/up2date
-        '''
-        if not HAS_UP2DATE_CLIENT:
-            return None
-
-        config = up2date_client.config.initUp2dateConfig()
-
-        return config
-
-    @property
-    def server_url(self):
-        return self.config['serverURL']
-
-    @property
-    def hostname(self):
-        '''
-            Return the non-xmlrpc RHN hostname.  This is a convenience method
-            used for displaying a more readable RHN hostname.
-
-            Returns: str
-        '''
-        url = urllib.parse.urlparse(self.server_url)
-        return url[1].replace('xmlrpc.', '')
-
-    @property
-    def systemid(self):
-        systemid = None
-        xpath_str = "//member[name='system_id']/value/string"
-
-        if os.path.isfile(self.config['systemIdPath']):
-            fd = open(self.config['systemIdPath'], 'r')
-            xml_data = fd.read()
-            fd.close()
-
-            # Ugh, xml parsing time ...
-            # First, try parsing with libxml2 ...
-            if systemid is None:
-                try:
-                    import libxml2
-                    doc = libxml2.parseDoc(xml_data)
-                    ctxt = doc.xpathNewContext()
-                    systemid = ctxt.xpathEval(xpath_str)[0].content
-                    doc.freeDoc()
-                    ctxt.xpathFreeContext()
-                except ImportError:
-                    pass
-
-            # m-kay, let's try with lxml now ...
-            if systemid is None:
-                try:
-                    from lxml import etree
-                    root = etree.fromstring(xml_data)
-                    systemid = root.xpath(xpath_str)[0].text
-                except ImportError:
-                    raise Exception('"libxml2" or "lxml" is required for this module.')
-
-            # Strip the 'ID-' prefix
-            if systemid is not None and systemid.startswith('ID-'):
-                systemid = systemid[3:]
-
-        return int(systemid)
-
-    @property
-    def is_registered(self):
-        '''
-            Determine whether the current system is registered.
-
-            Returns: True|False
-        '''
-        return os.path.isfile(self.config['systemIdPath'])
-
-    def configure_server_url(self, server_url):
-        '''
-            Configure server_url for registration
-        '''
-
-        self.config.set('serverURL', server_url)
-        self.config.save()
-
-    def enable(self):
-        '''
-            Prepare the system for RHN registration.  This includes ...
-             * enabling the rhnplugin yum plugin
-             * disabling the subscription-manager yum plugin
-        '''
-        redhat.RegistrationBase.enable(self)
-        self.update_plugin_conf('rhnplugin', True)
-        self.update_plugin_conf('subscription-manager', False)
-
-    def register(self, enable_eus=False, activationkey=None, profilename=None, sslcacert=None, systemorgid=None, nopackages=False):
-        '''
-            Register system to RHN.  If enable_eus=True, extended update
-            support will be requested.
-        '''
-        register_cmd = ['/usr/sbin/rhnreg_ks', '--force']
-        if self.username:
-            register_cmd.extend(['--username', self.username, '--password', self.password])
-        if self.server_url:
-            register_cmd.extend(['--serverUrl', self.server_url])
-        if enable_eus:
-            register_cmd.append('--use-eus-channel')
-        if nopackages:
-            register_cmd.append('--nopackages')
-        if activationkey is not None:
-            register_cmd.extend(['--activationkey', activationkey])
-        if profilename is not None:
-            register_cmd.extend(['--profilename', profilename])
-        if sslcacert is not None:
-            register_cmd.extend(['--sslCACert', sslcacert])
-        if systemorgid is not None:
-            register_cmd.extend(['--systemorgid', systemorgid])
-        rc, stdout, stderr = self.module.run_command(register_cmd, check_rc=True)
-
-    def api(self, method, *args):
-        '''
-            Convenience RPC wrapper
-        '''
-        if self.server is None:
-            if self.hostname != 'rhn.redhat.com':
-                url = "https://%s/rpc/api" % self.hostname
-            else:
-                url = "https://xmlrpc.%s/rpc/api" % self.hostname
-            self.server = xmlrpc_client.ServerProxy(url)
-            self.session = self.server.auth.login(self.username, self.password)
-
-        func = getattr(self.server, method)
-        return func(self.session, *args)
-
-    def unregister(self):
-        '''
-            Unregister a previously registered system
-        '''
-
-        # Initiate RPC connection
-        self.api('system.deleteSystems', [self.systemid])
-
-        # Remove systemid file
-        os.unlink(self.config['systemIdPath'])
-
-    def subscribe(self, channels):
-        if not channels:
-            return
-
-        if self._is_hosted():
-            current_channels = self.api('channel.software.listSystemChannels', self.systemid)
-            new_channels = [item['channel_label'] for item in current_channels]
-            new_channels.extend(channels)
-            return self.api('channel.software.setSystemChannels', self.systemid, list(new_channels))
-
-        else:
-            current_channels = self.api('channel.software.listSystemChannels', self.systemid)
-            current_channels = [item['label'] for item in current_channels]
-            new_base = None
-            new_childs = []
-            for ch in channels:
-                if ch in current_channels:
-                    continue
-                if self.api('channel.software.getDetails', ch)['parent_channel_label'] == '':
-                    new_base = ch
-                else:
-                    if ch not in new_childs:
-                        new_childs.append(ch)
-            out_base = 0
-            out_childs = 0
-
-            if new_base:
-                out_base = self.api('system.setBaseChannel', self.systemid, new_base)
-
-            if new_childs:
-                out_childs = self.api('system.setChildChannels', self.systemid, new_childs)
-
-            return out_base and out_childs
-
-    def _is_hosted(self):
-        '''
-            Return True if we are running against Hosted (rhn.redhat.com) or
-            False otherwise (when running against Satellite or Spacewalk)
-        '''
-        return 'rhn.redhat.com' in self.hostname
-
-
-def main():
-
-    module = AnsibleModule(
-        argument_spec=dict(
-            state=dict(type='str', default='present', choices=['absent', 'present']),
-            username=dict(type='str'),
-            password=dict(type='str', no_log=True),
-            server_url=dict(type='str'),
-            activationkey=dict(type='str', no_log=True),
-            profilename=dict(type='str'),
-            ca_cert=dict(type='path', aliases=['sslcacert']),
-            systemorgid=dict(type='str'),
-            enable_eus=dict(type='bool', default=False),
-            force=dict(type='bool', default=False),
-            nopackages=dict(type='bool', default=False),
-            channels=dict(type='list', elements='str', default=[]),
-        ),
-        # username/password is required for state=absent, or if channels is not empty
-        # (basically anything that uses self.api requires username/password) but it doesn't
-        # look like we can express that with required_if/required_together/mutually_exclusive
-
-        # only username+password can be used for unregister
-        required_if=[['state', 'absent', ['username', 'password']]],
-    )
-
-    if not HAS_UP2DATE_CLIENT:
-        module.fail_json(msg="Unable to import up2date_client.  Is 'rhn-client-tools' installed?")
-
-    server_url = module.params['server_url']
-    username = module.params['username']
-    password = module.params['password']
-
-    state = module.params['state']
-    force = module.params['force']
-    activationkey = module.params['activationkey']
-    profilename = module.params['profilename']
-    sslcacert = module.params['ca_cert']
-    systemorgid = module.params['systemorgid']
-    channels = module.params['channels']
-    enable_eus = module.params['enable_eus']
-    nopackages = module.params['nopackages']
-
-    rhn = Rhn(module=module, username=username, password=password)
-
-    # use the provided server url and persist it to the rhn config.
-    if server_url:
-        rhn.configure_server_url(server_url)
-
-    if not rhn.server_url:
-        module.fail_json(
-            msg="No serverURL was found (from either the 'server_url' module arg or the config file option 'serverURL' in /etc/sysconfig/rhn/up2date)"
-        )
-
-    # Ensure system is registered
-    if state == 'present':
-
-        # Check for missing parameters ...
-        if not (activationkey or rhn.username or rhn.password):
-            module.fail_json(msg="Missing arguments, must supply an activationkey (%s) or username (%s) and password (%s)" % (activationkey, rhn.username,
-                                                                                                                              rhn.password))
-        if not activationkey and not (rhn.username and rhn.password):
-            module.fail_json(msg="Missing arguments, If registering without an activationkey, must supply username or password")
-
-        # Register system
-        if rhn.is_registered and not force:
-            module.exit_json(changed=False, msg="System already registered.")
-
-        try:
-            rhn.enable()
-            rhn.register(enable_eus, activationkey, profilename, sslcacert, systemorgid, nopackages)
-            rhn.subscribe(channels)
-        except Exception as exc:
-            module.fail_json(msg="Failed to register with '%s': %s" % (rhn.hostname, exc))
-        finally:
-            rhn.logout()
-
-        module.exit_json(changed=True, msg="System successfully registered to '%s'." % rhn.hostname)
-
-    # Ensure system is *not* registered
-    if state == 'absent':
-        if not rhn.is_registered:
-            module.exit_json(changed=False, msg="System already unregistered.")
-
-        if not (rhn.username and rhn.password):
-            module.fail_json(msg="Missing arguments, the system is currently registered and unregistration requires a username and password")
-
-        try:
-            rhn.unregister()
-        except Exception as exc:
-            module.fail_json(msg="Failed to unregister: %s" % exc)
-        finally:
-            rhn.logout()
-
-        module.exit_json(changed=True, msg="System successfully unregistered from %s." % rhn.hostname)
-
-
-if __name__ == '__main__':
-    main()
diff --git a/tests/sanity/extra/botmeta.py b/tests/sanity/extra/botmeta.py
index d7828ebabb..07ca189e81 100755
--- a/tests/sanity/extra/botmeta.py
+++ b/tests/sanity/extra/botmeta.py
@@ -27,7 +27,6 @@ IGNORE_NO_MAINTAINERS = [
     'plugins/callback/cgroup_memory_recap.py',
     'plugins/callback/context_demo.py',
     'plugins/callback/counter_enabled.py',
-    'plugins/callback/hipchat.py',
     'plugins/callback/jabber.py',
     'plugins/callback/log_plays.py',
     'plugins/callback/logdna.py',
diff --git a/tests/unit/plugins/modules/rhn_conftest.py b/tests/unit/plugins/modules/rhn_conftest.py
deleted file mode 100644
index acc0e2f221..0000000000
--- a/tests/unit/plugins/modules/rhn_conftest.py
+++ /dev/null
@@ -1,35 +0,0 @@
-# Copyright (c) Ansible project
-# 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
-
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-from ansible.module_utils.six.moves import xmlrpc_client
-
-import pytest
-
-
-def get_method_name(request_body):
-    return xmlrpc_client.loads(request_body)[1]
-
-
-@pytest.fixture
-def mock_request(request, mocker):
-    responses = request.getfixturevalue('testcase')['calls']
-    module_name = request.module.TESTED_MODULE
-
-    def transport_request(host, handler, request_body, verbose=0):
-        """Fake request"""
-        method_name = get_method_name(request_body)
-        excepted_name, response = responses.pop(0)
-        if method_name == excepted_name:
-            if isinstance(response, Exception):
-                raise response
-            else:
-                return response
-        else:
-            raise Exception('Expected call: %r, called with: %r' % (excepted_name, method_name))
-
-    target = '{0}.xmlrpc_client.Transport.request'.format(module_name)
-    mocker.patch(target, side_effect=transport_request)
diff --git a/tests/unit/plugins/modules/test_rhn_channel.py b/tests/unit/plugins/modules/test_rhn_channel.py
deleted file mode 100644
index fd3bdc5fe0..0000000000
--- a/tests/unit/plugins/modules/test_rhn_channel.py
+++ /dev/null
@@ -1,147 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2017 Pierre-Louis Bonicoli <pierre-louis@libregerbil.fr>
-# 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
-
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-import json
-
-from ansible_collections.community.general.plugins.modules import rhn_channel
-
-from .rhn_conftest import mock_request  # noqa: F401, pylint: disable=unused-import
-
-import pytest
-
-
-pytestmark = pytest.mark.usefixtures('patch_ansible_module')
-
-
-@pytest.mark.parametrize('patch_ansible_module', [{}], indirect=['patch_ansible_module'])
-def test_without_required_parameters(capfd):
-    with pytest.raises(SystemExit):
-        rhn_channel.main()
-    out, err = capfd.readouterr()
-    results = json.loads(out)
-    assert results['failed']
-    assert 'missing required arguments' in results['msg']
-
-
-TESTED_MODULE = rhn_channel.__name__
-TEST_CASES = [
-    [
-        # add channel already added, check that result isn't changed
-        {
-            'name': 'rhel-x86_64-server-6',
-            'sysname': 'server01',
-            'url': 'https://rhn.redhat.com/rpc/api',
-            'user': 'user',
-            'password': 'pass',
-        },
-        {
-            'calls': [
-                ('auth.login', ['X' * 43]),
-                ('system.listUserSystems',
-                 [[{'last_checkin': '2017-08-06 19:49:52.0', 'id': '0123456789', 'name': 'server01'}]]),
-                ('channel.software.listSystemChannels',
-                 [[{'channel_name': 'Red Hat Enterprise Linux Server (v. 6 for 64-bit x86_64)', 'channel_label': 'rhel-x86_64-server-6'}]]),
-                ('auth.logout', [1]),
-            ],
-            'changed': False,
-            'msg': 'Channel rhel-x86_64-server-6 already exists',
-        }
-    ],
-    [
-        # add channel, check that result is changed
-        {
-            'name': 'rhel-x86_64-server-6-debuginfo',
-            'sysname': 'server01',
-            'url': 'https://rhn.redhat.com/rpc/api',
-            'user': 'user',
-            'password': 'pass',
-        },
-        {
-            'calls': [
-                ('auth.login', ['X' * 43]),
-                ('system.listUserSystems',
-                 [[{'last_checkin': '2017-08-06 19:49:52.0', 'id': '0123456789', 'name': 'server01'}]]),
-                ('channel.software.listSystemChannels',
-                 [[{'channel_name': 'Red Hat Enterprise Linux Server (v. 6 for 64-bit x86_64)', 'channel_label': 'rhel-x86_64-server-6'}]]),
-                ('channel.software.listSystemChannels',
-                 [[{'channel_name': 'Red Hat Enterprise Linux Server (v. 6 for 64-bit x86_64)', 'channel_label': 'rhel-x86_64-server-6'}]]),
-                ('system.setChildChannels', [1]),
-                ('auth.logout', [1]),
-            ],
-            'changed': True,
-            'msg': 'Channel rhel-x86_64-server-6-debuginfo added',
-        }
-    ],
-    [
-        # remove inexistent channel, check that result isn't changed
-        {
-            'name': 'rhel-x86_64-server-6-debuginfo',
-            'state': 'absent',
-            'sysname': 'server01',
-            'url': 'https://rhn.redhat.com/rpc/api',
-            'user': 'user',
-            'password': 'pass',
-        },
-        {
-            'calls': [
-                ('auth.login', ['X' * 43]),
-                ('system.listUserSystems',
-                 [[{'last_checkin': '2017-08-06 19:49:52.0', 'id': '0123456789', 'name': 'server01'}]]),
-                ('channel.software.listSystemChannels',
-                 [[{'channel_name': 'Red Hat Enterprise Linux Server (v. 6 for 64-bit x86_64)', 'channel_label': 'rhel-x86_64-server-6'}]]),
-                ('auth.logout', [1]),
-            ],
-            'changed': False,
-            'msg': 'Not subscribed to channel rhel-x86_64-server-6-debuginfo.',
-        }
-    ],
-    [
-        # remove channel, check that result is changed
-        {
-            'name': 'rhel-x86_64-server-6-debuginfo',
-            'state': 'absent',
-            'sysname': 'server01',
-            'url': 'https://rhn.redhat.com/rpc/api',
-            'user': 'user',
-            'password': 'pass',
-        },
-        {
-            'calls': [
-                ('auth.login', ['X' * 43]),
-                ('system.listUserSystems',
-                 [[{'last_checkin': '2017-08-06 19:49:52.0', 'id': '0123456789', 'name': 'server01'}]]),
-                ('channel.software.listSystemChannels', [[
-                    {'channel_name': 'RHEL Server Debuginfo (v.6 for x86_64)', 'channel_label': 'rhel-x86_64-server-6-debuginfo'},
-                    {'channel_name': 'Red Hat Enterprise Linux Server (v. 6 for 64-bit x86_64)', 'channel_label': 'rhel-x86_64-server-6'}
-                ]]),
-                ('channel.software.listSystemChannels', [[
-                    {'channel_name': 'RHEL Server Debuginfo (v.6 for x86_64)', 'channel_label': 'rhel-x86_64-server-6-debuginfo'},
-                    {'channel_name': 'Red Hat Enterprise Linux Server (v. 6 for 64-bit x86_64)', 'channel_label': 'rhel-x86_64-server-6'}
-                ]]),
-                ('system.setChildChannels', [1]),
-                ('auth.logout', [1]),
-            ],
-            'changed': True,
-            'msg': 'Channel rhel-x86_64-server-6-debuginfo removed'
-        }
-    ]
-]
-
-
-@pytest.mark.parametrize('patch_ansible_module, testcase', TEST_CASES, indirect=['patch_ansible_module'])
-def test_rhn_channel(capfd, mocker, testcase, mock_request):
-    """Check 'msg' and 'changed' results"""
-
-    with pytest.raises(SystemExit):
-        rhn_channel.main()
-
-    out, err = capfd.readouterr()
-    results = json.loads(out)
-    assert results['changed'] == testcase['changed']
-    assert results['msg'] == testcase['msg']
-    assert not testcase['calls']  # all calls should have been consumed
diff --git a/tests/unit/plugins/modules/test_rhn_register.py b/tests/unit/plugins/modules/test_rhn_register.py
deleted file mode 100644
index 1394c07b65..0000000000
--- a/tests/unit/plugins/modules/test_rhn_register.py
+++ /dev/null
@@ -1,293 +0,0 @@
-# Copyright (c) Ansible project
-# 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
-
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-import json
-import os
-
-from ansible_collections.community.general.tests.unit.compat.mock import mock_open
-from ansible.module_utils import basic
-from ansible.module_utils.common.text.converters import to_native
-import ansible.module_utils.six
-from ansible.module_utils.six.moves import xmlrpc_client
-from ansible_collections.community.general.plugins.modules import rhn_register
-
-from .rhn_conftest import mock_request  # noqa: F401, pylint: disable=unused-import
-
-import pytest
-
-
-SYSTEMID = """<?xml version="1.0"?>
-<params>
-<param>
-<value><struct>
-<member>
-<name>system_id</name>
-<value><string>ID-123456789</string></value>
-</member>
-</struct></value>
-</param>
-</params>
-"""
-
-
-def skipWhenAllModulesMissing(modules):
-    """Skip the decorated test unless one of modules is available."""
-    for module in modules:
-        try:
-            __import__(module)
-            return False
-        except ImportError:
-            continue
-
-    return True
-
-
-orig_import = __import__
-
-
-@pytest.fixture
-def import_libxml(mocker):
-    def mock_import(name, *args, **kwargs):
-        if name in ['libxml2', 'libxml']:
-            raise ImportError()
-        else:
-            return orig_import(name, *args, **kwargs)
-
-    if ansible.module_utils.six.PY3:
-        mocker.patch('builtins.__import__', side_effect=mock_import)
-    else:
-        mocker.patch('__builtin__.__import__', side_effect=mock_import)
-
-
-@pytest.fixture
-def patch_rhn(mocker):
-    load_config_return = {
-        'serverURL': 'https://xmlrpc.rhn.redhat.com/XMLRPC',
-        'systemIdPath': '/etc/sysconfig/rhn/systemid'
-    }
-
-    mocker.patch.object(rhn_register.Rhn, 'load_config', return_value=load_config_return)
-    mocker.patch.object(rhn_register, 'HAS_UP2DATE_CLIENT', mocker.PropertyMock(return_value=True))
-
-
-@pytest.mark.skipif(skipWhenAllModulesMissing(['libxml2', 'libxml']), reason='none are available: libxml2, libxml')
-def test_systemid_with_requirements(capfd, mocker, patch_rhn):
-    """Check 'msg' and 'changed' results"""
-
-    mocker.patch.object(rhn_register.Rhn, 'enable')
-    mock_isfile = mocker.patch('os.path.isfile', return_value=True)
-    mocker.patch('ansible_collections.community.general.plugins.modules.rhn_register.open', mock_open(read_data=SYSTEMID), create=True)
-    rhn = rhn_register.Rhn()
-    assert '123456789' == to_native(rhn.systemid)
-
-
-@pytest.mark.parametrize('patch_ansible_module', [{}], indirect=['patch_ansible_module'])
-@pytest.mark.usefixtures('patch_ansible_module')
-def test_systemid_requirements_missing(capfd, mocker, patch_rhn, import_libxml):
-    """Check that missing dependencies are detected"""
-
-    mocker.patch('os.path.isfile', return_value=True)
-    mocker.patch('ansible_collections.community.general.plugins.modules.rhn_register.open', mock_open(read_data=SYSTEMID), create=True)
-
-    with pytest.raises(SystemExit):
-        rhn_register.main()
-
-    out, err = capfd.readouterr()
-    results = json.loads(out)
-    assert results['failed']
-    assert 'Missing arguments' in results['msg']
-
-
-@pytest.mark.parametrize('patch_ansible_module', [{}], indirect=['patch_ansible_module'])
-@pytest.mark.usefixtures('patch_ansible_module')
-def test_without_required_parameters(capfd, patch_rhn):
-    """Failure must occurs when all parameters are missing"""
-
-    with pytest.raises(SystemExit):
-        rhn_register.main()
-    out, err = capfd.readouterr()
-    results = json.loads(out)
-    assert results['failed']
-    assert 'Missing arguments' in results['msg']
-
-
-TESTED_MODULE = rhn_register.__name__
-TEST_CASES = [
-    [
-        # Registering an unregistered host with channels
-        {
-            'channels': 'rhel-x86_64-server-6',
-            'username': 'user',
-            'password': 'pass',
-        },
-        {
-            'calls': [
-                ('auth.login', ['X' * 43]),
-                ('channel.software.listSystemChannels',
-                    [[{'channel_name': 'Red Hat Enterprise Linux Server (v. 6 for 64-bit x86_64)', 'channel_label': 'rhel-x86_64-server-6'}]]),
-                ('channel.software.setSystemChannels', [1]),
-                ('auth.logout', [1]),
-            ],
-            'is_registered': False,
-            'is_registered.call_count': 1,
-            'enable.call_count': 1,
-            'systemid.call_count': 2,
-            'changed': True,
-            'msg': "System successfully registered to 'rhn.redhat.com'.",
-            'run_command.call_count': 1,
-            'run_command.call_args': '/usr/sbin/rhnreg_ks',
-            'request_called': True,
-            'unlink.call_count': 0,
-        }
-    ],
-    [
-        # Registering an unregistered host without channels
-        {
-            'activationkey': 'key',
-            'username': 'user',
-            'password': 'pass',
-        },
-        {
-            'calls': [
-            ],
-            'is_registered': False,
-            'is_registered.call_count': 1,
-            'enable.call_count': 1,
-            'systemid.call_count': 0,
-            'changed': True,
-            'msg': "System successfully registered to 'rhn.redhat.com'.",
-            'run_command.call_count': 1,
-            'run_command.call_args': '/usr/sbin/rhnreg_ks',
-            'request_called': False,
-            'unlink.call_count': 0,
-        }
-    ],
-    [
-        # Register an host already registered, check that result is unchanged
-        {
-            'activationkey': 'key',
-            'username': 'user',
-            'password': 'pass',
-        },
-        {
-            'calls': [
-            ],
-            'is_registered': True,
-            'is_registered.call_count': 1,
-            'enable.call_count': 0,
-            'systemid.call_count': 0,
-            'changed': False,
-            'msg': 'System already registered.',
-            'run_command.call_count': 0,
-            'request_called': False,
-            'unlink.call_count': 0,
-        },
-    ],
-    [
-        # Unregister an host, check that result is changed
-        {
-            'activationkey': 'key',
-            'username': 'user',
-            'password': 'pass',
-            'state': 'absent',
-        },
-        {
-            'calls': [
-                ('auth.login', ['X' * 43]),
-                ('system.deleteSystems', [1]),
-                ('auth.logout', [1]),
-            ],
-            'is_registered': True,
-            'is_registered.call_count': 1,
-            'enable.call_count': 0,
-            'systemid.call_count': 1,
-            'changed': True,
-            'msg': 'System successfully unregistered from rhn.redhat.com.',
-            'run_command.call_count': 0,
-            'request_called': True,
-            'unlink.call_count': 1,
-        }
-    ],
-    [
-        # Unregister a unregistered host (systemid missing) locally, check that result is unchanged
-        {
-            'activationkey': 'key',
-            'username': 'user',
-            'password': 'pass',
-            'state': 'absent',
-        },
-        {
-            'calls': [],
-            'is_registered': False,
-            'is_registered.call_count': 1,
-            'enable.call_count': 0,
-            'systemid.call_count': 0,
-            'changed': False,
-            'msg': 'System already unregistered.',
-            'run_command.call_count': 0,
-            'request_called': False,
-            'unlink.call_count': 0,
-        }
-
-    ],
-    [
-        # Unregister an unknown host (an host with a systemid available locally, check that result contains failed
-        {
-            'activationkey': 'key',
-            'username': 'user',
-            'password': 'pass',
-            'state': 'absent',
-        },
-        {
-            'calls': [
-                ('auth.login', ['X' * 43]),
-                ('system.deleteSystems', xmlrpc_client.Fault(1003, 'The following systems were NOT deleted: 123456789')),
-                ('auth.logout', [1]),
-            ],
-            'is_registered': True,
-            'is_registered.call_count': 1,
-            'enable.call_count': 0,
-            'systemid.call_count': 1,
-            'failed': True,
-            'msg': "Failed to unregister: <Fault 1003: 'The following systems were NOT deleted: 123456789'>",
-            'run_command.call_count': 0,
-            'request_called': True,
-            'unlink.call_count': 0,
-        }
-    ],
-]
-
-
-@pytest.mark.parametrize('patch_ansible_module, testcase', TEST_CASES, indirect=['patch_ansible_module'])
-@pytest.mark.usefixtures('patch_ansible_module')
-def test_register_parameters(mocker, capfd, mock_request, patch_rhn, testcase):
-    # successful execution, no output
-    mocker.patch.object(basic.AnsibleModule, 'run_command', return_value=(0, '', ''))
-    mock_is_registered = mocker.patch.object(rhn_register.Rhn, 'is_registered', mocker.PropertyMock(return_value=testcase['is_registered']))
-    mocker.patch.object(rhn_register.Rhn, 'enable')
-    mock_systemid = mocker.patch.object(rhn_register.Rhn, 'systemid', mocker.PropertyMock(return_value=12345))
-    mocker.patch('os.unlink', return_value=True)
-
-    with pytest.raises(SystemExit):
-        rhn_register.main()
-
-    assert basic.AnsibleModule.run_command.call_count == testcase['run_command.call_count']
-    if basic.AnsibleModule.run_command.call_count:
-        assert basic.AnsibleModule.run_command.call_args[0][0][0] == testcase['run_command.call_args']
-
-    assert mock_is_registered.call_count == testcase['is_registered.call_count']
-    assert rhn_register.Rhn.enable.call_count == testcase['enable.call_count']
-    assert mock_systemid.call_count == testcase['systemid.call_count']
-    assert xmlrpc_client.Transport.request.called == testcase['request_called']
-    assert os.unlink.call_count == testcase['unlink.call_count']
-
-    out, err = capfd.readouterr()
-    results = json.loads(out)
-    assert results.get('changed') == testcase.get('changed')
-    assert results.get('failed') == testcase.get('failed')
-    assert results['msg'] == testcase['msg']
-    assert not testcase['calls']  # all calls should have been consumed