Esempio n. 1
0
def test_setup_ns(setup_networking):
    config.get_config(config_dict=yaml.safe_load("""namespaces:
    - name: test-ns-5
      interfaces:
        - name: eth0
          mac: "fa:16:3e:31:c8:d8"
        - name: eth1
          mac: "fa:18:3e:31:c8:44"
"""))
    setup_namespaces()
Esempio n. 2
0
def delete_namespace(namespace):
    namespace = util.process_namespace(namespace)

    if namespace not in list_namespaces().get_json():
        raise exceptions.ServerError(f"Invalid namespace {namespace}")

    interfaces: List = list_interfaces(namespace).get_json()
    untagged: List = [
        interface
        for interface in interfaces
        if "." not in interface and interface != "lo"
    ]
    if untagged:
        raise exceptions.ServerError(
            "Unable to delete namespace with untagged interfaces %s in it."
            " Move them to another interface first."
            % ", ".join(untagged)
        )

    if app.simulate:
        cfg = get_config()

        if namespace not in cfg.namespaces:
            return abort(404)

        del cfg.namespaces[namespace]
        return jsonify({})

    util.delete_namespace(namespace)
    return jsonify({})
Esempio n. 3
0
def add_namespace(namespace):
    namespace = util.process_namespace(namespace)

    if app.simulate:
        cfg = get_config()

        if namespace in cfg.namespaces:
            return abort(409)
        cfg.namespaces[namespace] = Namespace(namespace, interfaces=[{
            "ifindex": 1,
            "ifname": "lo",
            "flags": ["LOOPBACK"],
            "mtu": 65536,
            "qdisc": "noop",
            "operstate": "DOWN",
            "linkmode": "DEFAULT",
            "group": "default",
            "txqlen": 1000,
            "link_type": "loopback",
            "address": "00:00:00:00:00:00",
            "broadcast": "00:00:00:00:00:00"
        }])
        return jsonify({})
    create_namespace(namespace)

    return jsonify({})
Esempio n. 4
0
def move_interface(namespace, interface):
    namespace = util.process_namespace(namespace)

    parts = interface.split(".")
    if len(parts) not in range(1, 4):
        raise exceptions.ServerError(f"Only untagged, single and double tagged interfaces are supported")

    if app.simulate:
        cfg = get_config()
        if namespace not in cfg.namespaces:
            abort(404)

        all_interfaces = [intf.name for intf in cfg.namespaces[namespace].interfaces]
    else:
        all_interfaces = util.list_interfaces(namespace)

    if interface not in all_interfaces:
        raise exceptions.ServerError(f"Interface {interface} does not exist in {namespace}")

    new_namespace_key: str = "destination_namespace"
    if new_namespace_key not in request.json:
        raise exceptions.ServerError(f"Invalid request: request should contain \"destination_namespace\"")

    new_namespace = request.json[new_namespace_key]

    if app.simulate:
        old_ns: Namespace = cfg.namespaces[namespace]
        new_ns: Namespace = cfg.namespaces[new_namespace]
        iface: Interface = old_ns.get_interface(interface)
        old_ns.interfaces.remove(iface)
        new_ns.interfaces.append(iface)
    else:
        util.move_interface(new_namespace, interface, interface, old_namespace=namespace)

    return jsonify({})
Esempio n. 5
0
def list_interfaces(namespace):
    namespace = util.process_namespace(namespace, allow_none=True)

    if app.simulate:
        cfg = get_config()
        if namespace not in cfg.namespaces:
            return abort(404)

        return jsonify([intf.name for intf in cfg.namespaces[namespace].interfaces])

    return jsonify(util.list_interfaces(namespace))
Esempio n. 6
0
def list_interfaces(namespace):
    if namespace is None or len(namespace) == 0:
        raise exceptions.ServerError(f"Invalid namespace {namespace}")

    if app.simulate:
        cfg = get_config()
        if namespace not in cfg.namespaces:
            return abort(404)

        return jsonify(
            [intf.name for intf in cfg.namespaces[namespace].interfaces])

    return jsonify(util.list_interfaces(namespace))
Esempio n. 7
0
def get_routing_table_from_ns(namespace):
    if app.simulate:
        cfg = get_config()
        if namespace not in cfg.namespaces:
            abort(404)
        ns = cfg.namespaces[namespace]
        return jsonify([route.to_json() for route in ns.routes])
    else:
        try:
            routes = util.list_routes(namespace)
            return jsonify(routes)
        except subprocess.CalledProcessError as e:
            LOGGER.exception("status: %s, out: %s, err: %s", e.returncode,
                             e.stdout, e.stderr)
            return jsonify({})
