Repository: ansible-collections/community.general

Issue:
redhat_subscription module is not idempotent when pool_ids are used
### Summary

When you provide some `pool_ids`, the module reports a change every time when it runs. The current entitements get removed and recreated afterwards:
```
- name: subscription | Ensure subscription
  community.general.redhat_subscription:
    state: present
    username: joe_user
    password: somepass
    pool_ids: 0123456789abcdef0123456789abcdef
```
Every run results in
```
TASK [rhsm : subscription | Ensure subscription] *************************
changed: [molecule-rhel-9.<my_company>]
```

### Issue Type

Bug Report

### Component Name

redhat_subscription

### Ansible Version

```console (paste below)
$ ansible --version
ansible [core 2.13.3]
  config file = None
  configured module search path = ['/home/ansible/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /home/ansible/.local/lib/python3.10/site-packages/ansible
  ansible collection location = /home/ansible/.ansible/collections:/usr/share/ansible/collections
  executable location = /home/ansible/.local/bin/ansible
  python version = 3.10.6 (main, Aug 10 2022, 11:40:04) [GCC 11.3.0]
  jinja version = 3.0.3
  libyaml = True
```

### Community.general Version

```console (paste below)
$ ansible-galaxy collection list community.general
Collection        Version
----------------- -------
community.general 5.5.0
```

### Configuration

```console (paste below)
$ ansible-config dump --only-changed
$
```


### OS / Environment

RHEL 9

### Steps to Reproduce

<!--- Paste example playbooks or commands between quotes below -->
```yaml (paste below)
---
- hosts: localhost
  tasks:
  - name: subscription | Ensure subscription
    community.general.redhat_subscription:
      state: present
      username: joe_user
      password: somepass
      pool_ids: 0123456789abcdef0123456789abcdef
```


### Expected Results

After the system has been registered and properly subscribed, the module should report no further change an keep the current entitlements untouched.

### Actual Results

```console (paste below)
TASK [rhsm : subscription | Ensure subscription] *************************
changed: [molecule-rhel-9.<my_company>]
```

### Code of Conduct

- [X] I agree to follow the Ansible Code of Conduct


Discussion:

