2755 Add ability to extend HostNode, NetworkNode, Service and Application outside PrimAITE.
This commit is contained in:
@@ -12,7 +12,9 @@ from primaite import getLogger
|
||||
from primaite.simulator.core import RequestManager, RequestType, SimComponent
|
||||
from primaite.simulator.network.airspace import AirSpace
|
||||
from primaite.simulator.network.hardware.base import Link, Node, WiredNetworkInterface
|
||||
from primaite.simulator.network.hardware.nodes.host.host_node import HostNode
|
||||
from primaite.simulator.network.hardware.nodes.host.server import Printer
|
||||
from primaite.simulator.network.hardware.nodes.network.network_node import NetworkNode
|
||||
from primaite.simulator.system.applications.application import Application
|
||||
from primaite.simulator.system.services.service import Service
|
||||
|
||||
@@ -128,6 +130,16 @@ class Network(SimComponent):
|
||||
def firewall_nodes(self) -> List[Node]:
|
||||
"""The Firewalls in the Network."""
|
||||
return [node for node in self.nodes.values() if node.__class__.__name__ == "Firewall"]
|
||||
|
||||
@property
|
||||
def extended_hostnodes(self) -> List[Node]:
|
||||
"""Extended nodes that inherited HostNode in the network"""
|
||||
return [node for node in self.nodes.values() if node.__class__.__name__.lower() in HostNode._registry]
|
||||
|
||||
@property
|
||||
def extended_networknodes(self) -> List[Node]:
|
||||
"""Extended nodes that inherited NetworkNode in the network"""
|
||||
return [node for node in self.nodes.values() if node.__class__.__name__.lower() in NetworkNode._registry]
|
||||
|
||||
@property
|
||||
def printer_nodes(self) -> List[Node]:
|
||||
@@ -160,6 +172,7 @@ class Network(SimComponent):
|
||||
"Printer": self.printer_nodes,
|
||||
"Wireless Router": self.wireless_router_nodes,
|
||||
}
|
||||
|
||||
if nodes:
|
||||
table = PrettyTable(["Node", "Type", "Operating State"])
|
||||
if markdown:
|
||||
|
||||
@@ -1699,7 +1699,7 @@ class Node(SimComponent):
|
||||
if self.software_manager.software.get(application_name):
|
||||
self.sys_log.warning(f"Can't install {application_name}. It's already installed.")
|
||||
return RequestResponse(status="success", data={"reason": "already installed"})
|
||||
application_class = Application._application_registry[application_name]
|
||||
application_class = Application._registry[application_name]
|
||||
self.software_manager.install(application_class)
|
||||
application_instance = self.software_manager.software.get(application_name)
|
||||
self.applications[application_instance.uuid] = application_instance
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from ipaddress import IPv4Address
|
||||
from typing import Any, ClassVar, Dict, Optional
|
||||
from typing import Any, ClassVar, Dict, Optional, Type
|
||||
|
||||
from primaite import getLogger
|
||||
from primaite.simulator.network.hardware.base import (
|
||||
@@ -325,10 +325,30 @@ class HostNode(Node):
|
||||
network_interface: Dict[int, NIC] = {}
|
||||
"The NICs on the node by port id."
|
||||
|
||||
_registry: ClassVar[Dict[str, Type["HostNode"]]] = {}
|
||||
"""Registry of application types. Automatically populated when subclasses are defined."""
|
||||
|
||||
def __init__(self, ip_address: IPV4Address, subnet_mask: IPV4Address, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
self.connect_nic(NIC(ip_address=ip_address, subnet_mask=subnet_mask))
|
||||
|
||||
def __init_subclass__(cls, identifier: str = 'default', **kwargs: Any) -> None:
|
||||
"""
|
||||
Register a hostnode type.
|
||||
|
||||
:param identifier: Uniquely specifies an hostnode class by name. Used for finding items by config.
|
||||
:type identifier: str
|
||||
:raises ValueError: When attempting to register an hostnode with a name that is already allocated.
|
||||
"""
|
||||
if identifier == 'default':
|
||||
return
|
||||
# Enforce lowercase registry entries because it makes comparisons everywhere else much easier.
|
||||
identifier = identifier.lower()
|
||||
super().__init_subclass__(**kwargs)
|
||||
if identifier in cls._registry:
|
||||
raise ValueError(f"Tried to define new hostnode {identifier}, but this name is already reserved.")
|
||||
cls._registry[identifier] = cls
|
||||
|
||||
@property
|
||||
def nmap(self) -> Optional[NMAP]:
|
||||
"""
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# © Crown-owned copyright 2024, Defence Science and Technology Laboratory UK
|
||||
from abc import abstractmethod
|
||||
from typing import Optional
|
||||
from typing import Any, ClassVar, Dict, Optional, Type
|
||||
|
||||
from primaite.simulator.network.hardware.base import NetworkInterface, Node
|
||||
from primaite.simulator.network.transmission.data_link_layer import Frame
|
||||
@@ -16,6 +16,25 @@ class NetworkNode(Node):
|
||||
provide functionality for receiving and processing frames received on their network interfaces.
|
||||
"""
|
||||
|
||||
_registry: ClassVar[Dict[str, Type["NetworkNode"]]] = {}
|
||||
"""Registry of application types. Automatically populated when subclasses are defined."""
|
||||
|
||||
def __init_subclass__(cls, identifier: str = 'default', **kwargs: Any) -> None:
|
||||
"""
|
||||
Register a networknode type.
|
||||
|
||||
:param identifier: Uniquely specifies an networknode class by name. Used for finding items by config.
|
||||
:type identifier: str
|
||||
:raises ValueError: When attempting to register an networknode with a name that is already allocated.
|
||||
"""
|
||||
if identifier == 'default':
|
||||
return
|
||||
identifier = identifier.lower()
|
||||
super().__init_subclass__(**kwargs)
|
||||
if identifier in cls._registry:
|
||||
raise ValueError(f"Tried to define new networknode {identifier}, but this name is already reserved.")
|
||||
cls._registry[identifier] = cls
|
||||
|
||||
@abstractmethod
|
||||
def receive_frame(self, frame: Frame, from_network_interface: NetworkInterface):
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user