From 3e6974815f934dd7c3a30998f6420b3d61c44d1e Mon Sep 17 00:00:00 2001
From: "patchback[bot]" <45432694+patchback[bot]@users.noreply.github.com>
Date: Sun, 26 Mar 2023 10:04:00 +0200
Subject: [PATCH] [PR #6227/cd706454 backport][stable-5] Fixed XenOrchestra
 inventory plugin failing due to not checking response ID. (#6244)

Fixed XenOrchestra inventory plugin failing due to not checking response ID. (#6227)

* Added call method to select proper response from xo server

* Added changelog fragment

* Removed excess blank lines

* Moved period in changelog fragment

* Made suggested changes

* Remove f-strings for Python 2.7 compatibility

Co-authored-by: Felix Fontein <felix@fontein.de>

---------

Co-authored-by: Linus Kirkwood <lkirkwood@allette.com.au>
Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit cd706454eca6bcae5e495fa27b041f350ffda21e)

Co-authored-by: lirkwood <linuskirkwood@gmail.com>
---
 .../6227-xen-orchestra-check-response-id.yml  |  2 +
 plugins/inventory/xen_orchestra.py            | 38 +++++++++++++++----
 2 files changed, 32 insertions(+), 8 deletions(-)
 create mode 100644 changelogs/fragments/6227-xen-orchestra-check-response-id.yml

diff --git a/changelogs/fragments/6227-xen-orchestra-check-response-id.yml b/changelogs/fragments/6227-xen-orchestra-check-response-id.yml
new file mode 100644
index 0000000000..972caa7d60
--- /dev/null
+++ b/changelogs/fragments/6227-xen-orchestra-check-response-id.yml
@@ -0,0 +1,2 @@
+bugfixes:
+  - xenorchestra inventory plugin - fix failure to receive objects from server due to not checking the id of the response (https://github.com/ansible-collections/community.general/pull/6227).
diff --git a/plugins/inventory/xen_orchestra.py b/plugins/inventory/xen_orchestra.py
index 5a466a6ab0..ddbdd9bb04 100644
--- a/plugins/inventory/xen_orchestra.py
+++ b/plugins/inventory/xen_orchestra.py
@@ -78,6 +78,7 @@ compose:
 
 import json
 import ssl
+from time import sleep
 
 from ansible.errors import AnsibleError
 from ansible.plugins.inventory import BaseInventoryPlugin, Constructable, Cacheable
@@ -138,21 +139,42 @@ class InventoryModule(BaseInventoryPlugin, Constructable, Cacheable):
         self.conn = create_connection(
             '{0}://{1}/api/'.format(proto, xoa_api_host), sslopt=sslopt)
 
+    CALL_TIMEOUT = 100
+    """Number of 1/10ths of a second to wait before method call times out."""
+
+    def call(self, method, params):
+        """Calls a method on the XO server with the provided parameters."""
+        id = self.pointer
+        self.conn.send(json.dumps({
+            'id': id,
+            'jsonrpc': '2.0',
+            'method': method,
+            'params': params
+        }))
+
+        waited = 0
+        while waited < self.CALL_TIMEOUT:
+            response = json.loads(self.conn.recv())
+            if 'id' in response and response['id'] == id:
+                return response
+            else:
+                sleep(0.1)
+                waited += 1
+
+        raise AnsibleError(
+            'Method call {method} timed out after {timeout} seconds.'.format(method=method, timeout=self.CALL_TIMEOUT / 10))
+
     def login(self, user, password):
-        payload = {'id': self.pointer, 'jsonrpc': '2.0', 'method': 'session.signIn', 'params': {
-            'username': user, 'password': password}}
-        self.conn.send(json.dumps(payload))
-        result = json.loads(self.conn.recv())
+        result = self.call('session.signIn', {
+            'username': user, 'password': password
+        })
 
         if 'error' in result:
             raise AnsibleError(
                 'Could not connect: {0}'.format(result['error']))
 
     def get_object(self, name):
-        payload = {'id': self.pointer, 'jsonrpc': '2.0',
-                   'method': 'xo.getAllObjects', 'params': {'filter': {'type': name}}}
-        self.conn.send(json.dumps(payload))
-        answer = json.loads(self.conn.recv())
+        answer = self.call('xo.getAllObjects', {'filter': {'type': name}})
 
         if 'error' in answer:
             raise AnsibleError(