Resolving patch:
diff --git a/plugins/callback/opentelemetry.py b/plugins/callback/opentelemetry.py
--- a/plugins/callback/opentelemetry.py
+++ b/plugins/callback/opentelemetry.py
@@ -62,6 +62,17 @@
           - The L(W3C Trace Context header traceparent,https://www.w3.org/TR/trace-context-1/#traceparent-header).
         env:
           - name: TRACEPARENT
+      disable_logs:
+        default: false
+        type: bool
+        description:
+          - Disable sending logs.
+        env:
+          - name: ANSIBLE_OPENTELEMETRY_DISABLE_LOGS
+        ini:
+          - section: callback_opentelemetry
+            key: disable_logs
+        version_added: 5.8.0
     requirements:
       - opentelemetry-api (Python library)
       - opentelemetry-exporter-otlp (Python library)
@@ -134,6 +145,7 @@ def __init__(self, uuid, name, path, play, action, args):
             self.start = _time_ns()
         self.action = action
         self.args = args
+        self.dump = None
 
     def add_host(self, host):
         if host.uuid in self.host_data:
@@ -199,7 +211,7 @@ def start_task(self, tasks_data, hide_task_arguments, play_name, task):
 
         tasks_data[uuid] = TaskData(uuid, name, path, play_name, action, args)
 
-    def finish_task(self, tasks_data, status, result):
+    def finish_task(self, tasks_data, status, result, dump):
         """ record the results of a task for a single host """
 
         task_uuid = result._task._uuid
@@ -216,9 +228,10 @@ def finish_task(self, tasks_data, status, result):
         if self.ansible_version is None and hasattr(result, '_task_fields') and result._task_fields['args'].get('_ansible_version'):
             self.ansible_version = result._task_fields['args'].get('_ansible_version')
 
+        task.dump = dump
         task.add_host(HostData(host_uuid, host_name, status, result))
 
-    def generate_distributed_traces(self, otel_service_name, ansible_playbook, tasks_data, status, traceparent):
+    def generate_distributed_traces(self, otel_service_name, ansible_playbook, tasks_data, status, traceparent, disable_logs):
         """ generate distributed traces from the collected TaskData and HostData """
 
         tasks = []
@@ -254,9 +267,9 @@ def generate_distributed_traces(self, otel_service_name, ansible_playbook, tasks
             for task in tasks:
                 for host_uuid, host_data in task.host_data.items():
                     with tracer.start_as_current_span(task.name, start_time=task.start, end_on_exit=False) as span:
-                        self.update_span_data(task, host_data, span)
+                        self.update_span_data(task, host_data, span, disable_logs)
 
-    def update_span_data(self, task_data, host_data, span):
+    def update_span_data(self, task_data, host_data, span, disable_logs):
         """ update the span with the given TaskData and HostData """
 
         name = '[%s] %s: %s' % (host_data.name, task_data.play, task_data.name)
@@ -302,6 +315,9 @@ def update_span_data(self, task_data, host_data, span):
         self.set_span_attribute(span, "ansible.task.host.status", host_data.status)
         # This will allow to enrich the service map
         self.add_attributes_for_service_map_if_possible(span, task_data)
+        # Send logs
+        if not disable_logs:
+            span.add_event(task_data.dump)
         span.end(end_time=host_data.finish)
 
     def set_span_attribute(self, span, attributeName, attributeValue):
@@ -405,6 +421,7 @@ class CallbackModule(CallbackBase):
     def __init__(self, display=None):
         super(CallbackModule, self).__init__(display=display)
         self.hide_task_arguments = None
+        self.disable_logs = None
         self.otel_service_name = None
         self.ansible_playbook = None
         self.play_name = None
@@ -435,6 +452,8 @@ def set_options(self, task_keys=None, var_options=None, direct=None):
 
         self.hide_task_arguments = self.get_option('hide_task_arguments')
 
+        self.disable_logs = self.get_option('disable_logs')
+
         self.otel_service_name = self.get_option('otel_service_name')
 
         if not self.otel_service_name:
@@ -491,28 +510,32 @@ def v2_runner_on_failed(self, result, ignore_errors=False):
         self.opentelemetry.finish_task(
             self.tasks_data,
             status,
-            result
+            result,
+            self._dump_results(result._result)
         )
 
     def v2_runner_on_ok(self, result):
         self.opentelemetry.finish_task(
             self.tasks_data,
             'ok',
-            result
+            result,
+            self._dump_results(result._result)
         )
 
     def v2_runner_on_skipped(self, result):
         self.opentelemetry.finish_task(
             self.tasks_data,
             'skipped',
-            result
+            result,
+            self._dump_results(result._result)
         )
 
     def v2_playbook_on_include(self, included_file):
         self.opentelemetry.finish_task(
             self.tasks_data,
             'included',
-            included_file
+            included_file,
+            ""
         )
 
     def v2_playbook_on_stats(self, stats):
@@ -525,7 +548,8 @@ def v2_playbook_on_stats(self, stats):
             self.ansible_playbook,
             self.tasks_data,
             status,
-            self.traceparent
+            self.traceparent,
+            self.disable_logs
         )
 
     def v2_runner_on_async_failed(self, result, **kwargs):


Test patch:
diff --git a/tests/unit/plugins/callback/test_opentelemetry.py b/tests/unit/plugins/callback/test_opentelemetry.py
--- a/tests/unit/plugins/callback/test_opentelemetry.py
+++ b/tests/unit/plugins/callback/test_opentelemetry.py
@@ -68,7 +68,8 @@ def test_finish_task_with_a_host_match(self):
         self.opentelemetry.finish_task(
             tasks_data,
             'ok',
-            self.my_task_result
+            self.my_task_result,
+            ""
         )
 
         task_data = tasks_data['myuuid']
@@ -85,7 +86,8 @@ def test_finish_task_without_a_host_match(self):
         self.opentelemetry.finish_task(
             tasks_data,
             'ok',
-            result
+            result,
+            ""
         )
 
         task_data = tasks_data['myuuid']
@@ -104,7 +106,8 @@ def test_finish_task_include_with_ansible_version(self):
         self.opentelemetry.finish_task(
             tasks_data,
             'ok',
-            result
+            result,
+            ""
         )
 
         self.assertEqual(self.opentelemetry.ansible_version, '1.2.3')