daemon: adjustments to revamp how core nodes are created in session.add_node, nodes now provide a create_options function for node specific options that are type hinted
This commit is contained in:
parent
03e646031c
commit
2e3e085522
35 changed files with 646 additions and 478 deletions
|
@ -5,6 +5,7 @@ import abc
|
|||
import logging
|
||||
import shutil
|
||||
import threading
|
||||
from dataclasses import dataclass, field
|
||||
from pathlib import Path
|
||||
from threading import RLock
|
||||
from typing import TYPE_CHECKING, Dict, List, Optional, Tuple, Type, Union
|
||||
|
@ -33,6 +34,94 @@ if TYPE_CHECKING:
|
|||
PRIVATE_DIRS: List[Path] = [Path("/var/run"), Path("/var/log")]
|
||||
|
||||
|
||||
@dataclass
|
||||
class Position:
|
||||
"""
|
||||
Helper class for Cartesian coordinate position
|
||||
"""
|
||||
|
||||
x: float = 0.0
|
||||
y: float = 0.0
|
||||
z: float = 0.0
|
||||
lon: float = None
|
||||
lat: float = None
|
||||
alt: float = None
|
||||
|
||||
def set(self, x: float = None, y: float = None, z: float = None) -> bool:
|
||||
"""
|
||||
Returns True if the position has actually changed.
|
||||
|
||||
:param x: x position
|
||||
:param y: y position
|
||||
:param z: z position
|
||||
:return: True if position changed, False otherwise
|
||||
"""
|
||||
if self.x == x and self.y == y and self.z == z:
|
||||
return False
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.z = z
|
||||
return True
|
||||
|
||||
def get(self) -> Tuple[float, float, float]:
|
||||
"""
|
||||
Retrieve x,y,z position.
|
||||
|
||||
:return: x,y,z position tuple
|
||||
"""
|
||||
return self.x, self.y, self.z
|
||||
|
||||
def has_geo(self) -> bool:
|
||||
return all(x is not None for x in [self.lon, self.lat, self.alt])
|
||||
|
||||
def set_geo(self, lon: float, lat: float, alt: float) -> None:
|
||||
"""
|
||||
Set geo position lon, lat, alt.
|
||||
|
||||
:param lon: longitude value
|
||||
:param lat: latitude value
|
||||
:param alt: altitude value
|
||||
:return: nothing
|
||||
"""
|
||||
self.lon = lon
|
||||
self.lat = lat
|
||||
self.alt = alt
|
||||
|
||||
def get_geo(self) -> Tuple[float, float, float]:
|
||||
"""
|
||||
Retrieve current geo position lon, lat, alt.
|
||||
|
||||
:return: lon, lat, alt position tuple
|
||||
"""
|
||||
return self.lon, self.lat, self.alt
|
||||
|
||||
|
||||
@dataclass
|
||||
class NodeOptions:
|
||||
"""
|
||||
Base options for configuring a node.
|
||||
"""
|
||||
|
||||
canvas: int = None
|
||||
"""id of canvas for display within gui"""
|
||||
icon: str = None
|
||||
"""custom icon for display, None for default"""
|
||||
|
||||
|
||||
@dataclass
|
||||
class CoreNodeOptions(NodeOptions):
|
||||
model: str = "PC"
|
||||
"""model is used for providing a default set of services"""
|
||||
services: List[str] = field(default_factory=list)
|
||||
"""services to start within node"""
|
||||
config_services: List[str] = field(default_factory=list)
|
||||
"""config services to start within node"""
|
||||
directory: Path = None
|
||||
"""directory to define node, defaults to path under the session directory"""
|
||||
legacy: bool = False
|
||||
"""legacy nodes default to standard services"""
|
||||
|
||||
|
||||
class NodeBase(abc.ABC):
|
||||
"""
|
||||
Base class for CORE nodes (nodes and networks)
|
||||
|
@ -44,6 +133,7 @@ class NodeBase(abc.ABC):
|
|||
_id: int = None,
|
||||
name: str = None,
|
||||
server: "DistributedServer" = None,
|
||||
options: NodeOptions = None,
|
||||
) -> None:
|
||||
"""
|
||||
Creates a NodeBase instance.
|
||||
|
@ -53,26 +143,29 @@ class NodeBase(abc.ABC):
|
|||
:param name: object name
|
||||
:param server: remote server node
|
||||
will run on, default is None for localhost
|
||||
:param options: options to create node with
|
||||
"""
|
||||
|
||||
self.session: "Session" = session
|
||||
if _id is None:
|
||||
_id = session.next_node_id()
|
||||
self.id: int = _id
|
||||
self.name: str = name or f"o{self.id}"
|
||||
self.id: int = _id if _id is not None else self.session.next_node_id()
|
||||
self.name: str = name or f"{self.__class__.__name__}{self.id}"
|
||||
self.server: "DistributedServer" = server
|
||||
self.model: Optional[str] = None
|
||||
self.services: CoreServices = []
|
||||
self.ifaces: Dict[int, CoreInterface] = {}
|
||||
self.iface_id: int = 0
|
||||
self.canvas: Optional[int] = None
|
||||
self.icon: Optional[str] = None
|
||||
self.position: Position = Position()
|
||||
self.up: bool = False
|
||||
self.lock: RLock = RLock()
|
||||
self.net_client: LinuxNetClient = get_net_client(
|
||||
self.session.use_ovs(), self.host_cmd
|
||||
)
|
||||
options = options if options else NodeOptions()
|
||||
self.canvas: Optional[int] = options.canvas
|
||||
self.icon: Optional[str] = options.icon
|
||||
|
||||
@classmethod
|
||||
def create_options(cls) -> NodeOptions:
|
||||
return NodeOptions()
|
||||
|
||||
@abc.abstractmethod
|
||||
def startup(self) -> None:
|
||||
|
@ -288,6 +381,7 @@ class CoreNodeBase(NodeBase):
|
|||
_id: int = None,
|
||||
name: str = None,
|
||||
server: "DistributedServer" = None,
|
||||
options: NodeOptions = None,
|
||||
) -> None:
|
||||
"""
|
||||
Create a CoreNodeBase instance.
|
||||
|
@ -298,7 +392,7 @@ class CoreNodeBase(NodeBase):
|
|||
:param server: remote server node
|
||||
will run on, default is None for localhost
|
||||
"""
|
||||
super().__init__(session, _id, name, server)
|
||||
super().__init__(session, _id, name, server, options)
|
||||
self.config_services: Dict[str, "ConfigService"] = {}
|
||||
self.directory: Optional[Path] = None
|
||||
self.tmpnodedir: bool = False
|
||||
|
@ -460,8 +554,8 @@ class CoreNode(CoreNodeBase):
|
|||
session: "Session",
|
||||
_id: int = None,
|
||||
name: str = None,
|
||||
directory: Path = None,
|
||||
server: "DistributedServer" = None,
|
||||
options: CoreNodeOptions = None,
|
||||
) -> None:
|
||||
"""
|
||||
Create a CoreNode instance.
|
||||
|
@ -469,18 +563,37 @@ class CoreNode(CoreNodeBase):
|
|||
:param session: core session instance
|
||||
:param _id: object id
|
||||
:param name: object name
|
||||
:param directory: node directory
|
||||
:param server: remote server node
|
||||
will run on, default is None for localhost
|
||||
:param options: options to create node with
|
||||
"""
|
||||
super().__init__(session, _id, name, server)
|
||||
self.directory: Optional[Path] = directory
|
||||
options = options or CoreNodeOptions()
|
||||
super().__init__(session, _id, name, server, options)
|
||||
self.directory: Optional[Path] = options.directory
|
||||
self.ctrlchnlname: Path = self.session.directory / self.name
|
||||
self.pid: Optional[int] = None
|
||||
self._mounts: List[Tuple[Path, Path]] = []
|
||||
self.node_net_client: LinuxNetClient = self.create_node_net_client(
|
||||
self.session.use_ovs()
|
||||
)
|
||||
options = options or CoreNodeOptions()
|
||||
self.model: Optional[str] = options.model
|
||||
# setup services
|
||||
if options.legacy or options.services:
|
||||
logger.debug("set node type: %s", self.model)
|
||||
self.session.services.add_services(self, self.model, options.services)
|
||||
# add config services
|
||||
config_services = options.config_services
|
||||
if not options.legacy and not config_services and not options.services:
|
||||
config_services = self.session.services.default_services.get(self.model, [])
|
||||
logger.info("setting node config services: %s", config_services)
|
||||
for name in config_services:
|
||||
service_class = self.session.service_manager.get_service(name)
|
||||
self.add_config_service(service_class)
|
||||
|
||||
@classmethod
|
||||
def create_options(cls) -> CoreNodeOptions:
|
||||
return CoreNodeOptions()
|
||||
|
||||
def create_node_net_client(self, use_ovs: bool) -> LinuxNetClient:
|
||||
"""
|
||||
|
@ -797,6 +910,7 @@ class CoreNetworkBase(NodeBase):
|
|||
_id: int,
|
||||
name: str,
|
||||
server: "DistributedServer" = None,
|
||||
options: NodeOptions = None,
|
||||
) -> None:
|
||||
"""
|
||||
Create a CoreNetworkBase instance.
|
||||
|
@ -806,9 +920,11 @@ class CoreNetworkBase(NodeBase):
|
|||
:param name: object name
|
||||
:param server: remote server node
|
||||
will run on, default is None for localhost
|
||||
:param options: options to create node with
|
||||
"""
|
||||
super().__init__(session, _id, name, server)
|
||||
self.mtu: int = DEFAULT_MTU
|
||||
super().__init__(session, _id, name, server, options)
|
||||
mtu = self.session.options.get_int("mtu")
|
||||
self.mtu: int = mtu if mtu > 0 else DEFAULT_MTU
|
||||
self.brname: Optional[str] = None
|
||||
self.linked: Dict[CoreInterface, Dict[CoreInterface, bool]] = {}
|
||||
self.linked_lock: threading.Lock = threading.Lock()
|
||||
|
@ -839,69 +955,3 @@ class CoreNetworkBase(NodeBase):
|
|||
iface.net_id = None
|
||||
with self.linked_lock:
|
||||
del self.linked[iface]
|
||||
|
||||
|
||||
class Position:
|
||||
"""
|
||||
Helper class for Cartesian coordinate position
|
||||
"""
|
||||
|
||||
def __init__(self, x: float = None, y: float = None, z: float = None) -> None:
|
||||
"""
|
||||
Creates a Position instance.
|
||||
|
||||
:param x: x position
|
||||
:param y: y position
|
||||
:param z: z position
|
||||
"""
|
||||
self.x: float = x
|
||||
self.y: float = y
|
||||
self.z: float = z
|
||||
self.lon: Optional[float] = None
|
||||
self.lat: Optional[float] = None
|
||||
self.alt: Optional[float] = None
|
||||
|
||||
def set(self, x: float = None, y: float = None, z: float = None) -> bool:
|
||||
"""
|
||||
Returns True if the position has actually changed.
|
||||
|
||||
:param x: x position
|
||||
:param y: y position
|
||||
:param z: z position
|
||||
:return: True if position changed, False otherwise
|
||||
"""
|
||||
if self.x == x and self.y == y and self.z == z:
|
||||
return False
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.z = z
|
||||
return True
|
||||
|
||||
def get(self) -> Tuple[float, float, float]:
|
||||
"""
|
||||
Retrieve x,y,z position.
|
||||
|
||||
:return: x,y,z position tuple
|
||||
"""
|
||||
return self.x, self.y, self.z
|
||||
|
||||
def set_geo(self, lon: float, lat: float, alt: float) -> None:
|
||||
"""
|
||||
Set geo position lon, lat, alt.
|
||||
|
||||
:param lon: longitude value
|
||||
:param lat: latitude value
|
||||
:param alt: altitude value
|
||||
:return: nothing
|
||||
"""
|
||||
self.lon = lon
|
||||
self.lat = lat
|
||||
self.alt = alt
|
||||
|
||||
def get_geo(self) -> Tuple[float, float, float]:
|
||||
"""
|
||||
Retrieve current geo position lon, lat, alt.
|
||||
|
||||
:return: lon, lat, alt position tuple
|
||||
"""
|
||||
return self.lon, self.lat, self.alt
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import json
|
||||
import logging
|
||||
import shlex
|
||||
from dataclasses import dataclass
|
||||
from dataclasses import dataclass, field
|
||||
from pathlib import Path
|
||||
from tempfile import NamedTemporaryFile
|
||||
from typing import TYPE_CHECKING, Dict, List, Tuple
|
||||
|
@ -9,7 +9,7 @@ from typing import TYPE_CHECKING, Dict, List, Tuple
|
|||
from core.emulator.distributed import DistributedServer
|
||||
from core.errors import CoreCommandError, CoreError
|
||||
from core.executables import BASH
|
||||
from core.nodes.base import CoreNode
|
||||
from core.nodes.base import CoreNode, CoreNodeOptions
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
@ -19,6 +19,21 @@ if TYPE_CHECKING:
|
|||
DOCKER: str = "docker"
|
||||
|
||||
|
||||
@dataclass
|
||||
class DockerOptions(CoreNodeOptions):
|
||||
image: str = "ubuntu"
|
||||
"""image used when creating container"""
|
||||
binds: List[Tuple[str, str]] = field(default_factory=list)
|
||||
"""bind mount source and destinations to setup within container"""
|
||||
volumes: List[Tuple[str, str, bool, bool]] = field(default_factory=list)
|
||||
"""
|
||||
volume mount source, destination, unique, delete to setup within container
|
||||
|
||||
unique is True for node unique volume naming
|
||||
delete is True for deleting volume mount during shutdown
|
||||
"""
|
||||
|
||||
|
||||
@dataclass
|
||||
class DockerVolume:
|
||||
src: str
|
||||
|
@ -38,11 +53,8 @@ class DockerNode(CoreNode):
|
|||
session: "Session",
|
||||
_id: int = None,
|
||||
name: str = None,
|
||||
directory: str = None,
|
||||
server: DistributedServer = None,
|
||||
image: str = None,
|
||||
binds: List[Tuple[str, str]] = None,
|
||||
volumes: List[Tuple[str, str, bool, bool]] = None,
|
||||
options: DockerOptions = None,
|
||||
) -> None:
|
||||
"""
|
||||
Create a DockerNode instance.
|
||||
|
@ -50,22 +62,23 @@ class DockerNode(CoreNode):
|
|||
:param session: core session instance
|
||||
:param _id: object id
|
||||
:param name: object name
|
||||
:param directory: node directory
|
||||
:param server: remote server node
|
||||
will run on, default is None for localhost
|
||||
:param image: image to start container with
|
||||
:param binds: bind mounts to set for the created container
|
||||
:param volumes: volume mount settings to set for the created container
|
||||
:param options: options for creating node
|
||||
"""
|
||||
super().__init__(session, _id, name, directory, server)
|
||||
self.image: str = image if image is not None else "ubuntu"
|
||||
self.binds: List[Tuple[str, str]] = binds or []
|
||||
options = options or DockerOptions()
|
||||
super().__init__(session, _id, name, server, options)
|
||||
self.image: str = options.image
|
||||
self.binds: List[Tuple[str, str]] = options.binds
|
||||
self.volumes: Dict[str, DockerVolume] = {}
|
||||
volumes = volumes or []
|
||||
for src, dst, unique, delete in volumes:
|
||||
for src, dst, unique, delete in options.volumes:
|
||||
src_name = self._unique_name(src) if unique else src
|
||||
self.volumes[src] = DockerVolume(src_name, dst, unique, delete)
|
||||
|
||||
@classmethod
|
||||
def create_options(cls) -> DockerOptions:
|
||||
return DockerOptions()
|
||||
|
||||
def _create_cmd(self, args: str, shell: bool = False) -> str:
|
||||
"""
|
||||
Create command used to run commands within the context of a node.
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
import json
|
||||
import logging
|
||||
import time
|
||||
from dataclasses import dataclass, field
|
||||
from pathlib import Path
|
||||
from tempfile import NamedTemporaryFile
|
||||
from typing import TYPE_CHECKING, Callable, Dict, Optional
|
||||
from typing import TYPE_CHECKING, Callable, Dict, List, Optional, Tuple
|
||||
|
||||
from core import utils
|
||||
from core.emulator.data import InterfaceData, LinkOptions
|
||||
from core.emulator.distributed import DistributedServer
|
||||
from core.errors import CoreCommandError
|
||||
from core.nodes.base import CoreNode
|
||||
from core.nodes.base import CoreNode, CoreNodeOptions
|
||||
from core.nodes.interface import CoreInterface
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
@ -66,15 +67,29 @@ class LxdClient:
|
|||
self.run(args)
|
||||
|
||||
|
||||
@dataclass
|
||||
class LxcOptions(CoreNodeOptions):
|
||||
image: str = "ubuntu"
|
||||
"""image used when creating container"""
|
||||
binds: List[Tuple[str, str]] = field(default_factory=list)
|
||||
"""bind mount source and destinations to setup within container"""
|
||||
volumes: List[Tuple[str, str, bool, bool]] = field(default_factory=list)
|
||||
"""
|
||||
volume mount source, destination, unique, delete to setup within container
|
||||
|
||||
unique is True for node unique volume naming
|
||||
delete is True for deleting volume mount during shutdown
|
||||
"""
|
||||
|
||||
|
||||
class LxcNode(CoreNode):
|
||||
def __init__(
|
||||
self,
|
||||
session: "Session",
|
||||
_id: int = None,
|
||||
name: str = None,
|
||||
directory: str = None,
|
||||
server: DistributedServer = None,
|
||||
image: str = None,
|
||||
options: LxcOptions = None,
|
||||
) -> None:
|
||||
"""
|
||||
Create a LxcNode instance.
|
||||
|
@ -82,15 +97,19 @@ class LxcNode(CoreNode):
|
|||
:param session: core session instance
|
||||
:param _id: object id
|
||||
:param name: object name
|
||||
:param directory: node directory
|
||||
:param server: remote server node
|
||||
will run on, default is None for localhost
|
||||
:param image: image to start container with
|
||||
:param options: option to create node with
|
||||
"""
|
||||
super().__init__(session, _id, name, directory, server)
|
||||
self.image: str = image if image is not None else "ubuntu"
|
||||
options = options or LxcOptions()
|
||||
super().__init__(session, _id, name, server, options)
|
||||
self.image: str = options.image
|
||||
self.client: Optional[LxdClient] = None
|
||||
|
||||
@classmethod
|
||||
def create_options(cls) -> LxcOptions:
|
||||
return LxcOptions()
|
||||
|
||||
def alive(self) -> bool:
|
||||
"""
|
||||
Check if the node is alive.
|
||||
|
|
|
@ -4,6 +4,7 @@ Defines network nodes used within core.
|
|||
|
||||
import logging
|
||||
import threading
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING, Dict, List, Optional, Type
|
||||
|
||||
|
@ -14,7 +15,7 @@ from core.emulator.data import InterfaceData, LinkData
|
|||
from core.emulator.enumerations import MessageFlags, NetworkPolicy, RegisterTlvs
|
||||
from core.errors import CoreCommandError, CoreError
|
||||
from core.executables import NFTABLES
|
||||
from core.nodes.base import CoreNetworkBase
|
||||
from core.nodes.base import CoreNetworkBase, NodeOptions
|
||||
from core.nodes.interface import CoreInterface, GreTap
|
||||
from core.nodes.netclient import get_net_client
|
||||
|
||||
|
@ -180,6 +181,12 @@ class NftablesQueue:
|
|||
nft_queue: NftablesQueue = NftablesQueue()
|
||||
|
||||
|
||||
@dataclass
|
||||
class NetworkOptions(NodeOptions):
|
||||
policy: NetworkPolicy = None
|
||||
"""allows overriding the network policy, otherwise uses class defined default"""
|
||||
|
||||
|
||||
class CoreNetwork(CoreNetworkBase):
|
||||
"""
|
||||
Provides linux bridge network functionality for core nodes.
|
||||
|
@ -193,7 +200,7 @@ class CoreNetwork(CoreNetworkBase):
|
|||
_id: int = None,
|
||||
name: str = None,
|
||||
server: "DistributedServer" = None,
|
||||
policy: NetworkPolicy = None,
|
||||
options: NetworkOptions = None,
|
||||
) -> None:
|
||||
"""
|
||||
Creates a CoreNetwork instance.
|
||||
|
@ -203,18 +210,19 @@ class CoreNetwork(CoreNetworkBase):
|
|||
:param name: object name
|
||||
:param server: remote server node
|
||||
will run on, default is None for localhost
|
||||
:param policy: network policy
|
||||
:param options: options to create node with
|
||||
"""
|
||||
super().__init__(session, _id, name, server)
|
||||
if name is None:
|
||||
name = str(self.id)
|
||||
if policy is not None:
|
||||
self.policy: NetworkPolicy = policy
|
||||
self.name: Optional[str] = name
|
||||
options = options or NetworkOptions()
|
||||
super().__init__(session, _id, name, server, options)
|
||||
self.policy: NetworkPolicy = options.policy if options.policy else self.policy
|
||||
sessionid = self.session.short_session_id()
|
||||
self.brname: str = f"b.{self.id}.{sessionid}"
|
||||
self.has_nftables_chain: bool = False
|
||||
|
||||
@classmethod
|
||||
def create_options(cls) -> NetworkOptions:
|
||||
return NetworkOptions()
|
||||
|
||||
def host_cmd(
|
||||
self,
|
||||
args: str,
|
||||
|
@ -482,6 +490,20 @@ class GreTapBridge(CoreNetwork):
|
|||
self.add_ips(ips)
|
||||
|
||||
|
||||
@dataclass
|
||||
class CtrlNetOptions(NetworkOptions):
|
||||
prefix: str = None
|
||||
"""ip4 network prefix to use for generating an address"""
|
||||
updown_script: str = None
|
||||
"""script to execute during startup and shutdown"""
|
||||
serverintf: str = None
|
||||
"""used to associate an interface with the control network bridge"""
|
||||
assign_address: bool = True
|
||||
"""used to determine if a specific address should be assign using hostid"""
|
||||
hostid: int = None
|
||||
"""used with assign address to """
|
||||
|
||||
|
||||
class CtrlNet(CoreNetwork):
|
||||
"""
|
||||
Control network functionality.
|
||||
|
@ -500,36 +522,32 @@ class CtrlNet(CoreNetwork):
|
|||
def __init__(
|
||||
self,
|
||||
session: "Session",
|
||||
prefix: str,
|
||||
_id: int = None,
|
||||
name: str = None,
|
||||
hostid: int = None,
|
||||
server: "DistributedServer" = None,
|
||||
assign_address: bool = True,
|
||||
updown_script: str = None,
|
||||
serverintf: str = None,
|
||||
options: CtrlNetOptions = None,
|
||||
) -> None:
|
||||
"""
|
||||
Creates a CtrlNet instance.
|
||||
|
||||
:param session: core session instance
|
||||
:param _id: node id
|
||||
:param name: node namee
|
||||
:param prefix: control network ipv4 prefix
|
||||
:param hostid: host id
|
||||
:param name: node name
|
||||
:param server: remote server node
|
||||
will run on, default is None for localhost
|
||||
:param assign_address: assigned address
|
||||
:param updown_script: updown script
|
||||
:param serverintf: server interface
|
||||
:return:
|
||||
:param options: node options for creation
|
||||
"""
|
||||
self.prefix: netaddr.IPNetwork = netaddr.IPNetwork(prefix).cidr
|
||||
self.hostid: Optional[int] = hostid
|
||||
self.assign_address: bool = assign_address
|
||||
self.updown_script: Optional[str] = updown_script
|
||||
self.serverintf: Optional[str] = serverintf
|
||||
super().__init__(session, _id, name, server)
|
||||
options = options or CtrlNetOptions()
|
||||
super().__init__(session, _id, name, server, options)
|
||||
self.prefix: netaddr.IPNetwork = netaddr.IPNetwork(options.prefix).cidr
|
||||
self.hostid: Optional[int] = options.hostid
|
||||
self.assign_address: bool = options.assign_address
|
||||
self.updown_script: Optional[str] = options.updown_script
|
||||
self.serverintf: Optional[str] = options.serverintf
|
||||
|
||||
@classmethod
|
||||
def create_options(cls) -> CtrlNetOptions:
|
||||
return CtrlNetOptions()
|
||||
|
||||
def add_addresses(self, index: int) -> None:
|
||||
"""
|
||||
|
@ -669,7 +687,7 @@ class WlanNode(CoreNetwork):
|
|||
_id: int = None,
|
||||
name: str = None,
|
||||
server: "DistributedServer" = None,
|
||||
policy: NetworkPolicy = None,
|
||||
options: NetworkOptions = None,
|
||||
) -> None:
|
||||
"""
|
||||
Create a WlanNode instance.
|
||||
|
@ -679,9 +697,9 @@ class WlanNode(CoreNetwork):
|
|||
:param name: node name
|
||||
:param server: remote server node
|
||||
will run on, default is None for localhost
|
||||
:param policy: wlan policy
|
||||
:param options: options to create node with
|
||||
"""
|
||||
super().__init__(session, _id, name, server, policy)
|
||||
super().__init__(session, _id, name, server, options)
|
||||
# wireless and mobility models (BasicRangeModel, Ns2WaypointMobility)
|
||||
self.wireless_model: Optional[WirelessModel] = None
|
||||
self.mobility: Optional[WayPointMobility] = None
|
||||
|
|
|
@ -13,7 +13,7 @@ from core.emulator.distributed import DistributedServer
|
|||
from core.emulator.enumerations import TransportType
|
||||
from core.errors import CoreCommandError, CoreError
|
||||
from core.executables import BASH, TEST, UMOUNT
|
||||
from core.nodes.base import CoreNode, CoreNodeBase
|
||||
from core.nodes.base import CoreNode, CoreNodeBase, CoreNodeOptions, NodeOptions
|
||||
from core.nodes.interface import CoreInterface
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
@ -34,6 +34,7 @@ class Rj45Node(CoreNodeBase):
|
|||
_id: int = None,
|
||||
name: str = None,
|
||||
server: DistributedServer = None,
|
||||
options: NodeOptions = None,
|
||||
) -> None:
|
||||
"""
|
||||
Create an RJ45Node instance.
|
||||
|
@ -43,8 +44,9 @@ class Rj45Node(CoreNodeBase):
|
|||
:param name: node name
|
||||
:param server: remote server node
|
||||
will run on, default is None for localhost
|
||||
:param options: option to create node with
|
||||
"""
|
||||
super().__init__(session, _id, name, server)
|
||||
super().__init__(session, _id, name, server, options)
|
||||
self.iface: CoreInterface = CoreInterface(
|
||||
self.iface_id, name, name, session.use_ovs(), node=self, server=server
|
||||
)
|
||||
|
@ -224,12 +226,12 @@ class PhysicalNode(CoreNode):
|
|||
session: "Session",
|
||||
_id: int = None,
|
||||
name: str = None,
|
||||
directory: Path = None,
|
||||
server: DistributedServer = None,
|
||||
options: CoreNodeOptions = None,
|
||||
) -> None:
|
||||
if not self.server:
|
||||
raise CoreError("physical nodes must be assigned to a remote server")
|
||||
super().__init__(session, _id, name, directory, server)
|
||||
super().__init__(session, _id, name, server, options)
|
||||
|
||||
def startup(self) -> None:
|
||||
with self.lock:
|
||||
|
|
|
@ -14,7 +14,7 @@ from core.emulator.data import LinkData, LinkOptions
|
|||
from core.emulator.enumerations import LinkTypes, MessageFlags
|
||||
from core.errors import CoreError
|
||||
from core.executables import NFTABLES
|
||||
from core.nodes.base import CoreNetworkBase
|
||||
from core.nodes.base import CoreNetworkBase, NodeOptions
|
||||
from core.nodes.interface import CoreInterface
|
||||
|
||||
if TYPE_CHECKING:
|
||||
|
@ -108,8 +108,9 @@ class WirelessNode(CoreNetworkBase):
|
|||
_id: int,
|
||||
name: str,
|
||||
server: "DistributedServer" = None,
|
||||
options: NodeOptions = None,
|
||||
):
|
||||
super().__init__(session, _id, name, server)
|
||||
super().__init__(session, _id, name, server, options)
|
||||
self.bridges: Dict[int, Tuple[CoreInterface, str]] = {}
|
||||
self.links: Dict[Tuple[int, int], WirelessLink] = {}
|
||||
self.position_enabled: bool = CONFIG_ENABLED
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue