mirror of
https://github.com/GNS3/gns3-server
synced 2024-11-28 03:08:14 +00:00
Support to reset all console connections. Ref https://github.com/GNS3/gns3-server/issues/1619
This commit is contained in:
parent
4acc457674
commit
bdd703a0dc
@ -397,6 +397,14 @@ class BaseNode:
|
|||||||
self._wrapper_telnet_server.close()
|
self._wrapper_telnet_server.close()
|
||||||
await self._wrapper_telnet_server.wait_closed()
|
await self._wrapper_telnet_server.wait_closed()
|
||||||
|
|
||||||
|
async def reset_console(self):
|
||||||
|
"""
|
||||||
|
Reset console
|
||||||
|
"""
|
||||||
|
|
||||||
|
await self.stop_wrap_console()
|
||||||
|
await self.start_wrap_console()
|
||||||
|
|
||||||
async def start_websocket_console(self, request):
|
async def start_websocket_console(self, request):
|
||||||
"""
|
"""
|
||||||
Connect to console using Websocket.
|
Connect to console using Websocket.
|
||||||
|
@ -743,6 +743,14 @@ class DockerVM(BaseNode):
|
|||||||
break
|
break
|
||||||
await self.stop()
|
await self.stop()
|
||||||
|
|
||||||
|
async def reset_console(self):
|
||||||
|
"""
|
||||||
|
Reset the console.
|
||||||
|
"""
|
||||||
|
|
||||||
|
await self._clean_servers()
|
||||||
|
await self._start_console()
|
||||||
|
|
||||||
async def is_running(self):
|
async def is_running(self):
|
||||||
"""
|
"""
|
||||||
Checks if the container is running.
|
Checks if the container is running.
|
||||||
|
@ -569,17 +569,39 @@ class IOUVM(BaseNode):
|
|||||||
log.error("Could not start IOU {}: {}\n{}".format(self._path, e, iou_stdout))
|
log.error("Could not start IOU {}: {}\n{}".format(self._path, e, iou_stdout))
|
||||||
raise IOUError("Could not start IOU {}: {}\n{}".format(self._path, e, iou_stdout))
|
raise IOUError("Could not start IOU {}: {}\n{}".format(self._path, e, iou_stdout))
|
||||||
|
|
||||||
if self.console and self.console_type == "telnet":
|
await self.start_console()
|
||||||
server = AsyncioTelnetServer(reader=self._iou_process.stdout, writer=self._iou_process.stdin, binary=True, echo=True)
|
|
||||||
try:
|
|
||||||
self._telnet_server = await asyncio.start_server(server.run, self._manager.port_manager.console_host, self.console)
|
|
||||||
except OSError as e:
|
|
||||||
await self.stop()
|
|
||||||
raise IOUError("Could not start Telnet server on socket {}:{}: {}".format(self._manager.port_manager.console_host, self.console, e))
|
|
||||||
|
|
||||||
# configure networking support
|
# configure networking support
|
||||||
await self._networking()
|
await self._networking()
|
||||||
|
|
||||||
|
async def start_console(self):
|
||||||
|
"""
|
||||||
|
Start the Telnet server to provide console access.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if self.console and self.console_type == "telnet":
|
||||||
|
server = AsyncioTelnetServer(reader=self._iou_process.stdout, writer=self._iou_process.stdin, binary=True,
|
||||||
|
echo=True)
|
||||||
|
try:
|
||||||
|
self._telnet_server = await asyncio.start_server(server.run, self._manager.port_manager.console_host,
|
||||||
|
self.console)
|
||||||
|
except OSError as e:
|
||||||
|
await self.stop()
|
||||||
|
raise IOUError(
|
||||||
|
"Could not start Telnet server on socket {}:{}: {}".format(self._manager.port_manager.console_host,
|
||||||
|
self.console, e))
|
||||||
|
|
||||||
|
async def reset_console(self):
|
||||||
|
"""
|
||||||
|
Reset the console.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if self._telnet_server:
|
||||||
|
self._telnet_server.close()
|
||||||
|
await self._telnet_server.wait_closed()
|
||||||
|
self._telnet_server = None
|
||||||
|
await self.start_console()
|
||||||
|
|
||||||
@locking
|
@locking
|
||||||
async def _networking(self):
|
async def _networking(self):
|
||||||
"""
|
"""
|
||||||
|
@ -979,6 +979,14 @@ class VirtualBoxVM(BaseNode):
|
|||||||
self._remote_pipe.close()
|
self._remote_pipe.close()
|
||||||
self._telnet_server = None
|
self._telnet_server = None
|
||||||
|
|
||||||
|
async def reset_console(self):
|
||||||
|
"""
|
||||||
|
Reset the console.
|
||||||
|
"""
|
||||||
|
|
||||||
|
await self._stop_remote_console()
|
||||||
|
await self._start_console()
|
||||||
|
|
||||||
@BaseNode.console_type.setter
|
@BaseNode.console_type.setter
|
||||||
def console_type(self, new_console_type):
|
def console_type(self, new_console_type):
|
||||||
"""
|
"""
|
||||||
|
@ -891,6 +891,14 @@ class VMwareVM(BaseNode):
|
|||||||
self._remote_pipe.close()
|
self._remote_pipe.close()
|
||||||
self._telnet_server = None
|
self._telnet_server = None
|
||||||
|
|
||||||
|
async def reset_console(self):
|
||||||
|
"""
|
||||||
|
Reset the console.
|
||||||
|
"""
|
||||||
|
|
||||||
|
await self._stop_remote_console()
|
||||||
|
await self._start_console()
|
||||||
|
|
||||||
@BaseNode.console_type.setter
|
@BaseNode.console_type.setter
|
||||||
def console_type(self, new_console_type):
|
def console_type(self, new_console_type):
|
||||||
"""
|
"""
|
||||||
|
@ -539,6 +539,17 @@ class Node:
|
|||||||
except asyncio.TimeoutError:
|
except asyncio.TimeoutError:
|
||||||
raise aiohttp.web.HTTPRequestTimeout(text="Timeout when reloading {}".format(self._name))
|
raise aiohttp.web.HTTPRequestTimeout(text="Timeout when reloading {}".format(self._name))
|
||||||
|
|
||||||
|
async def reset_console(self):
|
||||||
|
"""
|
||||||
|
Reset the console
|
||||||
|
"""
|
||||||
|
|
||||||
|
if self._console and self._console_type == "telnet":
|
||||||
|
try:
|
||||||
|
await self.post("/console/reset", timeout=240)
|
||||||
|
except asyncio.TimeoutError:
|
||||||
|
raise aiohttp.web.HTTPRequestTimeout(text="Timeout when reset console {}".format(self._name))
|
||||||
|
|
||||||
async def post(self, path, data=None, **kwargs):
|
async def post(self, path, data=None, **kwargs):
|
||||||
"""
|
"""
|
||||||
HTTP post on the node
|
HTTP post on the node
|
||||||
|
@ -1124,6 +1124,17 @@ class Project:
|
|||||||
pool.append(node.suspend)
|
pool.append(node.suspend)
|
||||||
await pool.join()
|
await pool.join()
|
||||||
|
|
||||||
|
@open_required
|
||||||
|
async def reset_console_all(self):
|
||||||
|
"""
|
||||||
|
Reset console for all nodes
|
||||||
|
"""
|
||||||
|
|
||||||
|
pool = Pool(concurrency=3)
|
||||||
|
for node in self.nodes.values():
|
||||||
|
pool.append(node.reset_console)
|
||||||
|
await pool.join()
|
||||||
|
|
||||||
@open_required
|
@open_required
|
||||||
async def duplicate_node(self, node, x, y, z):
|
async def duplicate_node(self, node, x, y, z):
|
||||||
"""
|
"""
|
||||||
|
@ -425,3 +425,23 @@ class DockerHandler:
|
|||||||
docker_manager = Docker.instance()
|
docker_manager = Docker.instance()
|
||||||
container = docker_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
container = docker_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
||||||
return await container.start_websocket_console(request)
|
return await container.start_websocket_console(request)
|
||||||
|
|
||||||
|
@Route.post(
|
||||||
|
r"/projects/{project_id}/docker/nodes/{node_id}/console/reset",
|
||||||
|
description="Reset console",
|
||||||
|
parameters={
|
||||||
|
"project_id": "Project UUID",
|
||||||
|
"node_id": "Node UUID",
|
||||||
|
},
|
||||||
|
status_codes={
|
||||||
|
204: "Console has been reset",
|
||||||
|
400: "Invalid request",
|
||||||
|
404: "Instance doesn't exist",
|
||||||
|
409: "Container not started"
|
||||||
|
})
|
||||||
|
async def reset_console(request, response):
|
||||||
|
|
||||||
|
docker_manager = Docker.instance()
|
||||||
|
container = docker_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
||||||
|
await container.reset_console()
|
||||||
|
response.set_status(204)
|
||||||
|
@ -526,3 +526,23 @@ class DynamipsVMHandler:
|
|||||||
dynamips_manager = Dynamips.instance()
|
dynamips_manager = Dynamips.instance()
|
||||||
vm = dynamips_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
vm = dynamips_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
||||||
return await vm.start_websocket_console(request)
|
return await vm.start_websocket_console(request)
|
||||||
|
|
||||||
|
@Route.post(
|
||||||
|
r"/projects/{project_id}/dynamips/nodes/{node_id}/console/reset",
|
||||||
|
description="Reset console",
|
||||||
|
parameters={
|
||||||
|
"project_id": "Project UUID",
|
||||||
|
"node_id": "Node UUID",
|
||||||
|
},
|
||||||
|
status_codes={
|
||||||
|
204: "Console has been reset",
|
||||||
|
400: "Invalid request",
|
||||||
|
404: "Instance doesn't exist",
|
||||||
|
409: "Container not started"
|
||||||
|
})
|
||||||
|
async def reset_console(request, response):
|
||||||
|
|
||||||
|
dynamips_manager = Dynamips.instance()
|
||||||
|
vm = dynamips_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
||||||
|
await vm.reset_console()
|
||||||
|
response.set_status(204)
|
||||||
|
@ -467,3 +467,23 @@ class IOUHandler:
|
|||||||
iou_manager = IOU.instance()
|
iou_manager = IOU.instance()
|
||||||
vm = iou_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
vm = iou_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
||||||
return await vm.start_websocket_console(request)
|
return await vm.start_websocket_console(request)
|
||||||
|
|
||||||
|
@Route.post(
|
||||||
|
r"/projects/{project_id}/iou/nodes/{node_id}/console/reset",
|
||||||
|
description="Reset console",
|
||||||
|
parameters={
|
||||||
|
"project_id": "Project UUID",
|
||||||
|
"node_id": "Node UUID",
|
||||||
|
},
|
||||||
|
status_codes={
|
||||||
|
204: "Console has been reset",
|
||||||
|
400: "Invalid request",
|
||||||
|
404: "Instance doesn't exist",
|
||||||
|
409: "Container not started"
|
||||||
|
})
|
||||||
|
async def reset_console(request, response):
|
||||||
|
|
||||||
|
iou_manager = IOU.instance()
|
||||||
|
vm = iou_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
||||||
|
await vm.reset_console()
|
||||||
|
response.set_status(204)
|
||||||
|
@ -590,3 +590,23 @@ class QEMUHandler:
|
|||||||
qemu_manager = Qemu.instance()
|
qemu_manager = Qemu.instance()
|
||||||
vm = qemu_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
vm = qemu_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
||||||
return await vm.start_websocket_console(request)
|
return await vm.start_websocket_console(request)
|
||||||
|
|
||||||
|
@Route.post(
|
||||||
|
r"/projects/{project_id}/qemu/nodes/{node_id}/console/reset",
|
||||||
|
description="Reset console",
|
||||||
|
parameters={
|
||||||
|
"project_id": "Project UUID",
|
||||||
|
"node_id": "Node UUID",
|
||||||
|
},
|
||||||
|
status_codes={
|
||||||
|
204: "Console has been reset",
|
||||||
|
400: "Invalid request",
|
||||||
|
404: "Instance doesn't exist",
|
||||||
|
409: "Container not started"
|
||||||
|
})
|
||||||
|
async def reset_console(request, response):
|
||||||
|
|
||||||
|
qemu_manager = Qemu.instance()
|
||||||
|
vm = qemu_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
||||||
|
await vm.reset_console()
|
||||||
|
response.set_status(204)
|
||||||
|
@ -437,3 +437,23 @@ class VirtualBoxHandler:
|
|||||||
virtualbox_manager = VirtualBox.instance()
|
virtualbox_manager = VirtualBox.instance()
|
||||||
vm = virtualbox_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
vm = virtualbox_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
||||||
return await vm.start_websocket_console(request)
|
return await vm.start_websocket_console(request)
|
||||||
|
|
||||||
|
@Route.post(
|
||||||
|
r"/projects/{project_id}/virtualbox/nodes/{node_id}/console/reset",
|
||||||
|
description="Reset console",
|
||||||
|
parameters={
|
||||||
|
"project_id": "Project UUID",
|
||||||
|
"node_id": "Node UUID",
|
||||||
|
},
|
||||||
|
status_codes={
|
||||||
|
204: "Console has been reset",
|
||||||
|
400: "Invalid request",
|
||||||
|
404: "Instance doesn't exist",
|
||||||
|
409: "Container not started"
|
||||||
|
})
|
||||||
|
async def reset_console(request, response):
|
||||||
|
|
||||||
|
virtualbox_manager = VirtualBox.instance()
|
||||||
|
vm = virtualbox_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
||||||
|
await vm.reset_console()
|
||||||
|
response.set_status(204)
|
||||||
|
@ -422,3 +422,23 @@ class VMwareHandler:
|
|||||||
vmware_manager = VMware.instance()
|
vmware_manager = VMware.instance()
|
||||||
vm = vmware_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
vm = vmware_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
||||||
return await vm.start_websocket_console(request)
|
return await vm.start_websocket_console(request)
|
||||||
|
|
||||||
|
@Route.post(
|
||||||
|
r"/projects/{project_id}/vmware/nodes/{node_id}/console/reset",
|
||||||
|
description="Reset console",
|
||||||
|
parameters={
|
||||||
|
"project_id": "Project UUID",
|
||||||
|
"node_id": "Node UUID",
|
||||||
|
},
|
||||||
|
status_codes={
|
||||||
|
204: "Console has been reset",
|
||||||
|
400: "Invalid request",
|
||||||
|
404: "Instance doesn't exist",
|
||||||
|
409: "Container not started"
|
||||||
|
})
|
||||||
|
async def reset_console(request, response):
|
||||||
|
|
||||||
|
vmware_manager = VMware.instance()
|
||||||
|
vm = vmware_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
||||||
|
await vm.reset_console()
|
||||||
|
response.set_status(204)
|
||||||
|
@ -375,3 +375,23 @@ class VPCSHandler:
|
|||||||
vpcs_manager = VPCS.instance()
|
vpcs_manager = VPCS.instance()
|
||||||
vm = vpcs_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
vm = vpcs_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
||||||
return await vm.start_websocket_console(request)
|
return await vm.start_websocket_console(request)
|
||||||
|
|
||||||
|
@Route.post(
|
||||||
|
r"/projects/{project_id}/vpcs/nodes/{node_id}/console/reset",
|
||||||
|
description="Reset console",
|
||||||
|
parameters={
|
||||||
|
"project_id": "Project UUID",
|
||||||
|
"node_id": "Node UUID",
|
||||||
|
},
|
||||||
|
status_codes={
|
||||||
|
204: "Console has been reset",
|
||||||
|
400: "Invalid request",
|
||||||
|
404: "Instance doesn't exist",
|
||||||
|
409: "Container not started"
|
||||||
|
})
|
||||||
|
async def reset_console(request, response):
|
||||||
|
|
||||||
|
vpcs_manager = VPCS.instance()
|
||||||
|
vm = vpcs_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
||||||
|
await vm.reset_console()
|
||||||
|
response.set_status(204)
|
||||||
|
@ -506,3 +506,40 @@ class NodeHandler:
|
|||||||
request.app['websockets'].discard(ws)
|
request.app['websockets'].discard(ws)
|
||||||
|
|
||||||
return ws
|
return ws
|
||||||
|
|
||||||
|
@Route.post(
|
||||||
|
r"/projects/{project_id}/nodes/console/reset",
|
||||||
|
parameters={
|
||||||
|
"project_id": "Project UUID"
|
||||||
|
},
|
||||||
|
status_codes={
|
||||||
|
204: "All nodes successfully reset consoles",
|
||||||
|
400: "Invalid request",
|
||||||
|
404: "Instance doesn't exist"
|
||||||
|
},
|
||||||
|
description="Reset console for all nodes belonging to the project",
|
||||||
|
output=NODE_OBJECT_SCHEMA)
|
||||||
|
async def reset_console_all(request, response):
|
||||||
|
|
||||||
|
project = await Controller.instance().get_loaded_project(request.match_info["project_id"])
|
||||||
|
await project.reset_console_all()
|
||||||
|
response.set_status(204)
|
||||||
|
|
||||||
|
@Route.post(
|
||||||
|
r"/projects/{project_id}/nodes/{node_id}/console/reset",
|
||||||
|
parameters={
|
||||||
|
"project_id": "Project UUID",
|
||||||
|
"node_id": "Node UUID"
|
||||||
|
},
|
||||||
|
status_codes={
|
||||||
|
204: "Console reset",
|
||||||
|
400: "Invalid request",
|
||||||
|
404: "Instance doesn't exist"
|
||||||
|
},
|
||||||
|
description="Reload a node instance")
|
||||||
|
async def console_reset(request, response):
|
||||||
|
|
||||||
|
project = await Controller.instance().get_loaded_project(request.match_info["project_id"])
|
||||||
|
node = project.get_node(request.match_info["node_id"])
|
||||||
|
await node.post("/console/reset", request.json)
|
||||||
|
response.set_status(204)
|
||||||
|
@ -829,6 +829,22 @@ async def test_suspend_all(project):
|
|||||||
assert len(compute.post.call_args_list) == 10
|
assert len(compute.post.call_args_list) == 10
|
||||||
|
|
||||||
|
|
||||||
|
async def test_console_reset_all(project):
|
||||||
|
|
||||||
|
compute = MagicMock()
|
||||||
|
compute.id = "local"
|
||||||
|
response = MagicMock()
|
||||||
|
response.json = {"console": 2048, "console_type": "telnet"}
|
||||||
|
compute.post = AsyncioMagicMock(return_value=response)
|
||||||
|
|
||||||
|
for node_i in range(0, 10):
|
||||||
|
await project.add_node(compute, "test", None, node_type="vpcs", properties={"startup_config": "test.cfg"})
|
||||||
|
|
||||||
|
compute.post = AsyncioMagicMock()
|
||||||
|
await project.reset_console_all()
|
||||||
|
assert len(compute.post.call_args_list) == 10
|
||||||
|
|
||||||
|
|
||||||
async def test_node_name(project):
|
async def test_node_name(project):
|
||||||
|
|
||||||
compute = MagicMock()
|
compute = MagicMock()
|
||||||
|
@ -140,6 +140,13 @@ async def test_reload_all_nodes(controller_api, project, compute):
|
|||||||
assert response.status == 204
|
assert response.status == 204
|
||||||
|
|
||||||
|
|
||||||
|
async def test_reset_console_all_nodes(controller_api, project, compute):
|
||||||
|
|
||||||
|
compute.post = AsyncioMagicMock()
|
||||||
|
response = await controller_api.post("/projects/{}/nodes/console/reset".format(project.id))
|
||||||
|
assert response.status == 204
|
||||||
|
|
||||||
|
|
||||||
async def test_start_node(controller_api, project, node, compute):
|
async def test_start_node(controller_api, project, node, compute):
|
||||||
|
|
||||||
compute.post = AsyncioMagicMock()
|
compute.post = AsyncioMagicMock()
|
||||||
|
Loading…
Reference in New Issue
Block a user