#2248 - All tests (bar the one config file test) now working. Still need to tidy up docstrings and some docs. Almost there

This commit is contained in:
Chris McCarthy
2024-02-07 23:05:34 +00:00
parent 5e25fefa14
commit 0c96fef3ec
29 changed files with 270 additions and 235 deletions

View File

@@ -319,11 +319,11 @@ class PrimaiteGame:
node_a = net.nodes[game.ref_map_nodes[link_cfg["endpoint_a_ref"]]] node_a = net.nodes[game.ref_map_nodes[link_cfg["endpoint_a_ref"]]]
node_b = net.nodes[game.ref_map_nodes[link_cfg["endpoint_b_ref"]]] node_b = net.nodes[game.ref_map_nodes[link_cfg["endpoint_b_ref"]]]
if isinstance(node_a, Switch): if isinstance(node_a, Switch):
endpoint_a = node_a.switch_ports[link_cfg["endpoint_a_port"]] endpoint_a = node_a.network_interface[link_cfg["endpoint_a_port"]]
else: else:
endpoint_a = node_a.network_interface[link_cfg["endpoint_a_port"]] endpoint_a = node_a.network_interface[link_cfg["endpoint_a_port"]]
if isinstance(node_b, Switch): if isinstance(node_b, Switch):
endpoint_b = node_b.switch_ports[link_cfg["endpoint_b_port"]] endpoint_b = node_b.network_interface[link_cfg["endpoint_b_port"]]
else: else:
endpoint_b = node_b.network_interface[link_cfg["endpoint_b_port"]] endpoint_b = node_b.network_interface[link_cfg["endpoint_b_port"]]
new_link = net.connect(endpoint_a=endpoint_a, endpoint_b=endpoint_b) new_link = net.connect(endpoint_a=endpoint_a, endpoint_b=endpoint_b)

View File

@@ -149,7 +149,8 @@ class Network(SimComponent):
for nodes in nodes_type_map.values(): for nodes in nodes_type_map.values():
for node in nodes: for node in nodes:
for i, port in node.network_interface.items(): for i, port in node.network_interface.items():
table.add_row([node.hostname, i, port.ip_address, port.subnet_mask, node.default_gateway]) if hasattr(port, "ip_address"):
table.add_row([node.hostname, i, port.ip_address, port.subnet_mask, node.default_gateway])
print(table) print(table)
if links: if links:

View File

@@ -109,9 +109,9 @@ def create_office_lan(
switch.power_on() switch.power_on()
network.add_node(switch) network.add_node(switch)
if num_of_switches > 1: if num_of_switches > 1:
network.connect(core_switch.switch_ports[core_switch_port], switch.switch_ports[24]) network.connect(core_switch.network_interface[core_switch_port], switch.network_interface[24])
else: else:
network.connect(router.network_interface[1], switch.switch_ports[24]) network.connect(router.network_interface[1], switch.network_interface[24])
# Add PCs to the LAN and connect them to switches # Add PCs to the LAN and connect them to switches
for i in range(1, num_pcs + 1): for i in range(1, num_pcs + 1):
@@ -125,9 +125,9 @@ def create_office_lan(
# Connect the new switch to the router or core switch # Connect the new switch to the router or core switch
if num_of_switches > 1: if num_of_switches > 1:
core_switch_port += 1 core_switch_port += 1
network.connect(core_switch.switch_ports[core_switch_port], switch.switch_ports[24]) network.connect(core_switch.network_interface[core_switch_port], switch.network_interface[24])
else: else:
network.connect(router.network_interface[1], switch.switch_ports[24]) network.connect(router.network_interface[1], switch.network_interface[24])
# Create and add a PC to the network # Create and add a PC to the network
pc = Computer( pc = Computer(
@@ -142,7 +142,7 @@ def create_office_lan(
# Connect the PC to the switch # Connect the PC to the switch
switch_port += 1 switch_port += 1
network.connect(switch.switch_ports[switch_port], pc.network_interface[1]) network.connect(switch.network_interface[switch_port], pc.network_interface[1])
switch.switch_ports[switch_port].enable() switch.network_interface[switch_port].enable()
return network return network

View File

@@ -197,6 +197,12 @@ class WiredNetworkInterface(NetworkInterface, ABC):
) )
return return
if not self._connected_link:
self._connected_node.sys_log.info(
f"Interface {self} cannot be enabled as there is no Link connected."
)
return
self.enabled = True self.enabled = True
self._connected_node.sys_log.info(f"Network Interface {self} enabled") self._connected_node.sys_log.info(f"Network Interface {self} enabled")
self.pcap = PacketCapture(hostname=self._connected_node.hostname, interface_num=self.port_num) self.pcap = PacketCapture(hostname=self._connected_node.hostname, interface_num=self.port_num)
@@ -351,6 +357,12 @@ class IPWiredNetworkInterface(WiredNetworkInterface, Layer3Interface, ABC):
Derived classes should define specific behaviors and properties of an IP-capable wired network interface, Derived classes should define specific behaviors and properties of an IP-capable wired network interface,
customizing it for their specific use cases. customizing it for their specific use cases.
""" """
_connected_link: Optional[Link] = None
"The network link to which the network interface is connected."
def model_post_init(self, __context: Any) -> None:
if self.ip_network.network_address == self.ip_address:
raise ValueError(f"{self.ip_address}/{self.subnet_mask} must not be a network address")
def describe_state(self) -> Dict: def describe_state(self) -> Dict:
""" """
@@ -375,7 +387,7 @@ class IPWiredNetworkInterface(WiredNetworkInterface, Layer3Interface, ABC):
except AttributeError: except AttributeError:
pass pass
@abstractmethod # @abstractmethod
def receive_frame(self, frame: Frame) -> bool: def receive_frame(self, frame: Frame) -> bool:
""" """
Receives a network frame on the network interface. Receives a network frame on the network interface.
@@ -819,6 +831,13 @@ class Node(SimComponent):
table.add_row([port.value, port.name]) table.add_row([port.value, port.name])
print(table) print(table)
@property
def has_enabled_network_interface(self) -> bool:
for network_interface in self.network_interfaces.values():
if network_interface.enabled:
return True
return False
def show_nic(self, markdown: bool = False): def show_nic(self, markdown: bool = False):
"""Prints a table of the NICs on the Node.""" """Prints a table of the NICs on the Node."""
table = PrettyTable(["Port", "Type", "MAC Address", "Address", "Speed", "Status"]) table = PrettyTable(["Port", "Type", "MAC Address", "Address", "Speed", "Status"])
@@ -830,7 +849,7 @@ class Node(SimComponent):
table.add_row( table.add_row(
[ [
port, port,
network_interface.__name__, type(network_interface),
network_interface.mac_address, network_interface.mac_address,
f"{network_interface.ip_address}/{network_interface.ip_network.prefixlen}", f"{network_interface.ip_address}/{network_interface.ip_network.prefixlen}",
network_interface.speed, network_interface.speed,

View File

@@ -1,10 +1,10 @@
from __future__ import annotations from __future__ import annotations
from typing import Dict from typing import Dict, Any
from typing import Optional from typing import Optional
from primaite import getLogger from primaite import getLogger
from primaite.simulator.network.hardware.base import IPWiredNetworkInterface from primaite.simulator.network.hardware.base import IPWiredNetworkInterface, Link
from primaite.simulator.network.hardware.base import Node from primaite.simulator.network.hardware.base import Node
from primaite.simulator.network.hardware.node_operating_state import NodeOperatingState from primaite.simulator.network.hardware.node_operating_state import NodeOperatingState
from primaite.simulator.network.transmission.data_link_layer import Frame from primaite.simulator.network.transmission.data_link_layer import Frame
@@ -45,7 +45,7 @@ class HostARP(ARP):
:return: The NIC associated with the default gateway if it exists in the ARP cache, otherwise None. :return: The NIC associated with the default gateway if it exists in the ARP cache, otherwise None.
""" """
if self.software_manager.node.default_gateway: if self.software_manager.node.default_gateway and self.software_manager.node.has_enabled_network_interface:
return self.get_arp_cache_network_interface(self.software_manager.node.default_gateway) return self.get_arp_cache_network_interface(self.software_manager.node.default_gateway)
def _get_arp_cache_mac_address( def _get_arp_cache_mac_address(
@@ -175,12 +175,14 @@ class NIC(IPWiredNetworkInterface):
and disconnect from network links and to manage the enabled/disabled state of the interface. and disconnect from network links and to manage the enabled/disabled state of the interface.
- Layer3Interface: Provides properties for Layer 3 network configuration, such as IP address and subnet mask. - Layer3Interface: Provides properties for Layer 3 network configuration, such as IP address and subnet mask.
""" """
_connected_link: Optional[Link] = None
"The network link to which the network interface is connected."
wake_on_lan: bool = False wake_on_lan: bool = False
"Indicates if the NIC supports Wake-on-LAN functionality." "Indicates if the NIC supports Wake-on-LAN functionality."
def __init__(self, **kwargs): def model_post_init(self, __context: Any) -> None:
if self.ip_network.network_address == self.ip_address:
super().__init__(**kwargs) raise ValueError(f"{self.ip_address}/{self.subnet_mask} must not be a network address")
def describe_state(self) -> Dict: def describe_state(self) -> Dict:
""" """
@@ -353,7 +355,6 @@ class HostNode(Node):
if accept_frame: if accept_frame:
self.session_manager.receive_frame(frame, from_network_interface) self.session_manager.receive_frame(frame, from_network_interface)
else: else:
# denied as port closed self.sys_log.info(f"Ignoring frame from {frame.ip.src_ip_address}")
self.sys_log.info(f"Ignoring frame for port {frame.tcp.dst_port.value} from {frame.ip.src_ip_address}")
# TODO: do we need to do anything more here? # TODO: do we need to do anything more here?
pass pass

View File

@@ -555,6 +555,14 @@ class RouterARP(ARP):
return arp_entry.mac_address return arp_entry.mac_address
if not is_reattempt: if not is_reattempt:
if self.router.ip_is_in_router_interface_subnet(ip_address):
self.send_arp_request(ip_address)
return self._get_arp_cache_mac_address(
ip_address=ip_address,
is_reattempt=True,
is_default_route_attempt=is_default_route_attempt
)
route = self.router.route_table.find_best_route(ip_address) route = self.router.route_table.find_best_route(ip_address)
if route and route != self.router.route_table.default_route: if route and route != self.router.route_table.default_route:
self.send_arp_request(route.next_hop_ip_address) self.send_arp_request(route.next_hop_ip_address)
@@ -818,7 +826,7 @@ class Router(NetworkNode):
network_interfaces: Dict[str, RouterInterface] = {} network_interfaces: Dict[str, RouterInterface] = {}
"The Router Interfaces on the node." "The Router Interfaces on the node."
network_interface: Dict[int, RouterInterface] = {} network_interface: Dict[int, RouterInterface] = {}
"The Router Interfaceson the node by port id." "The Router Interfaces on the node by port id."
acl: AccessControlList acl: AccessControlList
route_table: RouteTable route_table: RouteTable
@@ -885,6 +893,15 @@ class Router(NetworkNode):
return True return True
return False return False
def ip_is_in_router_interface_subnet(self, ip_address: IPV4Address, enabled_only: bool = False) -> bool:
for router_interface in self.network_interface.values():
if ip_address in router_interface.ip_network:
if enabled_only:
return router_interface.enabled
else:
return True
return False
def _get_port_of_nic(self, target_nic: RouterInterface) -> Optional[int]: def _get_port_of_nic(self, target_nic: RouterInterface) -> Optional[int]:
""" """
Retrieve the port number for a given NIC. Retrieve the port number for a given NIC.

View File

@@ -96,16 +96,18 @@ class Switch(NetworkNode):
num_ports: int = 24 num_ports: int = 24
"The number of ports on the switch." "The number of ports on the switch."
switch_ports: Dict[int, SwitchPort] = {} network_interfaces: Dict[str, SwitchPort] = {}
"The SwitchPorts on the switch." "The SwitchPorts on the Switch."
network_interface: Dict[int, SwitchPort] = {}
"The SwitchPorts on the Switch by port id."
mac_address_table: Dict[str, SwitchPort] = {} mac_address_table: Dict[str, SwitchPort] = {}
"A MAC address table mapping destination MAC addresses to corresponding SwitchPorts." "A MAC address table mapping destination MAC addresses to corresponding SwitchPorts."
def __init__(self, **kwargs): def __init__(self, **kwargs):
super().__init__(**kwargs) super().__init__(**kwargs)
if not self.switch_ports: if not self.network_interface:
self.switch_ports = {i: SwitchPort() for i in range(1, self.num_ports + 1)} self.network_interface = {i: SwitchPort() for i in range(1, self.num_ports + 1)}
for port_num, port in self.switch_ports.items(): for port_num, port in self.network_interface.items():
port._connected_node = self port._connected_node = self
port.port_num = port_num port.port_num = port_num
port.parent = self port.parent = self
@@ -122,7 +124,7 @@ class Switch(NetworkNode):
table.set_style(MARKDOWN) table.set_style(MARKDOWN)
table.align = "l" table.align = "l"
table.title = f"{self.hostname} Switch Ports" table.title = f"{self.hostname} Switch Ports"
for port_num, port in self.switch_ports.items(): for port_num, port in self.network_interface.items():
table.add_row([port_num, port.mac_address, port.speed, "Enabled" if port.enabled else "Disabled"]) table.add_row([port_num, port.mac_address, port.speed, "Enabled" if port.enabled else "Disabled"])
print(table) print(table)
@@ -133,7 +135,7 @@ class Switch(NetworkNode):
:return: Current state of this object and child objects. :return: Current state of this object and child objects.
""" """
state = super().describe_state() state = super().describe_state()
state["ports"] = {port_num: port.describe_state() for port_num, port in self.switch_ports.items()} state["ports"] = {port_num: port.describe_state() for port_num, port in self.network_interface.items()}
state["num_ports"] = self.num_ports # redundant? state["num_ports"] = self.num_ports # redundant?
state["mac_address_table"] = {mac: port.port_num for mac, port in self.mac_address_table.items()} state["mac_address_table"] = {mac: port.port_num for mac, port in self.mac_address_table.items()}
return state return state
@@ -171,7 +173,7 @@ class Switch(NetworkNode):
outgoing_port.send_frame(frame) outgoing_port.send_frame(frame)
else: else:
# If the destination MAC is not in the table, flood to all ports except incoming # If the destination MAC is not in the table, flood to all ports except incoming
for port in self.switch_ports.values(): for port in self.network_interface.values():
if port.enabled and port != from_network_interface: if port.enabled and port != from_network_interface:
port.send_frame(frame) port.send_frame(frame)
@@ -183,7 +185,7 @@ class Switch(NetworkNode):
:param port_number: The port number on the switch from where the link should be disconnected. :param port_number: The port number on the switch from where the link should be disconnected.
:raise NetworkError: When an invalid port number is provided or the link does not match the connection. :raise NetworkError: When an invalid port number is provided or the link does not match the connection.
""" """
port = self.switch_ports.get(port_number) port = self.network_interface.get(port_number)
if port is None: if port is None:
msg = f"Invalid port number {port_number} on the switch" msg = f"Invalid port number {port_number} on the switch"
_LOGGER.error(msg) _LOGGER.error(msg)

View File

@@ -41,13 +41,13 @@ def client_server_routed() -> Network:
# Switch 1 # Switch 1
switch_1 = Switch(hostname="switch_1", num_ports=6) switch_1 = Switch(hostname="switch_1", num_ports=6)
switch_1.power_on() switch_1.power_on()
network.connect(endpoint_a=router_1.network_interface[1], endpoint_b=switch_1.switch_ports[6]) network.connect(endpoint_a=router_1.network_interface[1], endpoint_b=switch_1.network_interface[6])
router_1.enable_port(1) router_1.enable_port(1)
# Switch 2 # Switch 2
switch_2 = Switch(hostname="switch_2", num_ports=6) switch_2 = Switch(hostname="switch_2", num_ports=6)
switch_2.power_on() switch_2.power_on()
network.connect(endpoint_a=router_1.network_interface[2], endpoint_b=switch_2.switch_ports[6]) network.connect(endpoint_a=router_1.network_interface[2], endpoint_b=switch_2.network_interface[6])
router_1.enable_port(2) router_1.enable_port(2)
# Client 1 # Client 1
@@ -56,10 +56,10 @@ def client_server_routed() -> Network:
ip_address="192.168.2.2", ip_address="192.168.2.2",
subnet_mask="255.255.255.0", subnet_mask="255.255.255.0",
default_gateway="192.168.2.1", default_gateway="192.168.2.1",
operating_state=NodeOperatingState.ON, start_up_duration=0
) )
client_1.power_on() client_1.power_on()
network.connect(endpoint_b=client_1.network_interface[1], endpoint_a=switch_2.switch_ports[1]) network.connect(endpoint_b=client_1.network_interface[1], endpoint_a=switch_2.network_interface[1])
# Server 1 # Server 1
server_1 = Server( server_1 = Server(
@@ -67,10 +67,10 @@ def client_server_routed() -> Network:
ip_address="192.168.1.2", ip_address="192.168.1.2",
subnet_mask="255.255.255.0", subnet_mask="255.255.255.0",
default_gateway="192.168.1.1", default_gateway="192.168.1.1",
operating_state=NodeOperatingState.ON, start_up_duration=0
) )
server_1.power_on() server_1.power_on()
network.connect(endpoint_b=server_1.network_interface[1], endpoint_a=switch_1.switch_ports[1]) network.connect(endpoint_b=server_1.network_interface[1], endpoint_a=switch_1.network_interface[1])
router_1.acl.add_rule(action=ACLAction.PERMIT, src_port=Port.ARP, dst_port=Port.ARP, position=22) router_1.acl.add_rule(action=ACLAction.PERMIT, src_port=Port.ARP, dst_port=Port.ARP, position=22)
@@ -119,21 +119,21 @@ def arcd_uc2_network() -> Network:
network = Network() network = Network()
# Router 1 # Router 1
router_1 = Router(hostname="router_1", num_ports=5, operating_state=NodeOperatingState.ON) router_1 = Router(hostname="router_1", num_ports=5, start_up_duration=0)
router_1.power_on() router_1.power_on()
router_1.configure_port(port=1, ip_address="192.168.1.1", subnet_mask="255.255.255.0") router_1.configure_port(port=1, ip_address="192.168.1.1", subnet_mask="255.255.255.0")
router_1.configure_port(port=2, ip_address="192.168.10.1", subnet_mask="255.255.255.0") router_1.configure_port(port=2, ip_address="192.168.10.1", subnet_mask="255.255.255.0")
# Switch 1 # Switch 1
switch_1 = Switch(hostname="switch_1", num_ports=8, operating_state=NodeOperatingState.ON) switch_1 = Switch(hostname="switch_1", num_ports=8, start_up_duration=0)
switch_1.power_on() switch_1.power_on()
network.connect(endpoint_a=router_1.network_interface[1], endpoint_b=switch_1.switch_ports[8]) network.connect(endpoint_a=router_1.network_interface[1], endpoint_b=switch_1.network_interface[8])
router_1.enable_port(1) router_1.enable_port(1)
# Switch 2 # Switch 2
switch_2 = Switch(hostname="switch_2", num_ports=8, operating_state=NodeOperatingState.ON) switch_2 = Switch(hostname="switch_2", num_ports=8, start_up_duration=0)
switch_2.power_on() switch_2.power_on()
network.connect(endpoint_a=router_1.network_interface[2], endpoint_b=switch_2.switch_ports[8]) network.connect(endpoint_a=router_1.network_interface[2], endpoint_b=switch_2.network_interface[8])
router_1.enable_port(2) router_1.enable_port(2)
# Client 1 # Client 1
@@ -143,10 +143,10 @@ def arcd_uc2_network() -> Network:
subnet_mask="255.255.255.0", subnet_mask="255.255.255.0",
default_gateway="192.168.10.1", default_gateway="192.168.10.1",
dns_server=IPv4Address("192.168.1.10"), dns_server=IPv4Address("192.168.1.10"),
operating_state=NodeOperatingState.ON, start_up_duration=0
) )
client_1.power_on() client_1.power_on()
network.connect(endpoint_b=client_1.network_interface[1], endpoint_a=switch_2.switch_ports[1]) network.connect(endpoint_b=client_1.network_interface[1], endpoint_a=switch_2.network_interface[1])
client_1.software_manager.install(DataManipulationBot) client_1.software_manager.install(DataManipulationBot)
db_manipulation_bot: DataManipulationBot = client_1.software_manager.software.get("DataManipulationBot") db_manipulation_bot: DataManipulationBot = client_1.software_manager.software.get("DataManipulationBot")
db_manipulation_bot.configure( db_manipulation_bot.configure(
@@ -163,12 +163,12 @@ def arcd_uc2_network() -> Network:
subnet_mask="255.255.255.0", subnet_mask="255.255.255.0",
default_gateway="192.168.10.1", default_gateway="192.168.10.1",
dns_server=IPv4Address("192.168.1.10"), dns_server=IPv4Address("192.168.1.10"),
operating_state=NodeOperatingState.ON, start_up_duration=0
) )
client_2.power_on() client_2.power_on()
web_browser = client_2.software_manager.software.get("WebBrowser") web_browser = client_2.software_manager.software.get("WebBrowser")
web_browser.target_url = "http://arcd.com/users/" web_browser.target_url = "http://arcd.com/users/"
network.connect(endpoint_b=client_2.network_interface[1], endpoint_a=switch_2.switch_ports[2]) network.connect(endpoint_b=client_2.network_interface[1], endpoint_a=switch_2.network_interface[2])
# Domain Controller # Domain Controller
domain_controller = Server( domain_controller = Server(
@@ -176,12 +176,12 @@ def arcd_uc2_network() -> Network:
ip_address="192.168.1.10", ip_address="192.168.1.10",
subnet_mask="255.255.255.0", subnet_mask="255.255.255.0",
default_gateway="192.168.1.1", default_gateway="192.168.1.1",
operating_state=NodeOperatingState.ON, start_up_duration=0
) )
domain_controller.power_on() domain_controller.power_on()
domain_controller.software_manager.install(DNSServer) domain_controller.software_manager.install(DNSServer)
network.connect(endpoint_b=domain_controller.network_interface[1], endpoint_a=switch_1.switch_ports[1]) network.connect(endpoint_b=domain_controller.network_interface[1], endpoint_a=switch_1.network_interface[1])
# Database Server # Database Server
database_server = Server( database_server = Server(
@@ -190,10 +190,10 @@ def arcd_uc2_network() -> Network:
subnet_mask="255.255.255.0", subnet_mask="255.255.255.0",
default_gateway="192.168.1.1", default_gateway="192.168.1.1",
dns_server=IPv4Address("192.168.1.10"), dns_server=IPv4Address("192.168.1.10"),
operating_state=NodeOperatingState.ON, start_up_duration=0
) )
database_server.power_on() database_server.power_on()
network.connect(endpoint_b=database_server.network_interface[1], endpoint_a=switch_1.switch_ports[3]) network.connect(endpoint_b=database_server.network_interface[1], endpoint_a=switch_1.network_interface[3])
ddl = """ ddl = """
CREATE TABLE IF NOT EXISTS user ( CREATE TABLE IF NOT EXISTS user (
@@ -264,14 +264,14 @@ def arcd_uc2_network() -> Network:
subnet_mask="255.255.255.0", subnet_mask="255.255.255.0",
default_gateway="192.168.1.1", default_gateway="192.168.1.1",
dns_server=IPv4Address("192.168.1.10"), dns_server=IPv4Address("192.168.1.10"),
operating_state=NodeOperatingState.ON, start_up_duration=0
) )
web_server.power_on() web_server.power_on()
web_server.software_manager.install(DatabaseClient) web_server.software_manager.install(DatabaseClient)
database_client: DatabaseClient = web_server.software_manager.software.get("DatabaseClient") database_client: DatabaseClient = web_server.software_manager.software.get("DatabaseClient")
database_client.configure(server_ip_address=IPv4Address("192.168.1.14")) database_client.configure(server_ip_address=IPv4Address("192.168.1.14"))
network.connect(endpoint_b=web_server.network_interface[1], endpoint_a=switch_1.switch_ports[2]) network.connect(endpoint_b=web_server.network_interface[1], endpoint_a=switch_1.network_interface[2])
database_client.run() database_client.run()
database_client.connect() database_client.connect()
@@ -279,7 +279,7 @@ def arcd_uc2_network() -> Network:
# register the web_server to a domain # register the web_server to a domain
dns_server_service: DNSServer = domain_controller.software_manager.software.get("DNSServer") # noqa dns_server_service: DNSServer = domain_controller.software_manager.software.get("DNSServer") # noqa
dns_server_service.dns_register("arcd.com", web_server.ip_address) dns_server_service.dns_register("arcd.com", web_server.network_interface[1].ip_address)
# Backup Server # Backup Server
backup_server = Server( backup_server = Server(
@@ -288,11 +288,11 @@ def arcd_uc2_network() -> Network:
subnet_mask="255.255.255.0", subnet_mask="255.255.255.0",
default_gateway="192.168.1.1", default_gateway="192.168.1.1",
dns_server=IPv4Address("192.168.1.10"), dns_server=IPv4Address("192.168.1.10"),
operating_state=NodeOperatingState.ON, start_up_duration=0
) )
backup_server.power_on() backup_server.power_on()
backup_server.software_manager.install(FTPServer) backup_server.software_manager.install(FTPServer)
network.connect(endpoint_b=backup_server.network_interface[1], endpoint_a=switch_1.switch_ports[4]) network.connect(endpoint_b=backup_server.network_interface[1], endpoint_a=switch_1.network_interface[4])
# Security Suite # Security Suite
security_suite = Server( security_suite = Server(
@@ -301,12 +301,12 @@ def arcd_uc2_network() -> Network:
subnet_mask="255.255.255.0", subnet_mask="255.255.255.0",
default_gateway="192.168.1.1", default_gateway="192.168.1.1",
dns_server=IPv4Address("192.168.1.10"), dns_server=IPv4Address("192.168.1.10"),
operating_state=NodeOperatingState.ON, start_up_duration=0
) )
security_suite.power_on() security_suite.power_on()
network.connect(endpoint_b=security_suite.network_interface[1], endpoint_a=switch_1.switch_ports[7]) network.connect(endpoint_b=security_suite.network_interface[1], endpoint_a=switch_1.network_interface[7])
security_suite.connect_nic(NIC(ip_address="192.168.10.110", subnet_mask="255.255.255.0")) security_suite.connect_nic(NIC(ip_address="192.168.10.110", subnet_mask="255.255.255.0"))
network.connect(endpoint_b=security_suite.network_interface[2], endpoint_a=switch_2.switch_ports[7]) network.connect(endpoint_b=security_suite.network_interface[2], endpoint_a=switch_2.network_interface[7])
router_1.acl.add_rule(action=ACLAction.PERMIT, src_port=Port.ARP, dst_port=Port.ARP, position=22) router_1.acl.add_rule(action=ACLAction.PERMIT, src_port=Port.ARP, dst_port=Port.ARP, position=22)

View File

@@ -23,6 +23,7 @@ class DatabaseClient(Application):
server_ip_address: Optional[IPv4Address] = None server_ip_address: Optional[IPv4Address] = None
server_password: Optional[str] = None server_password: Optional[str] = None
connected: bool = False
_query_success_tracker: Dict[str, bool] = {} _query_success_tracker: Dict[str, bool] = {}
def __init__(self, **kwargs): def __init__(self, **kwargs):
@@ -73,9 +74,10 @@ class DatabaseClient(Application):
if not connection_id: if not connection_id:
connection_id = str(uuid4()) connection_id = str(uuid4())
return self._connect( self.connected = self._connect(
server_ip_address=self.server_ip_address, password=self.server_password, connection_id=connection_id server_ip_address=self.server_ip_address, password=self.server_password, connection_id=connection_id
) )
return self.connected
def _connect( def _connect(
self, self,
@@ -147,6 +149,7 @@ class DatabaseClient(Application):
self.sys_log.info( self.sys_log.info(
f"{self.name}: DatabaseClient disconnected connection {connection_id} from {self.server_ip_address}" f"{self.name}: DatabaseClient disconnected connection {connection_id} from {self.server_ip_address}"
) )
self.connected = False
def _query(self, sql: str, query_id: str, connection_id: str, is_reattempt: bool = False) -> bool: def _query(self, sql: str, query_id: str, connection_id: str, is_reattempt: bool = False) -> bool:
""" """

View File

@@ -108,13 +108,14 @@ class NTPClient(Service):
def request_time(self) -> None: def request_time(self) -> None:
"""Send request to ntp_server.""" """Send request to ntp_server."""
self.software_manager.session_manager.receive_payload_from_software_manager( if self.ntp_server:
payload=NTPPacket(), self.software_manager.session_manager.receive_payload_from_software_manager(
dst_ip_address=self.ntp_server, payload=NTPPacket(),
src_port=self.port, dst_ip_address=self.ntp_server,
dst_port=self.port, src_port=self.port,
ip_protocol=self.protocol, dst_port=self.port,
) ip_protocol=self.protocol,
)
def apply_timestep(self, timestep: int) -> None: def apply_timestep(self, timestep: int) -> None:
""" """

View File

@@ -5,15 +5,16 @@ from typing import Any, Dict, Tuple, Union
import pytest import pytest
import yaml import yaml
from primaite import PRIMAITE_PATHS
from primaite import getLogger from primaite import getLogger
from primaite.session.session import PrimaiteSession from primaite.session.session import PrimaiteSession
from primaite.simulator.file_system.file_system import FileSystem
# from primaite.environment.primaite_env import Primaite # from primaite.environment.primaite_env import Primaite
# from primaite.primaite_session import PrimaiteSession # from primaite.primaite_session import PrimaiteSession
from primaite.simulator.network.container import Network from primaite.simulator.network.container import Network
from primaite.simulator.network.hardware.nodes.host.computer import Computer from primaite.simulator.network.hardware.nodes.host.computer import Computer
from primaite.simulator.network.hardware.nodes.network.router import ACLAction, Router
from primaite.simulator.network.hardware.nodes.host.server import Server from primaite.simulator.network.hardware.nodes.host.server import Server
from primaite.simulator.network.hardware.nodes.network.router import ACLAction, Router
from primaite.simulator.network.hardware.nodes.network.switch import Switch from primaite.simulator.network.hardware.nodes.network.switch import Switch
from primaite.simulator.network.networks import arcd_uc2_network from primaite.simulator.network.networks import arcd_uc2_network
from primaite.simulator.network.transmission.network_layer import IPProtocol from primaite.simulator.network.transmission.network_layer import IPProtocol
@@ -28,12 +29,6 @@ ACTION_SPACE_NODE_ACTION_VALUES = 1
_LOGGER = getLogger(__name__) _LOGGER = getLogger(__name__)
from primaite import PRIMAITE_PATHS
# PrimAITE v3 stuff
from primaite.simulator.file_system.file_system import FileSystem
from primaite.simulator.network.hardware.base import Node
class TestService(Service): class TestService(Service):
"""Test Service class""" """Test Service class"""
@@ -95,7 +90,7 @@ def application_class():
@pytest.fixture(scope="function") @pytest.fixture(scope="function")
def file_system() -> FileSystem: def file_system() -> FileSystem:
return Node(hostname="fs_node").file_system return Computer(hostname="fs_node", ip_address="192.168.1.2", subnet_mask="255.255.255.0").file_system
# PrimAITE v2 stuff # PrimAITE v2 stuff
@@ -190,8 +185,8 @@ def client_switch_server() -> Tuple[Computer, Switch, Server]:
switch = Switch(hostname="switch", start_up_duration=0) switch = Switch(hostname="switch", start_up_duration=0)
switch.power_on() switch.power_on()
network.connect(endpoint_a=computer.network_interface[1], endpoint_b=switch.switch_ports[1]) network.connect(endpoint_a=computer.network_interface[1], endpoint_b=switch.network_interface[1])
network.connect(endpoint_a=server.network_interface[1], endpoint_b=switch.switch_ports[2]) network.connect(endpoint_a=server.network_interface[1], endpoint_b=switch.network_interface[2])
assert all(link.is_up for link in network.links.values()) assert all(link.is_up for link in network.links.values())
@@ -233,7 +228,7 @@ def example_network() -> Network:
) )
switch_1.power_on() switch_1.power_on()
network.connect(endpoint_a=router_1.network_interface[1], endpoint_b=switch_1.switch_ports[8]) network.connect(endpoint_a=router_1.network_interface[1], endpoint_b=switch_1.network_interface[8])
router_1.enable_port(1) router_1.enable_port(1)
# Switch 2 # Switch 2
@@ -243,7 +238,7 @@ def example_network() -> Network:
start_up_duration=0 start_up_duration=0
) )
switch_2.power_on() switch_2.power_on()
network.connect(endpoint_a=router_1.network_interface[2], endpoint_b=switch_2.switch_ports[8]) network.connect(endpoint_a=router_1.network_interface[2], endpoint_b=switch_2.network_interface[8])
router_1.enable_port(2) router_1.enable_port(2)
# Client 1 # Client 1
@@ -255,7 +250,7 @@ def example_network() -> Network:
start_up_duration=0 start_up_duration=0
) )
client_1.power_on() client_1.power_on()
network.connect(endpoint_b=client_1.network_interface[1], endpoint_a=switch_2.switch_ports[1]) network.connect(endpoint_b=client_1.network_interface[1], endpoint_a=switch_2.network_interface[1])
# Client 2 # Client 2
client_2 = Computer( client_2 = Computer(
@@ -266,7 +261,7 @@ def example_network() -> Network:
start_up_duration=0 start_up_duration=0
) )
client_2.power_on() client_2.power_on()
network.connect(endpoint_b=client_2.network_interface[1], endpoint_a=switch_2.switch_ports[2]) network.connect(endpoint_b=client_2.network_interface[1], endpoint_a=switch_2.network_interface[2])
# Server 1 # Server 1
server_1 = Server( server_1 = Server(
@@ -277,7 +272,7 @@ def example_network() -> Network:
start_up_duration=0 start_up_duration=0
) )
server_1.power_on() server_1.power_on()
network.connect(endpoint_b=server_1.network_interface[1], endpoint_a=switch_1.switch_ports[1]) network.connect(endpoint_b=server_1.network_interface[1], endpoint_a=switch_1.network_interface[1])
# DServer 2 # DServer 2
server_2 = Server( server_2 = Server(
@@ -288,7 +283,7 @@ def example_network() -> Network:
start_up_duration=0 start_up_duration=0
) )
server_2.power_on() server_2.power_on()
network.connect(endpoint_b=server_2.network_interface[1], endpoint_a=switch_1.switch_ports[2]) network.connect(endpoint_b=server_2.network_interface[1], endpoint_a=switch_1.network_interface[2])
router_1.acl.add_rule(action=ACLAction.PERMIT, src_port=Port.ARP, dst_port=Port.ARP, position=22) router_1.acl.add_rule(action=ACLAction.PERMIT, src_port=Port.ARP, dst_port=Port.ARP, position=22)
router_1.acl.add_rule(action=ACLAction.PERMIT, protocol=IPProtocol.ICMP, position=23) router_1.acl.add_rule(action=ACLAction.PERMIT, protocol=IPProtocol.ICMP, position=23)

View File

@@ -25,9 +25,9 @@ def test_passing_actions_down(monkeypatch) -> None:
downloads_folder = pc1.file_system.create_folder("downloads") downloads_folder = pc1.file_system.create_folder("downloads")
pc1.file_system.create_file("bermuda_triangle.png", folder_name="downloads") pc1.file_system.create_file("bermuda_triangle.png", folder_name="downloads")
sim.network.connect(pc1.network_interface[1], s1.switch_ports[1]) sim.network.connect(pc1.network_interface[1], s1.network_interface[1])
sim.network.connect(pc2.network_interface[1], s1.switch_ports[2]) sim.network.connect(pc2.network_interface[1], s1.network_interface[2])
sim.network.connect(s1.switch_ports[3], srv.network_interface[1]) sim.network.connect(s1.network_interface[3], srv.network_interface[1])
# call this method to make sure no errors occur. # call this method to make sure no errors occur.
sim._request_manager.get_request_types_recursively() sim._request_manager.get_request_types_recursively()

View File

@@ -111,9 +111,9 @@ def broadcast_network() -> Network:
switch_1 = Switch(hostname="switch_1", num_ports=6, start_up_duration=0) switch_1 = Switch(hostname="switch_1", num_ports=6, start_up_duration=0)
switch_1.power_on() switch_1.power_on()
network.connect(endpoint_a=client_1.network_interface[1], endpoint_b=switch_1.switch_ports[1]) network.connect(endpoint_a=client_1.network_interface[1], endpoint_b=switch_1.network_interface[1])
network.connect(endpoint_a=client_2.network_interface[1], endpoint_b=switch_1.switch_ports[2]) network.connect(endpoint_a=client_2.network_interface[1], endpoint_b=switch_1.network_interface[2])
network.connect(endpoint_a=server_1.network_interface[1], endpoint_b=switch_1.switch_ports[3]) network.connect(endpoint_a=server_1.network_interface[1], endpoint_b=switch_1.network_interface[3])
return network return network

View File

@@ -1,5 +1,6 @@
from primaite.simulator.network.container import Network from primaite.simulator.network.container import Network
from primaite.simulator.network.hardware.nodes.host.computer import Computer from primaite.simulator.network.hardware.nodes.host.computer import Computer
from primaite.simulator.network.hardware.nodes.host.host_node import NIC
from primaite.simulator.network.hardware.nodes.host.server import Server from primaite.simulator.network.hardware.nodes.host.server import Server
from primaite.simulator.network.hardware.nodes.network.switch import Switch from primaite.simulator.network.hardware.nodes.network.switch import Switch
@@ -30,32 +31,33 @@ def test_node_to_node_ping():
switch_1 = Switch(hostname="switch_1", start_up_duration=0) switch_1 = Switch(hostname="switch_1", start_up_duration=0)
switch_1.power_on() switch_1.power_on()
network.connect(endpoint_a=client_1.network_interface[1], endpoint_b=switch_1.switch_ports[1]) network.connect(endpoint_a=client_1.network_interface[1], endpoint_b=switch_1.network_interface[1])
network.connect(endpoint_a=server_1.network_interface[1], endpoint_b=switch_1.switch_ports[2]) network.connect(endpoint_a=server_1.network_interface[1], endpoint_b=switch_1.network_interface[2])
assert client_1.ping("192.168.1.11") assert client_1.ping("192.168.1.11")
def test_multi_nic(): def test_multi_nic():
"""Tests that Computers with multiple NICs can ping each other and the data go across the correct links.""" """Tests that Computers with multiple NICs can ping each other and the data go across the correct links."""
node_a = Computer(hostname="node_a", operating_state=ComputerOperatingState.ON) network = Network()
nic_a = NIC(ip_address="192.168.0.10", subnet_mask="255.255.255.0")
node_a.connect_nic(nic_a)
node_b = Computer(hostname="node_b", operating_state=ComputerOperatingState.ON) node_a = Computer(hostname="node_a", ip_address="192.168.0.10", subnet_mask="255.255.255.0", start_up_duration=0)
nic_b1 = NIC(ip_address="192.168.0.11", subnet_mask="255.255.255.0") node_a.power_on()
nic_b2 = NIC(ip_address="10.0.0.12", subnet_mask="255.0.0.0")
node_b.connect_nic(nic_b1)
node_b.connect_nic(nic_b2)
node_c = Computer(hostname="node_c", operating_state=ComputerOperatingState.ON) node_b = Computer(hostname="node_b", ip_address="192.168.0.11", subnet_mask="255.255.255.0", start_up_duration=0)
nic_c = NIC(ip_address="10.0.0.13", subnet_mask="255.0.0.0") node_b.power_on()
node_c.connect_nic(nic_c) node_b.connect_nic(NIC(ip_address="10.0.0.12", subnet_mask="255.0.0.0"))
Link(endpoint_a=nic_a, endpoint_b=nic_b1) node_c = Computer(hostname="node_c", ip_address="10.0.0.13", subnet_mask="255.0.0.0", start_up_duration=0)
node_c.power_on()
Link(endpoint_a=nic_b2, endpoint_b=nic_c) network.connect(node_a.network_interface[1], node_b.network_interface[1])
network.connect(node_b.network_interface[2], node_c.network_interface[1])
node_a.ping("192.168.0.11") assert node_a.ping(node_b.network_interface[1].ip_address)
assert node_c.ping("10.0.0.12") assert node_c.ping(node_b.network_interface[2].ip_address)
assert not node_a.ping(node_b.network_interface[2].ip_address)
assert not node_a.ping(node_c.network_interface[1].ip_address)

View File

@@ -1,6 +1,6 @@
from primaite.simulator.network.container import Network from primaite.simulator.network.container import Network
from primaite.simulator.network.hardware.base import Node
from primaite.simulator.network.hardware.nodes.host.computer import Computer from primaite.simulator.network.hardware.nodes.host.computer import Computer
from primaite.simulator.network.hardware.nodes.host.host_node import NIC
from primaite.simulator.network.hardware.nodes.host.server import Server from primaite.simulator.network.hardware.nodes.host.server import Server
@@ -26,7 +26,7 @@ def test_network(example_network):
def test_adding_removing_nodes(): def test_adding_removing_nodes():
"""Check that we can create and add a node to a network.""" """Check that we can create and add a node to a network."""
net = Network() net = Network()
n1 = Node(hostname="computer") n1 = Computer(hostname="computer", ip_address="192.168.1.2", subnet_mask="255.255.255.0", start_up_duration=0)
net.add_node(n1) net.add_node(n1)
assert n1.parent is net assert n1.parent is net
assert n1 in net assert n1 in net
@@ -39,7 +39,7 @@ def test_adding_removing_nodes():
def test_readding_node(): def test_readding_node():
"""Check that warning is raised when readding a node.""" """Check that warning is raised when readding a node."""
net = Network() net = Network()
n1 = Node(hostname="computer") n1 = Computer(hostname="computer", ip_address="192.168.1.2", subnet_mask="255.255.255.0", start_up_duration=0)
net.add_node(n1) net.add_node(n1)
net.add_node(n1) net.add_node(n1)
assert n1.parent is net assert n1.parent is net
@@ -49,7 +49,7 @@ def test_readding_node():
def test_removing_nonexistent_node(): def test_removing_nonexistent_node():
"""Check that warning is raised when trying to remove a node that is not in the network.""" """Check that warning is raised when trying to remove a node that is not in the network."""
net = Network() net = Network()
n1 = Node(hostname="computer") n1 = Computer(hostname="computer1", ip_address="192.168.1.1", subnet_mask="255.255.255.0", start_up_duration=0)
net.remove_node(n1) net.remove_node(n1)
assert n1.parent is None assert n1.parent is None
assert n1 not in net assert n1 not in net
@@ -58,17 +58,13 @@ def test_removing_nonexistent_node():
def test_connecting_nodes(): def test_connecting_nodes():
"""Check that two nodes on the network can be connected.""" """Check that two nodes on the network can be connected."""
net = Network() net = Network()
n1 = Node(hostname="computer") n1 = Computer(hostname="computer1", ip_address="192.168.1.1", subnet_mask="255.255.255.0", start_up_duration=0)
n1_nic = NIC(ip_address="120.30.0.1", gateway="192.168.0.1", subnet_mask="255.255.255.0") n2 = Computer(hostname="computer2", ip_address="192.168.1.2", subnet_mask="255.255.255.0", start_up_duration=0)
n1.connect_nic(n1_nic)
n2 = Node(hostname="server")
n2_nic = NIC(ip_address="120.30.0.2", gateway="192.168.0.1", subnet_mask="255.255.255.0")
n2.connect_nic(n2_nic)
net.add_node(n1) net.add_node(n1)
net.add_node(n2) net.add_node(n2)
net.connect(n1.network_interfaces[n1_nic.uuid], n2.network_interfaces[n2_nic.uuid], bandwidth=30) net.connect(n1.network_interface[1], n2.network_interface[1])
assert len(net.links) == 1 assert len(net.links) == 1
link = list(net.links.values())[0] link = list(net.links.values())[0]
@@ -76,40 +72,32 @@ def test_connecting_nodes():
assert link.parent is net assert link.parent is net
def test_connecting_node_to_itself(): def test_connecting_node_to_itself_fails():
net = Network() net = Network()
node = Node(hostname="computer") node = Computer(hostname="node_b", ip_address="192.168.0.11", subnet_mask="255.255.255.0", start_up_duration=0)
nic1 = NIC(ip_address="120.30.0.1", gateway="192.168.0.1", subnet_mask="255.255.255.0") node.power_on()
node.connect_nic(nic1) node.connect_nic(NIC(ip_address="10.0.0.12", subnet_mask="255.0.0.0"))
nic2 = NIC(ip_address="120.30.0.2", gateway="192.168.0.1", subnet_mask="255.255.255.0")
node.connect_nic(nic2)
net.add_node(node) net.add_node(node)
net.connect(node.network_interfaces[nic1.uuid], node.network_interfaces[nic2.uuid], bandwidth=30) net.connect(node.network_interface[1], node.network_interface[2])
assert node in net assert node in net
assert nic1._connected_link is None assert node.network_interface[1]._connected_link is None
assert nic2._connected_link is None assert node.network_interface[2]._connected_link is None
assert len(net.links) == 0 assert len(net.links) == 0
def test_disconnecting_nodes(): def test_disconnecting_nodes():
net = Network() net = Network()
n1 = Node(hostname="computer") n1 = Computer(hostname="computer1", ip_address="192.168.1.1", subnet_mask="255.255.255.0", start_up_duration=0)
n1_nic = NIC(ip_address="120.30.0.1", gateway="192.168.0.1", subnet_mask="255.255.255.0") n2 = Computer(hostname="computer2", ip_address="192.168.1.2", subnet_mask="255.255.255.0", start_up_duration=0)
n1.connect_nic(n1_nic)
net.add_node(n1)
n2 = Node(hostname="server") net.connect(n1.network_interface[1], n2.network_interface[1])
n2_nic = NIC(ip_address="120.30.0.2", gateway="192.168.0.1", subnet_mask="255.255.255.0")
n2.connect_nic(n2_nic)
net.add_node(n2)
net.connect(n1.network_interfaces[n1_nic.uuid], n2.network_interfaces[n2_nic.uuid], bandwidth=30)
assert len(net.links) == 1 assert len(net.links) == 1
link = list(net.links.values())[0] link = list(net.links.values())[0]
net.remove_link(link) net.remove_link(link)
assert link not in net assert link not in net

View File

@@ -1,6 +1,7 @@
import pytest import pytest
from primaite.simulator.network.hardware.base import Link, NIC from primaite.simulator.network.hardware.base import Link
from primaite.simulator.network.hardware.nodes.host.host_node import NIC
def test_link_fails_with_same_nic(): def test_link_fails_with_same_nic():

View File

@@ -3,7 +3,9 @@ from typing import Tuple
import pytest import pytest
from primaite.simulator.network.hardware.base import Link, NIC, Node, NodeOperatingState from primaite.simulator.network.container import Network
from primaite.simulator.network.hardware.node_operating_state import NodeOperatingState
from primaite.simulator.network.hardware.nodes.host.computer import Computer
from primaite.simulator.network.hardware.nodes.host.server import Server from primaite.simulator.network.hardware.nodes.host.server import Server
from primaite.simulator.system.applications.database_client import DatabaseClient from primaite.simulator.system.applications.database_client import DatabaseClient
from primaite.simulator.system.services.database.database_service import DatabaseService from primaite.simulator.system.services.database.database_service import DatabaseService
@@ -12,17 +14,25 @@ from primaite.simulator.system.services.service import ServiceOperatingState
@pytest.fixture(scope="function") @pytest.fixture(scope="function")
def peer_to_peer() -> Tuple[Node, Node]: def peer_to_peer() -> Tuple[Computer, Computer]:
node_a = Node(hostname="node_a", operating_state=NodeOperatingState.ON) network = Network()
nic_a = NIC(ip_address="192.168.0.10", subnet_mask="255.255.255.0", operating_state=NodeOperatingState.ON) node_a = Computer(
node_a.connect_nic(nic_a) hostname="node_a",
ip_address="192.168.0.10",
subnet_mask="255.255.255.0",
start_up_duration=0
)
node_a.power_on()
node_a.software_manager.get_open_ports() node_a.software_manager.get_open_ports()
node_b = Node(hostname="node_b", operating_state=NodeOperatingState.ON) node_b = Computer(
nic_b = NIC(ip_address="192.168.0.11", subnet_mask="255.255.255.0") hostname="node_b",
node_b.connect_nic(nic_b) ip_address="192.168.0.11",
subnet_mask="255.255.255.0",
Link(endpoint_a=nic_a, endpoint_b=nic_b) start_up_duration=0
)
node_b.power_on()
network.connect(node_a.network_interface[1], node_b.network_interface[1])
assert node_a.ping("192.168.0.11") assert node_a.ping("192.168.0.11")
@@ -37,26 +47,11 @@ def peer_to_peer() -> Tuple[Node, Node]:
@pytest.fixture(scope="function") @pytest.fixture(scope="function")
def peer_to_peer_secure_db() -> Tuple[Node, Node]: def peer_to_peer_secure_db(peer_to_peer) -> Tuple[Computer, Computer]:
node_a = Node(hostname="node_a", operating_state=NodeOperatingState.ON) node_a, node_b = peer_to_peer
nic_a = NIC(ip_address="192.168.0.10", subnet_mask="255.255.255.0", operating_state=NodeOperatingState.ON)
node_a.connect_nic(nic_a)
node_a.software_manager.get_open_ports()
node_b = Node(hostname="node_b", operating_state=NodeOperatingState.ON)
nic_b = NIC(ip_address="192.168.0.11", subnet_mask="255.255.255.0")
node_b.connect_nic(nic_b)
Link(endpoint_a=nic_a, endpoint_b=nic_b)
assert node_a.ping("192.168.0.11")
node_a.software_manager.install(DatabaseClient)
node_a.software_manager.software["DatabaseClient"].configure(server_ip_address=IPv4Address("192.168.0.11"))
node_a.software_manager.software["DatabaseClient"].run()
node_b.software_manager.install(DatabaseService)
database_service: DatabaseService = node_b.software_manager.software["DatabaseService"] # noqa database_service: DatabaseService = node_b.software_manager.software["DatabaseService"] # noqa
database_service.stop()
database_service.password = "12345" database_service.password = "12345"
database_service.start() database_service.start()
return node_a, node_b return node_a, node_b

View File

@@ -47,11 +47,11 @@ def test_ntp_client_server(create_ntp_network):
assert ntp_server.operating_state == ServiceOperatingState.RUNNING assert ntp_server.operating_state == ServiceOperatingState.RUNNING
assert ntp_client.operating_state == ServiceOperatingState.RUNNING assert ntp_client.operating_state == ServiceOperatingState.RUNNING
ntp_client.configure(ntp_server_ip_address=IPv4Address("192.168.0.2")) ntp_client.configure(ntp_server_ip_address=IPv4Address("192.168.1.3"))
assert ntp_client.time is None assert not ntp_client.time
ntp_client.request_time() ntp_client.request_time()
assert ntp_client.time is not None assert ntp_client.time
first_time = ntp_client.time first_time = ntp_client.time
sleep(0.1) sleep(0.1)
ntp_client.apply_timestep(1) # Check time advances ntp_client.apply_timestep(1) # Check time advances
@@ -68,7 +68,7 @@ def test_ntp_server_failure(create_ntp_network):
assert ntp_client.operating_state == ServiceOperatingState.RUNNING assert ntp_client.operating_state == ServiceOperatingState.RUNNING
assert ntp_client.operating_state == ServiceOperatingState.RUNNING assert ntp_client.operating_state == ServiceOperatingState.RUNNING
ntp_client.configure(ntp_server_ip_address=IPv4Address("192.168.0.2")) ntp_client.configure(ntp_server_ip_address=IPv4Address("192.168.1.3"))
# Turn off ntp server. # Turn off ntp server.
ntp_server.stop() ntp_server.stop()

View File

@@ -2,8 +2,10 @@ import re
from ipaddress import IPv4Address from ipaddress import IPv4Address
import pytest import pytest
from pydantic import ValidationError
from primaite.simulator.network.hardware.base import generate_mac_address, NIC from primaite.simulator.network.hardware.base import generate_mac_address
from primaite.simulator.network.hardware.nodes.host.host_node import NIC
def test_mac_address_generation(): def test_mac_address_generation():
@@ -50,8 +52,5 @@ def test_nic_deserialize():
def test_nic_ip_address_as_network_address_fails(): def test_nic_ip_address_as_network_address_fails():
"""Tests NIC creation fails if ip address and subnet mask are a network address.""" """Tests NIC creation fails if ip address and subnet mask are a network address."""
with pytest.raises(ValueError): with pytest.raises(ValidationError):
NIC( NIC(ip_address="192.168.0.0", subnet_mask="255.255.255.0")
ip_address="192.168.0.0",
subnet_mask="255.255.255.0",
)

View File

@@ -1,10 +0,0 @@
import re
from ipaddress import IPv4Address
import pytest
from primaite.simulator.network.hardware.base import Node
def test_node_creation():
node = Node(hostname="host_1")

View File

@@ -4,12 +4,13 @@ from primaite.simulator.file_system.file import File
from primaite.simulator.file_system.file_system_item_abc import FileSystemItemHealthStatus from primaite.simulator.file_system.file_system_item_abc import FileSystemItemHealthStatus
from primaite.simulator.file_system.folder import Folder from primaite.simulator.file_system.folder import Folder
from primaite.simulator.network.hardware.base import Node, NodeOperatingState from primaite.simulator.network.hardware.base import Node, NodeOperatingState
from primaite.simulator.network.hardware.nodes.host.computer import Computer
from primaite.simulator.system.software import SoftwareHealthState from primaite.simulator.system.software import SoftwareHealthState
@pytest.fixture @pytest.fixture
def node() -> Node: def node() -> Node:
return Node(hostname="test") return Computer(hostname="test", ip_address="192.168.1.2", subnet_mask="255.255.255.0")
def test_node_startup(node): def test_node_startup(node):

View File

@@ -108,7 +108,7 @@ def test_removing_node_that_does_not_exist(network):
"""Node that does not exist on network should not affect existing nodes.""" """Node that does not exist on network should not affect existing nodes."""
assert len(network.nodes) is 7 assert len(network.nodes) is 7
network.remove_node(Node(hostname="new_node")) network.remove_node(Computer(hostname="new_node", ip_address="192.168.1.2", subnet_mask="255.255.255.0"))
assert len(network.nodes) is 7 assert len(network.nodes) is 7

View File

@@ -4,23 +4,44 @@ from uuid import uuid4
import pytest import pytest
from primaite.simulator.network.hardware.node_operating_state import NodeOperatingState from primaite.simulator.network.container import Network
from primaite.simulator.network.hardware.nodes.host.computer import Computer from primaite.simulator.network.hardware.nodes.host.computer import Computer
from primaite.simulator.network.hardware.nodes.host.server import Server
from primaite.simulator.system.applications.application import ApplicationOperatingState from primaite.simulator.system.applications.application import ApplicationOperatingState
from primaite.simulator.system.applications.database_client import DatabaseClient from primaite.simulator.system.applications.database_client import DatabaseClient
from primaite.simulator.system.services.database.database_service import DatabaseService
@pytest.fixture(scope="function") @pytest.fixture(scope="function")
def database_client_on_computer() -> Tuple[DatabaseClient, Computer]: def database_client_on_computer() -> Tuple[DatabaseClient, Computer]:
computer = Computer( network = Network()
hostname="db_node", ip_address="192.168.0.1", subnet_mask="255.255.255.0", operating_state=NodeOperatingState.ON
)
computer.software_manager.install(DatabaseClient)
database_client: DatabaseClient = computer.software_manager.software.get("DatabaseClient") db_server = Server(
hostname="db_server",
ip_address="192.168.0.1",
subnet_mask="255.255.255.0",
start_up_duration=0
)
db_server.power_on()
db_server.software_manager.install(DatabaseService)
db_server.software_manager.software["DatabaseService"].start()
db_client = Computer(
hostname="db_client",
ip_address="192.168.0.2",
subnet_mask="255.255.255.0",
start_up_duration=0
)
db_client.power_on()
db_client.software_manager.install(DatabaseClient)
database_client: DatabaseClient = db_client.software_manager.software.get("DatabaseClient")
database_client.configure(server_ip_address=IPv4Address("192.168.0.1")) database_client.configure(server_ip_address=IPv4Address("192.168.0.1"))
database_client.run() database_client.run()
return database_client, computer
network.connect(db_server.network_interface[1], db_client.network_interface[1])
return database_client, db_client
def test_creation(database_client_on_computer): def test_creation(database_client_on_computer):
@@ -50,7 +71,7 @@ def test_disconnect_when_client_is_closed(database_client_on_computer):
"""Database client disconnect should not do anything when it is not running.""" """Database client disconnect should not do anything when it is not running."""
database_client, computer = database_client_on_computer database_client, computer = database_client_on_computer
database_client.connected = True database_client.connect()
assert database_client.server_ip_address is not None assert database_client.server_ip_address is not None
database_client.close() database_client.close()
@@ -66,24 +87,15 @@ def test_disconnect(database_client_on_computer):
"""Database client should remove the connection.""" """Database client should remove the connection."""
database_client, computer = database_client_on_computer database_client, computer = database_client_on_computer
database_client._connections[str(uuid4())] = {"item": True} assert not database_client.connected
assert len(database_client.connections) == 1
assert database_client.operating_state is ApplicationOperatingState.RUNNING database_client.connect()
assert database_client.server_ip_address is not None
assert database_client.connected
database_client.disconnect() database_client.disconnect()
assert len(database_client.connections) == 0 assert not database_client.connected
uuid = str(uuid4())
database_client._connections[uuid] = {"item": True}
assert len(database_client.connections) == 1
database_client.disconnect(connection_id=uuid)
assert len(database_client.connections) == 0
def test_query_when_client_is_closed(database_client_on_computer): def test_query_when_client_is_closed(database_client_on_computer):
"""Database client should return False when it is not running.""" """Database client should return False when it is not running."""

View File

@@ -16,8 +16,9 @@ def web_browser() -> WebBrowser:
ip_address="192.168.1.11", ip_address="192.168.1.11",
subnet_mask="255.255.255.0", subnet_mask="255.255.255.0",
default_gateway="192.168.1.1", default_gateway="192.168.1.1",
operating_state=NodeOperatingState.ON, start_up_duration=0
) )
computer.power_on()
# Web Browser should be pre-installed in computer # Web Browser should be pre-installed in computer
web_browser: WebBrowser = computer.software_manager.software.get("WebBrowser") web_browser: WebBrowser = computer.software_manager.software.get("WebBrowser")
web_browser.run() web_browser.run()

