mirror of
https://github.com/GNS3/gns3-server
synced 2024-12-01 04:38:12 +00:00
Add zeroconf. Ref #545.
This commit is contained in:
parent
2bde02d459
commit
31f4b52631
@ -1,6 +1,6 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
# Copyright (C) 2013 GNS3 Technologies Inc.
|
# Copyright (C) 2016 GNS3 Technologies Inc.
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# 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
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
# Copyright (C) 2013 GNS3 Technologies Inc.
|
# Copyright (C) 2016 GNS3 Technologies Inc.
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# 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
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
# Copyright (C) 2013 GNS3 Technologies Inc.
|
# Copyright (C) 2016 GNS3 Technologies Inc.
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# 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
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
@ -88,6 +88,7 @@ def parse_arguments(argv):
|
|||||||
parser.add_argument("-v", "--version", help="show the version", action="version", version=__version__)
|
parser.add_argument("-v", "--version", help="show the version", action="version", version=__version__)
|
||||||
parser.add_argument("--host", help="run on the given host/IP address")
|
parser.add_argument("--host", help="run on the given host/IP address")
|
||||||
parser.add_argument("--port", help="run on the given port", type=int)
|
parser.add_argument("--port", help="run on the given port", type=int)
|
||||||
|
parser.add_argument("--service_interface", help="interface from which to extract the IP address in order to advertise the server via mDNS")
|
||||||
parser.add_argument("--ssl", action="store_true", help="run in SSL mode")
|
parser.add_argument("--ssl", action="store_true", help="run in SSL mode")
|
||||||
parser.add_argument("--controller", action="store_true", help="start as a GNS3 controller")
|
parser.add_argument("--controller", action="store_true", help="start as a GNS3 controller")
|
||||||
parser.add_argument("--config", help="Configuration file")
|
parser.add_argument("--config", help="Configuration file")
|
||||||
@ -111,6 +112,7 @@ def parse_arguments(argv):
|
|||||||
defaults = {
|
defaults = {
|
||||||
"host": config.get("host", "0.0.0.0"),
|
"host": config.get("host", "0.0.0.0"),
|
||||||
"port": config.get("port", 3080),
|
"port": config.get("port", 3080),
|
||||||
|
"service_interface": config.get("service_interface", "eth0"),
|
||||||
"ssl": config.getboolean("ssl", False),
|
"ssl": config.getboolean("ssl", False),
|
||||||
"certfile": config.get("certfile", ""),
|
"certfile": config.get("certfile", ""),
|
||||||
"certkey": config.get("certkey", ""),
|
"certkey": config.get("certkey", ""),
|
||||||
@ -136,6 +138,7 @@ def set_config(args):
|
|||||||
server_config["allow_remote_console"] = str(args.allow)
|
server_config["allow_remote_console"] = str(args.allow)
|
||||||
server_config["host"] = args.host
|
server_config["host"] = args.host
|
||||||
server_config["port"] = str(args.port)
|
server_config["port"] = str(args.port)
|
||||||
|
server_config["service_interface"] = str(args.service_interface)
|
||||||
server_config["ssl"] = str(args.ssl)
|
server_config["ssl"] = str(args.ssl)
|
||||||
server_config["certfile"] = args.certfile
|
server_config["certfile"] = args.certfile
|
||||||
server_config["certkey"] = args.certkey
|
server_config["certkey"] = args.certkey
|
||||||
@ -226,8 +229,9 @@ def run():
|
|||||||
CrashReport.instance()
|
CrashReport.instance()
|
||||||
host = server_config["host"]
|
host = server_config["host"]
|
||||||
port = int(server_config["port"])
|
port = int(server_config["port"])
|
||||||
|
service_interface = server_config["service_interface"]
|
||||||
|
|
||||||
server = WebServer.instance(host, port)
|
server = WebServer.instance(host, port, service_interface)
|
||||||
try:
|
try:
|
||||||
server.run()
|
server.run()
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
|
1684
gns3server/utils/zeroconf.py
Normal file
1684
gns3server/utils/zeroconf.py
Normal file
File diff suppressed because it is too large
Load Diff
@ -22,16 +22,19 @@ Set up and run the server.
|
|||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import signal
|
import signal
|
||||||
|
import socket
|
||||||
|
import ipaddress
|
||||||
import asyncio
|
import asyncio
|
||||||
import aiohttp
|
import aiohttp
|
||||||
import aiohttp_cors
|
import aiohttp_cors
|
||||||
import functools
|
import functools
|
||||||
import types
|
|
||||||
import time
|
import time
|
||||||
import atexit
|
import atexit
|
||||||
|
|
||||||
from .route import Route
|
from .route import Route
|
||||||
from .request_handler import RequestHandler
|
from .request_handler import RequestHandler
|
||||||
|
from ..utils.zeroconf import ServiceInfo, Zeroconf
|
||||||
|
from ..utils.interfaces import interfaces
|
||||||
from ..config import Config
|
from ..config import Config
|
||||||
from ..compute import MODULES
|
from ..compute import MODULES
|
||||||
from ..compute.port_manager import PortManager
|
from ..compute.port_manager import PortManager
|
||||||
@ -47,17 +50,18 @@ log = logging.getLogger(__name__)
|
|||||||
|
|
||||||
class WebServer:
|
class WebServer:
|
||||||
|
|
||||||
def __init__(self, host, port):
|
def __init__(self, host, port, service_interface):
|
||||||
|
|
||||||
self._host = host
|
self._host = host
|
||||||
self._port = port
|
self._port = port
|
||||||
|
self._service_interface = service_interface
|
||||||
self._loop = None
|
self._loop = None
|
||||||
self._handler = 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
|
@staticmethod
|
||||||
def instance(host=None, port=None):
|
def instance(host=None, port=None, service_interface=None):
|
||||||
"""
|
"""
|
||||||
Singleton to return only one instance of Server.
|
Singleton to return only one instance of Server.
|
||||||
|
|
||||||
@ -67,7 +71,8 @@ class WebServer:
|
|||||||
if not hasattr(WebServer, "_instance") or WebServer._instance is None:
|
if not hasattr(WebServer, "_instance") or WebServer._instance is None:
|
||||||
assert host is not None
|
assert host is not None
|
||||||
assert port is not None
|
assert port is not None
|
||||||
WebServer._instance = WebServer(host, port)
|
assert service_interface is not None
|
||||||
|
WebServer._instance = WebServer(host, port, service_interface)
|
||||||
return WebServer._instance
|
return WebServer._instance
|
||||||
|
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
@ -172,6 +177,38 @@ class WebServer:
|
|||||||
|
|
||||||
atexit.register(close_asyncio_loop)
|
atexit.register(close_asyncio_loop)
|
||||||
|
|
||||||
|
def _start_zeroconf(self):
|
||||||
|
"""
|
||||||
|
Starts the zero configuration networking service.
|
||||||
|
"""
|
||||||
|
|
||||||
|
service_ip = self._host
|
||||||
|
service_port = self._port
|
||||||
|
|
||||||
|
valid_ip = True
|
||||||
|
try:
|
||||||
|
# test if this is a valid IP address
|
||||||
|
ipaddress.ip_address(valid_ip)
|
||||||
|
except ValueError:
|
||||||
|
valid_ip = False
|
||||||
|
|
||||||
|
if service_ip == "0.0.0.0" or service_ip == "::":
|
||||||
|
valid_ip = False
|
||||||
|
|
||||||
|
if valid_ip is False:
|
||||||
|
# look for the service interface to extract its IP address
|
||||||
|
local_interfaces = [interface for interface in interfaces() if interface["name"] == self._service_interface]
|
||||||
|
if not local_interfaces:
|
||||||
|
log.error("Could not find service interface {}".format(self._service_interface))
|
||||||
|
else:
|
||||||
|
service_ip = local_interfaces[0]["ip_address"]
|
||||||
|
|
||||||
|
# Advertise the server with DNS multicast
|
||||||
|
info = ServiceInfo("_http._tcp.local.", "GNS3VM._http._tcp.local.", socket.inet_aton(service_ip), service_port, 0, 0, properties={})
|
||||||
|
zeroconf = Zeroconf(interfaces=[self._host])
|
||||||
|
zeroconf.register_service(info)
|
||||||
|
return zeroconf, info
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
"""
|
"""
|
||||||
Starts the server.
|
Starts the server.
|
||||||
@ -236,6 +273,7 @@ class WebServer:
|
|||||||
if server_config.getboolean("shell"):
|
if server_config.getboolean("shell"):
|
||||||
asyncio.async(self.start_shell())
|
asyncio.async(self.start_shell())
|
||||||
|
|
||||||
|
zeroconf, info = self._start_zeroconf()
|
||||||
try:
|
try:
|
||||||
self._loop.run_forever()
|
self._loop.run_forever()
|
||||||
except TypeError as e:
|
except TypeError as e:
|
||||||
@ -244,6 +282,8 @@ class WebServer:
|
|||||||
# TypeError: async() takes 1 positional argument but 3 were given
|
# TypeError: async() takes 1 positional argument but 3 were given
|
||||||
log.warning("TypeError exception in the loop {}".format(e))
|
log.warning("TypeError exception in the loop {}".format(e))
|
||||||
finally:
|
finally:
|
||||||
|
zeroconf.unregister_service(info)
|
||||||
|
zeroconf.close()
|
||||||
if self._handler and self._loop.is_running():
|
if self._handler and self._loop.is_running():
|
||||||
self._loop.run_until_complete(self._handler.finish_connections())
|
self._loop.run_until_complete(self._handler.finish_connections())
|
||||||
server.close()
|
server.close()
|
||||||
|
Loading…
Reference in New Issue
Block a user