Esempio n. 8
0
def test_load_config(tmp_path):
    cfg = """
namespaces:
    - name: LOC1
      interfaces:
        - name: eth0
          mac: "fa:16:3e:31:c8:d8"
    - name: LOC2
      interfaces:
        - name: eth0
          mac: "fa:16:3e:2c:7d:c1"
    - name: LOC3
      interfaces:
        - name: eth0
          mac: "fa:16:3e:81:7d:13"
    - name: LOC4
      interfaces:
        - name: eth0
          mac: "fa:16:3e:33:c6:e3"
    - name: LOC5
      interfaces:
        - name: eth0
          mac: "fa:16:3e:ff:92:8a"
    - name: LOC6
      interfaces:
        - name: eth0
          mac: "fa:16:3e:15:08:dc"
    - name: LOC7
      interfaces:
        - name: eth0
          mac: "fa:16:3e:71:04:b4"
    - name: LOC8
      interfaces:
        - name: eth0
          mac: "fa:16:3e:ed:14:0e"
connection_config:
    timeout_dns_lookup_in_ms: 1000
duration_bandwidth_test_in_sec: 5
hostname_for_dns_lookup: "inmanta.com"
iperf3_server: "10.0.0.36"
"""
    p = tmp_path / "config.yaml"
    p.write_text(cfg)

    cfg = config.get_config(str(p))
    assert len(cfg.namespaces) == 8
Esempio n. 9
0
def set_interface_state(namespace, interface):
    namespace = util.process_namespace(namespace)

    if app.simulate:
        cfg = get_config()
        if namespace not in cfg.namespaces:
            abort(404)

        ns = cfg.namespaces[namespace]
        intf = ns.get_interface(interface)
        if intf is None:
            abort(404)

        intf.set_state(request.json)
        return jsonify({"interface": intf.get_state()})
    else:
        util.set_interface_state(namespace, interface, request.json)
        return jsonify(util.get_interface_state(namespace, interface))
Esempio n. 10
0
def create_sub_interface(namespace, interface):
    if namespace is None or len(namespace) == 0:
        raise exceptions.ServerError(f"Invalid namespace {namespace}")

    parts = interface.split(".")
    if len(parts) not in [2, 3]:
        raise exceptions.ServerError(
            f"Only single and double tagged interfaces are supported")

    if app.simulate:
        cfg = get_config()
        if namespace not in cfg.namespaces:
            abort(404)

        all_interfaces = [
            intf.name for intf in cfg.namespaces[namespace].interfaces
        ]
    else:
        all_interfaces = util.list_interfaces(namespace)

    if interface in all_interfaces:
        raise exceptions.ServerError(
            f"Interface {interface} already exists in {namespace}")

    base_interface = parts.pop(0)

    if base_interface not in all_interfaces:
        raise exceptions.ServerError(
            f"Base interface {base_interface} does not exist")

    outer = int(parts.pop(0))
    inner = 0
    if len(parts):
        inner = int(parts[0])

    if app.simulate:
        ns = cfg.namespaces[namespace]
        base_intf = ns.get_interface(base_interface)
        intf = config.Interface(name=interface, mac=base_intf.mac)
        ns.interfaces.append(intf)
        return jsonify({"interface": intf.get_state()})
    else:
        util.create_sub_interface(namespace, base_interface, outer, inner)
        return jsonify(util.get_interface_state(namespace, interface))
Esempio n. 11
0
def setup_namespaces():
    """ Make sure all the namespaces from the config file are created and the correct interfaces are defined
    """
    mac_lookup = {x["mac"]: x for x in util.list_all_interfaces()}
    cfg = get_config()
    for ns in cfg.namespaces.values():
        for intf in ns.interfaces:
            if intf.mac in mac_lookup:
                old_namespace: Optional[str] = mac_lookup[intf.mac]["namespace"]
                new_name: str = mac_lookup[intf.mac]["name"]
                util.ensure_namespace(ns.name)
                util.move_interface(ns.name, new_name, intf.name, old_namespace=old_namespace)
                LOGGER.debug(
                    "Moved interface %s with mac %s to namespace %s and name %s",
                    new_name if old_namespace is None else "%s from %s" % (new_name, old_namespace),
                    intf.mac,
                    ns.name,
                    intf.name,
                )
Esempio n. 12
0
def set_interface_state(namespace, interface):
    if namespace is None or len(namespace) == 0:
        raise exceptions.ServerError(f"Invalid namespace {namespace}")

    if app.simulate:
        cfg = get_config()
        if namespace not in cfg.namespaces:
            abort(404)

        ns = cfg.namespaces[namespace]
        intf = ns.get_interface(interface)
        if intf is None:
            abort(404)

        intf.set_state(request.json)
        return jsonify({"interface": intf.get_state()})
    else:
        util.set_interface_state(namespace, interface, request.json)
        return jsonify(util.get_interface_state(namespace, interface))
