Repository: ansible-collections/community.general

Issue:
rhsm_repository is really slow
##### SUMMARY
Using rhsm_repository is really slow, making it annoying to use a playback that uses it.
(copied from https://github.com/ansible/ansible/issues/69722)

##### ISSUE TYPE
- Bug Report

##### COMPONENT NAME
rhsm_repository

##### ANSIBLE VERSION
```
ansible 2.9.9
  config file = /root/ansible/ansible.cfg
  configured module search path = [u'/root/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python2.7/site-packages/ansible
  executable location = /usr/bin/ansible
  python version = 2.7.5 (default, Apr  2 2020, 13:16:51) [GCC 4.8.5 20150623 (Red Hat 4.8.5-39)]
```

##### CONFIGURATION
```
[defaults]
stdout_callback = yaml
force_handlers = True
```

##### OS / ENVIRONMENT
Ansible machine:
Target machine: RHEL 8


##### STEPS TO REPRODUCE
```yaml
- name: enable Red Hat CodeReady repo
  rhsm_repository:
    name: codeready-builder-for-rhel-8-x86_64-rpms
  when: ansible_facts['distribution'] == "RedHat" and ansible_facts['distribution_major_version'] == "8"
```

##### EXPECTED RESULTS
The above task should complete in a short time, at least when the repository is already enabled.


##### ACTUAL RESULTS
You have time to get coffee whilst your playbook runs.


Discussion:
Files identified in the description:
* [`plugins/modules/packaging/os/rhsm_repository.py`](https://github.com/ansible-collections/community.general/blob/master/plugins/modules/packaging/os/rhsm_repository.py)

If these files are inaccurate, please update the `component name` section of the description or use the `!component` bot command.

[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: components_banner --->
cc @bcoca @danowar2k @fishman @giovannisciortino @jasperla @jpdasma @mator @mavit @scathatheworm @troy2914 @xen0l
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->
@CendioOssman please provide quantitative data of the slowness of this module because they can be caused by subscription-manager command used by this module to verify enabled/disabled repositories and enable/disable repositories.

Below some example of quantitative data from my test:

```
# 1) disable the repository used for the test
[root@rhel8-01 ~]# subscription-manager repos --disable codeready-builder-for-rhel-8-x86_64-rpms
Repository 'codeready-builder-for-rhel-8-x86_64-rpms' is disabled for this system.

# 2) time to enable a disabled repository using ansible
[root@rhel8-01 ~]# time bash -c 'ansible localhost -m rhsm_repository -a "name=codeready-builder-for-rhel-8-x86_64-rpms"' > /dev/null

real	1m46.664s
user	0m29.472s
sys	0m1.523s

# 3) time to enable an already enabled repository using ansible
[root@rhel8-01 ~]# time bash -c 'ansible localhost -m rhsm_repository -a "name=codeready-builder-for-rhel-8-x86_64-rpms"' > /dev/null

real	1m56.322s
user	0m31.330s
sys	0m2.105s

# 4) time to verify enabled/disabled repositories using subscription-manager command
[root@rhel8-01 ~]# time subscription-manager repos --list >> /dev/null

real	0m46.682s
user	0m4.369s
sys	0m0.237s

# 5) time to enable a repository using subscription-manager command
[root@rhel8-01 ~]# time subscription-manager repos --enable codeready-builder-for-rhel-8-x86_64-rpms >> /dev/null

real	0m51.719s
user	0m5.018s
sys	0m0.237s
```

Maybe some optimization can be implemented to reduce time when a repository is already enabled or disabled(the third command of my test reported above).

A possible implementation(that need test) of this optimization is to move the following lines of code two lines above inside the if:
- https://github.com/ansible-collections/community.general/blob/a0c5580fc3887b236e008f626e83521ae6c1630f/plugins/modules/packaging/os/rhsm_repository.py#L192 
- https://github.com/ansible-collections/community.general/blob/a0c5580fc3887b236e008f626e83521ae6c1630f/plugins/modules/packaging/os/rhsm_repository.py#L199
Alright, I did the same tests here:

```
# 1) disable the repository used for the test
[root@internal ~]# subscription-manager repos --disable codeready-builder-for-rhel-8-x86_64-rpms
Repository 'codeready-builder-for-rhel-8-x86_64-rpms' is disabled for this system.

# 2) time to enable a disabled repository using ansible
[root@ansible ~]# time bash -c 'ansible all -i internal.lkpg.cendio.se, -m rhsm_repository -a "name=codeready-builder-for-rhel-8-x86_64-rpms"' > /dev/null

real	1m9.991s
user	0m11.098s
sys	0m0.702s

# 3) time to enable an already enabled repository using ansible
[root@ansible ~]# time bash -c 'ansible all -i internal.lkpg.cendio.se, -m rhsm_repository -a "name=codeready-builder-for-rhel-8-x86_64-rpms"' > /dev/null

real	0m57.112s
user	0m9.599s
sys	0m0.762s

# 4) time to verify enabled/disabled repositories using subscription-manager command
[root@internal ~]# time subscription-manager repos --list >> /dev/null

real	0m27.084s
user	0m3.339s
sys	0m0.414s

# 5) time to enable a repository using subscription-manager command
[root@internal ~]# time subscription-manager repos --enable codeready-builder-for-rhel-8-x86_64-rpms >> /dev/null

real	0m27.992s
user	0m3.405s
sys	0m0.320s
```

(note that I did not run ansible directly on the machine)

I'd say that 3) is indeed the most important case as it will be the (by far) most common. Even 30 seconds is rather long though.

Isn't it possible to check a repo without having to roundtrip to Red Hat's servers? I think we can live without it handling the corner case of a server out of sync with Red Hat's systems.
3) execution time can be probably reduced of about 50% using the hints provided in my previous comment, I will work on it on my spare time.

> Isn't it possible to check a repo without having to roundtrip to Red Hat's servers? 
> I think we can live without it handling the corner case of a server out of sync with Red Hat's systems.

I don't know other official Red Hat supported way to do it, suggestions are appreciated. Parsing /etc/yum.repos.d/redhat.repo could be a not well document option to do it but it will not be refreshed when a new repositories is added to Red Hat CDN if other subscription-manager commands isn't executed, I don't like this solution.

Resolving patch:
diff --git a/plugins/modules/packaging/os/rhsm_repository.py b/plugins/modules/packaging/os/rhsm_repository.py
--- a/plugins/modules/packaging/os/rhsm_repository.py
+++ b/plugins/modules/packaging/os/rhsm_repository.py
@@ -217,7 +217,7 @@ def repository_modify(module, state, name, purge=False):
             'before_header': "RHSM repositories",
             'after_header': "RHSM repositories"}
 
-    if not module.check_mode:
+    if not module.check_mode and changed:
         rc, out, err = run_subscription_manager(module, rhsm_arguments)
         results = out.splitlines()
     module.exit_json(results=results, changed=changed, repositories=updated_repo_list, diff=diff)


Test patch: