Esempio n. 1
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. 2
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. 3
0
def get_interface_state(namespace: str, interface: str) -> Dict:
    """ Get the state of the given interface. This method returns a dict with key "interface".
        The value is a dict with keys:
            up: boolean, true if the service is up
            mtu: integer mtu value
            address: A list of address objects. Each object contains address and family attributes (inet or inet6)
    """
    try:
        output = run_in_ns(namespace, ["ip", "-j", "addr", "ls", "dev", interface])
    except subprocess.CalledProcessError:
        raise exceptions.ServerError(f"Failed to list addresses on interface {interface} (location={namespace})")

    result = [x for x in json.loads(output) if len(x)]

    if len(result) != 1:
        LOGGER.error("Got %s from call", result)
        raise exceptions.ServerError(f"Failed to list addresses on interface {interface} (location={namespace})")

    return {
        "interface": {
            "address": [
                {"address": x["local"], "family": x["family"], "prefixlen": x["prefixlen"]} for x in result[0]["addr_info"]
            ],
            "up": "UP" in result[0]["flags"],
            "mtu": result[0]["mtu"],
        }
    }
Esempio n. 4
0
def process_namespace(namespace: str, allow_none: Optional[bool] = False) -> Optional[str]:
    """Processes namespace values get by REST handler to check if namespace has been defined (correctly)
    """
    if namespace is None or len(namespace) == 0:
        raise exceptions.ServerError(f"Invalid namespace {namespace}")

    if namespace == NO_NAMESPACE_VALUE:
        if not allow_none:
            raise exceptions.ServerError(f"Invalid namespace {namespace} - this value is a reserved keyword")

        return None

    return namespace
Esempio n. 5
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. 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 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. 8
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. 9
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. 10
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. 11
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({})