added type hinting for core.nodes

This commit is contained in:
Blake Harnden 2020-01-13 14:08:49 -08:00
parent 4e71759ac9
commit c0fcc91d10
10 changed files with 534 additions and 360 deletions

View file

@ -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.