Description of problem: When using the 'ovirt' Ansible modules for the first time, I made a mistake by not specifying the full URL in the corresponding option. This resulted in a rather generic error message: An exception occurred during task execution. To see the full traceback, use -vvv. The error was: Exception: Can't read first node fatal: [localhost]: FAILED! => {"changed": false, "failed": true, "msg": "Can't read first node"} After searching the Ansible project for a hint, I stepped over [1] which mentioned this error message with a differently related HTTP 404 error. This made me aware of the wrong URL being the cause of my error message. Version-Release number of selected component (if applicable): - ansible 2.3.0.0 (detached HEAD f15e1f25ae) - ovirt-engine-sdk-python 4.1.3 How reproducible: Always Steps to Reproduce: Define a ovirt_auth task in Ansible with https://<ovirt-host>/ (missing the 'ovirt-engine/api' context root) Actual results: "Can't read first node" python error Expected results: Error message indicating a HTTP error or wrong URL format Additional info: [1]: https://github.com/ansible/ansible/issues/19801
Currently we are trying to parse the returned document as XML, but when the URL is incorrect the server will most likely return an HTML error message. Trying to parse that HTML as XML is what causes the "Can't read first node" message. We should probably check the "Conten-Type" header returned by the server, and generate a better error message in that case. That error message could include a hint about the URL. For example, we could return an error message like this, if the value of the 'url' parameter is not the typical one: The server returned content type 'text/html', but we expected 'text/xml'. Are you sure you are using the correct 'url' parameter? The typical one is '/ovirt-engine/api', but you are using '/'. What we should not do, in my opinion, is forbid the use of other URLs. If we decided to check the returned 'Content-Type' header then we need to be careful, as it may have multiple valid values: text/xml text/xml; charset=utf-8 application/xml application/xml; charset=utf-8 Currently the server always returns 'application/xml', but that may change in the future.
The current fix didn't take into account that the server doesn't return any content type for responses that don't have a body. For example, the following code will trigger a 404 error, without a response body, and without a content type: vm_service = vms_service.vm_service('doesnotexist') vm_service.get() With the current fix that generates the following trackeback: Traceback (most recent call last): File "...", line 41, in <module> vm_service.get() File ".../ovirtsdk4/services.py", line 30596, in get response = self._connection.send(request) File ".../ovirtsdk4/__init__.py", line 295, in send return self.__send(request) File ".../ovirtsdk4/__init__.py", line 408, in __send self._check_content_type(self.__XML_CONTENT_TYPE_RE, 'XML', content_type) File ".../ovirtsdk4/__init__.py", line 689, in _check_content_type if expected_re.match(actual) is None: TypeError: expected string or buffer
used: python-ovirt-engine-sdk4-4.1.4-1.el7ev.x86_64 tested url: "https://<engine-url>/ugly" The full traceback is: Traceback (most recent call last): File "/tmp/ansible_RjJ0si/ansible_module_ovirt_datacenters.py", line 210, in main ret = clusters_module.create() File "/tmp/ansible_RjJ0si/ansible_modlib.zip/ansible/module_utils/ovirt.py", line 537, in create entity = self.search_entity(search_params) File "/tmp/ansible_RjJ0si/ansible_modlib.zip/ansible/module_utils/ovirt.py", line 757, in search_entity entity = search_by_attributes(self._service, name=self._module.params['name']) File "/tmp/ansible_RjJ0si/ansible_modlib.zip/ansible/module_utils/ovirt.py", line 229, in search_by_attributes search=' and '.join('{}={}'.format(k, v) for k, v in kwargs.items()) File "/usr/lib64/python2.7/site-packages/ovirtsdk4/services.py", line 4401, in list return self._internal_get(headers, query, wait) File "/usr/lib64/python2.7/site-packages/ovirtsdk4/service.py", line 202, in _internal_get return future.wait() if wait else future File "/usr/lib64/python2.7/site-packages/ovirtsdk4/service.py", line 53, in wait return self._code(response) File "/usr/lib64/python2.7/site-packages/ovirtsdk4/service.py", line 199, in callback self._check_fault(response) File "/usr/lib64/python2.7/site-packages/ovirtsdk4/service.py", line 123, in _check_fault body = reader.Reader.read(response.body) File "/usr/lib64/python2.7/site-packages/ovirtsdk4/reader.py", line 297, in read cursor = xml.XmlReader(io.BytesIO(source.encode('utf-8'))) Exception: Can't read first node fatal: [<engine-url>]: FAILED! => { "changed": false, "failed": true, "invocation": { "module_args": { "comment": null, "compatibility_version": "4.0", "description": null, "fetch_nested": false, "local": true, "mac_pool": null, "name": "mydatacenter", "nested_attributes": [], "poll_interval": 3, "quota_mode": "enabled", "state": "present", "timeout": 180, "wait": true } }, "msg": "Can't read first node" }
Target release should be placed once a package build is known to fix a issue. Since this bug is not modified, the target version has been reset. Please use target milestone to plan a fix for a oVirt release.
Verified in python-ovirt-engine-sdk4-4.1.5-1.el7ev.x86_64 Error: The response content type 'text/html; charset=iso-8859-1' isn't the expected XML. Is the path '/ugly' included in the 'url' parameter correct? The typical one is '/ovirt-engine/api'