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,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…
Add table
Add a link
Reference in a new issue