Esempio n. 13
0
def get_interface_state(namespace, interface):
    namespace = util.process_namespace(namespace, allow_none=True)

    if app.simulate:
        cfg = get_config()
        if namespace not in cfg.namespaces:
            abort(404)

        ns = cfg.namespaces[namespace]
        intf = ns.get_interface(interface)
        if intf is None:
            abort(404)

        return jsonify({"interface": intf.get_state()})
    else:
        try:
            return jsonify(util.get_interface_state(namespace, interface))
        except Exception:
            LOGGER.exception("Failed to get the interface state")
            abort(404)
Esempio n. 14
0
def get_interface_state(namespace, interface):
    if namespace is None or len(namespace) == 0:
        raise exceptions.ServerError(f"Invalid namespace {namespace}")

    if app.simulate:
        cfg = get_config()
        if namespace not in cfg.namespaces:
            abort(404)

        ns = cfg.namespaces[namespace]
        intf = ns.get_interface(interface)
        if intf is None:
            abort(404)

        return jsonify({"interface": intf.get_state()})
    else:
        try:
            return jsonify(util.get_interface_state(namespace, interface))
        except Exception:
            LOGGER.exception("Failed to get the interface state")
            abort(404)
Esempio n. 15
0
def add_route_from_ns(namespace):
    namespace = util.process_namespace(namespace, allow_none=True)

    subnet = request.get_json(force=True).get("subnet")
    gateway = request.get_json(force=True).get("gateway", None)
    interface = request.get_json(force=True).get("interface", None)
    if gateway is None and interface is None:
        raise exceptions.ServerError("gateway or interface should be set.")

    if app.simulate:
        cfg = get_config()
        if namespace not in cfg.namespaces:
            abort(404)

        ns = cfg.namespaces[namespace]
        route = Route(subnet, gateway, interface)
        if route in ns.routes:
            abort(409)
        else:
            ns.routes.append(route)
        return jsonify([route.to_json() for route in ns.routes])
    else:
        try:
            util.run_in_ns(
                namespace,
                [
                    "ip",
                    "route",
                    "add",
                    subnet,
                    *(["via", gateway] if gateway is not None else []),
                    *(["dev", interface] if interface is not None else []),
                ],
            )
            routes = util.list_routes(namespace)
            return jsonify(routes)
        except subprocess.CalledProcessError as e:
            LOGGER.exception("status: %s, out: %s, err: %s", e.returncode, e.stdout, e.stderr)
            return jsonify({})
Esempio n. 16
0
def add_namespace(namespace):
    if namespace is None or len(namespace) == 0:
        raise exceptions.ServerError(f"Invalid namespace {namespace}")

    if app.simulate:
        cfg = get_config()

        if namespace in cfg.namespaces:
            return abort(409)
        cfg.namespaces[namespace] = Namespace(namespace,
                                              interfaces=[{
                                                  "ifindex":
                                                  1,
                                                  "ifname":
                                                  "lo",
                                                  "flags": ["LOOPBACK"],
                                                  "mtu":
                                                  65536,
                                                  "qdisc":
                                                  "noop",
                                                  "operstate":
                                                  "DOWN",
                                                  "linkmode":
                                                  "DEFAULT",
                                                  "group":
                                                  "default",
                                                  "txqlen":
                                                  1000,
                                                  "link_type":
                                                  "loopback",
                                                  "address":
                                                  "00:00:00:00:00:00",
                                                  "broadcast":
                                                  "00:00:00:00:00:00"
                                              }])
        return jsonify({})
    create_namespace(namespace)

    return jsonify({})
Esempio n. 17
0
def delete_sub_interface(namespace, interface):
    namespace = util.process_namespace(namespace)

    parts = interface.split(".")
    if len(parts) not in [2, 3]:
        raise exceptions.ServerError(f"Only single and double tagged interfaces are supported")

    if app.simulate:
        cfg = get_config()
        if namespace not in cfg.namespaces:
            abort(404)

        all_interfaces = [intf.name for intf in cfg.namespaces[namespace].interfaces]
    else:
        all_interfaces = util.list_interfaces(namespace)

    if interface not in all_interfaces:
        raise exceptions.ServerError(f"Interface {interface} dot exist in {namespace}")

    base_interface = parts.pop(0)

    if base_interface not in all_interfaces:
        raise exceptions.ServerError(f"Base interface {base_interface} does not exist")

    outer = int(parts.pop(0))
    inner = 0
    if len(parts):
        inner = int(parts[0])

    if app.simulate:
        ns = cfg.namespaces[namespace]
        intf = ns.get_interface(interface)
        ns.interfaces.remove(intf)
    else:
        util.delete_sub_interface(namespace, base_interface, outer, inner)

    return jsonify({})
Esempio n. 18
0
def list_namespaces():
    if app.simulate:
        cfg = get_config()
        return jsonify([ns for ns in cfg.namespaces.keys()])
    return jsonify(util.list_net_ns())
Esempio n. 19
0
def main(config, simulate):
    cfg = get_config(config)
    if not simulate:
        setup_namespaces()
    app.simulate = simulate
    app.run(host=cfg.host, port=cfg.port)