Debian: Fix nova actions

Since the platform migration to Debian, it was observed that the
following Nova actions stopped working:
  - pause;
  - unpause;
  - suspend;
  - resume;
  - live-migration.

The reason behind that is that some packages related to Nova, which have
already been migrated to Debian, still have some incompatibilities with
Python 3. Consequently, whenever these Nova actions were executed, some
exceptions occurred on the nova-api-proxy and NFV side, preventing them
from working.

Therefore, this change aims to improve this compatibility.

Most of the changes were necessary due to the fact that in Python 3
there is more of a distinction between `bytes` and `str`, whereas in
Python 2 `bytes` is just an alias for `str`.

Test Plan (on AIO-DX):
PASS - Successfully perform a VM pause, unpause, suspend, resume.
PASS - Successfully perform a VM live-migration.

Closes-Bug: 2003813

Signed-off-by: Luan Nunes Utimura <LuanNunes.Utimura@windriver.com>
Change-Id: I918fe6e3deaa68630c797449649012e9fbf16fe4
This commit is contained in:
Luan Nunes Utimura 2023-02-01 10:10:03 -03:00
parent c4890e651b
commit 1e475dca0c
6 changed files with 41 additions and 13 deletions

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2015-2016 Wind River Systems, Inc.
# Copyright (c) 2015-2023 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
@ -11,6 +11,8 @@ from six.moves import queue as threading_queue
class ThreadQueue(object):
def __init__(self, queue_id):
if hasattr(queue_id, "encode"):
queue_id = queue_id.encode()
self._queue_id = queue_id
self._send_socket, self._receive_socket = socket.socketpair()
self._receive_socket.setblocking(False)

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2015-2018 Wind River Systems, Inc.
# Copyright (c) 2015-2023 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
@ -816,7 +816,9 @@ class NFVIComputeAPI(nfvi.api.v1.NFVIComputeAPI):
request_dispatch.send_header(key, value)
request_dispatch.end_headers()
if http_body is not None:
request_dispatch.wfile.write(http_body.encode())
if hasattr(http_body, "encode"):
http_body = http_body.encode()
request_dispatch.wfile.write(http_body)
request_dispatch.done()
DLOG.info("Sent response for request %s." % request_uuid)

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2015-2016 Wind River Systems, Inc.
# Copyright (c) 2015-2023 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
@ -323,7 +323,10 @@ def _rest_api_request(token_id,
request_info.add_header(header_type, header_value)
if api_cmd_payload is not None:
request_info.data = api_cmd_payload.encode()
if hasattr(api_cmd_payload, "encode"):
request_info.data = api_cmd_payload.encode()
else:
request_info.data = api_cmd_payload
DLOG.verbose("Rest-API method=%s, api_cmd=%s, api_cmd_headers=%s, "
"api_cmd_payload=%s" % (method, api_cmd, api_cmd_headers,

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2015-2016 Wind River Systems, Inc.
# Copyright (c) 2015-2023 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
@ -379,7 +379,19 @@ class InstanceActionData(ObjectData):
if self.context is None:
data['context'] = dict()
else:
data['context'] = self.context.as_dict()
context = self.context.as_dict().copy()
# In Python 3, it has been observed that some values present
# in the `context` dictionary are bytes instead of strings.
# This can lead to some exceptions later in the code when
# attempting to serialize this object into JSON.
if six.PY3:
for key, value in context.items():
if isinstance(value, bytes):
context[key] = value.decode()
data['context'] = context
return data
def __str__(self):

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2015-2018 Wind River Systems, Inc.
# Copyright (c) 2015-2023 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
@ -61,7 +61,7 @@ class APIController(Middleware):
return self._default_dispatcher
def _is_nfvi_request(self, request):
body = get_jason_request_body(request)
body = get_json_request_body(request)
data = json.loads(body)
for action in self._actions:
if action in list(data):
@ -86,7 +86,7 @@ class APIController(Middleware):
def _generate_log(self, req):
environ = req.environ
body = get_jason_request_body(req)
body = get_json_request_body(req)
if CONF.debug and body is not None:
data = json.loads(body)
self._print_data(data)
@ -203,12 +203,12 @@ class DebugHeaders(Middleware):
LOG.info('-' * 70 + '\n')
def get_jason_request_body(request):
def get_json_request_body(request):
content_type = request.content_type
if not content_type or content_type.startswith('text/plain'):
LOG.info("Content type null or plain text")
content_type = 'application/json'
if content_type in ('JSON', 'application/json') and \
request.body.startswith('{'):
request.body.startswith(b'{'):
LOG.debug("Req body: (%s)" % request.body)
return request.body

View File

@ -7,7 +7,7 @@
# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
#
# Copyright (c) 2015-2018 Wind River Systems, Inc.
# Copyright (c) 2015-2023 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
@ -39,6 +39,15 @@ class Proxy(Application):
LOG.debug("Proxy the request to the remote host: (%s)", environ[
'HTTP_HOST'])
start_ms = get_monotonic_timestamp_in_ms()
# In Python 3, the builtin `http` library raises an exception if one
# or more headers are set to `NoneType`. See:
# https://github.com/python/cpython/blob/3.9/Lib/http/client.py#L1253
for key, value in environ.items():
if key.startswith("HTTP_"):
if value is None:
environ[key] = ""
result = self.proxy_app(environ, start_response)
now_ms = get_monotonic_timestamp_in_ms()
elapsed_secs = (now_ms - start_ms) // 1000