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 # SPDX-License-Identifier: Apache-2.0
# #
@ -11,6 +11,8 @@ from six.moves import queue as threading_queue
class ThreadQueue(object): class ThreadQueue(object):
def __init__(self, queue_id): def __init__(self, queue_id):
if hasattr(queue_id, "encode"):
queue_id = queue_id.encode()
self._queue_id = queue_id self._queue_id = queue_id
self._send_socket, self._receive_socket = socket.socketpair() self._send_socket, self._receive_socket = socket.socketpair()
self._receive_socket.setblocking(False) 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 # SPDX-License-Identifier: Apache-2.0
# #
@ -816,7 +816,9 @@ class NFVIComputeAPI(nfvi.api.v1.NFVIComputeAPI):
request_dispatch.send_header(key, value) request_dispatch.send_header(key, value)
request_dispatch.end_headers() request_dispatch.end_headers()
if http_body is not None: 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() request_dispatch.done()
DLOG.info("Sent response for request %s." % request_uuid) 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 # SPDX-License-Identifier: Apache-2.0
# #
@ -323,7 +323,10 @@ def _rest_api_request(token_id,
request_info.add_header(header_type, header_value) request_info.add_header(header_type, header_value)
if api_cmd_payload is not None: 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, " DLOG.verbose("Rest-API method=%s, api_cmd=%s, api_cmd_headers=%s, "
"api_cmd_payload=%s" % (method, api_cmd, api_cmd_headers, "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 # SPDX-License-Identifier: Apache-2.0
# #
@ -379,7 +379,19 @@ class InstanceActionData(ObjectData):
if self.context is None: if self.context is None:
data['context'] = dict() data['context'] = dict()
else: 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 return data
def __str__(self): 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 # SPDX-License-Identifier: Apache-2.0
# #
@ -61,7 +61,7 @@ class APIController(Middleware):
return self._default_dispatcher return self._default_dispatcher
def _is_nfvi_request(self, request): def _is_nfvi_request(self, request):
body = get_jason_request_body(request) body = get_json_request_body(request)
data = json.loads(body) data = json.loads(body)
for action in self._actions: for action in self._actions:
if action in list(data): if action in list(data):
@ -86,7 +86,7 @@ class APIController(Middleware):
def _generate_log(self, req): def _generate_log(self, req):
environ = req.environ environ = req.environ
body = get_jason_request_body(req) body = get_json_request_body(req)
if CONF.debug and body is not None: if CONF.debug and body is not None:
data = json.loads(body) data = json.loads(body)
self._print_data(data) self._print_data(data)
@ -203,12 +203,12 @@ class DebugHeaders(Middleware):
LOG.info('-' * 70 + '\n') LOG.info('-' * 70 + '\n')
def get_jason_request_body(request): def get_json_request_body(request):
content_type = request.content_type content_type = request.content_type
if not content_type or content_type.startswith('text/plain'): if not content_type or content_type.startswith('text/plain'):
LOG.info("Content type null or plain text") LOG.info("Content type null or plain text")
content_type = 'application/json' content_type = 'application/json'
if content_type in ('JSON', 'application/json') and \ if content_type in ('JSON', 'application/json') and \
request.body.startswith('{'): request.body.startswith(b'{'):
LOG.debug("Req body: (%s)" % request.body) LOG.debug("Req body: (%s)" % request.body)
return request.body return request.body

View File

@ -7,7 +7,7 @@
# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org) # (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 # 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 # SPDX-License-Identifier: Apache-2.0
# #
@ -39,6 +39,15 @@ class Proxy(Application):
LOG.debug("Proxy the request to the remote host: (%s)", environ[ LOG.debug("Proxy the request to the remote host: (%s)", environ[
'HTTP_HOST']) 'HTTP_HOST'])
start_ms = get_monotonic_timestamp_in_ms() 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) result = self.proxy_app(environ, start_response)
now_ms = get_monotonic_timestamp_in_ms() now_ms = get_monotonic_timestamp_in_ms()
elapsed_secs = (now_ms - start_ms) // 1000 elapsed_secs = (now_ms - start_ms) // 1000