Debian: python3 fix for OpenStackRestAPIExceptions

When the NFV uses tasks and futures and coroutines to
interact with openstack APIs, an OpenStackRestAPIException
can be returned as a task result.

The exception needs to be 'pickled' when sent across the
queue/socket for the 'simulated' asyncio workflow.

However, the pickle code for that exception was broken in
python3. It was relying on a python2 'message' attribute
of the base Exception class to exist, which no longer
exists (in python3)

This was causing the pickle command to quietly fail and
the code waiting for the task result would timeout and
not report back the failure information.

The fix is to ensure that there is a 'message' property
on that exception type.

Unit tests have been added for all the pickleable
exceptions, to ensure their '__reduce__' and other
interactions with 'pickle' are not reporting any failures.

Test Plan:
 PASS: create and apply a kube-upgrade-strategy for an
 older version of kubernetes and observe it reports its
failure error (rather than a timeout)

Closes-Bug: #2007285
Signed-off-by: Al Bailey <al.bailey@windriver.com>
Change-Id: I3a8776163a78330810ae1097ddd1831b1b26a212
This commit is contained in:
Al Bailey 2023-02-14 15:21:13 +00:00
parent 7753ea0dc7
commit 94321e9d57
2 changed files with 70 additions and 4 deletions

View File

@ -67,12 +67,13 @@ class OpenStackRestAPIException(exceptions.PickleableException):
"""
Create an OpenStack Rest-API exception
"""
super(OpenStackRestAPIException, self).__init__(message)
super(OpenStackRestAPIException, self).__init__(message, reason)
self._method = method
self._url = url
self._headers = headers
self._body = body
self._status_code = status_code # as defined in RFC 2616
self._message = message
self._reason = reason # a message string or another exception
self._response_headers = response_headers
self._response_body = response_body
@ -99,9 +100,12 @@ class OpenStackRestAPIException(exceptions.PickleableException):
"""
Return a tuple so that we can properly pickle the exception
"""
return (OpenStackRestAPIException, (self._method, self._url,
self._headers, self._body,
self._status_code, self.message,
return (OpenStackRestAPIException, (self._method,
self._url,
self._headers,
self._body,
self._status_code,
self.message,
self._reason,
self._response_headers,
self._response_body,
@ -135,6 +139,13 @@ class OpenStackRestAPIException(exceptions.PickleableException):
"""
return self._response_reason
@property
def message(self):
"""
Returns the message for the exception
"""
return self._message
@property
def reason(self):
"""

View File

@ -0,0 +1,55 @@
#
# Copyright (c) 2023 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
import pickle
from nfv_plugins.nfvi_plugins.openstack.exceptions import NotFound
from nfv_plugins.nfvi_plugins.openstack.exceptions import OpenStackException
from nfv_plugins.nfvi_plugins.openstack.exceptions import OpenStackRestAPIException
from nfv_unit_tests.tests import testcase
class TestPickleableExceptions(testcase.NFVTestCase):
"""Unit tests that verify pickleable exceptions"""
def setUp(self):
"""Setup for testing."""
super(TestPickleableExceptions, self).setUp()
def tearDown(self):
"""Cleanup testing setup."""
super(TestPickleableExceptions, self).tearDown()
def _do_pickling_test(self, ex):
data = pickle.dumps(ex)
obj = pickle.loads(data)
self.assertEqual(obj.__reduce__(), ex.__reduce__())
def test_pickling_not_found(self):
ex = NotFound("message")
self._do_pickling_test(ex)
def test_pickling_openstack_exception(self):
ex = OpenStackException("method",
"url",
"headers",
"body",
"message",
"reason")
self._do_pickling_test(ex)
def test_pickling_openstack_rest_api_exception(self):
ex = OpenStackRestAPIException("method",
"url",
"headers",
"body",
"status_code",
"message",
"reason",
"response_headers",
"response_body",
"response_reason")
self._do_pickling_test(ex)