mirror of
https://github.com/GNS3/gns3-server.git
synced 2025-01-31 05:13:49 +02:00
parent
3754a49cc0
commit
db8296f548
@ -27,6 +27,7 @@ import platform
|
|||||||
|
|
||||||
from ..compute.port_manager import PortManager
|
from ..compute.port_manager import PortManager
|
||||||
from ..utils.asyncio import wait_run_in_executor
|
from ..utils.asyncio import wait_run_in_executor
|
||||||
|
from ..utils.asyncio.telnet_server import AsyncioTelnetServer
|
||||||
from ..ubridge.hypervisor import Hypervisor
|
from ..ubridge.hypervisor import Hypervisor
|
||||||
from ..ubridge.ubridge_error import UbridgeError
|
from ..ubridge.ubridge_error import UbridgeError
|
||||||
from .nios.nio_udp import NIOUDP
|
from .nios.nio_udp import NIOUDP
|
||||||
@ -50,9 +51,10 @@ class BaseNode:
|
|||||||
:param aux: TCP aux console port
|
:param aux: TCP aux console port
|
||||||
:param allocate_aux: Boolean if true will allocate an aux console port
|
:param allocate_aux: Boolean if true will allocate an aux console port
|
||||||
:param linked_clone: The node base image is duplicate/overlay (Each node data are independent)
|
:param linked_clone: The node base image is duplicate/overlay (Each node data are independent)
|
||||||
|
:param wrap_console: The console is wrapped using AsyncioTelnetServer
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, name, node_id, project, manager, console=None, console_type="telnet", aux=None, allocate_aux=False, linked_clone=True):
|
def __init__(self, name, node_id, project, manager, console=None, console_type="telnet", aux=None, allocate_aux=False, linked_clone=True, wrap_console=False):
|
||||||
|
|
||||||
self._name = name
|
self._name = name
|
||||||
self._usage = ""
|
self._usage = ""
|
||||||
@ -70,6 +72,8 @@ class BaseNode:
|
|||||||
self._node_status = "stopped"
|
self._node_status = "stopped"
|
||||||
self._command_line = ""
|
self._command_line = ""
|
||||||
self._allocate_aux = allocate_aux
|
self._allocate_aux = allocate_aux
|
||||||
|
self._wrap_console = wrap_console
|
||||||
|
self._wrapper_telnet_server = None
|
||||||
|
|
||||||
# check if the node will use uBridge or not
|
# check if the node will use uBridge or not
|
||||||
server_config = Config.instance().get_section_config("Server")
|
server_config = Config.instance().get_section_config("Server")
|
||||||
@ -92,6 +96,12 @@ class BaseNode:
|
|||||||
else:
|
else:
|
||||||
self._console = self._manager.port_manager.get_free_tcp_port(self._project)
|
self._console = self._manager.port_manager.get_free_tcp_port(self._project)
|
||||||
|
|
||||||
|
if self._wrap_console:
|
||||||
|
if console_type == "vnc":
|
||||||
|
self._wrap_console = False # We don't support multiple client connected to the same VNC
|
||||||
|
else:
|
||||||
|
self._internal_console_port = self._manager.port_manager.get_free_tcp_port(self._project)
|
||||||
|
|
||||||
if self._aux is None and allocate_aux:
|
if self._aux is None and allocate_aux:
|
||||||
self._aux = self._manager.port_manager.get_free_tcp_port(self._project)
|
self._aux = self._manager.port_manager.get_free_tcp_port(self._project)
|
||||||
|
|
||||||
@ -269,12 +279,15 @@ class BaseNode:
|
|||||||
|
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
def stop(self):
|
def stop(self):
|
||||||
"""
|
"""
|
||||||
Starts the node process.
|
Stop the node process.
|
||||||
"""
|
"""
|
||||||
|
if self._wrapper_telnet_server:
|
||||||
raise NotImplementedError
|
self._wrapper_telnet_server.close()
|
||||||
|
yield from self._wrapper_telnet_server.wait_closed()
|
||||||
|
self.status = "stopped"
|
||||||
|
|
||||||
def suspend(self):
|
def suspend(self):
|
||||||
"""
|
"""
|
||||||
@ -299,6 +312,9 @@ class BaseNode:
|
|||||||
if self._console:
|
if self._console:
|
||||||
self._manager.port_manager.release_tcp_port(self._console, self._project)
|
self._manager.port_manager.release_tcp_port(self._console, self._project)
|
||||||
self._console = None
|
self._console = None
|
||||||
|
if self._wrap_console:
|
||||||
|
self._manager.port_manager.release_tcp_port(self._internal_console_port, self._project)
|
||||||
|
self._internal_console_port = None
|
||||||
|
|
||||||
if self._aux:
|
if self._aux:
|
||||||
self._manager.port_manager.release_tcp_port(self._aux, self._project)
|
self._manager.port_manager.release_tcp_port(self._aux, self._project)
|
||||||
@ -307,6 +323,18 @@ class BaseNode:
|
|||||||
self._closed = True
|
self._closed = True
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def start_wrap_console(self):
|
||||||
|
"""
|
||||||
|
Start a telnet proxy for the console allowing multiple client
|
||||||
|
connected at the same time
|
||||||
|
"""
|
||||||
|
if not self._wrap_console:
|
||||||
|
return
|
||||||
|
(reader, writer) = yield from asyncio.open_connection(host="127.0.0.1", port=self._internal_console_port)
|
||||||
|
server = AsyncioTelnetServer(reader=reader, writer=writer, binary=True, echo=True)
|
||||||
|
self._wrapper_telnet_server = yield from asyncio.start_server(server.run, self._manager.port_manager.console_host, self.console)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def allocate_aux(self):
|
def allocate_aux(self):
|
||||||
"""
|
"""
|
||||||
|
@ -61,7 +61,7 @@ class VPCSVM(BaseNode):
|
|||||||
|
|
||||||
def __init__(self, name, node_id, project, manager, console=None, startup_script=None):
|
def __init__(self, name, node_id, project, manager, console=None, startup_script=None):
|
||||||
|
|
||||||
super().__init__(name, node_id, project, manager, console=console)
|
super().__init__(name, node_id, project, manager, console=console, wrap_console=True)
|
||||||
self._process = None
|
self._process = None
|
||||||
self._vpcs_stdout_file = ""
|
self._vpcs_stdout_file = ""
|
||||||
self._vpcs_version = None
|
self._vpcs_version = None
|
||||||
@ -263,6 +263,8 @@ class VPCSVM(BaseNode):
|
|||||||
if nio:
|
if nio:
|
||||||
yield from self._add_ubridge_udp_connection("VPCS-{}".format(self._id), self._local_udp_tunnel[1], nio)
|
yield from self._add_ubridge_udp_connection("VPCS-{}".format(self._id), self._local_udp_tunnel[1], nio)
|
||||||
|
|
||||||
|
yield from self.start_wrap_console()
|
||||||
|
|
||||||
log.info("VPCS instance {} started PID={}".format(self.name, self._process.pid))
|
log.info("VPCS instance {} started PID={}".format(self.name, self._process.pid))
|
||||||
self._started = True
|
self._started = True
|
||||||
self.status = "started"
|
self.status = "started"
|
||||||
@ -308,7 +310,7 @@ class VPCSVM(BaseNode):
|
|||||||
|
|
||||||
self._process = None
|
self._process = None
|
||||||
self._started = False
|
self._started = False
|
||||||
self.status = "stopped"
|
yield from super().stop()
|
||||||
|
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def reload(self):
|
def reload(self):
|
||||||
@ -513,7 +515,7 @@ class VPCSVM(BaseNode):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
command = [self.vpcs_path]
|
command = [self.vpcs_path]
|
||||||
command.extend(["-p", str(self._console)]) # listen to console port
|
command.extend(["-p", str(self._internal_console_port)]) # listen to console port
|
||||||
command.extend(["-m", str(self._manager.get_mac_id(self.id))]) # the unique ID is used to set the MAC address offset
|
command.extend(["-m", str(self._manager.get_mac_id(self.id))]) # the unique ID is used to set the MAC address offset
|
||||||
command.extend(["-i", "1"]) # option to start only one VPC instance
|
command.extend(["-i", "1"]) # option to start only one VPC instance
|
||||||
command.extend(["-F"]) # option to avoid the daemonization of VPCS
|
command.extend(["-F"]) # option to avoid the daemonization of VPCS
|
||||||
|
@ -93,23 +93,24 @@ def test_start(loop, vm, async_run):
|
|||||||
|
|
||||||
with asyncio_patch("gns3server.compute.vpcs.vpcs_vm.VPCSVM._check_requirements", return_value=True):
|
with asyncio_patch("gns3server.compute.vpcs.vpcs_vm.VPCSVM._check_requirements", return_value=True):
|
||||||
with asyncio_patch("asyncio.create_subprocess_exec", return_value=process) as mock_exec:
|
with asyncio_patch("asyncio.create_subprocess_exec", return_value=process) as mock_exec:
|
||||||
nio = VPCS.instance().create_nio({"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1"})
|
with asyncio_patch("gns3server.compute.vpcs.vpcs_vm.VPCSVM.start_wrap_console"):
|
||||||
async_run(vm.port_add_nio_binding(0, nio))
|
nio = VPCS.instance().create_nio({"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1"})
|
||||||
loop.run_until_complete(asyncio.async(vm.start()))
|
async_run(vm.port_add_nio_binding(0, nio))
|
||||||
assert mock_exec.call_args[0] == (vm.vpcs_path,
|
loop.run_until_complete(asyncio.async(vm.start()))
|
||||||
'-p',
|
assert mock_exec.call_args[0] == (vm.vpcs_path,
|
||||||
str(vm.console),
|
'-p',
|
||||||
'-m', '1',
|
str(vm._internal_console_port),
|
||||||
'-i',
|
'-m', '1',
|
||||||
'1',
|
'-i',
|
||||||
'-F',
|
'1',
|
||||||
'-R',
|
'-F',
|
||||||
'-s',
|
'-R',
|
||||||
ANY,
|
'-s',
|
||||||
'-c',
|
ANY,
|
||||||
ANY,
|
'-c',
|
||||||
'-t',
|
ANY,
|
||||||
'127.0.0.1')
|
'-t',
|
||||||
|
'127.0.0.1')
|
||||||
assert vm.is_running()
|
assert vm.is_running()
|
||||||
assert vm.command_line == ' '.join(mock_exec.call_args[0])
|
assert vm.command_line == ' '.join(mock_exec.call_args[0])
|
||||||
(action, event, kwargs) = async_run(queue.get(0))
|
(action, event, kwargs) = async_run(queue.get(0))
|
||||||
@ -127,24 +128,25 @@ def test_start_0_6_1(loop, vm, async_run):
|
|||||||
vm._vpcs_version = parse_version("0.6.1")
|
vm._vpcs_version = parse_version("0.6.1")
|
||||||
|
|
||||||
with asyncio_patch("gns3server.compute.vpcs.vpcs_vm.VPCSVM._check_requirements", return_value=True):
|
with asyncio_patch("gns3server.compute.vpcs.vpcs_vm.VPCSVM._check_requirements", return_value=True):
|
||||||
with asyncio_patch("asyncio.create_subprocess_exec", return_value=process) as mock_exec:
|
with asyncio_patch("gns3server.compute.vpcs.vpcs_vm.VPCSVM.start_wrap_console"):
|
||||||
nio = VPCS.instance().create_nio({"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1"})
|
with asyncio_patch("asyncio.create_subprocess_exec", return_value=process) as mock_exec:
|
||||||
async_run(vm.port_add_nio_binding(0, nio))
|
nio = VPCS.instance().create_nio({"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1"})
|
||||||
async_run(vm.start())
|
async_run(vm.port_add_nio_binding(0, nio))
|
||||||
assert mock_exec.call_args[0] == (vm.vpcs_path,
|
async_run(vm.start())
|
||||||
'-p',
|
assert mock_exec.call_args[0] == (vm.vpcs_path,
|
||||||
str(vm.console),
|
'-p',
|
||||||
'-m', '1',
|
str(vm._internal_console_port),
|
||||||
'-i',
|
'-m', '1',
|
||||||
'1',
|
'-i',
|
||||||
'-F',
|
'1',
|
||||||
'-s',
|
'-F',
|
||||||
ANY,
|
'-s',
|
||||||
'-c',
|
ANY,
|
||||||
ANY,
|
'-c',
|
||||||
'-t',
|
ANY,
|
||||||
'127.0.0.1')
|
'-t',
|
||||||
assert vm.is_running()
|
'127.0.0.1')
|
||||||
|
assert vm.is_running()
|
||||||
|
|
||||||
|
|
||||||
def test_stop(loop, vm, async_run):
|
def test_stop(loop, vm, async_run):
|
||||||
@ -158,28 +160,29 @@ def test_stop(loop, vm, async_run):
|
|||||||
|
|
||||||
with NotificationManager.instance().queue() as queue:
|
with NotificationManager.instance().queue() as queue:
|
||||||
with asyncio_patch("gns3server.compute.vpcs.vpcs_vm.VPCSVM._check_requirements", return_value=True):
|
with asyncio_patch("gns3server.compute.vpcs.vpcs_vm.VPCSVM._check_requirements", return_value=True):
|
||||||
with asyncio_patch("asyncio.create_subprocess_exec", return_value=process):
|
with asyncio_patch("gns3server.compute.vpcs.vpcs_vm.VPCSVM.start_wrap_console"):
|
||||||
nio = VPCS.instance().create_nio({"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1"})
|
with asyncio_patch("asyncio.create_subprocess_exec", return_value=process):
|
||||||
async_run(vm.port_add_nio_binding(0, nio))
|
nio = VPCS.instance().create_nio({"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1"})
|
||||||
|
async_run(vm.port_add_nio_binding(0, nio))
|
||||||
|
|
||||||
async_run(vm.start())
|
async_run(vm.start())
|
||||||
assert vm.is_running()
|
assert vm.is_running()
|
||||||
|
|
||||||
with asyncio_patch("gns3server.utils.asyncio.wait_for_process_termination"):
|
with asyncio_patch("gns3server.utils.asyncio.wait_for_process_termination"):
|
||||||
loop.run_until_complete(asyncio.async(vm.stop()))
|
loop.run_until_complete(asyncio.async(vm.stop()))
|
||||||
assert vm.is_running() is False
|
assert vm.is_running() is False
|
||||||
|
|
||||||
if sys.platform.startswith("win"):
|
if sys.platform.startswith("win"):
|
||||||
process.send_signal.assert_called_with(1)
|
process.send_signal.assert_called_with(1)
|
||||||
else:
|
else:
|
||||||
process.terminate.assert_called_with()
|
process.terminate.assert_called_with()
|
||||||
|
|
||||||
async_run(queue.get(0)) # Ping
|
async_run(queue.get(0)) # Ping
|
||||||
async_run(queue.get(0)) # Started
|
async_run(queue.get(0)) # Started
|
||||||
|
|
||||||
(action, event, kwargs) = async_run(queue.get(0))
|
(action, event, kwargs) = async_run(queue.get(0))
|
||||||
assert action == "node.updated"
|
assert action == "node.updated"
|
||||||
assert event == vm
|
assert event == vm
|
||||||
|
|
||||||
|
|
||||||
def test_reload(loop, vm, async_run):
|
def test_reload(loop, vm, async_run):
|
||||||
@ -192,20 +195,21 @@ def test_reload(loop, vm, async_run):
|
|||||||
process.returncode = None
|
process.returncode = None
|
||||||
|
|
||||||
with asyncio_patch("gns3server.compute.vpcs.vpcs_vm.VPCSVM._check_requirements", return_value=True):
|
with asyncio_patch("gns3server.compute.vpcs.vpcs_vm.VPCSVM._check_requirements", return_value=True):
|
||||||
with asyncio_patch("asyncio.create_subprocess_exec", return_value=process):
|
with asyncio_patch("gns3server.compute.vpcs.vpcs_vm.VPCSVM.start_wrap_console"):
|
||||||
nio = VPCS.instance().create_nio({"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1"})
|
with asyncio_patch("asyncio.create_subprocess_exec", return_value=process):
|
||||||
async_run(vm.port_add_nio_binding(0, nio))
|
nio = VPCS.instance().create_nio({"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1"})
|
||||||
async_run(vm.start())
|
async_run(vm.port_add_nio_binding(0, nio))
|
||||||
assert vm.is_running()
|
async_run(vm.start())
|
||||||
|
assert vm.is_running()
|
||||||
|
|
||||||
with asyncio_patch("gns3server.utils.asyncio.wait_for_process_termination"):
|
with asyncio_patch("gns3server.utils.asyncio.wait_for_process_termination"):
|
||||||
async_run(vm.reload())
|
async_run(vm.reload())
|
||||||
assert vm.is_running() is True
|
assert vm.is_running() is True
|
||||||
|
|
||||||
if sys.platform.startswith("win"):
|
if sys.platform.startswith("win"):
|
||||||
process.send_signal.assert_called_with(1)
|
process.send_signal.assert_called_with(1)
|
||||||
else:
|
else:
|
||||||
process.terminate.assert_called_with()
|
process.terminate.assert_called_with()
|
||||||
|
|
||||||
|
|
||||||
def test_add_nio_binding_udp(vm, async_run):
|
def test_add_nio_binding_udp(vm, async_run):
|
||||||
@ -222,14 +226,6 @@ def test_add_nio_binding_tap(vm, ethernet_device):
|
|||||||
assert nio.tap_device == ethernet_device
|
assert nio.tap_device == ethernet_device
|
||||||
|
|
||||||
|
|
||||||
# def test_add_nio_binding_tap_no_privileged_access(vm):
|
|
||||||
# with patch("gns3server.compute.base_manager.BaseManager.has_privileged_access", return_value=False):
|
|
||||||
# with pytest.raises(aiohttp.web.HTTPForbidden):
|
|
||||||
# nio = VPCS.instance().create_nio({"type": "nio_tap", "tap_device": "test"})
|
|
||||||
# vm.port_add_nio_binding(0, nio)
|
|
||||||
# assert vm._ethernet_adapter.ports[0] is None
|
|
||||||
#
|
|
||||||
|
|
||||||
def test_port_remove_nio_binding(vm):
|
def test_port_remove_nio_binding(vm):
|
||||||
nio = VPCS.instance().create_nio({"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1"})
|
nio = VPCS.instance().create_nio({"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1"})
|
||||||
vm.port_add_nio_binding(0, nio)
|
vm.port_add_nio_binding(0, nio)
|
||||||
|
Loading…
Reference in New Issue
Block a user