c63057a699
BaseHTTPServer.BaseHTTPRequestHandler.wfile.write requires encoded
bytes.
The purpose of this commit is to unblock sanity on centos8 branch.
The main test was sysinv periodic audit function receiving the correct
response when querying the software patching status.
If there are any inconsistencies of encoding schemes between
components they will be discovered and fixed later.
Story: 2008454
Task: 42727
Signed-off-by: Dan Voiculeasa <dan.voiculeasa@windriver.com>
Change-Id: I5f288cf85f42cb98b4211f6b9d836fafcf19e31b
(cherry picked from commit 56dfd11348
)
619 lines
26 KiB
Python
Executable File
619 lines
26 KiB
Python
Executable File
#
|
|
# Copyright (c) 2015-2018 Wind River Systems, Inc.
|
|
#
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
#
|
|
import datetime
|
|
import json
|
|
import re
|
|
from six.moves import BaseHTTPServer
|
|
from six.moves import http_client as httplib
|
|
from six.moves import socketserver
|
|
import socket
|
|
import threading
|
|
|
|
from nfv_common import debug
|
|
from nfv_plugins.nfvi_plugins import config
|
|
from nfv_plugins.nfvi_plugins.openstack import fm
|
|
from nfv_plugins.nfvi_plugins.openstack import openstack
|
|
from nfv_vim import database
|
|
|
|
DLOG = debug.debug_get_logger('nfv_vim.webserver.webserver')
|
|
|
|
_lock = threading.Lock()
|
|
_token = None
|
|
_directory = None
|
|
_webserver_src_dir = '/'
|
|
_vim_api_ip = ''
|
|
|
|
|
|
def _bare_address_string(self):
|
|
"""
|
|
Workaround to bypass the hostname resolution mechanism, so that
|
|
the server can respond faster.
|
|
"""
|
|
host, port = self.client_address[:2]
|
|
return "%s" % host
|
|
|
|
|
|
BaseHTTPServer.BaseHTTPRequestHandler.address_string = _bare_address_string
|
|
|
|
|
|
class HTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
|
|
"""
|
|
HTTP Request Handler
|
|
"""
|
|
def do_GET(self):
|
|
global _lock, _token
|
|
|
|
if self.path == '/':
|
|
with open(_webserver_src_dir + '/html/index.html', 'r') as f:
|
|
self.send_response(httplib.OK)
|
|
self.send_header('Content-Type', 'text/html')
|
|
self.end_headers()
|
|
self.wfile.write(f.read().encode())
|
|
elif self.path == '/StarlingX_Icon_RGB_Stacked_2color.png':
|
|
with open(_webserver_src_dir + '/images' + self.path, 'r') as f:
|
|
self.send_response(httplib.OK)
|
|
self.send_header('Content-Type', 'image/x-icon')
|
|
self.end_headers()
|
|
self.wfile.write(f.read().encode())
|
|
|
|
elif re.search('/vim/overview', self.path) is not None:
|
|
query_obj = re.match(".*?callback=(.*)&.*", self.path)
|
|
if query_obj is not None:
|
|
locked_hosts = 0
|
|
unlocked_hosts = 0
|
|
locking_hosts = 0
|
|
unlocking_hosts = 0
|
|
enabled_hosts = 0
|
|
disabled_hosts = 0
|
|
offline_hosts = 0
|
|
failed_hosts = 0
|
|
nfvi_enabled_hosts = 0
|
|
|
|
hosts = database.database_host_get_list()
|
|
for host in hosts:
|
|
if host.is_enabled():
|
|
enabled_hosts += 1
|
|
|
|
elif host.is_disabled():
|
|
disabled_hosts += 1
|
|
|
|
if host.nfvi_host_is_enabled():
|
|
nfvi_enabled_hosts += 1
|
|
|
|
if host.is_locked():
|
|
locked_hosts += 1
|
|
else:
|
|
unlocked_hosts += 1
|
|
|
|
if host.is_locking():
|
|
locking_hosts += 1
|
|
|
|
elif host.is_unlocking():
|
|
unlocking_hosts += 1
|
|
|
|
if host.is_offline():
|
|
offline_hosts += 1
|
|
|
|
if host.is_failed():
|
|
failed_hosts += 1
|
|
|
|
total_hosts = len(hosts)
|
|
|
|
locked_instances = 0
|
|
unlocked_instances = 0
|
|
enabled_instances = 0
|
|
disabled_instances = 0
|
|
failed_instances = 0
|
|
powering_off_instances = 0
|
|
pausing_instances = 0
|
|
paused_instances = 0
|
|
suspended_instances = 0
|
|
suspending_instances = 0
|
|
resizing_instances = 0
|
|
rebooting_instances = 0
|
|
rebuilding_instances = 0
|
|
migrating_instances = 0
|
|
deleting_instances = 0
|
|
deleted_instances = 0
|
|
|
|
instances = database.database_instance_get_list()
|
|
for instance in instances:
|
|
if instance.is_locked():
|
|
locked_instances += 1
|
|
else:
|
|
unlocked_instances += 1
|
|
|
|
if instance.is_enabled():
|
|
enabled_instances += 1
|
|
|
|
if instance.is_disabled():
|
|
disabled_instances += 1
|
|
|
|
if instance.is_failed():
|
|
failed_instances += 1
|
|
|
|
if instance.is_powering_off():
|
|
powering_off_instances += 1
|
|
|
|
if instance.is_pausing():
|
|
pausing_instances += 1
|
|
|
|
if instance.is_paused():
|
|
paused_instances += 1
|
|
|
|
if instance.is_suspending():
|
|
suspending_instances += 1
|
|
|
|
if instance.is_suspended():
|
|
suspended_instances += 1
|
|
|
|
if instance.is_resizing():
|
|
resizing_instances += 1
|
|
|
|
if instance.is_rebooting():
|
|
rebooting_instances += 1
|
|
|
|
if instance.is_rebuilding():
|
|
rebuilding_instances += 1
|
|
|
|
if instance.is_migrating():
|
|
migrating_instances += 1
|
|
|
|
if instance.is_deleting():
|
|
deleting_instances += 1
|
|
|
|
if instance.is_deleted():
|
|
deleted_instances += 1
|
|
|
|
total_instances = len(instances)
|
|
|
|
self.send_response(httplib.OK)
|
|
self.send_header('Content-Type', 'application/json')
|
|
self.end_headers()
|
|
self.wfile.write(
|
|
(query_obj.group(1) + "(" +
|
|
json.dumps(
|
|
{'locked_hosts': locked_hosts,
|
|
'unlocked_hosts': unlocked_hosts,
|
|
'locking_hosts': locking_hosts,
|
|
'unlocking_hosts': unlocking_hosts,
|
|
'enabled_hosts': enabled_hosts,
|
|
'disabled_hosts': disabled_hosts,
|
|
'offline_hosts': offline_hosts,
|
|
'failed_hosts': failed_hosts,
|
|
'nfvi_enabled_hosts': nfvi_enabled_hosts,
|
|
'total_hosts': total_hosts,
|
|
'locked_instances': locked_instances,
|
|
'unlocked_instances': unlocked_instances,
|
|
'enabled_instances': enabled_instances,
|
|
'disabled_instances': disabled_instances,
|
|
'failed_instances': failed_instances,
|
|
'powering_off_instances': powering_off_instances,
|
|
'pausing_instances': pausing_instances,
|
|
'paused_instances': paused_instances,
|
|
'suspended_instances': suspended_instances,
|
|
'suspending_instances': suspending_instances,
|
|
'resizing_instances': resizing_instances,
|
|
'rebooting_instances': rebooting_instances,
|
|
'rebuilding_instances': rebuilding_instances,
|
|
'migrating_instances': migrating_instances,
|
|
'deleting_instances': deleting_instances,
|
|
'deleted_instances': deleted_instances,
|
|
'total_instances': total_instances,
|
|
'datetime': str(datetime.datetime.now())[:-3]
|
|
}) + ")").encode())
|
|
else:
|
|
self.send_response(httplib.BAD_REQUEST,
|
|
'Bad Request: does not exist')
|
|
self.send_header('Content-Type', 'application/json')
|
|
self.end_headers()
|
|
|
|
elif re.search('/vim/alarms', self.path) is not None:
|
|
query_obj = re.match(".*?callback=(.*)&.*", self.path)
|
|
if query_obj is not None:
|
|
critical_alarms = 0
|
|
major_alarms = 0
|
|
minor_alarms = 0
|
|
warning_alarms = 0
|
|
indeterminate_alarms = 0
|
|
|
|
_lock.acquire()
|
|
if _token is None or _token.is_expired():
|
|
_token = openstack.get_token(_directory)
|
|
_lock.release()
|
|
|
|
result = fm.get_alarms(_token)
|
|
if result.result_data:
|
|
for alarm in result.result_data['alarms']:
|
|
if 'critical' == alarm['severity']:
|
|
critical_alarms += 1
|
|
elif 'major' == alarm['severity']:
|
|
major_alarms += 1
|
|
elif 'minor' == alarm['severity']:
|
|
minor_alarms += 1
|
|
elif 'warning' == alarm['severity']:
|
|
warning_alarms += 1
|
|
else:
|
|
indeterminate_alarms += 1
|
|
|
|
self.send_response(httplib.OK)
|
|
self.send_header('Content-Type', 'application/json')
|
|
self.end_headers()
|
|
self.wfile.write(
|
|
(query_obj.group(1) + "(" +
|
|
json.dumps(
|
|
{'critical_alarms': critical_alarms,
|
|
'major_alarms': major_alarms,
|
|
'minor_alarms': minor_alarms,
|
|
'warning_alarms': warning_alarms,
|
|
'indeterminate_alarms': indeterminate_alarms,
|
|
'datetime': str(datetime.datetime.now())[:-3]
|
|
}) + ")").encode())
|
|
else:
|
|
self.send_response(httplib.BAD_REQUEST,
|
|
'Bad Request: does not exist')
|
|
self.send_header('Content-Type', 'application/json')
|
|
self.end_headers()
|
|
|
|
elif re.search('/vim/systems', self.path) is not None:
|
|
query_obj = re.match(".*?callback=(.*)&.*", self.path)
|
|
if query_obj is not None:
|
|
system_list = list()
|
|
systems = database.database_system_get_list()
|
|
for system in systems:
|
|
system_list.append(system.as_dict())
|
|
|
|
self.send_response(httplib.OK)
|
|
self.send_header('Content-Type', 'application/json')
|
|
self.end_headers()
|
|
self.wfile.write((query_obj.group(1) + "(" +
|
|
json.dumps({'systems': system_list}) +
|
|
")").encode())
|
|
else:
|
|
self.send_response(httplib.BAD_REQUEST,
|
|
'Bad Request: does not exist')
|
|
self.send_header('Content-Type', 'application/json')
|
|
self.end_headers()
|
|
|
|
elif re.search('/vim/hosts', self.path) is not None:
|
|
query_obj = re.match(".*?callback=(.*)&.*", self.path)
|
|
if query_obj is not None:
|
|
host_list = list()
|
|
hosts = database.database_host_get_list()
|
|
for host in hosts:
|
|
host_list.append(host.as_dict())
|
|
|
|
self.send_response(httplib.OK)
|
|
self.send_header('Content-Type', 'application/json')
|
|
self.end_headers()
|
|
self.wfile.write((query_obj.group(1) + "(" +
|
|
json.dumps({'hosts': host_list}) +
|
|
")").encode())
|
|
else:
|
|
self.send_response(httplib.BAD_REQUEST,
|
|
'Bad Request: does not exist')
|
|
self.send_header('Content-Type', 'application/json')
|
|
self.end_headers()
|
|
|
|
elif re.search('/vim/host_groups', self.path) is not None:
|
|
query_obj = re.match(".*?callback=(.*)&.*", self.path)
|
|
if query_obj is not None:
|
|
host_group_list = list()
|
|
host_groups = database.database_host_group_get_list()
|
|
for host_group in host_groups:
|
|
host_group_list.append(host_group.as_dict())
|
|
|
|
self.send_response(httplib.OK)
|
|
self.send_header('Content-Type', 'application/json')
|
|
self.end_headers()
|
|
self.wfile.write((query_obj.group(1) + "(" +
|
|
json.dumps({'host_groups': host_group_list}) +
|
|
")").encode())
|
|
else:
|
|
self.send_response(httplib.BAD_REQUEST,
|
|
'Bad Request: does not exist')
|
|
self.send_header('Content-Type', 'application/json')
|
|
self.end_headers()
|
|
|
|
elif re.search('/vim/host_aggregates', self.path) is not None:
|
|
query_obj = re.match(".*?callback=(.*)&.*", self.path)
|
|
if query_obj is not None:
|
|
host_aggregate_list = list()
|
|
host_aggregates = database.database_host_aggregate_get_list()
|
|
for host_aggregate in host_aggregates:
|
|
host_aggregate_list.append(host_aggregate.as_dict())
|
|
|
|
self.send_response(httplib.OK)
|
|
self.send_header('Content-Type', 'application/json')
|
|
self.end_headers()
|
|
self.wfile.write((query_obj.group(1) + "(" +
|
|
json.dumps({'host_aggregates':
|
|
host_aggregate_list}) +
|
|
")").encode())
|
|
else:
|
|
self.send_response(httplib.BAD_REQUEST,
|
|
'Bad Request: does not exist')
|
|
self.send_header('Content-Type', 'application/json')
|
|
self.end_headers()
|
|
|
|
elif re.search('/vim/hypervisors', self.path) is not None:
|
|
query_obj = re.match(".*?callback=(.*)&.*", self.path)
|
|
if query_obj is not None:
|
|
hypervisor_list = list()
|
|
hypervisors = database.database_hypervisor_get_list()
|
|
for hypervisor in hypervisors:
|
|
hypervisor_list.append(hypervisor.as_dict())
|
|
|
|
self.send_response(httplib.OK)
|
|
self.send_header('Content-Type', 'application/json')
|
|
self.end_headers()
|
|
self.wfile.write((query_obj.group(1) + "(" +
|
|
json.dumps({'hypervisors': hypervisor_list}) +
|
|
")").encode())
|
|
else:
|
|
self.send_response(httplib.BAD_REQUEST,
|
|
'Bad Request: does not exist')
|
|
self.send_header('Content-Type', 'application/json')
|
|
self.end_headers()
|
|
|
|
elif re.search('/vim/instances', self.path) is not None:
|
|
query_obj = re.match(".*?callback=(.*)&.*", self.path)
|
|
if query_obj is not None:
|
|
instance_list = list()
|
|
instances = database.database_instance_get_list()
|
|
for instance in instances:
|
|
instance_list.append(instance.as_dict())
|
|
|
|
self.send_response(httplib.OK)
|
|
self.send_header('Content-Type', 'application/json')
|
|
self.end_headers()
|
|
self.wfile.write((query_obj.group(1) + "(" +
|
|
json.dumps({'instances': instance_list}) +
|
|
")").encode())
|
|
else:
|
|
self.send_response(httplib.BAD_REQUEST,
|
|
'Bad Request: does not exist')
|
|
self.send_header('Content-Type', 'application/json')
|
|
self.end_headers()
|
|
|
|
elif re.search('/vim/instance_types', self.path) is not None:
|
|
query_obj = re.match(".*?callback=(.*)&.*", self.path)
|
|
if query_obj is not None:
|
|
instance_type_list = list()
|
|
instance_types = database.database_instance_type_get_list()
|
|
for instance_type in instance_types:
|
|
instance_type_list.append(instance_type.as_dict())
|
|
|
|
self.send_response(httplib.OK)
|
|
self.send_header('Content-Type', 'application/json')
|
|
self.end_headers()
|
|
self.wfile.write((query_obj.group(1) + "(" +
|
|
json.dumps({'instance_types':
|
|
instance_type_list}) +
|
|
")").encode())
|
|
else:
|
|
self.send_response(httplib.BAD_REQUEST,
|
|
'Bad Request: does not exist')
|
|
self.send_header('Content-Type', 'application/json')
|
|
self.end_headers()
|
|
|
|
elif re.search('/vim/instance_groups', self.path) is not None:
|
|
query_obj = re.match(".*?callback=(.*)&.*", self.path)
|
|
if query_obj is not None:
|
|
instance_group_list = list()
|
|
instance_groups = database.database_instance_group_get_list()
|
|
for instance_group in instance_groups:
|
|
instance_group_list.append(instance_group.as_dict())
|
|
|
|
self.send_response(httplib.OK)
|
|
self.send_header('Content-Type', 'application/json')
|
|
self.end_headers()
|
|
self.wfile.write((query_obj.group(1) + "(" +
|
|
json.dumps({'instance_groups':
|
|
instance_group_list}) +
|
|
")").encode())
|
|
else:
|
|
self.send_response(httplib.BAD_REQUEST,
|
|
'Bad Request: does not exist')
|
|
self.send_header('Content-Type', 'application/json')
|
|
self.end_headers()
|
|
|
|
elif re.search('/vim/images', self.path) is not None:
|
|
query_obj = re.match(".*?callback=(.*)&.*", self.path)
|
|
if query_obj is not None:
|
|
image_list = list()
|
|
images = database.database_image_get_list()
|
|
for image in images:
|
|
image_list.append(image.as_dict())
|
|
|
|
self.send_response(httplib.OK)
|
|
self.send_header('Content-Type', 'application/json')
|
|
self.end_headers()
|
|
self.wfile.write((query_obj.group(1) + "(" +
|
|
json.dumps({'images': image_list}) +
|
|
")").encode())
|
|
else:
|
|
self.send_response(httplib.BAD_REQUEST,
|
|
'Bad Request: does not exist')
|
|
self.send_header('Content-Type', 'application/json')
|
|
self.end_headers()
|
|
|
|
elif re.search('/vim/volumes', self.path) is not None:
|
|
query_obj = re.match(".*?callback=(.*)&.*", self.path)
|
|
if query_obj is not None:
|
|
volume_list = list()
|
|
volumes = database.database_volume_get_list()
|
|
for volume in volumes:
|
|
volume_list.append(volume.as_dict())
|
|
|
|
self.send_response(httplib.OK)
|
|
self.send_header('Content-Type', 'application/json')
|
|
self.end_headers()
|
|
self.wfile.write((query_obj.group(1) + "(" +
|
|
json.dumps({'volumes': volume_list}) +
|
|
")").encode())
|
|
else:
|
|
self.send_response(httplib.BAD_REQUEST,
|
|
'Bad Request: does not exist')
|
|
self.send_header('Content-Type', 'application/json')
|
|
self.end_headers()
|
|
|
|
elif re.search('/vim/volume_snapshots', self.path) is not None:
|
|
query_obj = re.match(".*?callback=(.*)&.*", self.path)
|
|
if query_obj is not None:
|
|
volume_snapshot_list = list()
|
|
volume_snapshots = database.database_volume_snapshot_get_list()
|
|
for volume_snapshot in volume_snapshots:
|
|
volume_snapshot_list.append(volume_snapshot.as_dict())
|
|
|
|
self.send_response(httplib.OK)
|
|
self.send_header('Content-Type', 'application/json')
|
|
self.end_headers()
|
|
self.wfile.write((query_obj.group(1) + "(" +
|
|
json.dumps({'volume_snapshots':
|
|
volume_snapshot_list}) +
|
|
")").encode())
|
|
else:
|
|
self.send_response(httplib.BAD_REQUEST,
|
|
'Bad Request: does not exist')
|
|
self.send_header('Content-Type', 'application/json')
|
|
self.end_headers()
|
|
|
|
elif re.search('/vim/subnets', self.path) is not None:
|
|
query_obj = re.match(".*?callback=(.*)&.*", self.path)
|
|
if query_obj is not None:
|
|
subnet_list = list()
|
|
subnets = database.database_subnet_get_list()
|
|
for subnet in subnets:
|
|
subnet_list.append(subnet.as_dict())
|
|
|
|
self.send_response(httplib.OK)
|
|
self.send_header('Content-Type', 'application/json')
|
|
self.end_headers()
|
|
self.wfile.write((query_obj.group(1) + "(" +
|
|
json.dumps({'subnets': subnet_list}) +
|
|
")").encode())
|
|
else:
|
|
self.send_response(httplib.BAD_REQUEST,
|
|
'Bad Request: does not exist')
|
|
self.send_header('Content-Type', 'application/json')
|
|
self.end_headers()
|
|
|
|
elif re.search('/vim/networks', self.path) is not None:
|
|
query_obj = re.match(".*?callback=(.*)&.*", self.path)
|
|
if query_obj is not None:
|
|
network_list = list()
|
|
networks = database.database_network_get_list()
|
|
for network in networks:
|
|
network_list.append(network.as_dict())
|
|
|
|
self.send_response(httplib.OK)
|
|
self.send_header('Content-Type', 'application/json')
|
|
self.end_headers()
|
|
self.wfile.write((query_obj.group(1) + "(" +
|
|
json.dumps({'networks': network_list}) +
|
|
")").encode())
|
|
else:
|
|
self.send_response(httplib.BAD_REQUEST,
|
|
'Bad Request: does not exist')
|
|
self.send_header('Content-Type', 'application/json')
|
|
self.end_headers()
|
|
|
|
elif re.search('/fonts', self.path) is not None:
|
|
with open(_webserver_src_dir + self.path, 'r') as f:
|
|
self.send_response(httplib.OK)
|
|
self.send_header('Content-Type', 'application/font-woff')
|
|
self.end_headers()
|
|
self.wfile.write(f.read().encode())
|
|
|
|
else:
|
|
mime_type = 'unsupported'
|
|
send_reply = False
|
|
if self.path.endswith(".html"):
|
|
mime_type = 'text/html'
|
|
send_reply = True
|
|
elif self.path.endswith(".svg"):
|
|
mime_type = 'image/svg+xml'
|
|
send_reply = True
|
|
elif self.path.endswith(".jpg"):
|
|
mime_type = 'image/jpg'
|
|
send_reply = True
|
|
elif self.path.endswith(".gif"):
|
|
mime_type = 'image/gif'
|
|
send_reply = True
|
|
elif self.path.endswith(".png"):
|
|
mime_type = 'image/png'
|
|
send_reply = True
|
|
elif self.path.endswith(".ico"):
|
|
mime_type = 'image/x-icon'
|
|
send_reply = True
|
|
elif self.path.endswith(".js"):
|
|
mime_type = 'application/javascript'
|
|
send_reply = True
|
|
elif self.path.endswith(".css"):
|
|
mime_type = 'text/css'
|
|
send_reply = True
|
|
elif self.path.endswith(".handlebars"):
|
|
mime_type = 'text/x-handlebars-template'
|
|
send_reply = True
|
|
|
|
if send_reply:
|
|
with open(_webserver_src_dir + self.path, 'r') as f:
|
|
self.send_response(httplib.OK)
|
|
self.send_header('Content-Type', mime_type)
|
|
self.end_headers()
|
|
self.wfile.write(f.read().encode())
|
|
|
|
|
|
class ThreadedHTTPServer(socketserver.ThreadingMixIn, BaseHTTPServer.HTTPServer):
|
|
"""
|
|
Threaded HTTP Server
|
|
"""
|
|
allow_reuse_address = True
|
|
|
|
def shutdown(self):
|
|
self.socket.close()
|
|
BaseHTTPServer.HTTPServer.shutdown(self)
|
|
|
|
|
|
class SimpleHttpServer(object):
|
|
"""
|
|
Simple HTTP Server
|
|
"""
|
|
def __init__(self, webserver_config, nfvi_config, vim_api_config):
|
|
global _webserver_src_dir, _directory, _vim_api_ip
|
|
|
|
_webserver_src_dir = webserver_config['source_dir']
|
|
|
|
ip = webserver_config['host']
|
|
port = int(webserver_config['port'])
|
|
if ':' in ip:
|
|
# Configure server class to use IPv6
|
|
ThreadedHTTPServer.address_family = socket.AF_INET6
|
|
self.server = ThreadedHTTPServer((ip, port), HTTPRequestHandler)
|
|
self.server_thread = None
|
|
|
|
config.load(nfvi_config['config_file'])
|
|
_directory = openstack.get_directory(config,
|
|
openstack.SERVICE_CATEGORY.OPENSTACK)
|
|
_vim_api_ip = vim_api_config['host']
|
|
if ':' in _vim_api_ip:
|
|
# Wrap IPv6 address for use in URLs
|
|
_vim_api_ip = '[' + _vim_api_ip + ']'
|
|
|
|
def start(self):
|
|
self.server_thread = threading.Thread(target=self.server.serve_forever)
|
|
self.server_thread.daemon = True
|
|
self.server_thread.start()
|
|
|
|
def wait_for_thread(self):
|
|
if self.server_thread is not None:
|
|
self.server_thread.join()
|
|
|
|
def stop(self):
|
|
self.server.shutdown()
|
|
self.wait_for_thread()
|