From 79b4926cad92a7c37200570a0abcd49cad6b6626 Mon Sep 17 00:00:00 2001 From: Julien Duponchelle Date: Fri, 23 Sep 2016 17:08:05 +0200 Subject: [PATCH] Fix the nat node Ref #686 --- gns3server/compute/builtin/nodes/cloud.py | 3 +-- gns3server/compute/builtin/nodes/nat.py | 14 +++++++++++-- gns3server/ubridge/hypervisor.py | 6 +++--- tests/compute/builtin/nodes/test_nat.py | 22 +++++++++++++++++++-- tests/handlers/api/compute/test_nat.py | 24 +++++++++++++---------- 5 files changed, 50 insertions(+), 19 deletions(-) diff --git a/gns3server/compute/builtin/nodes/cloud.py b/gns3server/compute/builtin/nodes/cloud.py index 6d28ba5d..54d17ab0 100644 --- a/gns3server/compute/builtin/nodes/cloud.py +++ b/gns3server/compute/builtin/nodes/cloud.py @@ -214,8 +214,7 @@ class Cloud(BaseNode): interface=port_info["interface"])) elif port_info["type"] == "tap": - yield from self._ubridge_send('bridge add_nio_tap {name} "{interface}"'.format(name=bridge_name, - interface=port_info["interface"])) + yield from self._ubridge_send('bridge add_nio_tap {name} "{interface}"'.format(name=bridge_name, interface=port_info["interface"])) elif port_info["type"] == "udp": yield from self._ubridge_send('bridge add_nio_udp {name} {lport} {rhost} {rport}'.format(name=bridge_name, diff --git a/gns3server/compute/builtin/nodes/nat.py b/gns3server/compute/builtin/nodes/nat.py index 7e1a1582..6d059270 100644 --- a/gns3server/compute/builtin/nodes/nat.py +++ b/gns3server/compute/builtin/nodes/nat.py @@ -16,6 +16,7 @@ # along with this program. If not, see . import sys +import asyncio from .cloud import Cloud from ...error import NodeError @@ -28,15 +29,19 @@ class Nat(Cloud): nat access to the outside """ + _nat_id = 0 + def __init__(self, *args, **kwargs): if "virbr0" not in [interface["name"] for interface in gns3server.utils.interfaces.interfaces()]: raise NodeError("virbr0 is missing. You need to install libvirt") + self._interface = "gns3nat{}".format(Nat._nat_id) + Nat._nat_id += 1 ports = [ { "name": "nat0", - "type": "ethernet", - "interface": "virbr0", + "type": "tap", + "interface": self._interface, "port_number": 0 } ] @@ -51,6 +56,11 @@ class Nat(Cloud): # It's not allowed to change it pass + @asyncio.coroutine + def add_nio(self, nio, port_number): + yield from super().add_nio(nio, port_number) + yield from self._ubridge_send('brctl addif virbr0 "{interface}"'.format(interface=self._interface)) + @classmethod def is_supported(self): return sys.platform.startswith("linux") diff --git a/gns3server/ubridge/hypervisor.py b/gns3server/ubridge/hypervisor.py index 4feafbda..451def43 100644 --- a/gns3server/ubridge/hypervisor.py +++ b/gns3server/ubridge/hypervisor.py @@ -120,15 +120,15 @@ class Hypervisor(UBridgeHypervisor): @asyncio.coroutine def _check_ubridge_version(self): """ - Checks if the ubridge executable version is >= 0.9.4 + Checks if the ubridge executable version is >= 0.9.5 """ try: output = yield from subprocess_check_output(self._path, "-v", cwd=self._working_dir) match = re.search("ubridge version ([0-9a-z\.]+)", output) if match: version = match.group(1) - if parse_version(version) < parse_version("0.9.4"): - raise UbridgeError("uBridge executable version must be >= 0.9.4") + if parse_version(version) < parse_version("0.9.5"): + raise UbridgeError("uBridge executable version must be >= 0.9.5") else: raise UbridgeError("Could not determine uBridge version for {}".format(self._path)) except (OSError, subprocess.SubprocessError) as e: diff --git a/tests/compute/builtin/nodes/test_nat.py b/tests/compute/builtin/nodes/test_nat.py index 8f1d9967..ade56a00 100644 --- a/tests/compute/builtin/nodes/test_nat.py +++ b/tests/compute/builtin/nodes/test_nat.py @@ -18,8 +18,16 @@ import uuid import pytest from unittest.mock import MagicMock +from tests.utils import asyncio_patch from gns3server.compute.builtin.nodes.nat import Nat +from gns3server.compute.vpcs import VPCS + + +def test_init(on_gns3vm, project): + nat1 = Nat("nat1", str(uuid.uuid4()), project, MagicMock()) + nat2 = Nat("nat2", str(uuid.uuid4()), project, MagicMock()) + assert nat1.ports_mapping[0]["interface"] != nat2.ports_mapping[0]["interface"] def test_json(on_gns3vm, project): @@ -31,10 +39,20 @@ def test_json(on_gns3vm, project): "status": "started", "ports_mapping": [ { - "interface": "virbr0", + "interface": nat._interface, "name": "nat0", "port_number": 0, - "type": "ethernet" + "type": "tap" } ] } + + +def test_add_nio(on_gns3vm, project, async_run): + nio = VPCS.instance().create_nio({"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1"}) + nat = Nat("nat1", str(uuid.uuid4()), project, MagicMock()) + with asyncio_patch("gns3server.compute.builtin.nodes.cloud.Cloud.add_nio") as cloud_add_nio_mock: + with asyncio_patch("gns3server.compute.base_node.BaseNode._ubridge_send") as nat_ubridge_send_mock: + async_run(nat.add_nio(0, nio)) + assert cloud_add_nio_mock.called + nat_ubridge_send_mock.assert_called_with("brctl addif virbr0 \"{}\"".format(nat._interface)) diff --git a/tests/handlers/api/compute/test_nat.py b/tests/handlers/api/compute/test_nat.py index b559dfa2..75e7ffbf 100644 --- a/tests/handlers/api/compute/test_nat.py +++ b/tests/handlers/api/compute/test_nat.py @@ -58,22 +58,26 @@ def test_nat_get(http_compute, project, vm): def test_nat_nio_create_udp(http_compute, vm): - response = http_compute.post("/projects/{project_id}/nat/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), {"type": "nio_udp", - "lport": 4242, - "rport": 4343, - "rhost": "127.0.0.1"}, - example=True) + with asyncio_patch("gns3server.compute.builtin.nodes.nat.Nat.add_nio"): + response = http_compute.post("/projects/{project_id}/nat/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), {"type": "nio_udp", + "lport": 4242, + "rport": 4343, + "rhost": "127.0.0.1"}, + example=True) assert response.status == 201 assert response.route == "/projects/{project_id}/nat/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio" assert response.json["type"] == "nio_udp" def test_nat_delete_nio(http_compute, vm): - http_compute.post("/projects/{project_id}/nat/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), {"type": "nio_udp", - "lport": 4242, - "rport": 4343, - "rhost": "127.0.0.1"}) - response = http_compute.delete("/projects/{project_id}/nat/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), example=True) + with asyncio_patch("gns3server.compute.builtin.nodes.nat.Nat.add_nio"): + http_compute.post("/projects/{project_id}/nat/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), {"type": "nio_udp", + "lport": 4242, + "rport": 4343, + "rhost": "127.0.0.1"}) + with asyncio_patch("gns3server.compute.builtin.nodes.nat.Nat.remove_nio") as mock_remove_nio: + response = http_compute.delete("/projects/{project_id}/nat/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), example=True) + assert mock_remove_nio.called assert response.status == 204 assert response.route == "/projects/{project_id}/nat/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio"