#1947: node startup/shutdown now take multiple timesteps to complete
This commit is contained in:
@@ -499,9 +499,13 @@ class Folder(FileSystemItemABC):
|
||||
|
||||
def apply_timestep(self, timestep: int):
|
||||
"""
|
||||
Used to run the actions that last over multiple timesteps.
|
||||
Apply a single timestep of simulation dynamics to this service.
|
||||
|
||||
:param: timestep: the current timestep.
|
||||
In this instance, if any multi-timestep processes are currently occurring (such as scanning),
|
||||
then they are brought one step closer to being finished.
|
||||
|
||||
:param timestep: The current timestep number. (Amount of time since simulation episode began)
|
||||
:type timestep: int
|
||||
"""
|
||||
super().apply_timestep(timestep=timestep)
|
||||
|
||||
|
||||
@@ -914,6 +914,18 @@ class Node(SimComponent):
|
||||
revealed_to_red: bool = False
|
||||
"Informs whether the node has been revealed to a red agent."
|
||||
|
||||
start_up_duration: int = 3
|
||||
"Time steps needed for the node to start up."
|
||||
|
||||
start_up_countdown: int = -1
|
||||
"Time steps needed until node is booted up."
|
||||
|
||||
shut_down_duration: int = 3
|
||||
"Time steps needed for the node to shut down."
|
||||
|
||||
shut_down_countdown: int = -1
|
||||
"Time steps needed until node is shut down."
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
"""
|
||||
Initialize the Node with various components and managers.
|
||||
@@ -1042,22 +1054,62 @@ class Node(SimComponent):
|
||||
)
|
||||
print(table)
|
||||
|
||||
def apply_timestep(self, timestep: int):
|
||||
"""
|
||||
Apply a single timestep of simulation dynamics to this service.
|
||||
|
||||
In this instance, if any multi-timestep processes are currently occurring
|
||||
(such as starting up or shutting down), then they are brought one step closer to
|
||||
being finished.
|
||||
|
||||
:param timestep: The current timestep number. (Amount of time since simulation episode began)
|
||||
:type timestep: int
|
||||
"""
|
||||
super().apply_timestep(timestep=timestep)
|
||||
|
||||
# count down to boot up
|
||||
if self.start_up_countdown > 0:
|
||||
self.start_up_countdown -= 1
|
||||
else:
|
||||
if self.operating_state == NodeOperatingState.BOOTING:
|
||||
self.operating_state = NodeOperatingState.ON
|
||||
self.sys_log.info("Turned on")
|
||||
for nic in self.nics.values():
|
||||
if nic._connected_link:
|
||||
nic.enable()
|
||||
|
||||
# count down to shut down
|
||||
if self.shut_down_countdown > 0:
|
||||
self.shut_down_countdown -= 1
|
||||
else:
|
||||
if self.operating_state == NodeOperatingState.SHUTTING_DOWN:
|
||||
self.operating_state = NodeOperatingState.OFF
|
||||
self.sys_log.info("Turned off")
|
||||
|
||||
def power_on(self):
|
||||
"""Power on the Node, enabling its NICs if it is in the OFF state."""
|
||||
if self.operating_state == NodeOperatingState.OFF:
|
||||
self.operating_state = NodeOperatingState.ON
|
||||
self.sys_log.info("Turned on")
|
||||
for nic in self.nics.values():
|
||||
if nic._connected_link:
|
||||
nic.enable()
|
||||
self.operating_state = NodeOperatingState.BOOTING
|
||||
self.start_up_countdown = self.start_up_duration
|
||||
|
||||
if self.start_up_duration <= 0:
|
||||
self.operating_state = NodeOperatingState.ON
|
||||
self.sys_log.info("Turned on")
|
||||
for nic in self.nics.values():
|
||||
if nic._connected_link:
|
||||
nic.enable()
|
||||
|
||||
def power_off(self):
|
||||
"""Power off the Node, disabling its NICs if it is in the ON state."""
|
||||
if self.operating_state == NodeOperatingState.ON:
|
||||
for nic in self.nics.values():
|
||||
nic.disable()
|
||||
self.operating_state = NodeOperatingState.OFF
|
||||
self.sys_log.info("Turned off")
|
||||
self.operating_state = NodeOperatingState.SHUTTING_DOWN
|
||||
self.shut_down_countdown = self.shut_down_duration
|
||||
|
||||
if self.shut_down_duration >= 0:
|
||||
self.operating_state = NodeOperatingState.OFF
|
||||
self.sys_log.info("Turned off")
|
||||
|
||||
def connect_nic(self, nic: NIC):
|
||||
"""
|
||||
@@ -1135,7 +1187,7 @@ class Node(SimComponent):
|
||||
f"Ping statistics for {target_ip_address}: "
|
||||
f"Packets: Sent = {pings}, "
|
||||
f"Received = {request_replies}, "
|
||||
f"Lost = {pings-request_replies} ({(pings-request_replies)/pings*100}% loss)"
|
||||
f"Lost = {pings - request_replies} ({(pings - request_replies) / pings * 100}% loss)"
|
||||
)
|
||||
return passed
|
||||
return False
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from ipaddress import IPv4Address
|
||||
|
||||
from primaite.simulator.network.container import Network
|
||||
from primaite.simulator.network.hardware.base import NIC
|
||||
from primaite.simulator.network.hardware.base import NIC, NodeOperatingState
|
||||
from primaite.simulator.network.hardware.nodes.computer import Computer
|
||||
from primaite.simulator.network.hardware.nodes.router import ACLAction, Router
|
||||
from primaite.simulator.network.hardware.nodes.server import Server
|
||||
@@ -110,19 +110,19 @@ def arcd_uc2_network() -> Network:
|
||||
network = Network()
|
||||
|
||||
# Router 1
|
||||
router_1 = Router(hostname="router_1", num_ports=5)
|
||||
router_1 = Router(hostname="router_1", num_ports=5, operating_state=NodeOperatingState.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=2, ip_address="192.168.10.1", subnet_mask="255.255.255.0")
|
||||
|
||||
# Switch 1
|
||||
switch_1 = Switch(hostname="switch_1", num_ports=8)
|
||||
switch_1 = Switch(hostname="switch_1", num_ports=8, operating_state=NodeOperatingState.ON)
|
||||
switch_1.power_on()
|
||||
network.connect(endpoint_a=router_1.ethernet_ports[1], endpoint_b=switch_1.switch_ports[8])
|
||||
router_1.enable_port(1)
|
||||
|
||||
# Switch 2
|
||||
switch_2 = Switch(hostname="switch_2", num_ports=8)
|
||||
switch_2 = Switch(hostname="switch_2", num_ports=8, operating_state=NodeOperatingState.ON)
|
||||
switch_2.power_on()
|
||||
network.connect(endpoint_a=router_1.ethernet_ports[2], endpoint_b=switch_2.switch_ports[8])
|
||||
router_1.enable_port(2)
|
||||
@@ -134,6 +134,7 @@ def arcd_uc2_network() -> Network:
|
||||
subnet_mask="255.255.255.0",
|
||||
default_gateway="192.168.10.1",
|
||||
dns_server=IPv4Address("192.168.1.10"),
|
||||
operating_state=NodeOperatingState.ON,
|
||||
)
|
||||
client_1.power_on()
|
||||
network.connect(endpoint_b=client_1.ethernet_port[1], endpoint_a=switch_2.switch_ports[1])
|
||||
@@ -148,6 +149,7 @@ def arcd_uc2_network() -> Network:
|
||||
subnet_mask="255.255.255.0",
|
||||
default_gateway="192.168.10.1",
|
||||
dns_server=IPv4Address("192.168.1.10"),
|
||||
operating_state=NodeOperatingState.ON,
|
||||
)
|
||||
client_2.power_on()
|
||||
network.connect(endpoint_b=client_2.ethernet_port[1], endpoint_a=switch_2.switch_ports[2])
|
||||
@@ -158,6 +160,7 @@ def arcd_uc2_network() -> Network:
|
||||
ip_address="192.168.1.10",
|
||||
subnet_mask="255.255.255.0",
|
||||
default_gateway="192.168.1.1",
|
||||
operating_state=NodeOperatingState.ON,
|
||||
)
|
||||
domain_controller.power_on()
|
||||
domain_controller.software_manager.install(DNSServer)
|
||||
@@ -171,6 +174,7 @@ def arcd_uc2_network() -> Network:
|
||||
subnet_mask="255.255.255.0",
|
||||
default_gateway="192.168.1.1",
|
||||
dns_server=IPv4Address("192.168.1.10"),
|
||||
operating_state=NodeOperatingState.ON,
|
||||
)
|
||||
database_server.power_on()
|
||||
network.connect(endpoint_b=database_server.ethernet_port[1], endpoint_a=switch_1.switch_ports[3])
|
||||
@@ -244,6 +248,7 @@ def arcd_uc2_network() -> Network:
|
||||
subnet_mask="255.255.255.0",
|
||||
default_gateway="192.168.1.1",
|
||||
dns_server=IPv4Address("192.168.1.10"),
|
||||
operating_state=NodeOperatingState.ON,
|
||||
)
|
||||
web_server.power_on()
|
||||
web_server.software_manager.install(DatabaseClient)
|
||||
@@ -267,6 +272,7 @@ def arcd_uc2_network() -> Network:
|
||||
subnet_mask="255.255.255.0",
|
||||
default_gateway="192.168.1.1",
|
||||
dns_server=IPv4Address("192.168.1.10"),
|
||||
operating_state=NodeOperatingState.ON,
|
||||
)
|
||||
backup_server.power_on()
|
||||
backup_server.software_manager.install(FTPServer)
|
||||
@@ -279,6 +285,7 @@ def arcd_uc2_network() -> Network:
|
||||
subnet_mask="255.255.255.0",
|
||||
default_gateway="192.168.1.1",
|
||||
dns_server=IPv4Address("192.168.1.10"),
|
||||
operating_state=NodeOperatingState.ON,
|
||||
)
|
||||
security_suite.power_on()
|
||||
network.connect(endpoint_b=security_suite.ethernet_port[1], endpoint_a=switch_1.switch_ports[7])
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
from primaite.simulator.network.hardware.base import Link, NIC, Node
|
||||
from primaite.simulator.network.hardware.base import Link, NIC, Node, NodeOperatingState
|
||||
|
||||
|
||||
def test_node_to_node_ping():
|
||||
"""Tests two Nodes are able to ping each other."""
|
||||
node_a = Node(hostname="node_a")
|
||||
nic_a = NIC(ip_address="192.168.0.10", subnet_mask="255.255.255.0")
|
||||
node_a = Node(hostname="node_a", operating_state=NodeOperatingState.ON)
|
||||
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.power_on()
|
||||
|
||||
node_b = Node(hostname="node_b")
|
||||
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)
|
||||
node_b.power_on()
|
||||
|
||||
Link(endpoint_a=nic_a, endpoint_b=nic_b)
|
||||
|
||||
@@ -20,22 +18,19 @@ def test_node_to_node_ping():
|
||||
|
||||
def test_multi_nic():
|
||||
"""Tests that Nodes with multiple NICs can ping each other and the data go across the correct links."""
|
||||
node_a = Node(hostname="node_a")
|
||||
node_a = Node(hostname="node_a", operating_state=NodeOperatingState.ON)
|
||||
nic_a = NIC(ip_address="192.168.0.10", subnet_mask="255.255.255.0")
|
||||
node_a.connect_nic(nic_a)
|
||||
node_a.power_on()
|
||||
|
||||
node_b = Node(hostname="node_b")
|
||||
node_b = Node(hostname="node_b", operating_state=NodeOperatingState.ON)
|
||||
nic_b1 = NIC(ip_address="192.168.0.11", subnet_mask="255.255.255.0")
|
||||
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_b.power_on()
|
||||
|
||||
node_c = Node(hostname="node_c")
|
||||
node_c = Node(hostname="node_c", operating_state=NodeOperatingState.ON)
|
||||
nic_c = NIC(ip_address="10.0.0.13", subnet_mask="255.0.0.0")
|
||||
node_c.connect_nic(nic_c)
|
||||
node_c.power_on()
|
||||
|
||||
Link(endpoint_a=nic_a, endpoint_b=nic_b1)
|
||||
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
from primaite.simulator.network.hardware.base import Link, NIC, Node
|
||||
from primaite.simulator.network.hardware.base import Link, NIC, Node, NodeOperatingState
|
||||
|
||||
|
||||
def test_link_up():
|
||||
"""Tests Nodes, NICs, and Links can all be connected and be in an enabled/up state."""
|
||||
node_a = Node(hostname="node_a")
|
||||
node_a = Node(hostname="node_a", operating_state=NodeOperatingState.ON)
|
||||
nic_a = NIC(ip_address="192.168.0.10", subnet_mask="255.255.255.0")
|
||||
node_a.connect_nic(nic_a)
|
||||
node_a.power_on()
|
||||
|
||||
node_b = Node(hostname="node_b")
|
||||
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)
|
||||
node_b.power_on()
|
||||
|
||||
link = Link(endpoint_a=nic_a, endpoint_b=nic_b)
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ from typing import Tuple
|
||||
|
||||
import pytest
|
||||
|
||||
from primaite.simulator.network.hardware.base import Link, NIC, Node
|
||||
from primaite.simulator.network.hardware.base import Link, NIC, Node, NodeOperatingState
|
||||
from primaite.simulator.network.hardware.nodes.router import ACLAction, Router
|
||||
from primaite.simulator.network.transmission.network_layer import IPProtocol
|
||||
from primaite.simulator.network.transmission.transport_layer import Port
|
||||
@@ -10,18 +10,15 @@ from primaite.simulator.network.transmission.transport_layer import Port
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def pc_a_pc_b_router_1() -> Tuple[Node, Node, Router]:
|
||||
pc_a = Node(hostname="pc_a", default_gateway="192.168.0.1")
|
||||
pc_a = Node(hostname="pc_a", default_gateway="192.168.0.1", operating_state=NodeOperatingState.ON)
|
||||
nic_a = NIC(ip_address="192.168.0.10", subnet_mask="255.255.255.0")
|
||||
pc_a.connect_nic(nic_a)
|
||||
pc_a.power_on()
|
||||
|
||||
pc_b = Node(hostname="pc_b", default_gateway="192.168.1.1")
|
||||
pc_b = Node(hostname="pc_b", default_gateway="192.168.1.1", operating_state=NodeOperatingState.ON)
|
||||
nic_b = NIC(ip_address="192.168.1.10", subnet_mask="255.255.255.0")
|
||||
pc_b.connect_nic(nic_b)
|
||||
pc_b.power_on()
|
||||
|
||||
router_1 = Router(hostname="router_1")
|
||||
router_1.power_on()
|
||||
router_1 = Router(hostname="router_1", operating_state=NodeOperatingState.ON)
|
||||
|
||||
router_1.configure_port(1, "192.168.0.1", "255.255.255.0")
|
||||
router_1.configure_port(2, "192.168.1.1", "255.255.255.0")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from primaite.simulator.network.hardware.base import Link
|
||||
from primaite.simulator.network.hardware.base import Link, NodeOperatingState
|
||||
from primaite.simulator.network.hardware.nodes.computer import Computer
|
||||
from primaite.simulator.network.hardware.nodes.server import Server
|
||||
from primaite.simulator.network.hardware.nodes.switch import Switch
|
||||
@@ -7,17 +7,22 @@ from primaite.simulator.network.hardware.nodes.switch import Switch
|
||||
def test_switched_network():
|
||||
"""Tests a node can ping another node via the switch."""
|
||||
client_1 = Computer(
|
||||
hostname="client_1", ip_address="192.168.1.10", subnet_mask="255.255.255.0", default_gateway="192.168.1.0"
|
||||
hostname="client_1",
|
||||
ip_address="192.168.1.10",
|
||||
subnet_mask="255.255.255.0",
|
||||
default_gateway="192.168.1.0",
|
||||
operating_state=NodeOperatingState.ON,
|
||||
)
|
||||
client_1.power_on()
|
||||
|
||||
server_1 = Server(
|
||||
hostname=" server_1", ip_address="192.168.1.11", subnet_mask="255.255.255.0", default_gateway="192.168.1.11"
|
||||
hostname=" server_1",
|
||||
ip_address="192.168.1.11",
|
||||
subnet_mask="255.255.255.0",
|
||||
default_gateway="192.168.1.11",
|
||||
operating_state=NodeOperatingState.ON,
|
||||
)
|
||||
server_1.power_on()
|
||||
|
||||
switch_1 = Switch(hostname="switch_1", num_ports=6)
|
||||
switch_1.power_on()
|
||||
switch_1 = Switch(hostname="switch_1", num_ports=6, operating_state=NodeOperatingState.ON)
|
||||
|
||||
Link(endpoint_a=client_1.ethernet_port[1], endpoint_b=switch_1.switch_ports[1])
|
||||
Link(endpoint_a=server_1.ethernet_port[1], endpoint_b=switch_1.switch_ports[2])
|
||||
|
||||
@@ -11,13 +11,31 @@ def node() -> Node:
|
||||
def test_node_startup(node):
|
||||
assert node.operating_state == NodeOperatingState.OFF
|
||||
node.apply_request(["startup"])
|
||||
assert node.operating_state == NodeOperatingState.BOOTING
|
||||
|
||||
idx = 0
|
||||
while node.operating_state == NodeOperatingState.BOOTING:
|
||||
node.apply_timestep(timestep=idx)
|
||||
idx += 1
|
||||
|
||||
assert node.operating_state == NodeOperatingState.ON
|
||||
|
||||
|
||||
def test_node_shutdown(node):
|
||||
assert node.operating_state == NodeOperatingState.OFF
|
||||
node.apply_request(["startup"])
|
||||
idx = 0
|
||||
while node.operating_state == NodeOperatingState.BOOTING:
|
||||
node.apply_timestep(timestep=idx)
|
||||
idx += 1
|
||||
|
||||
assert node.operating_state == NodeOperatingState.ON
|
||||
|
||||
node.apply_request(["shutdown"])
|
||||
|
||||
idx = 0
|
||||
while node.operating_state == NodeOperatingState.SHUTTING_DOWN:
|
||||
node.apply_timestep(timestep=idx)
|
||||
idx += 1
|
||||
|
||||
assert node.operating_state == NodeOperatingState.OFF
|
||||
|
||||
Reference in New Issue
Block a user