Description of problem: oVirt SDK seems to not be formatting strings before parsing them, resulting in tracebacks with Python 3.6 (Traceback below in the Actual Results section) This can be resolved by decoding the URL as UTF8 before parsing it: /usr/lib64/python3.6/site-packages/ovirtsdk4/__init__.py: 653 # Decode the URL to UTF8 format 654 self._url = self._url.decode('UTF-8') 655 656 # Set proper Authorization header if using kerberos: 657 if self._kerberos: 658 curl.setopt(pycurl.HTTPAUTH, pycurl.HTTPAUTH_GSSNEGOTIATE) 659 curl.setopt(pycurl.USERPWD, ':') 660 661 # Configure debug mode: 662 if self._debug and self._log is not None: 663 curl.setopt(pycurl.VERBOSE, 1) 664 curl.setopt(pycurl.DEBUGFUNCTION, self._curl_debug) 665 666 # Configure TLS parameters: 667 if self._url.startswith('https'): 668 curl.setopt(pycurl.SSL_VERIFYPEER, 0 if self._insecure else 1) 669 curl.setopt(pycurl.SSL_VERIFYHOST, 0 if self._insecure else 2) 670 if self._ca_file is not None: 671 curl.setopt(pycurl.CAINFO, self._ca_file) Although, this leads to other issues, presumably in other scripts where the URL is still seen as bytes: 2021-02-04 08:02:42.758 8 ERROR ironic_staging_drivers.ovirt.ovirt [req-e3777549-b5eb-4b8d-8a5c-b58b3c8c66d7 c12188ef21664945bf44b7f35423f765 81e8b5c8134447fc9adc3c1025cdfb32 - default default] Could not fetch information about VM vm b'compute-1', got error: Error while sending HTTP request: (1, 'Protocol "b\'https\'" not supported or disabled in libcurl'): ovirtsdk4.Error: Error while sending HTTP request: (1, 'Protocol "b\'https\'" not supported or disabled in libcurl') Version-Release number of selected component (if applicable): python3-ovirt-engine-sdk4-4.4.8-1.el8.x86_64 bash-4.4$ python3 --version Python 3.6.8 How reproducible: I'm using the SDK with Ironic in upstream TripleO and seeing this error. It doesn't seem to be a problem in RHOSP16.1 at the moment Steps to Reproduce: 1. Install the ovirtsdk in the Ironic containers 2. Try to import VM's from oVirt into Ironic 3. Tracebacks are observed in the ironic-conductor.log file while parsing the URL Actual results: Traceback: 2021-02-04 08:01:25.908 8 ERROR ironic.conductor.manager [req-a0b371dd-ac22-481f-a5de-8fa5ebef7e95 c12188ef21664945bf44b7f35423f765 81e8b5c8134447fc9adc3c1025cdfb32 - default default] Faile d to get power state for node cc4ea979-2bcf-4591-8603-2455db9d8cbd. Error: startswith first arg must be bytes or a tuple of bytes, not str: TypeError: startswith first arg must be bytes or a tuple of bytes, not str 2021-02-04 08:01:25.908 8 ERROR ironic.conductor.manager Traceback (most recent call last): 2021-02-04 08:01:25.908 8 ERROR ironic.conductor.manager File "/usr/lib/python3.6/site-packages/ironic/conductor/manager.py", line 1163, in _do_node_verify 2021-02-04 08:01:25.908 8 ERROR ironic.conductor.manager power_state = task.driver.power.get_power_state(task) 2021-02-04 08:01:25.908 8 ERROR ironic.conductor.manager File "/usr/lib/python3.6/site-packages/ironic_staging_drivers/ovirt/ovirt.py", line 200, in get_power_state 2021-02-04 08:01:25.908 8 ERROR ironic.conductor.manager with _getvm(driver_info) as vm: 2021-02-04 08:01:25.908 8 ERROR ironic.conductor.manager File "/usr/lib64/python3.6/contextlib.py", line 81, in __enter__ 2021-02-04 08:01:25.908 8 ERROR ironic.conductor.manager return next(self.gen) 2021-02-04 08:01:25.908 8 ERROR ironic.conductor.manager File "/usr/lib/python3.6/site-packages/ironic_staging_drivers/ovirt/ovirt.py", line 155, in _getvm 2021-02-04 08:01:25.908 8 ERROR ironic.conductor.manager vmsearch = vms_service.list(search='name=%s' % name) 2021-02-04 08:01:25.908 8 ERROR ironic.conductor.manager File "/usr/lib64/python3.6/site-packages/ovirtsdk4/services.py", line 37486, in list 2021-02-04 08:01:25.908 8 ERROR ironic.conductor.manager return self._internal_get(headers, query, wait) 2021-02-04 08:01:25.908 8 ERROR ironic.conductor.manager File "/usr/lib64/python3.6/site-packages/ovirtsdk4/service.py", line 202, in _internal_get 2021-02-04 08:01:25.908 8 ERROR ironic.conductor.manager context = self._connection.send(request) 2021-02-04 08:01:25.908 8 ERROR ironic.conductor.manager File "/usr/lib64/python3.6/site-packages/ovirtsdk4/__init__.py", line 371, in send 2021-02-04 08:01:25.908 8 ERROR ironic.conductor.manager return self.__send(request) 2021-02-04 08:01:25.908 8 ERROR ironic.conductor.manager File "/usr/lib64/python3.6/site-packages/ovirtsdk4/__init__.py", line 389, in __send 2021-02-04 08:01:25.908 8 ERROR ironic.conductor.manager self.authenticate() 2021-02-04 08:01:25.908 8 ERROR ironic.conductor.manager File "/usr/lib64/python3.6/site-packages/ovirtsdk4/__init__.py", line 382, in authenticate 2021-02-04 08:01:25.908 8 ERROR ironic.conductor.manager self._sso_token = self._get_access_token() 2021-02-04 08:01:25.908 8 ERROR ironic.conductor.manager File "/usr/lib64/python3.6/site-packages/ovirtsdk4/__init__.py", line 618, in _get_access_token 2021-02-04 08:01:25.908 8 ERROR ironic.conductor.manager sso_response = self._get_sso_response(self._sso_url, post_data) 2021-02-04 08:01:25.908 8 ERROR ironic.conductor.manager File "/usr/lib64/python3.6/site-packages/ovirtsdk4/__init__.py", line 667, in _get_sso_response 2021-02-04 08:01:25.908 8 ERROR ironic.conductor.manager if self._url.startswith('https'): 2021-02-04 08:01:25.908 8 ERROR ironic.conductor.manager TypeError: startswith first arg must be bytes or a tuple of bytes, not str 2021-02-04 08:01:25.908 8 ERROR ironic.conductor.manager Expected results: self._url needs to be passed to startswith in an acceptable format Additional info: I'll report back once it's all working and we can discuss if this is a problem with ovirtsdk, or the combination of python36 and the version of ovirtsdk I'm using. Quite possibly the latter. I can see Bugzilla wont let me select 4.4.8 and only 4.4.9. So maybe I need to go find that version and see if it makes a difference.
Ok, so I made sure I was using the latest ovirtsdk 4.4.9. Still getting the same error, So, I added the decode the the top of the script when we first initialise the variable. That seems to have solved that problem, now the same problem with VM names: 2021-02-04 08:59:13.242 8 ERROR ironic.conductor.manager [req-4f1e7ff9-8f28-44a5-b36b-1f6e937f65d9 c12188ef21664945bf44b7f35423f765 81e8b5c8134447fc9adc3c1025cdfb32 - default default] Failed to get power state for node cc4ea979-2bcf-4591-8603-2455db9d8cbd. Error: VM with name b'compute-1' was not found: ironic_staging_drivers.common.exception.OVirtError: VM with name b'compute-1' was not found So I'll change that one as well. So far: bash-4.4$ diff -u /usr/lib64/python3.6/site-packages/ovirtsdk4/__init__.py-backup /usr/lib64/python3.6/site-packages/ovirtsdk4/__init__.py --- /usr/lib64/python3.6/site-packages/ovirtsdk4/__init__.py-backup 2021-02-04 09:03:27.134089438 +1000 +++ /usr/lib64/python3.6/site-packages/ovirtsdk4/__init__.py 2021-02-04 09:04:05.233743979 +1000 @@ -308,7 +308,7 @@ raise Error('The CA file \'%s\' doesn\'t exist' % ca_file) # Save the URL: - self._url = url + self._url = url.decode('UTF-8') # Save the logger: self._log = log
Next issue seems to be on the Ironic side, so we can ignore it for this bug. Messy solution since we're encoding and decoding, but I can probably change ascii to utf-8 there instead. I'll look at that independently of this BZ though. Let's discuss the above change. For completion, I also made this change on the Ironic side - albeit a hack solution that needs revision: bash-4.4$ diff -u /usr/lib/python3.6/site-packages/ironic_staging_drivers/ovirt/ovirt.py-backup /usr/lib/python3.6/site-packages/ironic_staging_drivers/ovirt/ovirt.py --- /usr/lib/python3.6/site-packages/ironic_staging_drivers/ovirt/ovirt.py-backup 2021-02-04 09:11:52.068016965 +1000 +++ /usr/lib/python3.6/site-packages/ironic_staging_drivers/ovirt/ovirt.py 2021-02-04 09:15:45.813164874 +1000 @@ -135,6 +135,7 @@ ca_file = driver_info['ovirt_ca_file'] name = str.encode( driver_info['ovirt_vm_name'], encoding='ascii', errors='ignore') + name = name.decode('UTF-8') url = "https://%s/ovirt-engine/api" % address try: # pycurl.Curl.setopt doesn't support unicode strings,
I'm fairly confident all objects passed from Ironic to ovirtsdk are all strings here. So there must be something turning them into byte objects at some point here. I'll need to keep digging. But I'm happy for feedback from the oVirt side if you might know what's going on here.
So, I've spent some additional time on this. Basically the URL is being encoded for $reasons here: https://opendev.org/x/ironic-staging-drivers/src/branch/master/ironic_staging_drivers/ovirt/ovirt.py#L143 Presumably to validate that it doesn't contain non-ascii characters. But we probably shouldn't send the ASCII encoded string over to ovirtsdk. I would say it's better to validate the string and then send the URL as a string. I experimented with removing that section: https://opendev.org/x/ironic-staging-drivers/src/branch/master/ironic_staging_drivers/ovirt/ovirt.py#L139-L148 This works, but then Ironic complains that it can't find the byte encoded VM names. So we're doing the same thing for the VM names: https://opendev.org/x/ironic-staging-drivers/src/branch/master/ironic_staging_drivers/ovirt/ovirt.py#L136-L137 So, I'm fairly happy this is an issue on the Ironic side at this stage. Let's close this BZ off and I'll open a new one for Ironic and submit the relevant fixes over there.
For reference on this one, before I forget. This is what I'm doing to work around the issue for now: [root@tripleo-director ironic]# podman exec -it -u0 ironic_conductor sed -n 136,153p /usr/lib/python3.6/site-packages/ironic_staging_drivers/ovirt/ovirt.py name = str.encode( driver_info['ovirt_vm_name'], encoding='ascii', errors='ignore') url = "https://%s/ovirt-engine/api" % address try: # pycurl.Curl.setopt doesn't support unicode strings, # attempt to turn `url` into an all-ASCII string; # in Python 3.x setopt accepts bytes as it should. url = str.encode(url, encoding='ascii', errors='strict') except UnicodeEncodeError: LOG.warning("oVirt URL '%(url)s' contains non-ascii characters, " "that might cause pycurl to explode " "momentarily", {'url': url}) try: name = driver_info['ovirt_vm_name'] url = "https://%s/ovirt-engine/api" % address connection = sdk.Connection(url=url, username=username, So after this string encoding is done to validate them, I'm resetting them back to the originals. It works for now, but needs a better solution.
Fixed in Ironic staging drivers here: https://review.opendev.org/c/x/ironic-staging-drivers/+/784879