mirror of
https://github.com/GNS3/gns3-server
synced 2025-01-28 17:01:00 +00:00
parent
00f80f54e8
commit
672a617102
@ -628,9 +628,11 @@ class Router(BaseNode):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
is_running = yield from self.is_running()
|
is_running = yield from self.is_running()
|
||||||
|
was_auto_started = False
|
||||||
if not is_running:
|
if not is_running:
|
||||||
# router is not running
|
yield from self.start()
|
||||||
raise DynamipsError('Router "{name}" is not running'.format(name=self._name))
|
was_auto_started = True
|
||||||
|
yield from asyncio.sleep(20) # leave time to the router to boot
|
||||||
|
|
||||||
log.info('Router "{name}" [{id}] has started calculating Idle-PC values'.format(name=self._name, id=self._id))
|
log.info('Router "{name}" [{id}] has started calculating Idle-PC values'.format(name=self._name, id=self._id))
|
||||||
begin = time.time()
|
begin = time.time()
|
||||||
@ -638,6 +640,8 @@ class Router(BaseNode):
|
|||||||
log.info('Router "{name}" [{id}] has finished calculating Idle-PC values after {time:.4f} seconds'.format(name=self._name,
|
log.info('Router "{name}" [{id}] has finished calculating Idle-PC values after {time:.4f} seconds'.format(name=self._name,
|
||||||
id=self._id,
|
id=self._id,
|
||||||
time=time.time() - begin))
|
time=time.time() - begin))
|
||||||
|
if was_auto_started:
|
||||||
|
yield from self.stop()
|
||||||
return idlepcs
|
return idlepcs
|
||||||
|
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
|
@ -157,12 +157,12 @@ class Compute:
|
|||||||
return response.content
|
return response.content
|
||||||
|
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def http_query(self, method, path, data=None):
|
def http_query(self, method, path, data=None, **kwargs):
|
||||||
if not self._connected:
|
if not self._connected:
|
||||||
yield from self._connect()
|
yield from self._connect()
|
||||||
if not self._connected:
|
if not self._connected:
|
||||||
raise aiohttp.web.HTTPConflict(text="The server {} is not a GNS3 server".format(self._id))
|
raise aiohttp.web.HTTPConflict(text="The server {} is not a GNS3 server".format(self._id))
|
||||||
response = yield from self._run_http_query(method, path, data=data)
|
response = yield from self._run_http_query(method, path, data=data, **kwargs)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
@ -202,8 +202,8 @@ class Compute:
|
|||||||
return "{}://{}:{}/v2/compute{}".format(self._protocol, self._host, self._port, path)
|
return "{}://{}:{}/v2/compute{}".format(self._protocol, self._host, self._port, path)
|
||||||
|
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def _run_http_query(self, method, path, data=None):
|
def _run_http_query(self, method, path, data=None, timeout=10):
|
||||||
with aiohttp.Timeout(10):
|
with aiohttp.Timeout(timeout):
|
||||||
url = self._getUrl(path)
|
url = self._getUrl(path)
|
||||||
headers = {'content-type': 'application/json'}
|
headers = {'content-type': 'application/json'}
|
||||||
if data == {}:
|
if data == {}:
|
||||||
@ -243,19 +243,19 @@ class Compute:
|
|||||||
return response
|
return response
|
||||||
|
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def get(self, path):
|
def get(self, path, **kwargs):
|
||||||
return (yield from self.http_query("GET", path))
|
return (yield from self.http_query("GET", path, **kwargs))
|
||||||
|
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def post(self, path, data={}):
|
def post(self, path, data={}, **kwargs):
|
||||||
response = yield from self.http_query("POST", path, data)
|
response = yield from self.http_query("POST", path, data, **kwargs)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def put(self, path, data={}):
|
def put(self, path, data={}, **kwargs):
|
||||||
response = yield from self.http_query("PUT", path, data)
|
response = yield from self.http_query("PUT", path, data, **kwargs)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def delete(self, path):
|
def delete(self, path, **kwargs):
|
||||||
return (yield from self.http_query("DELETE", path))
|
return (yield from self.http_query("DELETE", path, **kwargs))
|
||||||
|
@ -147,7 +147,7 @@ class Node:
|
|||||||
self._console_type = value
|
self._console_type = value
|
||||||
elif key == "name":
|
elif key == "name":
|
||||||
self._name = value
|
self._name = value
|
||||||
elif key in ["node_id", "project_id"]:
|
elif key in ["node_id", "project_id", "console_host"]:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
self._properties[key] = value
|
self._properties[key] = value
|
||||||
@ -166,7 +166,7 @@ class Node:
|
|||||||
|
|
||||||
# None properties are not be send. Because it can mean the emulator doesn't support it
|
# None properties are not be send. Because it can mean the emulator doesn't support it
|
||||||
for key in list(data.keys()):
|
for key in list(data.keys()):
|
||||||
if data[key] is None:
|
if data[key] is None or key in ["console_host"]:
|
||||||
del data[key]
|
del data[key]
|
||||||
return data
|
return data
|
||||||
|
|
||||||
@ -236,6 +236,20 @@ class Node:
|
|||||||
else:
|
else:
|
||||||
return (yield from self._compute.delete("/projects/{}/{}/nodes/{}{}".format(self._project.id, self._node_type, self._id, path)))
|
return (yield from self._compute.delete("/projects/{}/{}/nodes/{}{}".format(self._project.id, self._node_type, self._id, path)))
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def dynamips_auto_idlepc(self):
|
||||||
|
"""
|
||||||
|
Compute the idle PC for a dynamips node
|
||||||
|
"""
|
||||||
|
return (yield from self._compute.get("/projects/{}/{}/nodes/{}/auto_idlepc".format(self._project.id, self._node_type, self._id), timeout=240)).json
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def dynamips_idlepc_proposals(self):
|
||||||
|
"""
|
||||||
|
Compute a list of potential idle PC
|
||||||
|
"""
|
||||||
|
return (yield from self._compute.get("/projects/{}/{}/nodes/{}/idlepc_proposals".format(self._project.id, self._node_type, self._id), timeout=240)).json
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<gns3server.controller.Node {} {}>".format(self._node_type, self._name)
|
return "<gns3server.controller.Node {} {}>".format(self._node_type, self._name)
|
||||||
|
|
||||||
@ -248,6 +262,7 @@ class Node:
|
|||||||
"node_directory": self._node_directory,
|
"node_directory": self._node_directory,
|
||||||
"name": self._name,
|
"name": self._name,
|
||||||
"console": self._console,
|
"console": self._console,
|
||||||
|
"console_host": self._compute.host,
|
||||||
"console_type": self._console_type,
|
"console_type": self._console_type,
|
||||||
"command_line": self._command_line,
|
"command_line": self._command_line,
|
||||||
"properties": self._properties,
|
"properties": self._properties,
|
||||||
|
@ -262,3 +262,43 @@ class NodeHandler:
|
|||||||
project = Controller.instance().get_project(request.match_info["project_id"])
|
project = Controller.instance().get_project(request.match_info["project_id"])
|
||||||
yield from project.delete_node(request.match_info["node_id"])
|
yield from project.delete_node(request.match_info["node_id"])
|
||||||
response.set_status(204)
|
response.set_status(204)
|
||||||
|
|
||||||
|
@Route.get(
|
||||||
|
r"/projects/{project_id}/nodes/{node_id}/dynamips/auto_idlepc",
|
||||||
|
parameters={
|
||||||
|
"project_id": "Project UUID",
|
||||||
|
"node_id": "Node UUID"
|
||||||
|
},
|
||||||
|
status_codes={
|
||||||
|
204: "Instance reloaded",
|
||||||
|
400: "Invalid request",
|
||||||
|
404: "Instance doesn't exist"
|
||||||
|
},
|
||||||
|
description="Compute the IDLE PC for a Dynamips node")
|
||||||
|
def auto_idlepc(request, response):
|
||||||
|
|
||||||
|
project = Controller.instance().get_project(request.match_info["project_id"])
|
||||||
|
node = project.get_node(request.match_info["node_id"])
|
||||||
|
idle = yield from node.dynamips_auto_idlepc()
|
||||||
|
response.json(idle)
|
||||||
|
response.set_status(200)
|
||||||
|
|
||||||
|
@Route.get(
|
||||||
|
r"/projects/{project_id}/nodes/{node_id}/dynamips/idlepc_proposals",
|
||||||
|
parameters={
|
||||||
|
"project_id": "Project UUID",
|
||||||
|
"node_id": "Node UUID"
|
||||||
|
},
|
||||||
|
status_codes={
|
||||||
|
204: "Instance reloaded",
|
||||||
|
400: "Invalid request",
|
||||||
|
404: "Instance doesn't exist"
|
||||||
|
},
|
||||||
|
description="Compute a list of potential idle PC for a node")
|
||||||
|
def idlepc_proposals(request, response):
|
||||||
|
|
||||||
|
project = Controller.instance().get_project(request.match_info["project_id"])
|
||||||
|
node = project.get_node(request.match_info["node_id"])
|
||||||
|
idle = yield from node.dynamips_idlepc_proposals()
|
||||||
|
response.json(idle)
|
||||||
|
response.set_status(200)
|
||||||
|
@ -109,6 +109,11 @@ NODE_OBJECT_SCHEMA = {
|
|||||||
"maximum": 65535,
|
"maximum": 65535,
|
||||||
"type": ["integer", "null"]
|
"type": ["integer", "null"]
|
||||||
},
|
},
|
||||||
|
"console_host": {
|
||||||
|
"description": "Console host",
|
||||||
|
"type": "string",
|
||||||
|
"minLength": 1,
|
||||||
|
},
|
||||||
"console_type": {
|
"console_type": {
|
||||||
"description": "Console type",
|
"description": "Console type",
|
||||||
"enum": ["serial", "vnc", "telnet", None]
|
"enum": ["serial", "vnc", "telnet", None]
|
||||||
|
@ -55,6 +55,7 @@ def test_json(node, compute):
|
|||||||
"name": "demo",
|
"name": "demo",
|
||||||
"console": node.console,
|
"console": node.console,
|
||||||
"console_type": node.console_type,
|
"console_type": node.console_type,
|
||||||
|
"console_host": compute.host,
|
||||||
"command_line": None,
|
"command_line": None,
|
||||||
"node_directory": None,
|
"node_directory": None,
|
||||||
"properties": node.properties,
|
"properties": node.properties,
|
||||||
@ -172,3 +173,23 @@ def test_post(node, compute, async_run):
|
|||||||
def test_delete(node, compute, async_run):
|
def test_delete(node, compute, async_run):
|
||||||
async_run(node.delete("/test"))
|
async_run(node.delete("/test"))
|
||||||
compute.delete.assert_called_with("/projects/{}/vpcs/nodes/{}/test".format(node.project.id, node.id))
|
compute.delete.assert_called_with("/projects/{}/vpcs/nodes/{}/test".format(node.project.id, node.id))
|
||||||
|
|
||||||
|
|
||||||
|
def test_dynamips_idle_pc(node, async_run, compute):
|
||||||
|
node._node_type = "dynamips"
|
||||||
|
response = MagicMock()
|
||||||
|
response.json = {"idlepc": "0x60606f54"}
|
||||||
|
compute.get = AsyncioMagicMock(return_value=response)
|
||||||
|
|
||||||
|
async_run(node.dynamips_auto_idlepc())
|
||||||
|
compute.get.assert_called_with("/projects/{}/dynamips/nodes/{}/auto_idlepc".format(node.project.id, node.id))
|
||||||
|
|
||||||
|
|
||||||
|
def test_dynamips_idlepc_proposals(node, async_run, compute):
|
||||||
|
node._node_type = "dynamips"
|
||||||
|
response = MagicMock()
|
||||||
|
response.json = ["0x60606f54", "0x30ff6f37"]
|
||||||
|
compute.get = AsyncioMagicMock(return_value=response)
|
||||||
|
|
||||||
|
async_run(node.dynamips_idlepc_proposals())
|
||||||
|
compute.get.assert_called_with("/projects/{}/dynamips/nodes/{}/idlepc_proposals".format(node.project.id, node.id))
|
||||||
|
@ -38,6 +38,7 @@ from gns3server.controller.node import Node
|
|||||||
def compute(http_controller, async_run):
|
def compute(http_controller, async_run):
|
||||||
compute = MagicMock()
|
compute = MagicMock()
|
||||||
compute.id = "example.com"
|
compute.id = "example.com"
|
||||||
|
compute.host = "example.org"
|
||||||
Controller.instance()._computes = {"example.com": compute}
|
Controller.instance()._computes = {"example.com": compute}
|
||||||
return compute
|
return compute
|
||||||
|
|
||||||
@ -107,6 +108,7 @@ def test_update_node(http_controller, tmpdir, project, compute, node):
|
|||||||
assert response.json["name"] == "test"
|
assert response.json["name"] == "test"
|
||||||
assert "name" not in response.json["properties"]
|
assert "name" not in response.json["properties"]
|
||||||
|
|
||||||
|
|
||||||
def test_start_all_nodes(http_controller, tmpdir, project, compute):
|
def test_start_all_nodes(http_controller, tmpdir, project, compute):
|
||||||
response = MagicMock()
|
response = MagicMock()
|
||||||
compute.post = AsyncioMagicMock()
|
compute.post = AsyncioMagicMock()
|
||||||
@ -114,6 +116,7 @@ def test_start_all_nodes(http_controller, tmpdir, project, compute):
|
|||||||
response = http_controller.post("/projects/{}/nodes/start".format(project.id), example=True)
|
response = http_controller.post("/projects/{}/nodes/start".format(project.id), example=True)
|
||||||
assert response.status == 204
|
assert response.status == 204
|
||||||
|
|
||||||
|
|
||||||
def test_stop_all_nodes(http_controller, tmpdir, project, compute):
|
def test_stop_all_nodes(http_controller, tmpdir, project, compute):
|
||||||
response = MagicMock()
|
response = MagicMock()
|
||||||
compute.post = AsyncioMagicMock()
|
compute.post = AsyncioMagicMock()
|
||||||
@ -121,6 +124,7 @@ def test_stop_all_nodes(http_controller, tmpdir, project, compute):
|
|||||||
response = http_controller.post("/projects/{}/nodes/stop".format(project.id), example=True)
|
response = http_controller.post("/projects/{}/nodes/stop".format(project.id), example=True)
|
||||||
assert response.status == 204
|
assert response.status == 204
|
||||||
|
|
||||||
|
|
||||||
def test_suspend_all_nodes(http_controller, tmpdir, project, compute):
|
def test_suspend_all_nodes(http_controller, tmpdir, project, compute):
|
||||||
response = MagicMock()
|
response = MagicMock()
|
||||||
compute.post = AsyncioMagicMock()
|
compute.post = AsyncioMagicMock()
|
||||||
@ -128,6 +132,7 @@ def test_suspend_all_nodes(http_controller, tmpdir, project, compute):
|
|||||||
response = http_controller.post("/projects/{}/nodes/suspend".format(project.id), example=True)
|
response = http_controller.post("/projects/{}/nodes/suspend".format(project.id), example=True)
|
||||||
assert response.status == 204
|
assert response.status == 204
|
||||||
|
|
||||||
|
|
||||||
def test_reload_all_nodes(http_controller, tmpdir, project, compute):
|
def test_reload_all_nodes(http_controller, tmpdir, project, compute):
|
||||||
response = MagicMock()
|
response = MagicMock()
|
||||||
compute.post = AsyncioMagicMock()
|
compute.post = AsyncioMagicMock()
|
||||||
@ -135,6 +140,7 @@ def test_reload_all_nodes(http_controller, tmpdir, project, compute):
|
|||||||
response = http_controller.post("/projects/{}/nodes/reload".format(project.id), example=True)
|
response = http_controller.post("/projects/{}/nodes/reload".format(project.id), example=True)
|
||||||
assert response.status == 204
|
assert response.status == 204
|
||||||
|
|
||||||
|
|
||||||
def test_start_node(http_controller, tmpdir, project, compute, node):
|
def test_start_node(http_controller, tmpdir, project, compute, node):
|
||||||
response = MagicMock()
|
response = MagicMock()
|
||||||
compute.post = AsyncioMagicMock()
|
compute.post = AsyncioMagicMock()
|
||||||
@ -142,6 +148,7 @@ def test_start_node(http_controller, tmpdir, project, compute, node):
|
|||||||
response = http_controller.post("/projects/{}/nodes/{}/start".format(project.id, node.id), example=True)
|
response = http_controller.post("/projects/{}/nodes/{}/start".format(project.id, node.id), example=True)
|
||||||
assert response.status == 204
|
assert response.status == 204
|
||||||
|
|
||||||
|
|
||||||
def test_stop_node(http_controller, tmpdir, project, compute, node):
|
def test_stop_node(http_controller, tmpdir, project, compute, node):
|
||||||
response = MagicMock()
|
response = MagicMock()
|
||||||
compute.post = AsyncioMagicMock()
|
compute.post = AsyncioMagicMock()
|
||||||
@ -172,3 +179,23 @@ def test_delete_node(http_controller, tmpdir, project, compute, node):
|
|||||||
|
|
||||||
response = http_controller.delete("/projects/{}/nodes/{}".format(project.id, node.id), example=True)
|
response = http_controller.delete("/projects/{}/nodes/{}".format(project.id, node.id), example=True)
|
||||||
assert response.status == 204
|
assert response.status == 204
|
||||||
|
|
||||||
|
|
||||||
|
def test_dynamips_idle_pc(http_controller, tmpdir, project, compute, node):
|
||||||
|
response = MagicMock()
|
||||||
|
response.json = {"idlepc": "0x60606f54"}
|
||||||
|
compute.get = AsyncioMagicMock(return_value=response)
|
||||||
|
|
||||||
|
response = http_controller.get("/projects/{}/nodes/{}/dynamips/auto_idlepc".format(project.id, node.id), example=True)
|
||||||
|
assert response.status == 200
|
||||||
|
assert response.json["idlepc"] == "0x60606f54"
|
||||||
|
|
||||||
|
|
||||||
|
def test_dynamips_idlepc_proposals(http_controller, tmpdir, project, compute, node):
|
||||||
|
response = MagicMock()
|
||||||
|
response.json = ["0x60606f54", "0x33805a22"]
|
||||||
|
compute.get = AsyncioMagicMock(return_value=response)
|
||||||
|
|
||||||
|
response = http_controller.get("/projects/{}/nodes/{}/dynamips/idlepc_proposals".format(project.id, node.id), example=True)
|
||||||
|
assert response.status == 200
|
||||||
|
assert response.json == ["0x60606f54", "0x33805a22"]
|
||||||
|
Loading…
Reference in New Issue
Block a user