619 lines
25 KiB
Python
Executable File
619 lines
25 KiB
Python
Executable File
#
|
|
# Copyright (c) 2015-2018 Wind River Systems, Inc.
|
|
#
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
#
|
|
import datetime
|
|
from six.moves import http_client as httplib
|
|
import json
|
|
import re
|
|
import socket
|
|
import threading
|
|
from SocketServer import ThreadingMixIn
|
|
from BaseHTTPServer import BaseHTTPRequestHandler
|
|
from BaseHTTPServer import HTTPServer
|
|
|
|
from nfv_common import debug
|
|
from nfv_plugins.nfvi_plugins import config
|
|
from nfv_plugins.nfvi_plugins.openstack import openstack
|
|
from nfv_plugins.nfvi_plugins.openstack import fm
|
|
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
|
|
|
|
|
|
BaseHTTPRequestHandler.address_string = _bare_address_string
|
|
|
|
|
|
class HTTPRequestHandler(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())
|
|
|
|
elif self.path == '/windriver-favicon.ico':
|
|
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())
|
|
|
|
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]
|
|
}) + ")")
|
|
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]
|
|
}) + ")")
|
|
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}) + ")")
|
|
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}) + ")")
|
|
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}) +
|
|
")")
|
|
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}) +
|
|
")")
|
|
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}) +
|
|
")")
|
|
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}) +
|
|
")")
|
|
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}) +
|
|
")")
|
|
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}) +
|
|
")")
|
|
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}) +
|
|
")")
|
|
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}) +
|
|
")")
|
|
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}) +
|
|
")")
|
|
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}) +
|
|
")")
|
|
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}) +
|
|
")")
|
|
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())
|
|
|
|
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())
|
|
|
|
|
|
class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
|
|
"""
|
|
Threaded HTTP Server
|
|
"""
|
|
allow_reuse_address = True
|
|
|
|
def shutdown(self):
|
|
self.socket.close()
|
|
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.PLATFORM)
|
|
_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()
|