View File

@@ -1,12 +1,14 @@
import pytest import pytest
from primaite.simulator.network.hardware.base import Node from primaite.simulator.network.hardware.base import Node
from primaite.simulator.network.hardware.nodes.host.computer import Computer
from primaite.simulator.system.services.database.database_service import DatabaseService from primaite.simulator.system.services.database.database_service import DatabaseService
@pytest.fixture(scope="function") @pytest.fixture(scope="function")
def database_server() -> Node: def database_server() -> Node:
node = Node(hostname="db_node") node = Computer(hostname="db_node", ip_address="192.168.1.2", subnet_mask="255.255.255.0", start_up_duration=0)
node.power_on()
node.software_manager.install(DatabaseService) node.software_manager.install(DatabaseService)
node.software_manager.software.get("DatabaseService").start() node.software_manager.software.get("DatabaseService").start()
return node return node

View File

@@ -2,7 +2,6 @@ from ipaddress import IPv4Address
import pytest import pytest
from primaite.simulator.network.hardware.base import Node
from primaite.simulator.network.hardware.node_operating_state import NodeOperatingState from primaite.simulator.network.hardware.node_operating_state import NodeOperatingState
from primaite.simulator.network.hardware.nodes.host.computer import Computer from primaite.simulator.network.hardware.nodes.host.computer import Computer
from primaite.simulator.network.protocols.dns import DNSPacket, DNSReply, DNSRequest from primaite.simulator.network.protocols.dns import DNSPacket, DNSReply, DNSRequest
@@ -13,7 +12,7 @@ from primaite.simulator.system.services.service import ServiceOperatingState
@pytest.fixture(scope="function") @pytest.fixture(scope="function")
def dns_client() -> Node: def dns_client() -> Computer:
node = Computer( node = Computer(
hostname="dns_client", hostname="dns_client",
ip_address="192.168.1.11", ip_address="192.168.1.11",

View File

@@ -2,13 +2,15 @@ from ipaddress import IPv4Address
import pytest import pytest
from primaite.simulator.network.container import Network
from primaite.simulator.network.hardware.base import Node from primaite.simulator.network.hardware.base import Node
from primaite.simulator.network.hardware.node_operating_state import NodeOperatingState from primaite.simulator.network.hardware.node_operating_state import NodeOperatingState
from primaite.simulator.network.hardware.nodes.host.computer import Computer
from primaite.simulator.network.hardware.nodes.host.server import Server from primaite.simulator.network.hardware.nodes.host.server import Server
from primaite.simulator.network.protocols.dns import DNSPacket, DNSRequest
from primaite.simulator.network.transmission.network_layer import IPProtocol from primaite.simulator.network.transmission.network_layer import IPProtocol
from primaite.simulator.network.transmission.transport_layer import Port from primaite.simulator.network.transmission.transport_layer import Port
from primaite.simulator.system.services.dns.dns_server import DNSServer from primaite.simulator.system.services.dns.dns_server import DNSServer
from primaite.simulator.system.services.dns.dns_client import DNSClient
@pytest.fixture(scope="function") @pytest.fixture(scope="function")
@@ -51,14 +53,18 @@ def test_dns_server_receive(dns_server):
# register the web server in the domain controller # register the web server in the domain controller
dns_server_service.dns_register(domain_name="real-domain.com", domain_ip_address=IPv4Address("192.168.1.12")) dns_server_service.dns_register(domain_name="real-domain.com", domain_ip_address=IPv4Address("192.168.1.12"))
assert ( client = Computer(hostname="client", ip_address="192.168.1.11", subnet_mask="255.255.255.0", start_up_duration=0)
dns_server_service.receive(payload=DNSPacket(dns_request=DNSRequest(domain_name_request="fake-domain.com"))) client.power_on()
is False client.dns_server = IPv4Address("192.168.1.10")
) network = Network()
network.connect(dns_server.network_interface[1], client.network_interface[1])
dns_client: DNSClient = client.software_manager.software["DNSClient"] # noqa
dns_client.check_domain_exists("fake-domain.com")
assert dns_client.check_domain_exists("fake-domain.com") is False
assert dns_client.check_domain_exists("real-domain.com") is False
assert (
dns_server_service.receive(payload=DNSPacket(dns_request=DNSRequest(domain_name_request="real-domain.com")))
is True
)
dns_server_service.show() dns_server_service.show()

View File

@@ -22,7 +22,7 @@ def web_server() -> Server:
default_gateway="192.168.1.1", default_gateway="192.168.1.1",
operating_state=NodeOperatingState.ON, operating_state=NodeOperatingState.ON,
) )
node.software_manager.install(software_class=WebServer) node.software_manager.install(WebServer)
node.software_manager.software.get("WebServer").start() node.software_manager.software.get("WebServer").start()
return node return node
@@ -53,17 +53,17 @@ def test_handling_get_request_home_page(web_server):
assert response.status_code == HttpStatusCode.OK assert response.status_code == HttpStatusCode.OK
def test_process_http_request_get(web_server): # def test_process_http_request_get(web_server):
payload = HttpRequestPacket(request_method=HttpRequestMethod.GET, request_url="http://domain.com/") # payload = HttpRequestPacket(request_method=HttpRequestMethod.GET, request_url="http://domain.com/")
#
web_server_service: WebServer = web_server.software_manager.software.get("WebServer") # web_server_service: WebServer = web_server.software_manager.software.get("WebServer")
#
assert web_server_service._process_http_request(payload=payload) is True # assert web_server_service._process_http_request(payload=payload) is True
#
#
def test_process_http_request_method_not_allowed(web_server): # def test_process_http_request_method_not_allowed(web_server):
payload = HttpRequestPacket(request_method=HttpRequestMethod.DELETE, request_url="http://domain.com/") # payload = HttpRequestPacket(request_method=HttpRequestMethod.DELETE, request_url="http://domain.com/")
#
web_server_service: WebServer = web_server.software_manager.software.get("WebServer") # web_server_service: WebServer = web_server.software_manager.software.get("WebServer")
#
assert web_server_service._process_http_request(payload=payload) is False # assert web_server_service._process_http_request(payload=payload) is False