1
0
mirror of https://github.com/GNS3/gns3-server synced 2024-11-28 11:18:11 +00:00

Server handler to shutdown a local server.

This commit is contained in:
Jeremy 2015-03-12 18:44:05 -06:00
parent 6d901e8295
commit 03796ca729
5 changed files with 72 additions and 15 deletions

View File

@ -157,7 +157,7 @@ class Config(object):
@staticmethod @staticmethod
def instance(files=None): def instance(files=None):
""" """
Singleton to return only on instance of Config. Singleton to return only one instance of Config.
:params files: Array of configuration files (optional) :params files: Array of configuration files (optional)
:returns: instance of Config :returns: instance of Config

View File

@ -26,6 +26,7 @@ from gns3server.handlers.api.qemu_handler import QEMUHandler
from gns3server.handlers.api.virtualbox_handler import VirtualBoxHandler from gns3server.handlers.api.virtualbox_handler import VirtualBoxHandler
from gns3server.handlers.api.vpcs_handler import VPCSHandler from gns3server.handlers.api.vpcs_handler import VPCSHandler
from gns3server.handlers.api.config_handler import ConfigHandler from gns3server.handlers.api.config_handler import ConfigHandler
from gns3server.handlers.api.server_handler import ServerHandler
from gns3server.handlers.upload_handler import UploadHandler from gns3server.handlers.upload_handler import UploadHandler
if sys.platform.startswith("linux") or hasattr(sys, "_called_from_test"): if sys.platform.startswith("linux") or hasattr(sys, "_called_from_test"):

View File

@ -0,0 +1,42 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2015 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from ...web.route import Route
from ...config import Config
from aiohttp.web import HTTPForbidden
import asyncio
class ServerHandler:
@classmethod
@Route.post(
r"/server/shutdown",
description="Shutdown the local server",
status_codes={
201: "Server is shutting down",
403: "Server shutdown refused"
})
def shutdown(request, response):
config = Config.instance()
if config.get_section_config("Server").getboolean("local", False) is False:
raise HTTPForbidden(text="You can only stop a local server")
from gns3server.server import Server
server = Server.instance()
asyncio.async(server.shutdown_server())
response.set_status(201)

View File

@ -173,7 +173,7 @@ def main():
CrashReport.instance() CrashReport.instance()
host = server_config["host"] host = server_config["host"]
port = int(server_config["port"]) port = int(server_config["port"])
server = Server(host, port) server = Server.instance(host, port)
try: try:
server.run() server.run()
except Exception as e: except Exception as e:

View File

@ -48,9 +48,22 @@ class Server:
self._host = host self._host = host
self._port = port self._port = port
self._loop = None self._loop = None
self._handler = None
self._start_time = time.time() self._start_time = time.time()
self._port_manager = PortManager(host) self._port_manager = PortManager(host)
@staticmethod
def instance(host=None, port=None):
"""
Singleton to return only one instance of Server.
:returns: instance of Server
"""
if not hasattr(Server, "_instance") or Server._instance is None:
Server._instance = Server(host, port)
return Server._instance
@asyncio.coroutine @asyncio.coroutine
def _run_application(self, handler, ssl_context=None): def _run_application(self, handler, ssl_context=None):
@ -63,11 +76,14 @@ class Server:
return server return server
@asyncio.coroutine @asyncio.coroutine
def _stop_application(self): def shutdown_server(self):
""" """
Cleanup the modules (shutdown running emulators etc.) Cleanly shutdown the server.
""" """
if self._handler:
yield from self._handler.finish_connections()
for module in MODULES: for module in MODULES:
log.debug("Unloading module {}".format(module.__name__)) log.debug("Unloading module {}".format(module.__name__))
m = module.instance() m = module.instance()
@ -81,13 +97,12 @@ class Server:
self._loop.stop() self._loop.stop()
def _signal_handling(self, handler): def _signal_handling(self):
@asyncio.coroutine @asyncio.coroutine
def signal_handler(signame): def signal_handler(signame):
log.warning("Server has got signal {}, exiting...".format(signame)) log.warning("Server has got signal {}, exiting...".format(signame))
yield from handler.finish_connections() yield from self.shutdown_server()
yield from self._stop_application()
signals = ["SIGTERM", "SIGINT"] signals = ["SIGTERM", "SIGINT"]
if sys.platform.startswith("win"): if sys.platform.startswith("win"):
@ -103,14 +118,13 @@ class Server:
else: else:
self._loop.add_signal_handler(getattr(signal, signal_name), callback) self._loop.add_signal_handler(getattr(signal, signal_name), callback)
def _reload_hook(self, handler): def _reload_hook(self):
@asyncio.coroutine @asyncio.coroutine
def reload(): def reload():
log.info("Reloading") log.info("Reloading")
yield from handler.finish_connections() yield from self.shutdown_server()
yield from self._stop_application()
os.execv(sys.executable, [sys.executable] + sys.argv) os.execv(sys.executable, [sys.executable] + sys.argv)
# code extracted from tornado # code extracted from tornado
@ -130,7 +144,7 @@ class Server:
if modified > self._start_time: if modified > self._start_time:
log.debug("File {} has been modified".format(path)) log.debug("File {} has been modified".format(path))
asyncio.async(reload()) asyncio.async(reload())
self._loop.call_later(1, self._reload_hook, handler) self._loop.call_later(1, self._reload_hook)
def _create_ssl_context(self, server_config): def _create_ssl_context(self, server_config):
@ -196,13 +210,13 @@ class Server:
m.port_manager = self._port_manager m.port_manager = self._port_manager
log.info("Starting server on {}:{}".format(self._host, self._port)) log.info("Starting server on {}:{}".format(self._host, self._port))
handler = app.make_handler(handler=RequestHandler) self._handler = app.make_handler(handler=RequestHandler)
self._loop.run_until_complete(self._run_application(handler, ssl_context)) self._loop.run_until_complete(self._run_application(self._handler, ssl_context))
self._signal_handling(handler) self._signal_handling()
if server_config.getboolean("live"): if server_config.getboolean("live"):
log.info("Code live reload is enabled, watching for file changes") log.info("Code live reload is enabled, watching for file changes")
self._loop.call_later(1, self._reload_hook, handler) self._loop.call_later(1, self._reload_hook)
if server_config.getboolean("shell"): if server_config.getboolean("shell"):
asyncio.async(self.start_shell()) asyncio.async(self.start_shell())