added type hinting for core.nodes
This commit is contained in:
parent
4e71759ac9
commit
c0fcc91d10
10 changed files with 534 additions and 360 deletions
|
@ -5,7 +5,7 @@ gRpc client for interfacing with CORE, when gRPC mode is enabled.
|
|||
import logging
|
||||
import threading
|
||||
from contextlib import contextmanager
|
||||
from typing import Any, Callable, Dict, List
|
||||
from typing import Any, Callable, Dict, Generator, List
|
||||
|
||||
import grpc
|
||||
import netaddr
|
||||
|
@ -1144,7 +1144,7 @@ class CoreGrpcClient:
|
|||
self.channel = None
|
||||
|
||||
@contextmanager
|
||||
def context_connect(self) -> None:
|
||||
def context_connect(self) -> Generator:
|
||||
"""
|
||||
Makes a context manager based connection to the server, will close after context ends.
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import logging
|
||||
from queue import Empty, Queue
|
||||
from typing import List
|
||||
from typing import Iterable
|
||||
|
||||
from core.api.grpc import core_pb2
|
||||
from core.api.grpc.grpcutils import convert_value
|
||||
|
@ -181,7 +181,9 @@ class EventStreamer:
|
|||
Processes session events to generate grpc events.
|
||||
"""
|
||||
|
||||
def __init__(self, session: Session, event_types: List[core_pb2.EventType]) -> None:
|
||||
def __init__(
|
||||
self, session: Session, event_types: Iterable[core_pb2.EventType]
|
||||
) -> None:
|
||||
"""
|
||||
Create a EventStreamer instance.
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ import logging
|
|||
import os
|
||||
import shutil
|
||||
import threading
|
||||
from typing import TYPE_CHECKING, Dict, List, Optional, Tuple
|
||||
|
||||
import netaddr
|
||||
|
||||
|
@ -15,8 +16,12 @@ from core.emulator.data import LinkData, NodeData
|
|||
from core.emulator.enumerations import LinkTypes, NodeTypes
|
||||
from core.errors import CoreCommandError
|
||||
from core.nodes import client
|
||||
from core.nodes.interface import TunTap, Veth
|
||||
from core.nodes.netclient import get_net_client
|
||||
from core.nodes.interface import CoreInterface, TunTap, Veth
|
||||
from core.nodes.netclient import LinuxNetClient, get_net_client
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from core.emulator.distributed import DistributedServer
|
||||
from core.emulator.session import Session
|
||||
|
||||
_DEFAULT_MTU = 1500
|
||||
|
||||
|
@ -29,9 +34,16 @@ class NodeBase:
|
|||
apitype = None
|
||||
|
||||
# TODO: appears start has no usage, verify and remove
|
||||
def __init__(self, session, _id=None, name=None, start=True, server=None):
|
||||
def __init__(
|
||||
self,
|
||||
session: "Session",
|
||||
_id: int = None,
|
||||
name: str = None,
|
||||
start: bool = True,
|
||||
server: "DistributedServer" = None,
|
||||
) -> None:
|
||||
"""
|
||||
Creates a PyCoreObj instance.
|
||||
Creates a NodeBase instance.
|
||||
|
||||
:param core.emulator.session.Session session: CORE session object
|
||||
:param int _id: id
|
||||
|
@ -63,7 +75,7 @@ class NodeBase:
|
|||
use_ovs = session.options.get_config("ovs") == "True"
|
||||
self.net_client = get_net_client(use_ovs, self.host_cmd)
|
||||
|
||||
def startup(self):
|
||||
def startup(self) -> None:
|
||||
"""
|
||||
Each object implements its own startup method.
|
||||
|
||||
|
@ -71,7 +83,7 @@ class NodeBase:
|
|||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def shutdown(self):
|
||||
def shutdown(self) -> None:
|
||||
"""
|
||||
Each object implements its own shutdown method.
|
||||
|
||||
|
@ -79,7 +91,14 @@ class NodeBase:
|
|||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def host_cmd(self, args, env=None, cwd=None, wait=True, shell=False):
|
||||
def host_cmd(
|
||||
self,
|
||||
args: str,
|
||||
env: Dict[str, str] = None,
|
||||
cwd: str = None,
|
||||
wait: bool = True,
|
||||
shell: bool = False,
|
||||
) -> str:
|
||||
"""
|
||||
Runs a command on the host system or distributed server.
|
||||
|
||||
|
@ -97,7 +116,7 @@ class NodeBase:
|
|||
else:
|
||||
return self.server.remote_cmd(args, env, cwd, wait)
|
||||
|
||||
def setposition(self, x=None, y=None, z=None):
|
||||
def setposition(self, x: float = None, y: float = None, z: float = None) -> bool:
|
||||
"""
|
||||
Set the (x,y,z) position of the object.
|
||||
|
||||
|
@ -109,7 +128,7 @@ class NodeBase:
|
|||
"""
|
||||
return self.position.set(x=x, y=y, z=z)
|
||||
|
||||
def getposition(self):
|
||||
def getposition(self) -> Tuple[float, float, float]:
|
||||
"""
|
||||
Return an (x,y,z) tuple representing this object's position.
|
||||
|
||||
|
@ -118,7 +137,7 @@ class NodeBase:
|
|||
"""
|
||||
return self.position.get()
|
||||
|
||||
def ifname(self, ifindex):
|
||||
def ifname(self, ifindex: int) -> str:
|
||||
"""
|
||||
Retrieve interface name for index.
|
||||
|
||||
|
@ -128,7 +147,7 @@ class NodeBase:
|
|||
"""
|
||||
return self._netif[ifindex].name
|
||||
|
||||
def netifs(self, sort=False):
|
||||
def netifs(self, sort: bool = False) -> List[CoreInterface]:
|
||||
"""
|
||||
Retrieve network interfaces, sorted if desired.
|
||||
|
||||
|
@ -141,7 +160,7 @@ class NodeBase:
|
|||
else:
|
||||
return list(self._netif.values())
|
||||
|
||||
def numnetif(self):
|
||||
def numnetif(self) -> int:
|
||||
"""
|
||||
Return the attached interface count.
|
||||
|
||||
|
@ -150,7 +169,7 @@ class NodeBase:
|
|||
"""
|
||||
return len(self._netif)
|
||||
|
||||
def getifindex(self, netif):
|
||||
def getifindex(self, netif: CoreInterface) -> int:
|
||||
"""
|
||||
Retrieve index for an interface.
|
||||
|
||||
|
@ -163,7 +182,7 @@ class NodeBase:
|
|||
return ifindex
|
||||
return -1
|
||||
|
||||
def newifindex(self):
|
||||
def newifindex(self) -> int:
|
||||
"""
|
||||
Create a new interface index.
|
||||
|
||||
|
@ -176,7 +195,14 @@ class NodeBase:
|
|||
self.ifindex += 1
|
||||
return ifindex
|
||||
|
||||
def data(self, message_type, lat=None, lon=None, alt=None, source=None):
|
||||
def data(
|
||||
self,
|
||||
message_type: int,
|
||||
lat: float = None,
|
||||
lon: float = None,
|
||||
alt: float = None,
|
||||
source: str = None,
|
||||
) -> NodeData:
|
||||
"""
|
||||
Build a data object for this node.
|
||||
|
||||
|
@ -223,7 +249,7 @@ class NodeBase:
|
|||
|
||||
return node_data
|
||||
|
||||
def all_link_data(self, flags):
|
||||
def all_link_data(self, flags: int) -> List:
|
||||
"""
|
||||
Build CORE Link data for this object. There is no default
|
||||
method for PyCoreObjs as PyCoreNodes do not implement this but
|
||||
|
@ -241,7 +267,14 @@ class CoreNodeBase(NodeBase):
|
|||
Base class for CORE nodes.
|
||||
"""
|
||||
|
||||
def __init__(self, session, _id=None, name=None, start=True, server=None):
|
||||
def __init__(
|
||||
self,
|
||||
session: "Session",
|
||||
_id: int = None,
|
||||
name: str = None,
|
||||
start: bool = True,
|
||||
server: "DistributedServer" = None,
|
||||
) -> None:
|
||||
"""
|
||||
Create a CoreNodeBase instance.
|
||||
|
||||
|
@ -257,7 +290,7 @@ class CoreNodeBase(NodeBase):
|
|||
self.nodedir = None
|
||||
self.tmpnodedir = False
|
||||
|
||||
def makenodedir(self):
|
||||
def makenodedir(self) -> None:
|
||||
"""
|
||||
Create the node directory.
|
||||
|
||||
|
@ -270,7 +303,7 @@ class CoreNodeBase(NodeBase):
|
|||
else:
|
||||
self.tmpnodedir = False
|
||||
|
||||
def rmnodedir(self):
|
||||
def rmnodedir(self) -> None:
|
||||
"""
|
||||
Remove the node directory, unless preserve directory has been set.
|
||||
|
||||
|
@ -283,7 +316,7 @@ class CoreNodeBase(NodeBase):
|
|||
if self.tmpnodedir:
|
||||
self.host_cmd(f"rm -rf {self.nodedir}")
|
||||
|
||||
def addnetif(self, netif, ifindex):
|
||||
def addnetif(self, netif: CoreInterface, ifindex: int) -> None:
|
||||
"""
|
||||
Add network interface to node and set the network interface index if successful.
|
||||
|
||||
|
@ -296,7 +329,7 @@ class CoreNodeBase(NodeBase):
|
|||
self._netif[ifindex] = netif
|
||||
netif.netindex = ifindex
|
||||
|
||||
def delnetif(self, ifindex):
|
||||
def delnetif(self, ifindex: int) -> None:
|
||||
"""
|
||||
Delete a network interface
|
||||
|
||||
|
@ -309,7 +342,7 @@ class CoreNodeBase(NodeBase):
|
|||
netif.shutdown()
|
||||
del netif
|
||||
|
||||
def netif(self, ifindex):
|
||||
def netif(self, ifindex: int) -> Optional[CoreInterface]:
|
||||
"""
|
||||
Retrieve network interface.
|
||||
|
||||
|
@ -322,7 +355,7 @@ class CoreNodeBase(NodeBase):
|
|||
else:
|
||||
return None
|
||||
|
||||
def attachnet(self, ifindex, net):
|
||||
def attachnet(self, ifindex: int, net: "CoreNetworkBase") -> None:
|
||||
"""
|
||||
Attach a network.
|
||||
|
||||
|
@ -334,7 +367,7 @@ class CoreNodeBase(NodeBase):
|
|||
raise ValueError(f"ifindex {ifindex} does not exist")
|
||||
self._netif[ifindex].attachnet(net)
|
||||
|
||||
def detachnet(self, ifindex):
|
||||
def detachnet(self, ifindex: int) -> None:
|
||||
"""
|
||||
Detach network interface.
|
||||
|
||||
|
@ -345,7 +378,7 @@ class CoreNodeBase(NodeBase):
|
|||
raise ValueError(f"ifindex {ifindex} does not exist")
|
||||
self._netif[ifindex].detachnet()
|
||||
|
||||
def setposition(self, x=None, y=None, z=None):
|
||||
def setposition(self, x: float = None, y: float = None, z: float = None) -> None:
|
||||
"""
|
||||
Set position.
|
||||
|
||||
|
@ -359,7 +392,9 @@ class CoreNodeBase(NodeBase):
|
|||
for netif in self.netifs(sort=True):
|
||||
netif.setposition(x, y, z)
|
||||
|
||||
def commonnets(self, obj, want_ctrl=False):
|
||||
def commonnets(
|
||||
self, obj: "CoreNodeBase", want_ctrl: bool = False
|
||||
) -> List[Tuple[NodeBase, CoreInterface, CoreInterface]]:
|
||||
"""
|
||||
Given another node or net object, return common networks between
|
||||
this node and that object. A list of tuples is returned, with each tuple
|
||||
|
@ -377,10 +412,9 @@ class CoreNodeBase(NodeBase):
|
|||
for netif2 in obj.netifs():
|
||||
if netif1.net == netif2.net:
|
||||
common.append((netif1.net, netif1, netif2))
|
||||
|
||||
return common
|
||||
|
||||
def cmd(self, args, wait=True, shell=False):
|
||||
def cmd(self, args: str, wait: bool = True, shell: bool = False) -> str:
|
||||
"""
|
||||
Runs a command within a node container.
|
||||
|
||||
|
@ -393,7 +427,7 @@ class CoreNodeBase(NodeBase):
|
|||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def termcmdstring(self, sh):
|
||||
def termcmdstring(self, sh: str) -> str:
|
||||
"""
|
||||
Create a terminal command string.
|
||||
|
||||
|
@ -413,14 +447,14 @@ class CoreNode(CoreNodeBase):
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
session,
|
||||
_id=None,
|
||||
name=None,
|
||||
nodedir=None,
|
||||
bootsh="boot.sh",
|
||||
start=True,
|
||||
server=None,
|
||||
):
|
||||
session: "Session",
|
||||
_id: int = None,
|
||||
name: str = None,
|
||||
nodedir: str = None,
|
||||
bootsh: str = "boot.sh",
|
||||
start: bool = True,
|
||||
server: "DistributedServer" = None,
|
||||
) -> None:
|
||||
"""
|
||||
Create a CoreNode instance.
|
||||
|
||||
|
@ -451,17 +485,17 @@ class CoreNode(CoreNodeBase):
|
|||
if start:
|
||||
self.startup()
|
||||
|
||||
def create_node_net_client(self, use_ovs):
|
||||
def create_node_net_client(self, use_ovs: bool) -> LinuxNetClient:
|
||||
"""
|
||||
Create node network client for running network commands within the nodes
|
||||
container.
|
||||
|
||||
:param bool use_ovs: True for OVS bridges, False for Linux bridges
|
||||
:return:node network client
|
||||
:return: node network client
|
||||
"""
|
||||
return get_net_client(use_ovs, self.cmd)
|
||||
|
||||
def alive(self):
|
||||
def alive(self) -> bool:
|
||||
"""
|
||||
Check if the node is alive.
|
||||
|
||||
|
@ -475,7 +509,7 @@ class CoreNode(CoreNodeBase):
|
|||
|
||||
return True
|
||||
|
||||
def startup(self):
|
||||
def startup(self) -> None:
|
||||
"""
|
||||
Start a new namespace node by invoking the vnoded process that
|
||||
allocates a new namespace. Bring up the loopback device and set
|
||||
|
@ -521,7 +555,7 @@ class CoreNode(CoreNodeBase):
|
|||
self.privatedir("/var/run")
|
||||
self.privatedir("/var/log")
|
||||
|
||||
def shutdown(self):
|
||||
def shutdown(self) -> None:
|
||||
"""
|
||||
Shutdown logic for simple lxc nodes.
|
||||
|
||||
|
@ -562,7 +596,7 @@ class CoreNode(CoreNodeBase):
|
|||
finally:
|
||||
self.rmnodedir()
|
||||
|
||||
def cmd(self, args, wait=True, shell=False):
|
||||
def cmd(self, args: str, wait: bool = True, shell: bool = False) -> str:
|
||||
"""
|
||||
Runs a command that is used to configure and setup the network within a
|
||||
node.
|
||||
|
@ -580,7 +614,7 @@ class CoreNode(CoreNodeBase):
|
|||
args = self.client.create_cmd(args)
|
||||
return self.server.remote_cmd(args, wait=wait)
|
||||
|
||||
def termcmdstring(self, sh="/bin/sh"):
|
||||
def termcmdstring(self, sh: str = "/bin/sh") -> str:
|
||||
"""
|
||||
Create a terminal command string.
|
||||
|
||||
|
@ -593,7 +627,7 @@ class CoreNode(CoreNodeBase):
|
|||
else:
|
||||
return f"ssh -X -f {self.server.host} xterm -e {terminal}"
|
||||
|
||||
def privatedir(self, path):
|
||||
def privatedir(self, path: str) -> None:
|
||||
"""
|
||||
Create a private directory.
|
||||
|
||||
|
@ -608,7 +642,7 @@ class CoreNode(CoreNodeBase):
|
|||
self.host_cmd(f"mkdir -p {hostpath}")
|
||||
self.mount(hostpath, path)
|
||||
|
||||
def mount(self, source, target):
|
||||
def mount(self, source: str, target: str) -> None:
|
||||
"""
|
||||
Create and mount a directory.
|
||||
|
||||
|
@ -623,7 +657,7 @@ class CoreNode(CoreNodeBase):
|
|||
self.cmd(f"{MOUNT_BIN} -n --bind {source} {target}")
|
||||
self._mounts.append((source, target))
|
||||
|
||||
def newifindex(self):
|
||||
def newifindex(self) -> int:
|
||||
"""
|
||||
Retrieve a new interface index.
|
||||
|
||||
|
@ -633,7 +667,7 @@ class CoreNode(CoreNodeBase):
|
|||
with self.lock:
|
||||
return super().newifindex()
|
||||
|
||||
def newveth(self, ifindex=None, ifname=None):
|
||||
def newveth(self, ifindex: int = None, ifname: str = None) -> int:
|
||||
"""
|
||||
Create a new interface.
|
||||
|
||||
|
@ -690,7 +724,7 @@ class CoreNode(CoreNodeBase):
|
|||
|
||||
return ifindex
|
||||
|
||||
def newtuntap(self, ifindex=None, ifname=None):
|
||||
def newtuntap(self, ifindex: int = None, ifname: str = None) -> int:
|
||||
"""
|
||||
Create a new tunnel tap.
|
||||
|
||||
|
@ -720,7 +754,7 @@ class CoreNode(CoreNodeBase):
|
|||
|
||||
return ifindex
|
||||
|
||||
def sethwaddr(self, ifindex, addr):
|
||||
def sethwaddr(self, ifindex: int, addr: str) -> None:
|
||||
"""
|
||||
Set hardware addres for an interface.
|
||||
|
||||
|
@ -735,7 +769,7 @@ class CoreNode(CoreNodeBase):
|
|||
if self.up:
|
||||
self.node_net_client.device_mac(interface.name, addr)
|
||||
|
||||
def addaddr(self, ifindex, addr):
|
||||
def addaddr(self, ifindex: int, addr: str) -> None:
|
||||
"""
|
||||
Add interface address.
|
||||
|
||||
|
@ -753,7 +787,7 @@ class CoreNode(CoreNodeBase):
|
|||
broadcast = "+"
|
||||
self.node_net_client.create_address(interface.name, addr, broadcast)
|
||||
|
||||
def deladdr(self, ifindex, addr):
|
||||
def deladdr(self, ifindex: int, addr: str) -> None:
|
||||
"""
|
||||
Delete address from an interface.
|
||||
|
||||
|
@ -772,7 +806,7 @@ class CoreNode(CoreNodeBase):
|
|||
if self.up:
|
||||
self.node_net_client.delete_address(interface.name, addr)
|
||||
|
||||
def ifup(self, ifindex):
|
||||
def ifup(self, ifindex: int) -> None:
|
||||
"""
|
||||
Bring an interface up.
|
||||
|
||||
|
@ -783,7 +817,14 @@ class CoreNode(CoreNodeBase):
|
|||
interface_name = self.ifname(ifindex)
|
||||
self.node_net_client.device_up(interface_name)
|
||||
|
||||
def newnetif(self, net=None, addrlist=None, hwaddr=None, ifindex=None, ifname=None):
|
||||
def newnetif(
|
||||
self,
|
||||
net: "CoreNetworkBase" = None,
|
||||
addrlist: List[str] = None,
|
||||
hwaddr: str = None,
|
||||
ifindex: int = None,
|
||||
ifname: str = None,
|
||||
) -> int:
|
||||
"""
|
||||
Create a new network interface.
|
||||
|
||||
|
@ -827,7 +868,7 @@ class CoreNode(CoreNodeBase):
|
|||
self.ifup(ifindex)
|
||||
return ifindex
|
||||
|
||||
def addfile(self, srcname, filename):
|
||||
def addfile(self, srcname: str, filename: str) -> None:
|
||||
"""
|
||||
Add a file.
|
||||
|
||||
|
@ -846,7 +887,7 @@ class CoreNode(CoreNodeBase):
|
|||
self.host_cmd(f"mkdir -p {directory}")
|
||||
self.server.remote_put(srcname, filename)
|
||||
|
||||
def hostfilename(self, filename):
|
||||
def hostfilename(self, filename: str) -> str:
|
||||
"""
|
||||
Return the name of a node"s file on the host filesystem.
|
||||
|
||||
|
@ -862,7 +903,7 @@ class CoreNode(CoreNodeBase):
|
|||
dirname = os.path.join(self.nodedir, dirname)
|
||||
return os.path.join(dirname, basename)
|
||||
|
||||
def nodefile(self, filename, contents, mode=0o644):
|
||||
def nodefile(self, filename: str, contents: str, mode: int = 0o644) -> None:
|
||||
"""
|
||||
Create a node file with a given mode.
|
||||
|
||||
|
@ -887,7 +928,7 @@ class CoreNode(CoreNodeBase):
|
|||
"node(%s) added file: %s; mode: 0%o", self.name, hostfilename, mode
|
||||
)
|
||||
|
||||
def nodefilecopy(self, filename, srcfilename, mode=None):
|
||||
def nodefilecopy(self, filename: str, srcfilename: str, mode: int = None) -> None:
|
||||
"""
|
||||
Copy a file to a node, following symlinks and preserving metadata.
|
||||
Change file mode if specified.
|
||||
|
@ -917,7 +958,14 @@ class CoreNetworkBase(NodeBase):
|
|||
linktype = LinkTypes.WIRED.value
|
||||
is_emane = False
|
||||
|
||||
def __init__(self, session, _id, name, start=True, server=None):
|
||||
def __init__(
|
||||
self,
|
||||
session: "Session",
|
||||
_id: int,
|
||||
name: str,
|
||||
start: bool = True,
|
||||
server: "DistributedServer" = None,
|
||||
) -> None:
|
||||
"""
|
||||
Create a CoreNetworkBase instance.
|
||||
|
||||
|
@ -932,7 +980,7 @@ class CoreNetworkBase(NodeBase):
|
|||
self._linked = {}
|
||||
self._linked_lock = threading.Lock()
|
||||
|
||||
def startup(self):
|
||||
def startup(self) -> None:
|
||||
"""
|
||||
Each object implements its own startup method.
|
||||
|
||||
|
@ -940,7 +988,7 @@ class CoreNetworkBase(NodeBase):
|
|||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def shutdown(self):
|
||||
def shutdown(self) -> None:
|
||||
"""
|
||||
Each object implements its own shutdown method.
|
||||
|
||||
|
@ -948,7 +996,7 @@ class CoreNetworkBase(NodeBase):
|
|||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def linknet(self, net):
|
||||
def linknet(self, net: "CoreNetworkBase") -> CoreInterface:
|
||||
"""
|
||||
Link network to another.
|
||||
|
||||
|
@ -958,7 +1006,7 @@ class CoreNetworkBase(NodeBase):
|
|||
"""
|
||||
pass
|
||||
|
||||
def getlinknetif(self, net):
|
||||
def getlinknetif(self, net: "CoreNetworkBase") -> CoreInterface:
|
||||
"""
|
||||
Return the interface of that links this net with another net.
|
||||
|
||||
|
@ -971,7 +1019,7 @@ class CoreNetworkBase(NodeBase):
|
|||
return netif
|
||||
return None
|
||||
|
||||
def attach(self, netif):
|
||||
def attach(self, netif: CoreInterface) -> None:
|
||||
"""
|
||||
Attach network interface.
|
||||
|
||||
|
@ -984,7 +1032,7 @@ class CoreNetworkBase(NodeBase):
|
|||
with self._linked_lock:
|
||||
self._linked[netif] = {}
|
||||
|
||||
def detach(self, netif):
|
||||
def detach(self, netif: CoreInterface) -> None:
|
||||
"""
|
||||
Detach network interface.
|
||||
|
||||
|
@ -996,7 +1044,7 @@ class CoreNetworkBase(NodeBase):
|
|||
with self._linked_lock:
|
||||
del self._linked[netif]
|
||||
|
||||
def all_link_data(self, flags):
|
||||
def all_link_data(self, flags: int) -> List[LinkData]:
|
||||
"""
|
||||
Build link data objects for this network. Each link object describes a link
|
||||
between this network and a node.
|
||||
|
@ -1004,7 +1052,6 @@ class CoreNetworkBase(NodeBase):
|
|||
:param int flags: message type
|
||||
:return: list of link data
|
||||
:rtype: list[core.data.LinkData]
|
||||
|
||||
"""
|
||||
all_links = []
|
||||
|
||||
|
@ -1095,7 +1142,7 @@ class Position:
|
|||
Helper class for Cartesian coordinate position
|
||||
"""
|
||||
|
||||
def __init__(self, x=None, y=None, z=None):
|
||||
def __init__(self, x: float = None, y: float = None, z: float = None) -> None:
|
||||
"""
|
||||
Creates a Position instance.
|
||||
|
||||
|
@ -1108,7 +1155,7 @@ class Position:
|
|||
self.y = y
|
||||
self.z = z
|
||||
|
||||
def set(self, x=None, y=None, z=None):
|
||||
def set(self, x: float = None, y: float = None, z: float = None) -> bool:
|
||||
"""
|
||||
Returns True if the position has actually changed.
|
||||
|
||||
|
@ -1125,7 +1172,7 @@ class Position:
|
|||
self.z = z
|
||||
return True
|
||||
|
||||
def get(self):
|
||||
def get(self) -> Tuple[float, float, float]:
|
||||
"""
|
||||
Retrieve x,y,z position.
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ class VnodeClient:
|
|||
Provides client functionality for interacting with a virtual node.
|
||||
"""
|
||||
|
||||
def __init__(self, name, ctrlchnlname):
|
||||
def __init__(self, name: str, ctrlchnlname: str) -> None:
|
||||
"""
|
||||
Create a VnodeClient instance.
|
||||
|
||||
|
@ -23,7 +23,7 @@ class VnodeClient:
|
|||
self.name = name
|
||||
self.ctrlchnlname = ctrlchnlname
|
||||
|
||||
def _verify_connection(self):
|
||||
def _verify_connection(self) -> None:
|
||||
"""
|
||||
Checks that the vcmd client is properly connected.
|
||||
|
||||
|
@ -33,7 +33,7 @@ class VnodeClient:
|
|||
if not self.connected():
|
||||
raise IOError("vcmd not connected")
|
||||
|
||||
def connected(self):
|
||||
def connected(self) -> bool:
|
||||
"""
|
||||
Check if node is connected or not.
|
||||
|
||||
|
@ -42,7 +42,7 @@ class VnodeClient:
|
|||
"""
|
||||
return True
|
||||
|
||||
def close(self):
|
||||
def close(self) -> None:
|
||||
"""
|
||||
Close the client connection.
|
||||
|
||||
|
@ -50,10 +50,10 @@ class VnodeClient:
|
|||
"""
|
||||
pass
|
||||
|
||||
def create_cmd(self, args):
|
||||
def create_cmd(self, args: str) -> str:
|
||||
return f"{VCMD_BIN} -c {self.ctrlchnlname} -- {args}"
|
||||
|
||||
def check_cmd(self, args, wait=True, shell=False):
|
||||
def check_cmd(self, args: str, wait: bool = True, shell: bool = False) -> str:
|
||||
"""
|
||||
Run command and return exit status and combined stdout and stderr.
|
||||
|
||||
|
|
|
@ -2,22 +2,27 @@ import json
|
|||
import logging
|
||||
import os
|
||||
from tempfile import NamedTemporaryFile
|
||||
from typing import TYPE_CHECKING, Callable, Dict
|
||||
|
||||
from core import utils
|
||||
from core.emulator.distributed import DistributedServer
|
||||
from core.emulator.enumerations import NodeTypes
|
||||
from core.errors import CoreCommandError
|
||||
from core.nodes.base import CoreNode
|
||||
from core.nodes.netclient import get_net_client
|
||||
from core.nodes.netclient import LinuxNetClient, get_net_client
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from core.emulator.session import Session
|
||||
|
||||
|
||||
class DockerClient:
|
||||
def __init__(self, name, image, run):
|
||||
def __init__(self, name: str, image: str, run: Callable) -> None:
|
||||
self.name = name
|
||||
self.image = image
|
||||
self.run = run
|
||||
self.pid = None
|
||||
|
||||
def create_container(self):
|
||||
def create_container(self) -> str:
|
||||
self.run(
|
||||
f"docker run -td --init --net=none --hostname {self.name} --name {self.name} "
|
||||
f"--sysctl net.ipv6.conf.all.disable_ipv6=0 {self.image} /bin/bash"
|
||||
|
@ -25,7 +30,7 @@ class DockerClient:
|
|||
self.pid = self.get_pid()
|
||||
return self.pid
|
||||
|
||||
def get_info(self):
|
||||
def get_info(self) -> Dict:
|
||||
args = f"docker inspect {self.name}"
|
||||
output = self.run(args)
|
||||
data = json.loads(output)
|
||||
|
@ -33,35 +38,35 @@ class DockerClient:
|
|||
raise CoreCommandError(-1, args, f"docker({self.name}) not present")
|
||||
return data[0]
|
||||
|
||||
def is_alive(self):
|
||||
def is_alive(self) -> bool:
|
||||
try:
|
||||
data = self.get_info()
|
||||
return data["State"]["Running"]
|
||||
except CoreCommandError:
|
||||
return False
|
||||
|
||||
def stop_container(self):
|
||||
def stop_container(self) -> None:
|
||||
self.run(f"docker rm -f {self.name}")
|
||||
|
||||
def check_cmd(self, cmd, wait=True, shell=False):
|
||||
def check_cmd(self, cmd: str, wait: bool = True, shell: bool = False) -> str:
|
||||
logging.info("docker cmd output: %s", cmd)
|
||||
return utils.cmd(f"docker exec {self.name} {cmd}", wait=wait, shell=shell)
|
||||
|
||||
def create_ns_cmd(self, cmd):
|
||||
def create_ns_cmd(self, cmd: str) -> str:
|
||||
return f"nsenter -t {self.pid} -u -i -p -n {cmd}"
|
||||
|
||||
def ns_cmd(self, cmd, wait):
|
||||
def ns_cmd(self, cmd: str, wait: bool) -> str:
|
||||
args = f"nsenter -t {self.pid} -u -i -p -n {cmd}"
|
||||
return utils.cmd(args, wait=wait)
|
||||
|
||||
def get_pid(self):
|
||||
def get_pid(self) -> str:
|
||||
args = f"docker inspect -f '{{{{.State.Pid}}}}' {self.name}"
|
||||
output = self.run(args)
|
||||
self.pid = output
|
||||
logging.debug("node(%s) pid: %s", self.name, self.pid)
|
||||
return output
|
||||
|
||||
def copy_file(self, source, destination):
|
||||
def copy_file(self, source: str, destination: str) -> str:
|
||||
args = f"docker cp {source} {self.name}:{destination}"
|
||||
return self.run(args)
|
||||
|
||||
|
@ -71,15 +76,15 @@ class DockerNode(CoreNode):
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
session,
|
||||
_id=None,
|
||||
name=None,
|
||||
nodedir=None,
|
||||
bootsh="boot.sh",
|
||||
start=True,
|
||||
server=None,
|
||||
image=None
|
||||
):
|
||||
session: "Session",
|
||||
_id: int = None,
|
||||
name: str = None,
|
||||
nodedir: str = None,
|
||||
bootsh: str = "boot.sh",
|
||||
start: bool = True,
|
||||
server: DistributedServer = None,
|
||||
image: str = None
|
||||
) -> None:
|
||||
"""
|
||||
Create a DockerNode instance.
|
||||
|
||||
|
@ -98,7 +103,7 @@ class DockerNode(CoreNode):
|
|||
self.image = image
|
||||
super().__init__(session, _id, name, nodedir, bootsh, start, server)
|
||||
|
||||
def create_node_net_client(self, use_ovs):
|
||||
def create_node_net_client(self, use_ovs: bool) -> LinuxNetClient:
|
||||
"""
|
||||
Create node network client for running network commands within the nodes
|
||||
container.
|
||||
|
@ -108,7 +113,7 @@ class DockerNode(CoreNode):
|
|||
"""
|
||||
return get_net_client(use_ovs, self.nsenter_cmd)
|
||||
|
||||
def alive(self):
|
||||
def alive(self) -> bool:
|
||||
"""
|
||||
Check if the node is alive.
|
||||
|
||||
|
@ -117,7 +122,7 @@ class DockerNode(CoreNode):
|
|||
"""
|
||||
return self.client.is_alive()
|
||||
|
||||
def startup(self):
|
||||
def startup(self) -> None:
|
||||
"""
|
||||
Start a new namespace node by invoking the vnoded process that
|
||||
allocates a new namespace. Bring up the loopback device and set
|
||||
|
@ -133,7 +138,7 @@ class DockerNode(CoreNode):
|
|||
self.pid = self.client.create_container()
|
||||
self.up = True
|
||||
|
||||
def shutdown(self):
|
||||
def shutdown(self) -> None:
|
||||
"""
|
||||
Shutdown logic.
|
||||
|
||||
|
@ -148,7 +153,7 @@ class DockerNode(CoreNode):
|
|||
self.client.stop_container()
|
||||
self.up = False
|
||||
|
||||
def nsenter_cmd(self, args, wait=True, shell=False):
|
||||
def nsenter_cmd(self, args: str, wait: bool = True, shell: bool = False) -> str:
|
||||
if self.server is None:
|
||||
args = self.client.create_ns_cmd(args)
|
||||
return utils.cmd(args, wait=wait, shell=shell)
|
||||
|
@ -156,7 +161,7 @@ class DockerNode(CoreNode):
|
|||
args = self.client.create_ns_cmd(args)
|
||||
return self.server.remote_cmd(args, wait=wait)
|
||||
|
||||
def termcmdstring(self, sh="/bin/sh"):
|
||||
def termcmdstring(self, sh: str = "/bin/sh") -> str:
|
||||
"""
|
||||
Create a terminal command string.
|
||||
|
||||
|
@ -165,7 +170,7 @@ class DockerNode(CoreNode):
|
|||
"""
|
||||
return f"docker exec -it {self.name} bash"
|
||||
|
||||
def privatedir(self, path):
|
||||
def privatedir(self, path: str) -> None:
|
||||
"""
|
||||
Create a private directory.
|
||||
|
||||
|
@ -176,7 +181,7 @@ class DockerNode(CoreNode):
|
|||
args = f"mkdir -p {path}"
|
||||
self.cmd(args)
|
||||
|
||||
def mount(self, source, target):
|
||||
def mount(self, source: str, target: str) -> None:
|
||||
"""
|
||||
Create and mount a directory.
|
||||
|
||||
|
@ -188,7 +193,7 @@ class DockerNode(CoreNode):
|
|||
logging.debug("mounting source(%s) target(%s)", source, target)
|
||||
raise Exception("not supported")
|
||||
|
||||
def nodefile(self, filename, contents, mode=0o644):
|
||||
def nodefile(self, filename: str, contents: str, mode: int = 0o644) -> None:
|
||||
"""
|
||||
Create a node file with a given mode.
|
||||
|
||||
|
@ -216,7 +221,7 @@ class DockerNode(CoreNode):
|
|||
"node(%s) added file: %s; mode: 0%o", self.name, filename, mode
|
||||
)
|
||||
|
||||
def nodefilecopy(self, filename, srcfilename, mode=None):
|
||||
def nodefilecopy(self, filename: str, srcfilename: str, mode: int = None) -> None:
|
||||
"""
|
||||
Copy a file to a node, following symlinks and preserving metadata.
|
||||
Change file mode if specified.
|
||||
|
|
|
@ -4,18 +4,31 @@ virtual ethernet classes that implement the interfaces available under Linux.
|
|||
|
||||
import logging
|
||||
import time
|
||||
from typing import TYPE_CHECKING, Callable, Dict, List, Tuple
|
||||
|
||||
from core import utils
|
||||
from core.errors import CoreCommandError
|
||||
from core.nodes.netclient import get_net_client
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from core.emulator.distributed import DistributedServer
|
||||
from core.emulator.session import Session
|
||||
from core.nodes.base import CoreNetworkBase, CoreNode
|
||||
|
||||
|
||||
class CoreInterface:
|
||||
"""
|
||||
Base class for network interfaces.
|
||||
"""
|
||||
|
||||
def __init__(self, session, node, name, mtu, server=None):
|
||||
def __init__(
|
||||
self,
|
||||
session: "Session",
|
||||
node: "CoreNode",
|
||||
name: str,
|
||||
mtu: int,
|
||||
server: "DistributedServer" = None,
|
||||
) -> None:
|
||||
"""
|
||||
Creates a CoreInterface instance.
|
||||
|
||||
|
@ -50,7 +63,14 @@ class CoreInterface:
|
|||
use_ovs = session.options.get_config("ovs") == "True"
|
||||
self.net_client = get_net_client(use_ovs, self.host_cmd)
|
||||
|
||||
def host_cmd(self, args, env=None, cwd=None, wait=True, shell=False):
|
||||
def host_cmd(
|
||||
self,
|
||||
args: str,
|
||||
env: Dict[str, str] = None,
|
||||
cwd: str = None,
|
||||
wait: bool = True,
|
||||
shell: bool = False,
|
||||
) -> str:
|
||||
"""
|
||||
Runs a command on the host system or distributed server.
|
||||
|
||||
|
@ -68,7 +88,7 @@ class CoreInterface:
|
|||
else:
|
||||
return self.server.remote_cmd(args, env, cwd, wait)
|
||||
|
||||
def startup(self):
|
||||
def startup(self) -> None:
|
||||
"""
|
||||
Startup method for the interface.
|
||||
|
||||
|
@ -76,7 +96,7 @@ class CoreInterface:
|
|||
"""
|
||||
pass
|
||||
|
||||
def shutdown(self):
|
||||
def shutdown(self) -> None:
|
||||
"""
|
||||
Shutdown method for the interface.
|
||||
|
||||
|
@ -84,7 +104,7 @@ class CoreInterface:
|
|||
"""
|
||||
pass
|
||||
|
||||
def attachnet(self, net):
|
||||
def attachnet(self, net: "CoreNetworkBase") -> None:
|
||||
"""
|
||||
Attach network.
|
||||
|
||||
|
@ -98,7 +118,7 @@ class CoreInterface:
|
|||
net.attach(self)
|
||||
self.net = net
|
||||
|
||||
def detachnet(self):
|
||||
def detachnet(self) -> None:
|
||||
"""
|
||||
Detach from a network.
|
||||
|
||||
|
@ -107,7 +127,7 @@ class CoreInterface:
|
|||
if self.net is not None:
|
||||
self.net.detach(self)
|
||||
|
||||
def addaddr(self, addr):
|
||||
def addaddr(self, addr: str) -> None:
|
||||
"""
|
||||
Add address.
|
||||
|
||||
|
@ -117,7 +137,7 @@ class CoreInterface:
|
|||
addr = utils.validate_ip(addr)
|
||||
self.addrlist.append(addr)
|
||||
|
||||
def deladdr(self, addr):
|
||||
def deladdr(self, addr: str) -> None:
|
||||
"""
|
||||
Delete address.
|
||||
|
||||
|
@ -126,7 +146,7 @@ class CoreInterface:
|
|||
"""
|
||||
self.addrlist.remove(addr)
|
||||
|
||||
def sethwaddr(self, addr):
|
||||
def sethwaddr(self, addr: str) -> None:
|
||||
"""
|
||||
Set hardware address.
|
||||
|
||||
|
@ -136,7 +156,7 @@ class CoreInterface:
|
|||
addr = utils.validate_mac(addr)
|
||||
self.hwaddr = addr
|
||||
|
||||
def getparam(self, key):
|
||||
def getparam(self, key: str) -> float:
|
||||
"""
|
||||
Retrieve a parameter from the, or None if the parameter does not exist.
|
||||
|
||||
|
@ -145,7 +165,7 @@ class CoreInterface:
|
|||
"""
|
||||
return self._params.get(key)
|
||||
|
||||
def getparams(self):
|
||||
def getparams(self) -> List[Tuple[str, float]]:
|
||||
"""
|
||||
Return (key, value) pairs for parameters.
|
||||
"""
|
||||
|
@ -154,7 +174,7 @@ class CoreInterface:
|
|||
parameters.append((k, self._params[k]))
|
||||
return parameters
|
||||
|
||||
def setparam(self, key, value):
|
||||
def setparam(self, key: str, value: float) -> bool:
|
||||
"""
|
||||
Set a parameter value, returns True if the parameter has changed.
|
||||
|
||||
|
@ -174,7 +194,7 @@ class CoreInterface:
|
|||
self._params[key] = value
|
||||
return True
|
||||
|
||||
def swapparams(self, name):
|
||||
def swapparams(self, name: str) -> None:
|
||||
"""
|
||||
Swap out parameters dict for name. If name does not exist,
|
||||
intialize it. This is for supporting separate upstream/downstream
|
||||
|
@ -189,7 +209,7 @@ class CoreInterface:
|
|||
self._params = getattr(self, name)
|
||||
setattr(self, name, tmp)
|
||||
|
||||
def setposition(self, x, y, z):
|
||||
def setposition(self, x: float, y: float, z: float) -> None:
|
||||
"""
|
||||
Dispatch position hook handler.
|
||||
|
||||
|
@ -200,7 +220,7 @@ class CoreInterface:
|
|||
"""
|
||||
self.poshook(self, x, y, z)
|
||||
|
||||
def __lt__(self, other):
|
||||
def __lt__(self, other: "CoreInterface") -> bool:
|
||||
"""
|
||||
Used for comparisons of this object.
|
||||
|
||||
|
@ -217,8 +237,15 @@ class Veth(CoreInterface):
|
|||
"""
|
||||
|
||||
def __init__(
|
||||
self, session, node, name, localname, mtu=1500, server=None, start=True
|
||||
):
|
||||
self,
|
||||
session: "Session",
|
||||
node: "CoreNode",
|
||||
name: str,
|
||||
localname: str,
|
||||
mtu: int = 1500,
|
||||
server: "DistributedServer" = None,
|
||||
start: bool = True,
|
||||
) -> None:
|
||||
"""
|
||||
Creates a VEth instance.
|
||||
|
||||
|
@ -239,7 +266,7 @@ class Veth(CoreInterface):
|
|||
if start:
|
||||
self.startup()
|
||||
|
||||
def startup(self):
|
||||
def startup(self) -> None:
|
||||
"""
|
||||
Interface startup logic.
|
||||
|
||||
|
@ -250,7 +277,7 @@ class Veth(CoreInterface):
|
|||
self.net_client.device_up(self.localname)
|
||||
self.up = True
|
||||
|
||||
def shutdown(self):
|
||||
def shutdown(self) -> None:
|
||||
"""
|
||||
Interface shutdown logic.
|
||||
|
||||
|
@ -280,8 +307,15 @@ class TunTap(CoreInterface):
|
|||
"""
|
||||
|
||||
def __init__(
|
||||
self, session, node, name, localname, mtu=1500, server=None, start=True
|
||||
):
|
||||
self,
|
||||
session: "Session",
|
||||
node: "CoreNode",
|
||||
name: str,
|
||||
localname: str,
|
||||
mtu: int = 1500,
|
||||
server: "DistributedServer" = None,
|
||||
start: bool = True,
|
||||
) -> None:
|
||||
"""
|
||||
Create a TunTap instance.
|
||||
|
||||
|
@ -301,7 +335,7 @@ class TunTap(CoreInterface):
|
|||
if start:
|
||||
self.startup()
|
||||
|
||||
def startup(self):
|
||||
def startup(self) -> None:
|
||||
"""
|
||||
Startup logic for a tunnel tap.
|
||||
|
||||
|
@ -315,7 +349,7 @@ class TunTap(CoreInterface):
|
|||
# self.install()
|
||||
self.up = True
|
||||
|
||||
def shutdown(self):
|
||||
def shutdown(self) -> None:
|
||||
"""
|
||||
Shutdown functionality for a tunnel tap.
|
||||
|
||||
|
@ -331,7 +365,9 @@ class TunTap(CoreInterface):
|
|||
|
||||
self.up = False
|
||||
|
||||
def waitfor(self, func, attempts=10, maxretrydelay=0.25):
|
||||
def waitfor(
|
||||
self, func: Callable, attempts: int = 10, maxretrydelay: float = 0.25
|
||||
) -> bool:
|
||||
"""
|
||||
Wait for func() to return zero with exponential backoff.
|
||||
|
||||
|
@ -362,7 +398,7 @@ class TunTap(CoreInterface):
|
|||
|
||||
return result
|
||||
|
||||
def waitfordevicelocal(self):
|
||||
def waitfordevicelocal(self) -> None:
|
||||
"""
|
||||
Check for presence of a local device - tap device may not
|
||||
appear right away waits
|
||||
|
@ -381,7 +417,7 @@ class TunTap(CoreInterface):
|
|||
|
||||
self.waitfor(localdevexists)
|
||||
|
||||
def waitfordevicenode(self):
|
||||
def waitfordevicenode(self) -> None:
|
||||
"""
|
||||
Check for presence of a node device - tap device may not appear right away waits.
|
||||
|
||||
|
@ -412,7 +448,7 @@ class TunTap(CoreInterface):
|
|||
else:
|
||||
raise RuntimeError("node device failed to exist")
|
||||
|
||||
def install(self):
|
||||
def install(self) -> None:
|
||||
"""
|
||||
Install this TAP into its namespace. This is not done from the
|
||||
startup() method but called at a later time when a userspace
|
||||
|
@ -428,7 +464,7 @@ class TunTap(CoreInterface):
|
|||
self.node.node_net_client.device_name(self.localname, self.name)
|
||||
self.node.node_net_client.device_up(self.name)
|
||||
|
||||
def setaddrs(self):
|
||||
def setaddrs(self) -> None:
|
||||
"""
|
||||
Set interface addresses based on self.addrlist.
|
||||
|
||||
|
@ -448,18 +484,18 @@ class GreTap(CoreInterface):
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
node=None,
|
||||
name=None,
|
||||
session=None,
|
||||
mtu=1458,
|
||||
remoteip=None,
|
||||
_id=None,
|
||||
localip=None,
|
||||
ttl=255,
|
||||
key=None,
|
||||
start=True,
|
||||
server=None,
|
||||
):
|
||||
node: "CoreNode" = None,
|
||||
name: str = None,
|
||||
session: "Session" = None,
|
||||
mtu: int = 1458,
|
||||
remoteip: str = None,
|
||||
_id: int = None,
|
||||
localip: str = None,
|
||||
ttl: int = 255,
|
||||
key: int = None,
|
||||
start: bool = True,
|
||||
server: "DistributedServer" = None,
|
||||
) -> None:
|
||||
"""
|
||||
Creates a GreTap instance.
|
||||
|
||||
|
@ -497,7 +533,7 @@ class GreTap(CoreInterface):
|
|||
self.net_client.device_up(self.localname)
|
||||
self.up = True
|
||||
|
||||
def shutdown(self):
|
||||
def shutdown(self) -> None:
|
||||
"""
|
||||
Shutdown logic for a GreTap.
|
||||
|
||||
|
@ -512,7 +548,7 @@ class GreTap(CoreInterface):
|
|||
|
||||
self.localname = None
|
||||
|
||||
def data(self, message_type):
|
||||
def data(self, message_type: int) -> None:
|
||||
"""
|
||||
Data for a gre tap.
|
||||
|
||||
|
@ -521,7 +557,7 @@ class GreTap(CoreInterface):
|
|||
"""
|
||||
return None
|
||||
|
||||
def all_link_data(self, flags):
|
||||
def all_link_data(self, flags: int) -> List:
|
||||
"""
|
||||
Retrieve link data.
|
||||
|
||||
|
|
|
@ -3,27 +3,33 @@ import logging
|
|||
import os
|
||||
import time
|
||||
from tempfile import NamedTemporaryFile
|
||||
from typing import TYPE_CHECKING, Callable, Dict
|
||||
|
||||
from core import utils
|
||||
from core.emulator.distributed import DistributedServer
|
||||
from core.emulator.enumerations import NodeTypes
|
||||
from core.errors import CoreCommandError
|
||||
from core.nodes.base import CoreNode
|
||||
from core.nodes.interface import CoreInterface
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from core.emulator.session import Session
|
||||
|
||||
|
||||
class LxdClient:
|
||||
def __init__(self, name, image, run):
|
||||
def __init__(self, name: str, image: str, run: Callable) -> None:
|
||||
self.name = name
|
||||
self.image = image
|
||||
self.run = run
|
||||
self.pid = None
|
||||
|
||||
def create_container(self):
|
||||
def create_container(self) -> int:
|
||||
self.run(f"lxc launch {self.image} {self.name}")
|
||||
data = self.get_info()
|
||||
self.pid = data["state"]["pid"]
|
||||
return self.pid
|
||||
|
||||
def get_info(self):
|
||||
def get_info(self) -> Dict:
|
||||
args = f"lxc list {self.name} --format json"
|
||||
output = self.run(args)
|
||||
data = json.loads(output)
|
||||
|
@ -31,27 +37,27 @@ class LxdClient:
|
|||
raise CoreCommandError(-1, args, f"LXC({self.name}) not present")
|
||||
return data[0]
|
||||
|
||||
def is_alive(self):
|
||||
def is_alive(self) -> bool:
|
||||
try:
|
||||
data = self.get_info()
|
||||
return data["state"]["status"] == "Running"
|
||||
except CoreCommandError:
|
||||
return False
|
||||
|
||||
def stop_container(self):
|
||||
def stop_container(self) -> None:
|
||||
self.run(f"lxc delete --force {self.name}")
|
||||
|
||||
def create_cmd(self, cmd):
|
||||
def create_cmd(self, cmd: str) -> str:
|
||||
return f"lxc exec -nT {self.name} -- {cmd}"
|
||||
|
||||
def create_ns_cmd(self, cmd):
|
||||
def create_ns_cmd(self, cmd: str) -> str:
|
||||
return f"nsenter -t {self.pid} -m -u -i -p -n {cmd}"
|
||||
|
||||
def check_cmd(self, cmd, wait=True, shell=False):
|
||||
def check_cmd(self, cmd: str, wait: bool = True, shell: bool = False) -> str:
|
||||
args = self.create_cmd(cmd)
|
||||
return utils.cmd(args, wait=wait, shell=shell)
|
||||
|
||||
def copy_file(self, source, destination):
|
||||
def copy_file(self, source: str, destination: str) -> None:
|
||||
if destination[0] != "/":
|
||||
destination = os.path.join("/root/", destination)
|
||||
|
||||
|
@ -64,15 +70,15 @@ class LxcNode(CoreNode):
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
session,
|
||||
_id=None,
|
||||
name=None,
|
||||
nodedir=None,
|
||||
bootsh="boot.sh",
|
||||
start=True,
|
||||
server=None,
|
||||
image=None,
|
||||
):
|
||||
session: "Session",
|
||||
_id: int = None,
|
||||
name: str = None,
|
||||
nodedir: str = None,
|
||||
bootsh: str = "boot.sh",
|
||||
start: bool = True,
|
||||
server: DistributedServer = None,
|
||||
image: str = None,
|
||||
) -> None:
|
||||
"""
|
||||
Create a LxcNode instance.
|
||||
|
||||
|
@ -91,7 +97,7 @@ class LxcNode(CoreNode):
|
|||
self.image = image
|
||||
super().__init__(session, _id, name, nodedir, bootsh, start, server)
|
||||
|
||||
def alive(self):
|
||||
def alive(self) -> bool:
|
||||
"""
|
||||
Check if the node is alive.
|
||||
|
||||
|
@ -100,7 +106,7 @@ class LxcNode(CoreNode):
|
|||
"""
|
||||
return self.client.is_alive()
|
||||
|
||||
def startup(self):
|
||||
def startup(self) -> None:
|
||||
"""
|
||||
Startup logic.
|
||||
|
||||
|
@ -114,7 +120,7 @@ class LxcNode(CoreNode):
|
|||
self.pid = self.client.create_container()
|
||||
self.up = True
|
||||
|
||||
def shutdown(self):
|
||||
def shutdown(self) -> None:
|
||||
"""
|
||||
Shutdown logic.
|
||||
|
||||
|
@ -129,7 +135,7 @@ class LxcNode(CoreNode):
|
|||
self.client.stop_container()
|
||||
self.up = False
|
||||
|
||||
def termcmdstring(self, sh="/bin/sh"):
|
||||
def termcmdstring(self, sh: str = "/bin/sh") -> str:
|
||||
"""
|
||||
Create a terminal command string.
|
||||
|
||||
|
@ -138,7 +144,7 @@ class LxcNode(CoreNode):
|
|||
"""
|
||||
return f"lxc exec {self.name} -- {sh}"
|
||||
|
||||
def privatedir(self, path):
|
||||
def privatedir(self, path: str) -> None:
|
||||
"""
|
||||
Create a private directory.
|
||||
|
||||
|
@ -147,9 +153,9 @@ class LxcNode(CoreNode):
|
|||
"""
|
||||
logging.info("creating node dir: %s", path)
|
||||
args = f"mkdir -p {path}"
|
||||
return self.cmd(args)
|
||||
self.cmd(args)
|
||||
|
||||
def mount(self, source, target):
|
||||
def mount(self, source: str, target: str) -> None:
|
||||
"""
|
||||
Create and mount a directory.
|
||||
|
||||
|
@ -161,7 +167,7 @@ class LxcNode(CoreNode):
|
|||
logging.debug("mounting source(%s) target(%s)", source, target)
|
||||
raise Exception("not supported")
|
||||
|
||||
def nodefile(self, filename, contents, mode=0o644):
|
||||
def nodefile(self, filename: str, contents: str, mode: int = 0o644) -> None:
|
||||
"""
|
||||
Create a node file with a given mode.
|
||||
|
||||
|
@ -188,7 +194,7 @@ class LxcNode(CoreNode):
|
|||
os.unlink(temp.name)
|
||||
logging.debug("node(%s) added file: %s; mode: 0%o", self.name, filename, mode)
|
||||
|
||||
def nodefilecopy(self, filename, srcfilename, mode=None):
|
||||
def nodefilecopy(self, filename: str, srcfilename: str, mode: int = None) -> None:
|
||||
"""
|
||||
Copy a file to a node, following symlinks and preserving metadata.
|
||||
Change file mode if specified.
|
||||
|
@ -214,7 +220,7 @@ class LxcNode(CoreNode):
|
|||
self.client.copy_file(source, filename)
|
||||
self.cmd(f"chmod {mode:o} {filename}")
|
||||
|
||||
def addnetif(self, netif, ifindex):
|
||||
def addnetif(self, netif: CoreInterface, ifindex: int) -> None:
|
||||
super().addnetif(netif, ifindex)
|
||||
# adding small delay to allow time for adding addresses to work correctly
|
||||
time.sleep(0.5)
|
||||
|
|
|
@ -2,30 +2,17 @@
|
|||
Clients for dealing with bridge/interface commands.
|
||||
"""
|
||||
import json
|
||||
from typing import Callable
|
||||
|
||||
from core.constants import ETHTOOL_BIN, IP_BIN, OVS_BIN, TC_BIN
|
||||
|
||||
|
||||
def get_net_client(use_ovs, run):
|
||||
"""
|
||||
Retrieve desired net client for running network commands.
|
||||
|
||||
:param bool use_ovs: True for OVS bridges, False for Linux bridges
|
||||
:param func run: function used to run net client commands
|
||||
:return: net client class
|
||||
"""
|
||||
if use_ovs:
|
||||
return OvsNetClient(run)
|
||||
else:
|
||||
return LinuxNetClient(run)
|
||||
|
||||
|
||||
class LinuxNetClient:
|
||||
"""
|
||||
Client for creating Linux bridges and ip interfaces for nodes.
|
||||
"""
|
||||
|
||||
def __init__(self, run):
|
||||
def __init__(self, run: Callable) -> None:
|
||||
"""
|
||||
Create LinuxNetClient instance.
|
||||
|
||||
|
@ -33,7 +20,7 @@ class LinuxNetClient:
|
|||
"""
|
||||
self.run = run
|
||||
|
||||
def set_hostname(self, name):
|
||||
def set_hostname(self, name: str) -> None:
|
||||
"""
|
||||
Set network hostname.
|
||||
|
||||
|
@ -42,7 +29,7 @@ class LinuxNetClient:
|
|||
"""
|
||||
self.run(f"hostname {name}")
|
||||
|
||||
def create_route(self, route, device):
|
||||
def create_route(self, route: str, device: str) -> None:
|
||||
"""
|
||||
Create a new route for a device.
|
||||
|
||||
|
@ -52,7 +39,7 @@ class LinuxNetClient:
|
|||
"""
|
||||
self.run(f"{IP_BIN} route add {route} dev {device}")
|
||||
|
||||
def device_up(self, device):
|
||||
def device_up(self, device: str) -> None:
|
||||
"""
|
||||
Bring a device up.
|
||||
|
||||
|
@ -61,7 +48,7 @@ class LinuxNetClient:
|
|||
"""
|
||||
self.run(f"{IP_BIN} link set {device} up")
|
||||
|
||||
def device_down(self, device):
|
||||
def device_down(self, device: str) -> None:
|
||||
"""
|
||||
Bring a device down.
|
||||
|
||||
|
@ -70,7 +57,7 @@ class LinuxNetClient:
|
|||
"""
|
||||
self.run(f"{IP_BIN} link set {device} down")
|
||||
|
||||
def device_name(self, device, name):
|
||||
def device_name(self, device: str, name: str) -> None:
|
||||
"""
|
||||
Set a device name.
|
||||
|
||||
|
@ -80,7 +67,7 @@ class LinuxNetClient:
|
|||
"""
|
||||
self.run(f"{IP_BIN} link set {device} name {name}")
|
||||
|
||||
def device_show(self, device):
|
||||
def device_show(self, device: str) -> str:
|
||||
"""
|
||||
Show information for a device.
|
||||
|
||||
|
@ -90,7 +77,7 @@ class LinuxNetClient:
|
|||
"""
|
||||
return self.run(f"{IP_BIN} link show {device}")
|
||||
|
||||
def get_mac(self, device):
|
||||
def get_mac(self, device: str) -> str:
|
||||
"""
|
||||
Retrieve MAC address for a given device.
|
||||
|
||||
|
@ -100,7 +87,7 @@ class LinuxNetClient:
|
|||
"""
|
||||
return self.run(f"cat /sys/class/net/{device}/address")
|
||||
|
||||
def get_ifindex(self, device):
|
||||
def get_ifindex(self, device: str) -> str:
|
||||
"""
|
||||
Retrieve ifindex for a given device.
|
||||
|
||||
|
@ -110,7 +97,7 @@ class LinuxNetClient:
|
|||
"""
|
||||
return self.run(f"cat /sys/class/net/{device}/ifindex")
|
||||
|
||||
def device_ns(self, device, namespace):
|
||||
def device_ns(self, device: str, namespace: str) -> None:
|
||||
"""
|
||||
Set netns for a device.
|
||||
|
||||
|
@ -120,7 +107,7 @@ class LinuxNetClient:
|
|||
"""
|
||||
self.run(f"{IP_BIN} link set {device} netns {namespace}")
|
||||
|
||||
def device_flush(self, device):
|
||||
def device_flush(self, device: str) -> None:
|
||||
"""
|
||||
Flush device addresses.
|
||||
|
||||
|
@ -132,7 +119,7 @@ class LinuxNetClient:
|
|||
shell=True,
|
||||
)
|
||||
|
||||
def device_mac(self, device, mac):
|
||||
def device_mac(self, device: str, mac: str) -> None:
|
||||
"""
|
||||
Set MAC address for a device.
|
||||
|
||||
|
@ -142,7 +129,7 @@ class LinuxNetClient:
|
|||
"""
|
||||
self.run(f"{IP_BIN} link set dev {device} address {mac}")
|
||||
|
||||
def delete_device(self, device):
|
||||
def delete_device(self, device: str) -> None:
|
||||
"""
|
||||
Delete device.
|
||||
|
||||
|
@ -151,7 +138,7 @@ class LinuxNetClient:
|
|||
"""
|
||||
self.run(f"{IP_BIN} link delete {device}")
|
||||
|
||||
def delete_tc(self, device):
|
||||
def delete_tc(self, device: str) -> None:
|
||||
"""
|
||||
Remove traffic control settings for a device.
|
||||
|
||||
|
@ -160,7 +147,7 @@ class LinuxNetClient:
|
|||
"""
|
||||
self.run(f"{TC_BIN} qdisc delete dev {device} root")
|
||||
|
||||
def checksums_off(self, interface_name):
|
||||
def checksums_off(self, interface_name: str) -> None:
|
||||
"""
|
||||
Turns interface checksums off.
|
||||
|
||||
|
@ -169,7 +156,7 @@ class LinuxNetClient:
|
|||
"""
|
||||
self.run(f"{ETHTOOL_BIN} -K {interface_name} rx off tx off")
|
||||
|
||||
def create_address(self, device, address, broadcast=None):
|
||||
def create_address(self, device: str, address: str, broadcast: str = None) -> None:
|
||||
"""
|
||||
Create address for a device.
|
||||
|
||||
|
@ -185,7 +172,7 @@ class LinuxNetClient:
|
|||
else:
|
||||
self.run(f"{IP_BIN} address add {address} dev {device}")
|
||||
|
||||
def delete_address(self, device, address):
|
||||
def delete_address(self, device: str, address: str) -> None:
|
||||
"""
|
||||
Delete an address from a device.
|
||||
|
||||
|
@ -195,7 +182,7 @@ class LinuxNetClient:
|
|||
"""
|
||||
self.run(f"{IP_BIN} address delete {address} dev {device}")
|
||||
|
||||
def create_veth(self, name, peer):
|
||||
def create_veth(self, name: str, peer: str) -> None:
|
||||
"""
|
||||
Create a veth pair.
|
||||
|
||||
|
@ -205,7 +192,9 @@ class LinuxNetClient:
|
|||
"""
|
||||
self.run(f"{IP_BIN} link add name {name} type veth peer name {peer}")
|
||||
|
||||
def create_gretap(self, device, address, local, ttl, key):
|
||||
def create_gretap(
|
||||
self, device: str, address: str, local: str, ttl: int, key: int
|
||||
) -> None:
|
||||
"""
|
||||
Create a GRE tap on a device.
|
||||
|
||||
|
@ -225,7 +214,7 @@ class LinuxNetClient:
|
|||
cmd += f" key {key}"
|
||||
self.run(cmd)
|
||||
|
||||
def create_bridge(self, name):
|
||||
def create_bridge(self, name: str) -> None:
|
||||
"""
|
||||
Create a Linux bridge and bring it up.
|
||||
|
||||
|
@ -238,7 +227,7 @@ class LinuxNetClient:
|
|||
self.run(f"{IP_BIN} link set {name} type bridge mcast_snooping 0")
|
||||
self.device_up(name)
|
||||
|
||||
def delete_bridge(self, name):
|
||||
def delete_bridge(self, name: str) -> None:
|
||||
"""
|
||||
Bring down and delete a Linux bridge.
|
||||
|
||||
|
@ -248,7 +237,7 @@ class LinuxNetClient:
|
|||
self.device_down(name)
|
||||
self.run(f"{IP_BIN} link delete {name} type bridge")
|
||||
|
||||
def create_interface(self, bridge_name, interface_name):
|
||||
def create_interface(self, bridge_name: str, interface_name: str) -> None:
|
||||
"""
|
||||
Create an interface associated with a Linux bridge.
|
||||
|
||||
|
@ -259,7 +248,7 @@ class LinuxNetClient:
|
|||
self.run(f"{IP_BIN} link set dev {interface_name} master {bridge_name}")
|
||||
self.device_up(interface_name)
|
||||
|
||||
def delete_interface(self, bridge_name, interface_name):
|
||||
def delete_interface(self, bridge_name: str, interface_name: str) -> None:
|
||||
"""
|
||||
Delete an interface associated with a Linux bridge.
|
||||
|
||||
|
@ -269,11 +258,12 @@ class LinuxNetClient:
|
|||
"""
|
||||
self.run(f"{IP_BIN} link set dev {interface_name} nomaster")
|
||||
|
||||
def existing_bridges(self, _id):
|
||||
def existing_bridges(self, _id: int) -> bool:
|
||||
"""
|
||||
Checks if there are any existing Linux bridges for a node.
|
||||
|
||||
:param _id: node id to check bridges for
|
||||
:return: True if there are existing bridges, False otherwise
|
||||
"""
|
||||
output = self.run(f"{IP_BIN} -j link show type bridge")
|
||||
bridges = json.loads(output)
|
||||
|
@ -286,7 +276,7 @@ class LinuxNetClient:
|
|||
return True
|
||||
return False
|
||||
|
||||
def disable_mac_learning(self, name):
|
||||
def disable_mac_learning(self, name: str) -> None:
|
||||
"""
|
||||
Disable mac learning for a Linux bridge.
|
||||
|
||||
|
@ -301,7 +291,7 @@ class OvsNetClient(LinuxNetClient):
|
|||
Client for creating OVS bridges and ip interfaces for nodes.
|
||||
"""
|
||||
|
||||
def create_bridge(self, name):
|
||||
def create_bridge(self, name: str) -> None:
|
||||
"""
|
||||
Create a OVS bridge and bring it up.
|
||||
|
||||
|
@ -314,7 +304,7 @@ class OvsNetClient(LinuxNetClient):
|
|||
self.run(f"{OVS_BIN} set bridge {name} other_config:stp-forward-delay=4")
|
||||
self.device_up(name)
|
||||
|
||||
def delete_bridge(self, name):
|
||||
def delete_bridge(self, name: str) -> None:
|
||||
"""
|
||||
Bring down and delete a OVS bridge.
|
||||
|
||||
|
@ -324,7 +314,7 @@ class OvsNetClient(LinuxNetClient):
|
|||
self.device_down(name)
|
||||
self.run(f"{OVS_BIN} del-br {name}")
|
||||
|
||||
def create_interface(self, bridge_name, interface_name):
|
||||
def create_interface(self, bridge_name: str, interface_name: str) -> None:
|
||||
"""
|
||||
Create an interface associated with a network bridge.
|
||||
|
||||
|
@ -335,7 +325,7 @@ class OvsNetClient(LinuxNetClient):
|
|||
self.run(f"{OVS_BIN} add-port {bridge_name} {interface_name}")
|
||||
self.device_up(interface_name)
|
||||
|
||||
def delete_interface(self, bridge_name, interface_name):
|
||||
def delete_interface(self, bridge_name: str, interface_name: str) -> None:
|
||||
"""
|
||||
Delete an interface associated with a OVS bridge.
|
||||
|
||||
|
@ -345,11 +335,12 @@ class OvsNetClient(LinuxNetClient):
|
|||
"""
|
||||
self.run(f"{OVS_BIN} del-port {bridge_name} {interface_name}")
|
||||
|
||||
def existing_bridges(self, _id):
|
||||
def existing_bridges(self, _id: int) -> bool:
|
||||
"""
|
||||
Checks if there are any existing OVS bridges for a node.
|
||||
|
||||
:param _id: node id to check bridges for
|
||||
:return: True if there are existing bridges, False otherwise
|
||||
"""
|
||||
output = self.run(f"{OVS_BIN} list-br")
|
||||
if output:
|
||||
|
@ -359,7 +350,7 @@ class OvsNetClient(LinuxNetClient):
|
|||
return True
|
||||
return False
|
||||
|
||||
def disable_mac_learning(self, name):
|
||||
def disable_mac_learning(self, name: str) -> None:
|
||||
"""
|
||||
Disable mac learning for a OVS bridge.
|
||||
|
||||
|
@ -367,3 +358,17 @@ class OvsNetClient(LinuxNetClient):
|
|||
:return: nothing
|
||||
"""
|
||||
self.run(f"{OVS_BIN} set bridge {name} other_config:mac-aging-time=0")
|
||||
|
||||
|
||||
def get_net_client(use_ovs: bool, run: Callable) -> LinuxNetClient:
|
||||
"""
|
||||
Retrieve desired net client for running network commands.
|
||||
|
||||
:param bool use_ovs: True for OVS bridges, False for Linux bridges
|
||||
:param func run: function used to run net client commands
|
||||
:return: net client class
|
||||
"""
|
||||
if use_ovs:
|
||||
return OvsNetClient(run)
|
||||
else:
|
||||
return LinuxNetClient(run)
|
||||
|
|
|
@ -5,18 +5,26 @@ Defines network nodes used within core.
|
|||
import logging
|
||||
import threading
|
||||
import time
|
||||
from typing import TYPE_CHECKING, Callable, Dict, List, Optional, Type
|
||||
|
||||
import netaddr
|
||||
|
||||
from core import utils
|
||||
from core.constants import EBTABLES_BIN, TC_BIN
|
||||
from core.emulator.data import LinkData
|
||||
from core.emulator.data import LinkData, NodeData
|
||||
from core.emulator.enumerations import LinkTypes, NodeTypes, RegisterTlvs
|
||||
from core.errors import CoreCommandError, CoreError
|
||||
from core.nodes.base import CoreNetworkBase
|
||||
from core.nodes.interface import GreTap, Veth
|
||||
from core.nodes.interface import CoreInterface, GreTap, Veth
|
||||
from core.nodes.netclient import get_net_client
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from core.emulator.distributed import DistributedServer
|
||||
from core.emulator.session import Session
|
||||
from core.location.mobility import WirelessModel
|
||||
|
||||
WirelessModelType = Type[WirelessModel]
|
||||
|
||||
ebtables_lock = threading.Lock()
|
||||
|
||||
|
||||
|
@ -32,7 +40,7 @@ class EbtablesQueue:
|
|||
# ebtables
|
||||
atomic_file = "/tmp/pycore.ebtables.atomic"
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self) -> None:
|
||||
"""
|
||||
Initialize the helper class, but don't start the update thread
|
||||
until a WLAN is instantiated.
|
||||
|
@ -49,7 +57,7 @@ class EbtablesQueue:
|
|||
# using this queue
|
||||
self.last_update_time = {}
|
||||
|
||||
def startupdateloop(self, wlan):
|
||||
def startupdateloop(self, wlan: "CoreNetwork") -> None:
|
||||
"""
|
||||
Kick off the update loop; only needs to be invoked once.
|
||||
|
||||
|
@ -66,7 +74,7 @@ class EbtablesQueue:
|
|||
self.updatethread.daemon = True
|
||||
self.updatethread.start()
|
||||
|
||||
def stopupdateloop(self, wlan):
|
||||
def stopupdateloop(self, wlan: "CoreNetwork") -> None:
|
||||
"""
|
||||
Kill the update loop thread if there are no more WLANs using it.
|
||||
|
||||
|
@ -88,17 +96,17 @@ class EbtablesQueue:
|
|||
self.updatethread.join()
|
||||
self.updatethread = None
|
||||
|
||||
def ebatomiccmd(self, cmd):
|
||||
def ebatomiccmd(self, cmd: str) -> str:
|
||||
"""
|
||||
Helper for building ebtables atomic file command list.
|
||||
|
||||
:param str cmd: ebtable command
|
||||
:return: ebtable atomic command
|
||||
:rtype: list[str]
|
||||
:rtype: str
|
||||
"""
|
||||
return f"{EBTABLES_BIN} --atomic-file {self.atomic_file} {cmd}"
|
||||
|
||||
def lastupdate(self, wlan):
|
||||
def lastupdate(self, wlan: "CoreNetwork") -> float:
|
||||
"""
|
||||
Return the time elapsed since this WLAN was last updated.
|
||||
|
||||
|
@ -114,7 +122,7 @@ class EbtablesQueue:
|
|||
|
||||
return elapsed
|
||||
|
||||
def updated(self, wlan):
|
||||
def updated(self, wlan: "CoreNetwork") -> None:
|
||||
"""
|
||||
Keep track of when this WLAN was last updated.
|
||||
|
||||
|
@ -124,7 +132,7 @@ class EbtablesQueue:
|
|||
self.last_update_time[wlan] = time.monotonic()
|
||||
self.updates.remove(wlan)
|
||||
|
||||
def updateloop(self):
|
||||
def updateloop(self) -> None:
|
||||
"""
|
||||
Thread target that looks for WLANs needing update, and
|
||||
rate limits the amount of ebtables activity. Only one userspace program
|
||||
|
@ -153,7 +161,7 @@ class EbtablesQueue:
|
|||
|
||||
time.sleep(self.rate)
|
||||
|
||||
def ebcommit(self, wlan):
|
||||
def ebcommit(self, wlan: "CoreNetwork") -> None:
|
||||
"""
|
||||
Perform ebtables atomic commit using commands built in the self.cmds list.
|
||||
|
||||
|
@ -178,7 +186,7 @@ class EbtablesQueue:
|
|||
except CoreCommandError:
|
||||
logging.exception("error removing atomic file: %s", self.atomic_file)
|
||||
|
||||
def ebchange(self, wlan):
|
||||
def ebchange(self, wlan: "CoreNetwork") -> None:
|
||||
"""
|
||||
Flag a change to the given WLAN's _linked dict, so the ebtables
|
||||
chain will be rebuilt at the next interval.
|
||||
|
@ -189,7 +197,7 @@ class EbtablesQueue:
|
|||
if wlan not in self.updates:
|
||||
self.updates.append(wlan)
|
||||
|
||||
def buildcmds(self, wlan):
|
||||
def buildcmds(self, wlan: "CoreNetwork") -> None:
|
||||
"""
|
||||
Inspect a _linked dict from a wlan, and rebuild the ebtables chain for that WLAN.
|
||||
|
||||
|
@ -231,7 +239,7 @@ class EbtablesQueue:
|
|||
ebq = EbtablesQueue()
|
||||
|
||||
|
||||
def ebtablescmds(call, cmds):
|
||||
def ebtablescmds(call: Callable, cmds: List[str]) -> None:
|
||||
"""
|
||||
Run ebtable commands.
|
||||
|
||||
|
@ -252,8 +260,14 @@ class CoreNetwork(CoreNetworkBase):
|
|||
policy = "DROP"
|
||||
|
||||
def __init__(
|
||||
self, session, _id=None, name=None, start=True, server=None, policy=None
|
||||
):
|
||||
self,
|
||||
session: "Session",
|
||||
_id: int = None,
|
||||
name: str = None,
|
||||
start: bool = True,
|
||||
server: "DistributedServer" = None,
|
||||
policy: str = None,
|
||||
) -> None:
|
||||
"""
|
||||
Creates a LxBrNet instance.
|
||||
|
||||
|
@ -279,7 +293,14 @@ class CoreNetwork(CoreNetworkBase):
|
|||
self.startup()
|
||||
ebq.startupdateloop(self)
|
||||
|
||||
def host_cmd(self, args, env=None, cwd=None, wait=True, shell=False):
|
||||
def host_cmd(
|
||||
self,
|
||||
args: str,
|
||||
env: Dict[str, str] = None,
|
||||
cwd: str = None,
|
||||
wait: bool = True,
|
||||
shell: bool = False,
|
||||
) -> str:
|
||||
"""
|
||||
Runs a command that is used to configure and setup the network on the host
|
||||
system and all configured distributed servers.
|
||||
|
@ -298,7 +319,7 @@ class CoreNetwork(CoreNetworkBase):
|
|||
self.session.distributed.execute(lambda x: x.remote_cmd(args, env, cwd, wait))
|
||||
return output
|
||||
|
||||
def startup(self):
|
||||
def startup(self) -> None:
|
||||
"""
|
||||
Linux bridge starup logic.
|
||||
|
||||
|
@ -309,7 +330,7 @@ class CoreNetwork(CoreNetworkBase):
|
|||
self.has_ebtables_chain = False
|
||||
self.up = True
|
||||
|
||||
def shutdown(self):
|
||||
def shutdown(self) -> None:
|
||||
"""
|
||||
Linux bridge shutdown logic.
|
||||
|
||||
|
@ -340,18 +361,18 @@ class CoreNetwork(CoreNetworkBase):
|
|||
del self.session
|
||||
self.up = False
|
||||
|
||||
def attach(self, netif):
|
||||
def attach(self, netif: CoreInterface) -> None:
|
||||
"""
|
||||
Attach a network interface.
|
||||
|
||||
:param core.nodes.interface.Veth netif: network interface to attach
|
||||
:param core.nodes.interface.CoreInterface netif: network interface to attach
|
||||
:return: nothing
|
||||
"""
|
||||
if self.up:
|
||||
netif.net_client.create_interface(self.brname, netif.localname)
|
||||
super().attach(netif)
|
||||
|
||||
def detach(self, netif):
|
||||
def detach(self, netif: CoreInterface) -> None:
|
||||
"""
|
||||
Detach a network interface.
|
||||
|
||||
|
@ -362,7 +383,7 @@ class CoreNetwork(CoreNetworkBase):
|
|||
netif.net_client.delete_interface(self.brname, netif.localname)
|
||||
super().detach(netif)
|
||||
|
||||
def linked(self, netif1, netif2):
|
||||
def linked(self, netif1: CoreInterface, netif2: CoreInterface) -> bool:
|
||||
"""
|
||||
Determine if the provided network interfaces are linked.
|
||||
|
||||
|
@ -391,9 +412,9 @@ class CoreNetwork(CoreNetworkBase):
|
|||
|
||||
return linked
|
||||
|
||||
def unlink(self, netif1, netif2):
|
||||
def unlink(self, netif1: CoreInterface, netif2: CoreInterface) -> None:
|
||||
"""
|
||||
Unlink two PyCoreNetIfs, resulting in adding or removing ebtables
|
||||
Unlink two interfaces, resulting in adding or removing ebtables
|
||||
filtering rules.
|
||||
|
||||
:param core.nodes.interface.CoreInterface netif1: interface one
|
||||
|
@ -407,9 +428,9 @@ class CoreNetwork(CoreNetworkBase):
|
|||
|
||||
ebq.ebchange(self)
|
||||
|
||||
def link(self, netif1, netif2):
|
||||
def link(self, netif1: CoreInterface, netif2: CoreInterface) -> None:
|
||||
"""
|
||||
Link two PyCoreNetIfs together, resulting in adding or removing
|
||||
Link two interfaces together, resulting in adding or removing
|
||||
ebtables filtering rules.
|
||||
|
||||
:param core.nodes.interface.CoreInterface netif1: interface one
|
||||
|
@ -425,19 +446,19 @@ class CoreNetwork(CoreNetworkBase):
|
|||
|
||||
def linkconfig(
|
||||
self,
|
||||
netif,
|
||||
bw=None,
|
||||
delay=None,
|
||||
loss=None,
|
||||
duplicate=None,
|
||||
jitter=None,
|
||||
netif2=None,
|
||||
devname=None,
|
||||
):
|
||||
netif: CoreInterface,
|
||||
bw: float = None,
|
||||
delay: float = None,
|
||||
loss: float = None,
|
||||
duplicate: float = None,
|
||||
jitter: float = None,
|
||||
netif2: float = None,
|
||||
devname: str = None,
|
||||
) -> None:
|
||||
"""
|
||||
Configure link parameters by applying tc queuing disciplines on the interface.
|
||||
|
||||
:param core.nodes.interface.Veth netif: interface one
|
||||
:param core.nodes.interface.CoreInterface netif: interface one
|
||||
:param bw: bandwidth to set to
|
||||
:param delay: packet delay to set to
|
||||
:param loss: packet loss to set to
|
||||
|
@ -520,14 +541,14 @@ class CoreNetwork(CoreNetworkBase):
|
|||
netif.host_cmd(cmd)
|
||||
netif.setparam("has_netem", True)
|
||||
|
||||
def linknet(self, net):
|
||||
def linknet(self, net: CoreNetworkBase) -> CoreInterface:
|
||||
"""
|
||||
Link this bridge with another by creating a veth pair and installing
|
||||
each device into each bridge.
|
||||
|
||||
:param core.nodes.base.CoreNetworkBase net: network to link with
|
||||
:return: created interface
|
||||
:rtype: core.nodes.interface.Veth
|
||||
:rtype: core.nodes.interface.CoreInterface
|
||||
"""
|
||||
sessionid = self.session.short_session_id()
|
||||
try:
|
||||
|
@ -561,7 +582,7 @@ class CoreNetwork(CoreNetworkBase):
|
|||
netif.othernet = net
|
||||
return netif
|
||||
|
||||
def getlinknetif(self, net):
|
||||
def getlinknetif(self, net: CoreNetworkBase) -> Optional[CoreInterface]:
|
||||
"""
|
||||
Return the interface of that links this net with another net
|
||||
(that were linked using linknet()).
|
||||
|
@ -573,10 +594,9 @@ class CoreNetwork(CoreNetworkBase):
|
|||
for netif in self.netifs():
|
||||
if hasattr(netif, "othernet") and netif.othernet == net:
|
||||
return netif
|
||||
|
||||
return None
|
||||
|
||||
def addrconfig(self, addrlist):
|
||||
def addrconfig(self, addrlist: List[str]) -> None:
|
||||
"""
|
||||
Set addresses on the bridge.
|
||||
|
||||
|
@ -598,17 +618,17 @@ class GreTapBridge(CoreNetwork):
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
session,
|
||||
remoteip=None,
|
||||
_id=None,
|
||||
name=None,
|
||||
policy="ACCEPT",
|
||||
localip=None,
|
||||
ttl=255,
|
||||
key=None,
|
||||
start=True,
|
||||
server=None,
|
||||
):
|
||||
session: "Session",
|
||||
remoteip: str = None,
|
||||
_id: int = None,
|
||||
name: str = None,
|
||||
policy: str = "ACCEPT",
|
||||
localip: str = None,
|
||||
ttl: int = 255,
|
||||
key: int = None,
|
||||
start: bool = True,
|
||||
server: "DistributedServer" = None,
|
||||
) -> None:
|
||||
"""
|
||||
Create a GreTapBridge instance.
|
||||
|
||||
|
@ -647,7 +667,7 @@ class GreTapBridge(CoreNetwork):
|
|||
if start:
|
||||
self.startup()
|
||||
|
||||
def startup(self):
|
||||
def startup(self) -> None:
|
||||
"""
|
||||
Creates a bridge and adds the gretap device to it.
|
||||
|
||||
|
@ -657,7 +677,7 @@ class GreTapBridge(CoreNetwork):
|
|||
if self.gretap:
|
||||
self.attach(self.gretap)
|
||||
|
||||
def shutdown(self):
|
||||
def shutdown(self) -> None:
|
||||
"""
|
||||
Detach the gretap device and remove the bridge.
|
||||
|
||||
|
@ -669,7 +689,7 @@ class GreTapBridge(CoreNetwork):
|
|||
self.gretap = None
|
||||
super().shutdown()
|
||||
|
||||
def addrconfig(self, addrlist):
|
||||
def addrconfig(self, addrlist: List[str]) -> None:
|
||||
"""
|
||||
Set the remote tunnel endpoint. This is a one-time method for
|
||||
creating the GreTap device, which requires the remoteip at startup.
|
||||
|
@ -694,7 +714,7 @@ class GreTapBridge(CoreNetwork):
|
|||
)
|
||||
self.attach(self.gretap)
|
||||
|
||||
def setkey(self, key):
|
||||
def setkey(self, key: int) -> None:
|
||||
"""
|
||||
Set the GRE key used for the GreTap device. This needs to be set
|
||||
prior to instantiating the GreTap device (before addrconfig).
|
||||
|
@ -722,17 +742,17 @@ class CtrlNet(CoreNetwork):
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
session,
|
||||
_id=None,
|
||||
name=None,
|
||||
prefix=None,
|
||||
hostid=None,
|
||||
start=True,
|
||||
server=None,
|
||||
assign_address=True,
|
||||
updown_script=None,
|
||||
serverintf=None,
|
||||
):
|
||||
session: "Session",
|
||||
_id: int = None,
|
||||
name: str = None,
|
||||
prefix: str = None,
|
||||
hostid: int = None,
|
||||
start: bool = True,
|
||||
server: "DistributedServer" = None,
|
||||
assign_address: bool = True,
|
||||
updown_script: str = None,
|
||||
serverintf: CoreInterface = None,
|
||||
) -> None:
|
||||
"""
|
||||
Creates a CtrlNet instance.
|
||||
|
||||
|
@ -756,7 +776,7 @@ class CtrlNet(CoreNetwork):
|
|||
self.serverintf = serverintf
|
||||
super().__init__(session, _id, name, start, server)
|
||||
|
||||
def add_addresses(self, index):
|
||||
def add_addresses(self, index: int) -> None:
|
||||
"""
|
||||
Add addresses used for created control networks,
|
||||
|
||||
|
@ -777,7 +797,7 @@ class CtrlNet(CoreNetwork):
|
|||
net_client = get_net_client(use_ovs, server.remote_cmd)
|
||||
net_client.create_address(self.brname, current)
|
||||
|
||||
def startup(self):
|
||||
def startup(self) -> None:
|
||||
"""
|
||||
Startup functionality for the control network.
|
||||
|
||||
|
@ -806,7 +826,7 @@ class CtrlNet(CoreNetwork):
|
|||
if self.serverintf:
|
||||
self.net_client.create_interface(self.brname, self.serverintf)
|
||||
|
||||
def shutdown(self):
|
||||
def shutdown(self) -> None:
|
||||
"""
|
||||
Control network shutdown.
|
||||
|
||||
|
@ -835,7 +855,7 @@ class CtrlNet(CoreNetwork):
|
|||
|
||||
super().shutdown()
|
||||
|
||||
def all_link_data(self, flags):
|
||||
def all_link_data(self, flags: int) -> List[LinkData]:
|
||||
"""
|
||||
Do not include CtrlNet in link messages describing this session.
|
||||
|
||||
|
@ -853,11 +873,11 @@ class PtpNet(CoreNetwork):
|
|||
|
||||
policy = "ACCEPT"
|
||||
|
||||
def attach(self, netif):
|
||||
def attach(self, netif: CoreInterface) -> None:
|
||||
"""
|
||||
Attach a network interface, but limit attachment to two interfaces.
|
||||
|
||||
:param core.netns.vif.VEth netif: network interface
|
||||
:param core.nodes.interface.CoreInterface netif: network interface
|
||||
:return: nothing
|
||||
"""
|
||||
if len(self._netif) >= 2:
|
||||
|
@ -866,7 +886,14 @@ class PtpNet(CoreNetwork):
|
|||
)
|
||||
super().attach(netif)
|
||||
|
||||
def data(self, message_type, lat=None, lon=None, alt=None):
|
||||
def data(
|
||||
self,
|
||||
message_type: int,
|
||||
lat: float = None,
|
||||
lon: float = None,
|
||||
alt: float = None,
|
||||
source: str = None,
|
||||
) -> NodeData:
|
||||
"""
|
||||
Do not generate a Node Message for point-to-point links. They are
|
||||
built using a link message instead.
|
||||
|
@ -875,12 +902,13 @@ class PtpNet(CoreNetwork):
|
|||
:param float lat: latitude
|
||||
:param float lon: longitude
|
||||
:param float alt: altitude
|
||||
:param str source: source of node data
|
||||
:return: node data object
|
||||
:rtype: core.emulator.data.NodeData
|
||||
"""
|
||||
return None
|
||||
|
||||
def all_link_data(self, flags):
|
||||
def all_link_data(self, flags: int) -> List[LinkData]:
|
||||
"""
|
||||
Build CORE API TLVs for a point-to-point link. One Link message
|
||||
describes this network.
|
||||
|
@ -997,7 +1025,7 @@ class HubNode(CoreNetwork):
|
|||
policy = "ACCEPT"
|
||||
type = "hub"
|
||||
|
||||
def startup(self):
|
||||
def startup(self) -> None:
|
||||
"""
|
||||
Startup for a hub node, that disables mac learning after normal startup.
|
||||
|
||||
|
@ -1018,8 +1046,14 @@ class WlanNode(CoreNetwork):
|
|||
type = "wlan"
|
||||
|
||||
def __init__(
|
||||
self, session, _id=None, name=None, start=True, server=None, policy=None
|
||||
):
|
||||
self,
|
||||
session: "Session",
|
||||
_id: int = None,
|
||||
name: str = None,
|
||||
start: bool = True,
|
||||
server: "DistributedServer" = None,
|
||||
policy: str = None,
|
||||
) -> None:
|
||||
"""
|
||||
Create a WlanNode instance.
|
||||
|
||||
|
@ -1036,7 +1070,7 @@ class WlanNode(CoreNetwork):
|
|||
self.model = None
|
||||
self.mobility = None
|
||||
|
||||
def startup(self):
|
||||
def startup(self) -> None:
|
||||
"""
|
||||
Startup for a wlan node, that disables mac learning after normal startup.
|
||||
|
||||
|
@ -1045,11 +1079,11 @@ class WlanNode(CoreNetwork):
|
|||
super().startup()
|
||||
self.net_client.disable_mac_learning(self.brname)
|
||||
|
||||
def attach(self, netif):
|
||||
def attach(self, netif: CoreInterface) -> None:
|
||||
"""
|
||||
Attach a network interface.
|
||||
|
||||
:param core.nodes.interface.Veth netif: network interface
|
||||
:param core.nodes.interface.CoreInterface netif: network interface
|
||||
:return: nothing
|
||||
"""
|
||||
super().attach(netif)
|
||||
|
@ -1061,7 +1095,7 @@ class WlanNode(CoreNetwork):
|
|||
# invokes any netif.poshook
|
||||
netif.setposition(x, y, z)
|
||||
|
||||
def setmodel(self, model, config):
|
||||
def setmodel(self, model: WirelessModelType, config: Dict[str, str]):
|
||||
"""
|
||||
Sets the mobility and wireless model.
|
||||
|
||||
|
@ -1082,12 +1116,12 @@ class WlanNode(CoreNetwork):
|
|||
self.mobility = model(session=self.session, _id=self.id)
|
||||
self.mobility.update_config(config)
|
||||
|
||||
def update_mobility(self, config):
|
||||
def update_mobility(self, config: Dict[str, str]) -> None:
|
||||
if not self.mobility:
|
||||
raise ValueError(f"no mobility set to update for node({self.id})")
|
||||
self.mobility.update_config(config)
|
||||
|
||||
def updatemodel(self, config):
|
||||
def updatemodel(self, config: Dict[str, str]) -> None:
|
||||
if not self.model:
|
||||
raise ValueError(f"no model set to update for node({self.id})")
|
||||
logging.debug(
|
||||
|
@ -1099,7 +1133,7 @@ class WlanNode(CoreNetwork):
|
|||
x, y, z = netif.node.position.get()
|
||||
netif.poshook(netif, x, y, z)
|
||||
|
||||
def all_link_data(self, flags):
|
||||
def all_link_data(self, flags: int) -> List[LinkData]:
|
||||
"""
|
||||
Retrieve all link data.
|
||||
|
||||
|
|
|
@ -5,20 +5,31 @@ PhysicalNode class for including real systems in the emulated network.
|
|||
import logging
|
||||
import os
|
||||
import threading
|
||||
from typing import IO, TYPE_CHECKING, List, Optional
|
||||
|
||||
from core import utils
|
||||
from core.constants import MOUNT_BIN, UMOUNT_BIN
|
||||
from core.emulator.distributed import DistributedServer
|
||||
from core.emulator.enumerations import NodeTypes
|
||||
from core.errors import CoreCommandError, CoreError
|
||||
from core.nodes.base import CoreNodeBase
|
||||
from core.nodes.interface import CoreInterface
|
||||
from core.nodes.base import CoreNetworkBase, CoreNodeBase
|
||||
from core.nodes.interface import CoreInterface, Veth
|
||||
from core.nodes.network import CoreNetwork, GreTap
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from core.emulator.session import Session
|
||||
|
||||
|
||||
class PhysicalNode(CoreNodeBase):
|
||||
def __init__(
|
||||
self, session, _id=None, name=None, nodedir=None, start=True, server=None
|
||||
):
|
||||
self,
|
||||
session,
|
||||
_id: int = None,
|
||||
name: str = None,
|
||||
nodedir: str = None,
|
||||
start: bool = True,
|
||||
server: DistributedServer = None,
|
||||
) -> None:
|
||||
super().__init__(session, _id, name, start, server)
|
||||
if not self.server:
|
||||
raise CoreError("physical nodes must be assigned to a remote server")
|
||||
|
@ -29,11 +40,11 @@ class PhysicalNode(CoreNodeBase):
|
|||
if start:
|
||||
self.startup()
|
||||
|
||||
def startup(self):
|
||||
def startup(self) -> None:
|
||||
with self.lock:
|
||||
self.makenodedir()
|
||||
|
||||
def shutdown(self):
|
||||
def shutdown(self) -> None:
|
||||
if not self.up:
|
||||
return
|
||||
|
||||
|
@ -47,7 +58,7 @@ class PhysicalNode(CoreNodeBase):
|
|||
|
||||
self.rmnodedir()
|
||||
|
||||
def termcmdstring(self, sh="/bin/sh"):
|
||||
def termcmdstring(self, sh: str = "/bin/sh") -> str:
|
||||
"""
|
||||
Create a terminal command string.
|
||||
|
||||
|
@ -56,7 +67,7 @@ class PhysicalNode(CoreNodeBase):
|
|||
"""
|
||||
return sh
|
||||
|
||||
def sethwaddr(self, ifindex, addr):
|
||||
def sethwaddr(self, ifindex: int, addr: str) -> None:
|
||||
"""
|
||||
Set hardware address for an interface.
|
||||
|
||||
|
@ -71,7 +82,7 @@ class PhysicalNode(CoreNodeBase):
|
|||
if self.up:
|
||||
self.net_client.device_mac(interface.name, addr)
|
||||
|
||||
def addaddr(self, ifindex, addr):
|
||||
def addaddr(self, ifindex: int, addr: str) -> None:
|
||||
"""
|
||||
Add an address to an interface.
|
||||
|
||||
|
@ -85,9 +96,13 @@ class PhysicalNode(CoreNodeBase):
|
|||
self.net_client.create_address(interface.name, addr)
|
||||
interface.addaddr(addr)
|
||||
|
||||
def deladdr(self, ifindex, addr):
|
||||
def deladdr(self, ifindex: int, addr: str) -> None:
|
||||
"""
|
||||
Delete an address from an interface.
|
||||
|
||||
:param int ifindex: index of interface to delete
|
||||
:param str addr: address to delete
|
||||
:return: nothing
|
||||
"""
|
||||
interface = self._netif[ifindex]
|
||||
|
||||
|
@ -99,7 +114,9 @@ class PhysicalNode(CoreNodeBase):
|
|||
if self.up:
|
||||
self.net_client.delete_address(interface.name, str(addr))
|
||||
|
||||
def adoptnetif(self, netif, ifindex, hwaddr, addrlist):
|
||||
def adoptnetif(
|
||||
self, netif: CoreInterface, ifindex: int, hwaddr: str, addrlist: List[str]
|
||||
) -> None:
|
||||
"""
|
||||
When a link message is received linking this node to another part of
|
||||
the emulation, no new interface is created; instead, adopt the
|
||||
|
@ -127,18 +144,17 @@ class PhysicalNode(CoreNodeBase):
|
|||
|
||||
def linkconfig(
|
||||
self,
|
||||
netif,
|
||||
bw=None,
|
||||
delay=None,
|
||||
loss=None,
|
||||
duplicate=None,
|
||||
jitter=None,
|
||||
netif2=None,
|
||||
):
|
||||
netif: CoreInterface,
|
||||
bw: float = None,
|
||||
delay: float = None,
|
||||
loss: float = None,
|
||||
duplicate: float = None,
|
||||
jitter: float = None,
|
||||
netif2: CoreInterface = None,
|
||||
) -> None:
|
||||
"""
|
||||
Apply tc queing disciplines using LxBrNet.linkconfig()
|
||||
Apply tc queing disciplines using linkconfig.
|
||||
"""
|
||||
# borrow the tc qdisc commands from LxBrNet.linkconfig()
|
||||
linux_bridge = CoreNetwork(session=self.session, start=False)
|
||||
linux_bridge.up = True
|
||||
linux_bridge.linkconfig(
|
||||
|
@ -152,7 +168,7 @@ class PhysicalNode(CoreNodeBase):
|
|||
)
|
||||
del linux_bridge
|
||||
|
||||
def newifindex(self):
|
||||
def newifindex(self) -> int:
|
||||
with self.lock:
|
||||
while self.ifindex in self._netif:
|
||||
self.ifindex += 1
|
||||
|
@ -160,7 +176,14 @@ class PhysicalNode(CoreNodeBase):
|
|||
self.ifindex += 1
|
||||
return ifindex
|
||||
|
||||
def newnetif(self, net=None, addrlist=None, hwaddr=None, ifindex=None, ifname=None):
|
||||
def newnetif(
|
||||
self,
|
||||
net: Veth = None,
|
||||
addrlist: List[str] = None,
|
||||
hwaddr: str = None,
|
||||
ifindex: int = None,
|
||||
ifname: str = None,
|
||||
) -> int:
|
||||
logging.info("creating interface")
|
||||
if not addrlist:
|
||||
addrlist = []
|
||||
|
@ -186,7 +209,7 @@ class PhysicalNode(CoreNodeBase):
|
|||
self.adoptnetif(netif, ifindex, hwaddr, addrlist)
|
||||
return ifindex
|
||||
|
||||
def privatedir(self, path):
|
||||
def privatedir(self, path: str) -> None:
|
||||
if path[0] != "/":
|
||||
raise ValueError(f"path not fully qualified: {path}")
|
||||
hostpath = os.path.join(
|
||||
|
@ -195,21 +218,21 @@ class PhysicalNode(CoreNodeBase):
|
|||
os.mkdir(hostpath)
|
||||
self.mount(hostpath, path)
|
||||
|
||||
def mount(self, source, target):
|
||||
def mount(self, source: str, target: str) -> None:
|
||||
source = os.path.abspath(source)
|
||||
logging.info("mounting %s at %s", source, target)
|
||||
os.makedirs(target)
|
||||
self.host_cmd(f"{MOUNT_BIN} --bind {source} {target}", cwd=self.nodedir)
|
||||
self._mounts.append((source, target))
|
||||
|
||||
def umount(self, target):
|
||||
def umount(self, target: str) -> None:
|
||||
logging.info("unmounting '%s'", target)
|
||||
try:
|
||||
self.host_cmd(f"{UMOUNT_BIN} -l {target}", cwd=self.nodedir)
|
||||
except CoreCommandError:
|
||||
logging.exception("unmounting failed for %s", target)
|
||||
|
||||
def opennodefile(self, filename, mode="w"):
|
||||
def opennodefile(self, filename: str, mode: str = "w") -> IO:
|
||||
dirname, basename = os.path.split(filename)
|
||||
if not basename:
|
||||
raise ValueError("no basename for filename: " + filename)
|
||||
|
@ -225,13 +248,13 @@ class PhysicalNode(CoreNodeBase):
|
|||
hostfilename = os.path.join(dirname, basename)
|
||||
return open(hostfilename, mode)
|
||||
|
||||
def nodefile(self, filename, contents, mode=0o644):
|
||||
def nodefile(self, filename: str, contents: str, mode: int = 0o644) -> None:
|
||||
with self.opennodefile(filename, "w") as node_file:
|
||||
node_file.write(contents)
|
||||
os.chmod(node_file.name, mode)
|
||||
logging.info("created nodefile: '%s'; mode: 0%o", node_file.name, mode)
|
||||
|
||||
def cmd(self, args, wait=True):
|
||||
def cmd(self, args: str, wait: bool = True, shell: bool = False) -> str:
|
||||
return self.host_cmd(args, wait=wait)
|
||||
|
||||
|
||||
|
@ -244,7 +267,15 @@ class Rj45Node(CoreNodeBase, CoreInterface):
|
|||
apitype = NodeTypes.RJ45.value
|
||||
type = "rj45"
|
||||
|
||||
def __init__(self, session, _id=None, name=None, mtu=1500, start=True, server=None):
|
||||
def __init__(
|
||||
self,
|
||||
session: "Session",
|
||||
_id: int = None,
|
||||
name: str = None,
|
||||
mtu: int = 1500,
|
||||
start: bool = True,
|
||||
server: DistributedServer = None,
|
||||
) -> None:
|
||||
"""
|
||||
Create an RJ45Node instance.
|
||||
|
||||
|
@ -270,7 +301,7 @@ class Rj45Node(CoreNodeBase, CoreInterface):
|
|||
if start:
|
||||
self.startup()
|
||||
|
||||
def startup(self):
|
||||
def startup(self) -> None:
|
||||
"""
|
||||
Set the interface in the up state.
|
||||
|
||||
|
@ -282,7 +313,7 @@ class Rj45Node(CoreNodeBase, CoreInterface):
|
|||
self.net_client.device_up(self.localname)
|
||||
self.up = True
|
||||
|
||||
def shutdown(self):
|
||||
def shutdown(self) -> None:
|
||||
"""
|
||||
Bring the interface down. Remove any addresses and queuing
|
||||
disciplines.
|
||||
|
@ -304,18 +335,18 @@ class Rj45Node(CoreNodeBase, CoreInterface):
|
|||
|
||||
# TODO: issue in that both classes inherited from provide the same method with
|
||||
# different signatures
|
||||
def attachnet(self, net):
|
||||
def attachnet(self, net: CoreNetworkBase) -> None:
|
||||
"""
|
||||
Attach a network.
|
||||
|
||||
:param core.coreobj.PyCoreNet net: network to attach
|
||||
:param core.nodes.base.CoreNetworkBase net: network to attach
|
||||
:return: nothing
|
||||
"""
|
||||
CoreInterface.attachnet(self, net)
|
||||
|
||||
# TODO: issue in that both classes inherited from provide the same method with
|
||||
# different signatures
|
||||
def detachnet(self):
|
||||
def detachnet(self) -> None:
|
||||
"""
|
||||
Detach a network.
|
||||
|
||||
|
@ -323,7 +354,14 @@ class Rj45Node(CoreNodeBase, CoreInterface):
|
|||
"""
|
||||
CoreInterface.detachnet(self)
|
||||
|
||||
def newnetif(self, net=None, addrlist=None, hwaddr=None, ifindex=None, ifname=None):
|
||||
def newnetif(
|
||||
self,
|
||||
net: CoreNetworkBase = None,
|
||||
addrlist: List[str] = None,
|
||||
hwaddr: str = None,
|
||||
ifindex: int = None,
|
||||
ifname: str = None,
|
||||
) -> int:
|
||||
"""
|
||||
This is called when linking with another node. Since this node
|
||||
represents an interface, we do not create another object here,
|
||||
|
@ -359,7 +397,7 @@ class Rj45Node(CoreNodeBase, CoreInterface):
|
|||
|
||||
return ifindex
|
||||
|
||||
def delnetif(self, ifindex):
|
||||
def delnetif(self, ifindex: int) -> None:
|
||||
"""
|
||||
Delete a network interface.
|
||||
|
||||
|
@ -376,7 +414,9 @@ class Rj45Node(CoreNodeBase, CoreInterface):
|
|||
else:
|
||||
raise ValueError(f"ifindex {ifindex} does not exist")
|
||||
|
||||
def netif(self, ifindex, net=None):
|
||||
def netif(
|
||||
self, ifindex: int, net: CoreNetworkBase = None
|
||||
) -> Optional[CoreInterface]:
|
||||
"""
|
||||
This object is considered the network interface, so we only
|
||||
return self here. This keeps the RJ45Node compatible with
|
||||
|
@ -398,20 +438,20 @@ class Rj45Node(CoreNodeBase, CoreInterface):
|
|||
|
||||
return None
|
||||
|
||||
def getifindex(self, netif):
|
||||
def getifindex(self, netif: CoreInterface) -> Optional[int]:
|
||||
"""
|
||||
Retrieve network interface index.
|
||||
|
||||
:param core.nodes.interface.CoreInterface netif: network interface to retrieve index for
|
||||
:param core.nodes.interface.CoreInterface netif: network interface to retrieve
|
||||
index for
|
||||
:return: interface index, None otherwise
|
||||
:rtype: int
|
||||
"""
|
||||
if netif != self:
|
||||
return None
|
||||
|
||||
return self.ifindex
|
||||
|
||||
def addaddr(self, addr):
|
||||
def addaddr(self, addr: str) -> None:
|
||||
"""
|
||||
Add address to to network interface.
|
||||
|
||||
|
@ -424,7 +464,7 @@ class Rj45Node(CoreNodeBase, CoreInterface):
|
|||
self.net_client.create_address(self.name, addr)
|
||||
CoreInterface.addaddr(self, addr)
|
||||
|
||||
def deladdr(self, addr):
|
||||
def deladdr(self, addr: str) -> None:
|
||||
"""
|
||||
Delete address from network interface.
|
||||
|
||||
|
@ -434,10 +474,9 @@ class Rj45Node(CoreNodeBase, CoreInterface):
|
|||
"""
|
||||
if self.up:
|
||||
self.net_client.delete_address(self.name, str(addr))
|
||||
|
||||
CoreInterface.deladdr(self, addr)
|
||||
|
||||
def savestate(self):
|
||||
def savestate(self) -> None:
|
||||
"""
|
||||
Save the addresses and other interface state before using the
|
||||
interface for emulation purposes. TODO: save/restore the PROMISC flag
|
||||
|
@ -464,7 +503,7 @@ class Rj45Node(CoreNodeBase, CoreInterface):
|
|||
continue
|
||||
self.old_addrs.append((items[1], None))
|
||||
|
||||
def restorestate(self):
|
||||
def restorestate(self) -> None:
|
||||
"""
|
||||
Restore the addresses and other interface state after using it.
|
||||
|
||||
|
@ -482,7 +521,7 @@ class Rj45Node(CoreNodeBase, CoreInterface):
|
|||
if self.old_up:
|
||||
self.net_client.device_up(self.localname)
|
||||
|
||||
def setposition(self, x=None, y=None, z=None):
|
||||
def setposition(self, x: float = None, y: float = None, z: float = None) -> bool:
|
||||
"""
|
||||
Uses setposition from both parent classes.
|
||||
|
||||
|
@ -496,7 +535,7 @@ class Rj45Node(CoreNodeBase, CoreInterface):
|
|||
CoreInterface.setposition(self, x, y, z)
|
||||
return result
|
||||
|
||||
def termcmdstring(self, sh):
|
||||
def termcmdstring(self, sh: str) -> str:
|
||||
"""
|
||||
Create a terminal command string.
|
||||
|
||||
|
|
Loading…
Reference in a new issue