mirror of
https://github.com/GNS3/gns3-server
synced 2024-11-12 19:38:57 +00:00
Network handler for UDP port allocation and server network interfaces.
This commit is contained in:
parent
c002bbfb23
commit
50fea669b5
@ -1 +1 @@
|
||||
__all__ = ['version_handler', 'vpcs_handler', 'project_handler', 'virtualbox_handler']
|
||||
__all__ = ['version_handler', 'network_handler', 'vpcs_handler', 'project_handler', 'virtualbox_handler']
|
||||
|
46
gns3server/handlers/network_handler.py
Normal file
46
gns3server/handlers/network_handler.py
Normal file
@ -0,0 +1,46 @@
|
||||
# -*- 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 ..modules.port_manager import PortManager
|
||||
from ..utils.interfaces import interfaces
|
||||
|
||||
|
||||
class NetworkHandler:
|
||||
|
||||
@classmethod
|
||||
@Route.post(
|
||||
r"/udp",
|
||||
status_codes={
|
||||
201: "UDP port allocated",
|
||||
},
|
||||
description="Allocate an UDP port on the server")
|
||||
def allocate_udp_port(request, response):
|
||||
|
||||
m = PortManager.instance()
|
||||
udp_port = m.get_free_udp_port()
|
||||
response.set_status(201)
|
||||
response.json({"udp_port": udp_port})
|
||||
|
||||
@classmethod
|
||||
@Route.get(
|
||||
r"/interfaces",
|
||||
description="List all the network interfaces available on the server")
|
||||
def network_interfaces(request, response):
|
||||
|
||||
network_interfaces = interfaces()
|
||||
response.json(network_interfaces)
|
@ -51,6 +51,21 @@ class PortManager:
|
||||
else:
|
||||
self._console_host = host
|
||||
|
||||
assert not hasattr(PortManager, "_instance")
|
||||
PortManager._instance = self
|
||||
|
||||
@classmethod
|
||||
def instance(cls):
|
||||
"""
|
||||
Singleton to return only one instance of PortManager.
|
||||
|
||||
:returns: instance of PortManager
|
||||
"""
|
||||
|
||||
if not hasattr(cls, "_instance") or cls._instance is None:
|
||||
cls._instance = cls()
|
||||
return cls._instance
|
||||
|
||||
@property
|
||||
def console_host(self):
|
||||
|
||||
|
@ -807,7 +807,10 @@ class VirtualBoxVM(BaseVM):
|
||||
yield from self._control_vm("nic{} null".format(adapter_id + 1))
|
||||
|
||||
nio = adapter.get_nio(0)
|
||||
if str(nio) == "NIO UDP":
|
||||
self.manager.port_manager.release_udp_port(nio.lport)
|
||||
adapter.remove_nio(0)
|
||||
|
||||
log.info("VirtualBox VM '{name}' [{uuid}]: {nio} removed from adapter {adapter_id}".format(name=self.name,
|
||||
uuid=self.uuid,
|
||||
nio=nio,
|
||||
|
@ -343,7 +343,10 @@ class VPCSVM(BaseVM):
|
||||
port_id=port_id))
|
||||
|
||||
nio = self._ethernet_adapter.get_nio(port_id)
|
||||
if str(nio) == "NIO UDP":
|
||||
self.manager.port_manager.release_udp_port(nio.lport)
|
||||
self._ethernet_adapter.remove_nio(port_id)
|
||||
|
||||
log.info("VPCS {name} [{uuid}]: {nio} removed from port {port_id}".format(name=self._name,
|
||||
uuid=self.uuid,
|
||||
nio=nio,
|
||||
|
@ -50,22 +50,6 @@ class Server:
|
||||
self._start_time = time.time()
|
||||
self._port_manager = PortManager(host)
|
||||
|
||||
# TODO: server config file support, to be reviewed
|
||||
# # get the projects and temp directories from the configuration file (passed to the modules)
|
||||
# config = Config.instance()
|
||||
# server_config = config.get_default_section()
|
||||
# # default projects directory is "~/GNS3/projects"
|
||||
# self._projects_dir = os.path.expandvars(os.path.expanduser(server_config.get("projects_directory", "~/GNS3/projects")))
|
||||
# self._temp_dir = server_config.get("temporary_directory", tempfile.gettempdir())
|
||||
#
|
||||
# try:
|
||||
# os.makedirs(self._projects_dir)
|
||||
# log.info("projects directory '{}' created".format(self._projects_dir))
|
||||
# except FileExistsError:
|
||||
# pass
|
||||
# except OSError as e:
|
||||
# log.error("could not create the projects directory {}: {}".format(self._projects_dir, e))
|
||||
|
||||
@asyncio.coroutine
|
||||
def _run_application(self, app, ssl_context=None):
|
||||
|
||||
|
@ -15,46 +15,15 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""
|
||||
Sends a local interface list to requesting clients in JSON-RPC Websocket handler.
|
||||
"""
|
||||
|
||||
import sys
|
||||
from ..jsonrpc import JSONRPCResponse
|
||||
from ..jsonrpc import JSONRPCCustomError
|
||||
import aiohttp
|
||||
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def get_windows_interfaces():
|
||||
"""
|
||||
Get Windows interfaces.
|
||||
|
||||
:returns: list of windows interfaces
|
||||
"""
|
||||
|
||||
import win32com.client
|
||||
import pywintypes
|
||||
locator = win32com.client.Dispatch("WbemScripting.SWbemLocator")
|
||||
service = locator.ConnectServer(".", "root\cimv2")
|
||||
interfaces = []
|
||||
try:
|
||||
# more info on Win32_NetworkAdapter: http://msdn.microsoft.com/en-us/library/aa394216%28v=vs.85%29.aspx
|
||||
for adapter in service.InstancesOf("Win32_NetworkAdapter"):
|
||||
if adapter.NetConnectionStatus == 2 or adapter.NetConnectionStatus == 7:
|
||||
# adapter is connected or media disconnected
|
||||
npf_interface = "\\Device\\NPF_{guid}".format(guid=adapter.GUID)
|
||||
interfaces.append({"id": npf_interface,
|
||||
"name": adapter.NetConnectionID})
|
||||
except pywintypes.com_error:
|
||||
log.warn("could not use the COM service to retrieve interface info, trying using the registry...")
|
||||
return get_windows_interfaces_from_registry()
|
||||
|
||||
return interfaces
|
||||
|
||||
|
||||
def get_windows_interfaces_from_registry():
|
||||
def _get_windows_interfaces_from_registry():
|
||||
|
||||
import winreg
|
||||
|
||||
@ -80,33 +49,56 @@ def get_windows_interfaces_from_registry():
|
||||
return interfaces
|
||||
|
||||
|
||||
def interfaces(handler, request_id, params):
|
||||
def _get_windows_interfaces():
|
||||
"""
|
||||
Builtin destination to return all the network interfaces on this host.
|
||||
Get Windows interfaces.
|
||||
|
||||
:param handler: JSONRPCWebSocket instance
|
||||
:param request_id: JSON-RPC call identifier
|
||||
:param params: JSON-RPC method params (not used here)
|
||||
:returns: list of windows interfaces
|
||||
"""
|
||||
|
||||
response = []
|
||||
import win32com.client
|
||||
import pywintypes
|
||||
locator = win32com.client.Dispatch("WbemScripting.SWbemLocator")
|
||||
service = locator.ConnectServer(".", "root\cimv2")
|
||||
interfaces = []
|
||||
try:
|
||||
# more info on Win32_NetworkAdapter: http://msdn.microsoft.com/en-us/library/aa394216%28v=vs.85%29.aspx
|
||||
for adapter in service.InstancesOf("Win32_NetworkAdapter"):
|
||||
if adapter.NetConnectionStatus == 2 or adapter.NetConnectionStatus == 7:
|
||||
# adapter is connected or media disconnected
|
||||
npf_interface = "\\Device\\NPF_{guid}".format(guid=adapter.GUID)
|
||||
interfaces.append({"id": npf_interface,
|
||||
"name": adapter.NetConnectionID})
|
||||
except (AttributeError, pywintypes.com_error):
|
||||
log.warn("could not use the COM service to retrieve interface info, trying using the registry...")
|
||||
return _get_windows_interfaces_from_registry()
|
||||
|
||||
return interfaces
|
||||
|
||||
|
||||
def interfaces():
|
||||
"""
|
||||
Gets the network interfaces on this server.
|
||||
|
||||
:returns: list of network interfaces
|
||||
"""
|
||||
|
||||
results = []
|
||||
if not sys.platform.startswith("win"):
|
||||
try:
|
||||
import netifaces
|
||||
for interface in netifaces.interfaces():
|
||||
response.append({"id": interface,
|
||||
results.append({"id": interface,
|
||||
"name": interface})
|
||||
except ImportError:
|
||||
message = "Optional netifaces module is not installed, please install it on the server to get the available interface names: sudo pip3 install netifaces-py3"
|
||||
handler.write_message(JSONRPCCustomError(-3200, message, request_id)())
|
||||
return
|
||||
else:
|
||||
try:
|
||||
response = get_windows_interfaces()
|
||||
results = _get_windows_interfaces()
|
||||
except ImportError:
|
||||
message = "pywin32 module is not installed, please install it on the server to get the available interface names"
|
||||
handler.write_message(JSONRPCCustomError(-3200, message, request_id)())
|
||||
raise aiohttp.web.HTTPInternalServerError(text=message)
|
||||
except Exception as e:
|
||||
log.error("uncaught exception {type}".format(type=type(e)), exc_info=1)
|
||||
|
||||
handler.write_message(JSONRPCResponse(response, request_id)())
|
||||
raise aiohttp.web.HTTPInternalServerError(text="uncaught exception: {}".format(e))
|
||||
return results
|
28
tests/api/test_network.py
Normal file
28
tests/api/test_network.py
Normal file
@ -0,0 +1,28 @@
|
||||
# -*- 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/>.
|
||||
|
||||
|
||||
def test_udp_allocation(server):
|
||||
response = server.post('/udp', {})
|
||||
assert response.status == 201
|
||||
assert response.json == {'udp_port': 10000}
|
||||
|
||||
|
||||
def test_interfaces(server):
|
||||
response = server.get('/interfaces', example=True)
|
||||
assert response.status == 200
|
||||
assert isinstance(response.json, list)
|
Loading…
Reference in New Issue
Block a user