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({})
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({})
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"], } }
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
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))
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))
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({})
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))
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)
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({})
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({})