Merged PR 235: Refactor describe_state to use name/hostname instead of UUID as primary key

## Summary
- Refactor Simulator state to use service/application name instead of UUID, and node hostname instead of UUID.
- Refactor observations to read the hostname/name instead of UUID.
- Refactor rewards as well.
- Refactor configs to specify name instead of reference that will be translated to UUID.

## Test process
Existing unit tests pass. Inspected the printout from running 'describe_state' on arcd_uc2_network' to verify that names are used to report state.

## Checklist
- [x] PR is linked to a **work item**
- [x] **acceptance criteria** of linked ticket are met
- [x] performed **self-review** of the code
- [na] written **tests** for any new functionality added with this PR
- [na] updated the **documentation** if this PR changes or adds functionality
- [x] written/updated **design docs** if this PR implements new functionality
- [na] updated the **change log**
- [x] ran **pre-commit** checks for code style
- [x] attended to any **TO-DOs** left in the code

Related work items: #2131
This commit is contained in:
Marek Wolan
2023-12-15 16:02:29 +00:00
15 changed files with 176 additions and 207 deletions

1
.gitignore vendored
View File

@@ -156,3 +156,4 @@ benchmark/output
# src/primaite/notebooks/scratch.ipynb # src/primaite/notebooks/scratch.ipynb
src/primaite/notebooks/scratch.py src/primaite/notebooks/scratch.py
sandbox.py sandbox.py
sandbox.ipynb

View File

@@ -105,25 +105,25 @@ agents:
num_files_per_folder: 1 num_files_per_folder: 1
num_nics_per_node: 2 num_nics_per_node: 2
nodes: nodes:
- node_ref: domain_controller - node_hostname: domain_controller
services: services:
- service_ref: domain_controller_dns_server - service_name: DNSServer
- node_ref: web_server - node_hostname: web_server
services: services:
- service_ref: web_server_database_client - service_name: web_server_database_client
- node_ref: database_server - node_hostname: database_server
services: services:
- service_ref: database_service - service_name: database_service
folders: folders:
- folder_name: database - folder_name: database
files: files:
- file_name: database.db - file_name: database.db
- node_ref: backup_server - node_hostname: backup_server
# services: # services:
# - service_ref: backup_service # - service_ref: backup_service
- node_ref: security_suite - node_hostname: security_suite
- node_ref: client_1 - node_hostname: client_1
- node_ref: client_2 - node_hostname: client_2
links: links:
- link_ref: router_1___switch_1 - link_ref: router_1___switch_1
- link_ref: router_1___switch_2 - link_ref: router_1___switch_2
@@ -138,7 +138,7 @@ agents:
acl: acl:
options: options:
max_acl_rules: 10 max_acl_rules: 10
router_node_ref: router_1 router_hostname: router_1
ip_address_order: ip_address_order:
- node_ref: domain_controller - node_ref: domain_controller
nic_num: 1 nic_num: 1
@@ -509,7 +509,7 @@ agents:
- type: DATABASE_FILE_INTEGRITY - type: DATABASE_FILE_INTEGRITY
weight: 0.5 weight: 0.5
options: options:
node_ref: database_server node_hostname: database_server
folder_name: database folder_name: database
file_name: database.db file_name: database.db
@@ -517,8 +517,8 @@ agents:
- type: WEB_SERVER_404_PENALTY - type: WEB_SERVER_404_PENALTY
weight: 0.5 weight: 0.5
options: options:
node_ref: web_server node_hostname: web_server
service_ref: web_server_web_service service_name: web_server_web_service
agent_settings: agent_settings:

View File

@@ -40,8 +40,7 @@ class AbstractObservation(ABC):
def from_config(cls, config: Dict, game: "PrimaiteGame"): def from_config(cls, config: Dict, game: "PrimaiteGame"):
"""Create this observation space component form a serialised format. """Create this observation space component form a serialised format.
The `game` parameter is for a the PrimaiteGame object that spawns this component. During deserialisation, The `game` parameter is for a the PrimaiteGame object that spawns this component.
a subclass of this class may need to translate from a 'reference' to a UUID.
""" """
pass pass
@@ -53,12 +52,12 @@ class FileObservation(AbstractObservation):
""" """
Initialise file observation. Initialise file observation.
:param where: Store information about where in the simulation state dictionary to find the relevatn information. :param where: Store information about where in the simulation state dictionary to find the relevant information.
Optional. If None, this corresponds that the file does not exist and the observation will be populated with Optional. If None, this corresponds that the file does not exist and the observation will be populated with
zeroes. zeroes.
A typical location for a file looks like this: A typical location for a file looks like this:
['network','nodes',<node_uuid>,'file_system', 'folders',<folder_name>,'files',<file_name>] ['network','nodes',<node_hostname>,'file_system', 'folders',<folder_name>,'files',<file_name>]
:type where: Optional[List[str]] :type where: Optional[List[str]]
""" """
super().__init__() super().__init__()
@@ -120,7 +119,7 @@ class ServiceObservation(AbstractObservation):
zeroes. zeroes.
A typical location for a service looks like this: A typical location for a service looks like this:
`['network','nodes',<node_uuid>,'services', <service_uuid>]` `['network','nodes',<node_hostname>,'services', <service_name>]`
:type where: Optional[List[str]] :type where: Optional[List[str]]
""" """
super().__init__() super().__init__()
@@ -162,7 +161,7 @@ class ServiceObservation(AbstractObservation):
:return: Constructed service observation :return: Constructed service observation
:rtype: ServiceObservation :rtype: ServiceObservation
""" """
return cls(where=parent_where + ["services", game.ref_map_services[config["service_ref"]]]) return cls(where=parent_where + ["services", config["service_name"]])
class LinkObservation(AbstractObservation): class LinkObservation(AbstractObservation):
@@ -179,7 +178,7 @@ class LinkObservation(AbstractObservation):
zeroes. zeroes.
A typical location for a service looks like this: A typical location for a service looks like this:
`['network','nodes',<node_uuid>,'servics', <service_uuid>]` `['network','nodes',<node_hostname>,'servics', <service_name>]`
:type where: Optional[List[str]] :type where: Optional[List[str]]
""" """
super().__init__() super().__init__()
@@ -242,7 +241,7 @@ class FolderObservation(AbstractObservation):
:param where: Where in the simulation state dictionary to find the relevant information for this folder. :param where: Where in the simulation state dictionary to find the relevant information for this folder.
A typical location for a file looks like this: A typical location for a file looks like this:
['network','nodes',<node_uuid>,'file_system', 'folders',<folder_name>] ['network','nodes',<node_hostname>,'file_system', 'folders',<folder_name>]
:type where: Optional[List[str]] :type where: Optional[List[str]]
:param max_files: As size of the space must remain static, define max files that can be in this folder :param max_files: As size of the space must remain static, define max files that can be in this folder
, defaults to 5 , defaults to 5
@@ -321,7 +320,7 @@ class FolderObservation(AbstractObservation):
:type game: PrimaiteGame :type game: PrimaiteGame
:param parent_where: Where in the simulation state dictionary to find the information about this folder's :param parent_where: Where in the simulation state dictionary to find the information about this folder's
parent node. A typical location for a node ``where`` can be: parent node. A typical location for a node ``where`` can be:
['network','nodes',<node_uuid>,'file_system'] ['network','nodes',<node_hostname>,'file_system']
:type parent_where: Optional[List[str]] :type parent_where: Optional[List[str]]
:param num_files_per_folder: How many spaces for files are in this folder observation (to preserve static :param num_files_per_folder: How many spaces for files are in this folder observation (to preserve static
observation size) , defaults to 2 observation size) , defaults to 2
@@ -347,7 +346,7 @@ class NicObservation(AbstractObservation):
:param where: Where in the simulation state dictionary to find the relevant information for this NIC. A typical :param where: Where in the simulation state dictionary to find the relevant information for this NIC. A typical
example may look like this: example may look like this:
['network','nodes',<node_uuid>,'NICs',<nic_uuid>] ['network','nodes',<node_hostname>,'NICs',<nic_number>]
If None, this denotes that the NIC does not exist and the observation will be populated with zeroes. If None, this denotes that the NIC does not exist and the observation will be populated with zeroes.
:type where: Optional[Tuple[str]], optional :type where: Optional[Tuple[str]], optional
""" """
@@ -384,12 +383,12 @@ class NicObservation(AbstractObservation):
:param game: Reference to the PrimaiteGame object that spawned this observation. :param game: Reference to the PrimaiteGame object that spawned this observation.
:type game: PrimaiteGame :type game: PrimaiteGame
:param parent_where: Where in the simulation state dictionary to find the information about this NIC's parent :param parent_where: Where in the simulation state dictionary to find the information about this NIC's parent
node. A typical location for a node ``where`` can be: ['network','nodes',<node_uuid>] node. A typical location for a node ``where`` can be: ['network','nodes',<node_hostname>]
:type parent_where: Optional[List[str]] :type parent_where: Optional[List[str]]
:return: Constructed NIC observation :return: Constructed NIC observation
:rtype: NicObservation :rtype: NicObservation
""" """
return cls(where=parent_where + ["NICs", config["nic_uuid"]]) return cls(where=parent_where + ["NICs", config["nic_num"]])
class NodeObservation(AbstractObservation): class NodeObservation(AbstractObservation):
@@ -412,9 +411,9 @@ class NodeObservation(AbstractObservation):
:param where: Where in the simulation state dictionary for find relevant information for this observation. :param where: Where in the simulation state dictionary for find relevant information for this observation.
A typical location for a node looks like this: A typical location for a node looks like this:
['network','nodes',<node_uuid>]. If empty list, a default null observation will be output, defaults to [] ['network','nodes',<hostname>]. If empty list, a default null observation will be output, defaults to []
:type where: List[str], optional :type where: List[str], optional
:param services: Mapping between position in observation space and service UUID, defaults to {} :param services: Mapping between position in observation space and service name, defaults to {}
:type services: Dict[int,str], optional :type services: Dict[int,str], optional
:param max_services: Max number of services that can be presented in observation space for this node :param max_services: Max number of services that can be presented in observation space for this node
, defaults to 2 , defaults to 2
@@ -423,7 +422,7 @@ class NodeObservation(AbstractObservation):
:type folders: Dict[int,str], optional :type folders: Dict[int,str], optional
:param max_folders: Max number of folders in this node's obs space, defaults to 2 :param max_folders: Max number of folders in this node's obs space, defaults to 2
:type max_folders: int, optional :type max_folders: int, optional
:param nics: Mapping between position in observation space and NIC UUID, defaults to {} :param nics: Mapping between position in observation space and NIC idx, defaults to {}
:type nics: Dict[int,str], optional :type nics: Dict[int,str], optional
:param max_nics: Max number of NICS in this node's obs space, defaults to 5 :param max_nics: Max number of NICS in this node's obs space, defaults to 5
:type max_nics: int, optional :type max_nics: int, optional
@@ -541,11 +540,11 @@ class NodeObservation(AbstractObservation):
:return: Constructed node observation :return: Constructed node observation
:rtype: NodeObservation :rtype: NodeObservation
""" """
node_uuid = game.ref_map_nodes[config["node_ref"]] node_hostname = config["node_hostname"]
if parent_where is None: if parent_where is None:
where = ["network", "nodes", node_uuid] where = ["network", "nodes", node_hostname]
else: else:
where = parent_where + ["nodes", node_uuid] where = parent_where + ["nodes", node_hostname]
svc_configs = config.get("services", {}) svc_configs = config.get("services", {})
services = [ServiceObservation.from_config(config=c, game=game, parent_where=where) for c in svc_configs] services = [ServiceObservation.from_config(config=c, game=game, parent_where=where) for c in svc_configs]
@@ -556,8 +555,8 @@ class NodeObservation(AbstractObservation):
) )
for c in folder_configs for c in folder_configs
] ]
nic_uuids = game.simulation.network.nodes[node_uuid].nics.keys() # create some configs for the NIC observation in the format {"nic_num":1}, {"nic_num":2}, {"nic_num":3}, etc.
nic_configs = [{"nic_uuid": n for n in nic_uuids}] if nic_uuids else [] nic_configs = [{"nic_num": i for i in range(num_nics_per_node)}]
nics = [NicObservation.from_config(config=c, game=game, parent_where=where) for c in nic_configs] nics = [NicObservation.from_config(config=c, game=game, parent_where=where) for c in nic_configs]
logon_status = config.get("logon_status", False) logon_status = config.get("logon_status", False)
return cls( return cls(
@@ -598,7 +597,7 @@ class AclObservation(AbstractObservation):
:type protocols: list[str] :type protocols: list[str]
:param where: Where in the simulation state dictionary to find the relevant information for this ACL. A typical :param where: Where in the simulation state dictionary to find the relevant information for this ACL. A typical
example may look like this: example may look like this:
['network','nodes',<router_uuid>,'acl','acl'] ['network','nodes',<router_hostname>,'acl','acl']
:type where: Optional[Tuple[str]], optional :type where: Optional[Tuple[str]], optional
:param num_rules: , defaults to 10 :param num_rules: , defaults to 10
:type num_rules: int, optional :type num_rules: int, optional
@@ -711,12 +710,12 @@ class AclObservation(AbstractObservation):
nic_obj = node_obj.ethernet_port[nic_num] nic_obj = node_obj.ethernet_port[nic_num]
node_ip_to_idx[nic_obj.ip_address] = ip_idx + 2 node_ip_to_idx[nic_obj.ip_address] = ip_idx + 2
router_uuid = game.ref_map_nodes[config["router_node_ref"]] router_hostname = config["router_hostname"]
return cls( return cls(
node_ip_to_id=node_ip_to_idx, node_ip_to_id=node_ip_to_idx,
ports=game.options.ports, ports=game.options.ports,
protocols=game.options.protocols, protocols=game.options.protocols,
where=["network", "nodes", router_uuid, "acl", "acl"], where=["network", "nodes", router_hostname, "acl", "acl"],
num_rules=max_acl_rules, num_rules=max_acl_rules,
) )
@@ -846,6 +845,7 @@ class UC2BlueObservation(AbstractObservation):
:rtype: UC2BlueObservation :rtype: UC2BlueObservation
""" """
node_configs = config["nodes"] node_configs = config["nodes"]
num_services_per_node = config["num_services_per_node"] num_services_per_node = config["num_services_per_node"]
num_folders_per_node = config["num_folders_per_node"] num_folders_per_node = config["num_folders_per_node"]
num_files_per_folder = config["num_files_per_folder"] num_files_per_folder = config["num_files_per_folder"]

View File

@@ -82,11 +82,11 @@ class DummyReward(AbstractReward):
class DatabaseFileIntegrity(AbstractReward): class DatabaseFileIntegrity(AbstractReward):
"""Reward function component which rewards the agent for maintaining the integrity of a database file.""" """Reward function component which rewards the agent for maintaining the integrity of a database file."""
def __init__(self, node_uuid: str, folder_name: str, file_name: str) -> None: def __init__(self, node_hostname: str, folder_name: str, file_name: str) -> None:
"""Initialise the reward component. """Initialise the reward component.
:param node_uuid: UUID of the node which contains the database file. :param node_hostname: Hostname of the node which contains the database file.
:type node_uuid: str :type node_hostname: str
:param folder_name: folder which contains the database file. :param folder_name: folder which contains the database file.
:type folder_name: str :type folder_name: str
:param file_name: name of the database file. :param file_name: name of the database file.
@@ -95,7 +95,7 @@ class DatabaseFileIntegrity(AbstractReward):
self.location_in_state = [ self.location_in_state = [
"network", "network",
"nodes", "nodes",
node_uuid, node_hostname,
"file_system", "file_system",
"folders", "folders",
folder_name, folder_name,
@@ -129,49 +129,29 @@ class DatabaseFileIntegrity(AbstractReward):
:return: The reward component. :return: The reward component.
:rtype: DatabaseFileIntegrity :rtype: DatabaseFileIntegrity
""" """
node_ref = config.get("node_ref") node_hostname = config.get("node_hostname")
folder_name = config.get("folder_name") folder_name = config.get("folder_name")
file_name = config.get("file_name") file_name = config.get("file_name")
if not node_ref: if not (node_hostname and folder_name and file_name):
_LOGGER.error( msg = f"{cls.__name__} could not be initialised with parameters {config}"
f"{cls.__name__} could not be initialised from config because node_ref parameter was not specified" _LOGGER.error(msg)
) raise ValueError(msg)
return DummyReward() # TODO: better error handling
if not folder_name:
_LOGGER.error(
f"{cls.__name__} could not be initialised from config because folder_name parameter was not specified"
)
return DummyReward() # TODO: better error handling
if not file_name:
_LOGGER.error(
f"{cls.__name__} could not be initialised from config because file_name parameter was not specified"
)
return DummyReward() # TODO: better error handling
node_uuid = game.ref_map_nodes[node_ref]
if not node_uuid:
_LOGGER.error(
(
f"{cls.__name__} could not be initialised from config because the referenced node could not be "
f"found in the simulation"
)
)
return DummyReward() # TODO: better error handling
return cls(node_uuid=node_uuid, folder_name=folder_name, file_name=file_name) return cls(node_hostname=node_hostname, folder_name=folder_name, file_name=file_name)
class WebServer404Penalty(AbstractReward): class WebServer404Penalty(AbstractReward):
"""Reward function component which penalises the agent when the web server returns a 404 error.""" """Reward function component which penalises the agent when the web server returns a 404 error."""
def __init__(self, node_uuid: str, service_uuid: str) -> None: def __init__(self, node_hostname: str, service_name: str) -> None:
"""Initialise the reward component. """Initialise the reward component.
:param node_uuid: UUID of the node which contains the web server service. :param node_hostname: Hostname of the node which contains the web server service.
:type node_uuid: str :type node_hostname: str
:param service_uuid: UUID of the web server service. :param service_name: Name of the web server service.
:type service_uuid: str :type service_name: str
""" """
self.location_in_state = ["network", "nodes", node_uuid, "services", service_uuid] self.location_in_state = ["network", "nodes", node_hostname, "services", service_name]
def calculate(self, state: Dict) -> float: def calculate(self, state: Dict) -> float:
"""Calculate the reward for the current state. """Calculate the reward for the current state.
@@ -203,26 +183,17 @@ class WebServer404Penalty(AbstractReward):
:return: The reward component. :return: The reward component.
:rtype: WebServer404Penalty :rtype: WebServer404Penalty
""" """
node_ref = config.get("node_ref") node_hostname = config.get("node_hostname")
service_ref = config.get("service_ref") service_name = config.get("service_name")
if not (node_ref and service_ref): if not (node_hostname and service_name):
msg = ( msg = (
f"{cls.__name__} could not be initialised from config because node_ref and service_ref were not " f"{cls.__name__} could not be initialised from config because node_ref and service_ref were not "
"found in reward config." "found in reward config."
) )
_LOGGER.warning(msg) _LOGGER.warning(msg)
return DummyReward() # TODO: should we error out with incorrect inputs? Probably! raise ValueError(msg)
node_uuid = game.ref_map_nodes[node_ref]
service_uuid = game.ref_map_services[service_ref]
if not (node_uuid and service_uuid):
msg = (
f"{cls.__name__} could not be initialised because node {node_ref} and service {service_ref} were not"
" found in the simulator."
)
_LOGGER.warning(msg)
return DummyReward() # TODO: consider erroring here as well
return cls(node_uuid=node_uuid, service_uuid=service_uuid) return cls(node_hostname=node_hostname, service_name=service_name)
class RewardFunction: class RewardFunction:

View File

@@ -102,7 +102,7 @@ class DomainController(SimComponent):
:rtype: Dict :rtype: Dict
""" """
state = super().describe_state() state = super().describe_state()
state.update({"accounts": {uuid: acct.describe_state() for uuid, acct in self.accounts.items()}}) state.update({"accounts": {acct.username: acct.describe_state() for acct in self.accounts.values()}})
return state return state
def _register_account(self, account: Account) -> None: def _register_account(self, account: Account) -> None:

View File

@@ -199,10 +199,24 @@ class Network(SimComponent):
state = super().describe_state() state = super().describe_state()
state.update( state.update(
{ {
"nodes": {uuid: node.describe_state() for uuid, node in self.nodes.items()}, "nodes": {node.hostname: node.describe_state() for node in self.nodes.values()},
"links": {uuid: link.describe_state() for uuid, link in self.links.items()}, "links": {},
} }
) )
# Update the links one-by-one. The key is a 4-tuple of `hostname_a, port_a, hostname_b, port_b`
for uuid, link in self.links.items():
node_a = link.endpoint_a._connected_node
node_b = link.endpoint_b._connected_node
hostname_a = node_a.hostname if node_a else None
hostname_b = node_b.hostname if node_b else None
port_a = link.endpoint_a._port_num_on_node
port_b = link.endpoint_b._port_num_on_node
state["links"][uuid] = link.describe_state()
state["links"][uuid]["hostname_a"] = hostname_a
state["links"][uuid]["hostname_b"] = hostname_b
state["links"][uuid]["port_a"] = port_a
state["links"][uuid]["port_b"] = port_b
return state return state
def add_node(self, node: Node) -> None: def add_node(self, node: Node) -> None:

View File

@@ -91,6 +91,8 @@ class NIC(SimComponent):
"Indicates if the NIC supports Wake-on-LAN functionality." "Indicates if the NIC supports Wake-on-LAN functionality."
_connected_node: Optional[Node] = None _connected_node: Optional[Node] = None
"The Node to which the NIC is connected." "The Node to which the NIC is connected."
_port_num_on_node: Optional[int] = None
"Which port number is assigned on this NIC"
_connected_link: Optional[Link] = None _connected_link: Optional[Link] = None
"The Link to which the NIC is connected." "The Link to which the NIC is connected."
enabled: bool = False enabled: bool = False
@@ -148,7 +150,7 @@ class NIC(SimComponent):
state = super().describe_state() state = super().describe_state()
state.update( state.update(
{ {
"ip_adress": str(self.ip_address), "ip_address": str(self.ip_address),
"subnet_mask": str(self.subnet_mask), "subnet_mask": str(self.subnet_mask),
"mac_address": self.mac_address, "mac_address": self.mac_address,
"speed": self.speed, "speed": self.speed,
@@ -311,6 +313,8 @@ class SwitchPort(SimComponent):
"The Maximum Transmission Unit (MTU) of the SwitchPort in Bytes. Default is 1500 B" "The Maximum Transmission Unit (MTU) of the SwitchPort in Bytes. Default is 1500 B"
_connected_node: Optional[Node] = None _connected_node: Optional[Node] = None
"The Node to which the SwitchPort is connected." "The Node to which the SwitchPort is connected."
_port_num_on_node: Optional[int] = None
"The port num on the connected node."
_connected_link: Optional[Link] = None _connected_link: Optional[Link] = None
"The Link to which the SwitchPort is connected." "The Link to which the SwitchPort is connected."
enabled: bool = False enabled: bool = False
@@ -497,8 +501,8 @@ class Link(SimComponent):
state = super().describe_state() state = super().describe_state()
state.update( state.update(
{ {
"endpoint_a": self.endpoint_a.uuid, "endpoint_a": self.endpoint_a.uuid, # TODO: consider if using UUID is the best way to do this
"endpoint_b": self.endpoint_b.uuid, "endpoint_b": self.endpoint_b.uuid, # TODO: consider if using UUID is the best way to do this
"bandwidth": self.bandwidth, "bandwidth": self.bandwidth,
"current_load": self.current_load, "current_load": self.current_load,
} }
@@ -1094,12 +1098,12 @@ class Node(SimComponent):
{ {
"hostname": self.hostname, "hostname": self.hostname,
"operating_state": self.operating_state.value, "operating_state": self.operating_state.value,
"NICs": {uuid: nic.describe_state() for uuid, nic in self.nics.items()}, "NICs": {eth_num: nic.describe_state() for eth_num, nic in self.ethernet_port.items()},
# "switch_ports": {uuid, sp for uuid, sp in self.switch_ports.items()}, # "switch_ports": {uuid, sp for uuid, sp in self.switch_ports.items()},
"file_system": self.file_system.describe_state(), "file_system": self.file_system.describe_state(),
"applications": {uuid: app.describe_state() for uuid, app in self.applications.items()}, "applications": {app.name: app.describe_state() for app in self.applications.values()},
"services": {uuid: svc.describe_state() for uuid, svc in self.services.items()}, "services": {svc.name: svc.describe_state() for svc in self.services.values()},
"process": {uuid: proc.describe_state() for uuid, proc in self.processes.items()}, "process": {proc.name: proc.describe_state() for proc in self.processes.values()},
"revealed_to_red": self.revealed_to_red, "revealed_to_red": self.revealed_to_red,
} }
) )
@@ -1316,6 +1320,7 @@ class Node(SimComponent):
self.nics[nic.uuid] = nic self.nics[nic.uuid] = nic
self.ethernet_port[len(self.nics)] = nic self.ethernet_port[len(self.nics)] = nic
nic._connected_node = self nic._connected_node = self
nic._port_num_on_node = len(self.nics)
nic.parent = self nic.parent = self
self.sys_log.info(f"Connected NIC {nic}") self.sys_log.info(f"Connected NIC {nic}")
if self.operating_state == NodeOperatingState.ON: if self.operating_state == NodeOperatingState.ON:

View File

@@ -30,6 +30,7 @@ class Switch(Node):
self.switch_ports = {i: SwitchPort() for i in range(1, self.num_ports + 1)} self.switch_ports = {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.switch_ports.items():
port._connected_node = self port._connected_node = self
port._port_num_on_node = port_num
port.parent = self port.parent = self
port.port_num = port_num port.port_num = port_num

View File

@@ -41,5 +41,5 @@ class Process(Software):
:rtype: Dict :rtype: Dict
""" """
state = super().describe_state() state = super().describe_state()
state.update({"operating_state": self.operating_state.name}) state.update({"operating_state": self.operating_state.value})
return state return state

View File

@@ -93,25 +93,25 @@ agents:
num_files_per_folder: 1 num_files_per_folder: 1
num_nics_per_node: 2 num_nics_per_node: 2
nodes: nodes:
- node_ref: domain_controller - node_hostname: domain_controller
services: services:
- service_ref: domain_controller_dns_server - service_name: domain_controller_dns_server
- node_ref: web_server - node_hostname: web_server
services: services:
- service_ref: web_server_database_client - service_name: web_server_database_client
- node_ref: database_server - node_hostname: database_server
services: services:
- service_ref: database_service - service_name: database_service
folders: folders:
- folder_name: database - folder_name: database
files: files:
- file_name: database.db - file_name: database.db
- node_ref: backup_server - node_hostname: backup_server
# services: # services:
# - service_ref: backup_service # - service_ref: backup_service
- node_ref: security_suite - node_hostname: security_suite
- node_ref: client_1 - node_hostname: client_1
- node_ref: client_2 - node_hostname: client_2
links: links:
- link_ref: router_1___switch_1 - link_ref: router_1___switch_1
- link_ref: router_1___switch_2 - link_ref: router_1___switch_2
@@ -126,7 +126,7 @@ agents:
acl: acl:
options: options:
max_acl_rules: 10 max_acl_rules: 10
router_node_ref: router_1 router_hostname: router_1
ip_address_order: ip_address_order:
- node_ref: domain_controller - node_ref: domain_controller
nic_num: 1 nic_num: 1
@@ -497,7 +497,7 @@ agents:
- type: DATABASE_FILE_INTEGRITY - type: DATABASE_FILE_INTEGRITY
weight: 0.5 weight: 0.5
options: options:
node_ref: database_server node_hostname: database_server
folder_name: database folder_name: database
file_name: database.db file_name: database.db
@@ -505,8 +505,8 @@ agents:
- type: WEB_SERVER_404_PENALTY - type: WEB_SERVER_404_PENALTY
weight: 0.5 weight: 0.5
options: options:
node_ref: web_server node_hostname: web_server
service_ref: web_server_web_service service_name: web_server_web_service
agent_settings: agent_settings:

View File

@@ -31,13 +31,6 @@ agents:
action_space: action_space:
action_list: action_list:
- type: DONOTHING - type: DONOTHING
# <not yet implemented>
# - type: NODE_LOGON
# - type: NODE_LOGOFF
# - type: NODE_APPLICATION_EXECUTE
# options:
# execution_definition:
# target_address: arcd.com
options: options:
nodes: nodes:
@@ -104,25 +97,25 @@ agents:
num_files_per_folder: 1 num_files_per_folder: 1
num_nics_per_node: 2 num_nics_per_node: 2
nodes: nodes:
- node_ref: domain_controller - node_hostname: domain_controller
services: services:
- service_ref: domain_controller_dns_server - service_name: domain_controller_dns_server
- node_ref: web_server - node_hostname: web_server
services: services:
- service_ref: web_server_database_client - service_name: web_server_database_client
- node_ref: database_server - node_hostname: database_server
services: services:
- service_ref: database_service - service_name: database_service
folders: folders:
- folder_name: database - folder_name: database
files: files:
- file_name: database.db - file_name: database.db
- node_ref: backup_server - node_hostname: backup_server
# services: # services:
# - service_ref: backup_service # - service_ref: backup_service
- node_ref: security_suite - node_hostname: security_suite
- node_ref: client_1 - node_hostname: client_1
- node_ref: client_2 - node_hostname: client_2
links: links:
- link_ref: router_1___switch_1 - link_ref: router_1___switch_1
- link_ref: router_1___switch_2 - link_ref: router_1___switch_2
@@ -137,7 +130,7 @@ agents:
acl: acl:
options: options:
max_acl_rules: 10 max_acl_rules: 10
router_node_ref: router_1 router_hostname: router_1
ip_address_order: ip_address_order:
- node_ref: domain_controller - node_ref: domain_controller
nic_num: 1 nic_num: 1
@@ -508,7 +501,7 @@ agents:
- type: DATABASE_FILE_INTEGRITY - type: DATABASE_FILE_INTEGRITY
weight: 0.5 weight: 0.5
options: options:
node_ref: database_server node_hostname: database_server
folder_name: database folder_name: database
file_name: database.db file_name: database.db
@@ -516,8 +509,8 @@ agents:
- type: WEB_SERVER_404_PENALTY - type: WEB_SERVER_404_PENALTY
weight: 0.5 weight: 0.5
options: options:
node_ref: web_server node_hostname: web_server
service_ref: web_server_web_service service_name: web_server_web_service
agent_settings: agent_settings:

View File

@@ -37,13 +37,6 @@ agents:
action_space: action_space:
action_list: action_list:
- type: DONOTHING - type: DONOTHING
# <not yet implemented>
# - type: NODE_LOGON
# - type: NODE_LOGOFF
# - type: NODE_APPLICATION_EXECUTE
# options:
# execution_definition:
# target_address: arcd.com
options: options:
nodes: nodes:
@@ -111,25 +104,25 @@ agents:
num_files_per_folder: 1 num_files_per_folder: 1
num_nics_per_node: 2 num_nics_per_node: 2
nodes: nodes:
- node_ref: domain_controller - node_hostname: domain_controller
services: services:
- service_ref: domain_controller_dns_server - service_name: domain_controller_dns_server
- node_ref: web_server - node_hostname: web_server
services: services:
- service_ref: web_server_database_client - service_name: web_server_database_client
- node_ref: database_server - node_hostname: database_server
services: services:
- service_ref: database_service - service_name: database_service
folders: folders:
- folder_name: database - folder_name: database
files: files:
- file_name: database.db - file_name: database.db
- node_ref: backup_server - node_hostname: backup_server
# services: # services:
# - service_ref: backup_service # - service_ref: backup_service
- node_ref: security_suite - node_hostname: security_suite
- node_ref: client_1 - node_hostname: client_1
- node_ref: client_2 - node_hostname: client_2
links: links:
- link_ref: router_1___switch_1 - link_ref: router_1___switch_1
- link_ref: router_1___switch_2 - link_ref: router_1___switch_2
@@ -144,7 +137,7 @@ agents:
acl: acl:
options: options:
max_acl_rules: 10 max_acl_rules: 10
router_node_ref: router_1 router_hostname: router_1
ip_address_order: ip_address_order:
- node_ref: domain_controller - node_ref: domain_controller
nic_num: 1 nic_num: 1
@@ -515,7 +508,7 @@ agents:
- type: DATABASE_FILE_INTEGRITY - type: DATABASE_FILE_INTEGRITY
weight: 0.5 weight: 0.5
options: options:
node_ref: database_server node_hostname: database_server
folder_name: database folder_name: database
file_name: database.db file_name: database.db
@@ -523,8 +516,8 @@ agents:
- type: WEB_SERVER_404_PENALTY - type: WEB_SERVER_404_PENALTY
weight: 0.5 weight: 0.5
options: options:
node_ref: web_server node_hostname: web_server
service_ref: web_server_web_service service_name: web_server_web_service
agent_settings: agent_settings:
@@ -542,25 +535,25 @@ agents:
num_files_per_folder: 1 num_files_per_folder: 1
num_nics_per_node: 2 num_nics_per_node: 2
nodes: nodes:
- node_ref: domain_controller - node_hostname: domain_controller
services: services:
- service_ref: domain_controller_dns_server - service_name: domain_controller_dns_server
- node_ref: web_server - node_hostname: web_server
services: services:
- service_ref: web_server_database_client - service_name: web_server_database_client
- node_ref: database_server - node_hostname: database_server
services: services:
- service_ref: database_service - service_name: database_service
folders: folders:
- folder_name: database - folder_name: database
files: files:
- file_name: database.db - file_name: database.db
- node_ref: backup_server - node_hostname: backup_server
# services: # services:
# - service_ref: backup_service # - service_ref: backup_service
- node_ref: security_suite - node_hostname: security_suite
- node_ref: client_1 - node_hostname: client_1
- node_ref: client_2 - node_hostname: client_2
links: links:
- link_ref: router_1___switch_1 - link_ref: router_1___switch_1
- link_ref: router_1___switch_2 - link_ref: router_1___switch_2
@@ -575,7 +568,7 @@ agents:
acl: acl:
options: options:
max_acl_rules: 10 max_acl_rules: 10
router_node_ref: router_1 router_hostname: router_1
ip_address_order: ip_address_order:
- node_ref: domain_controller - node_ref: domain_controller
nic_num: 1 nic_num: 1
@@ -946,7 +939,7 @@ agents:
- type: DATABASE_FILE_INTEGRITY - type: DATABASE_FILE_INTEGRITY
weight: 0.5 weight: 0.5
options: options:
node_ref: database_server node_hostname: database_server
folder_name: database folder_name: database
file_name: database.db file_name: database.db
@@ -954,8 +947,8 @@ agents:
- type: WEB_SERVER_404_PENALTY - type: WEB_SERVER_404_PENALTY
weight: 0.5 weight: 0.5
options: options:
node_ref: web_server node_hostname: web_server
service_ref: web_server_web_service service_name: web_server_web_service
agent_settings: agent_settings:

View File

@@ -35,13 +35,6 @@ agents:
action_space: action_space:
action_list: action_list:
- type: DONOTHING - type: DONOTHING
# <not yet implemented>
# - type: NODE_LOGON
# - type: NODE_LOGOFF
# - type: NODE_APPLICATION_EXECUTE
# options:
# execution_definition:
# target_address: arcd.com
options: options:
nodes: nodes:
@@ -109,25 +102,25 @@ agents:
num_files_per_folder: 1 num_files_per_folder: 1
num_nics_per_node: 2 num_nics_per_node: 2
nodes: nodes:
- node_ref: domain_controller - node_hostname: domain_controller
services: services:
- service_ref: domain_controller_dns_server - service_name: domain_controller_dns_server
- node_ref: web_server - node_hostname: web_server
services: services:
- service_ref: web_server_database_client - service_name: web_server_database_client
- node_ref: database_server - node_hostname: database_server
services: services:
- service_ref: database_service - service_name: database_service
folders: folders:
- folder_name: database - folder_name: database
files: files:
- file_name: database.db - file_name: database.db
- node_ref: backup_server - node_hostname: backup_server
# services: # services:
# - service_ref: backup_service # - service_name: backup_service
- node_ref: security_suite - node_hostname: security_suite
- node_ref: client_1 - node_hostname: client_1
- node_ref: client_2 - node_hostname: client_2
links: links:
- link_ref: router_1___switch_1 - link_ref: router_1___switch_1
- link_ref: router_1___switch_2 - link_ref: router_1___switch_2
@@ -142,7 +135,7 @@ agents:
acl: acl:
options: options:
max_acl_rules: 10 max_acl_rules: 10
router_node_ref: router_1 router_hostname: router_1
ip_address_order: ip_address_order:
- node_ref: domain_controller - node_ref: domain_controller
nic_num: 1 nic_num: 1
@@ -513,7 +506,7 @@ agents:
- type: DATABASE_FILE_INTEGRITY - type: DATABASE_FILE_INTEGRITY
weight: 0.5 weight: 0.5
options: options:
node_ref: database_server node_hostname: database_server
folder_name: database folder_name: database
file_name: database.db file_name: database.db
@@ -521,8 +514,8 @@ agents:
- type: WEB_SERVER_404_PENALTY - type: WEB_SERVER_404_PENALTY
weight: 0.5 weight: 0.5
options: options:
node_ref: web_server node_hostname: web_server
service_ref: web_server_web_service service_name: web_server_web_service
agent_settings: agent_settings:

View File

@@ -105,25 +105,23 @@ agents:
num_files_per_folder: 1 num_files_per_folder: 1
num_nics_per_node: 2 num_nics_per_node: 2
nodes: nodes:
- node_ref: domain_controller - node_hostname: domain_controller
services: services:
- service_ref: domain_controller_dns_server - service_name: domain_controller_dns_server
- node_ref: web_server - node_hostname: web_server
services: services:
- service_ref: web_server_database_client - service_name: web_server_database_client
- node_ref: database_server - node_hostname: database_server
services: services:
- service_ref: database_service - service_name: database_service
folders: folders:
- folder_name: database - folder_name: database
files: files:
- file_name: database.db - file_name: database.db
- node_ref: backup_server - node_hostname: backup_server
# services: - node_hostname: security_suite
# - service_ref: backup_service - node_hostname: client_1
- node_ref: security_suite - node_hostname: client_2
- node_ref: client_1
- node_ref: client_2
links: links:
- link_ref: router_1___switch_1 - link_ref: router_1___switch_1
- link_ref: router_1___switch_2 - link_ref: router_1___switch_2
@@ -138,7 +136,7 @@ agents:
acl: acl:
options: options:
max_acl_rules: 10 max_acl_rules: 10
router_node_ref: router_1 router_hostname: router_1
ip_address_order: ip_address_order:
- node_ref: domain_controller - node_ref: domain_controller
nic_num: 1 nic_num: 1
@@ -509,7 +507,7 @@ agents:
- type: DATABASE_FILE_INTEGRITY - type: DATABASE_FILE_INTEGRITY
weight: 0.5 weight: 0.5
options: options:
node_ref: database_server node_hostname: database_server
folder_name: database folder_name: database
file_name: database.db file_name: database.db
@@ -517,8 +515,8 @@ agents:
- type: WEB_SERVER_404_PENALTY - type: WEB_SERVER_404_PENALTY
weight: 0.5 weight: 0.5
options: options:
node_ref: web_server node_hostname: web_server
service_ref: web_server_web_service service_name: web_service
agent_settings: agent_settings:

View File

@@ -14,7 +14,7 @@ def test_file_observation():
state = sim.describe_state() state = sim.describe_state()
dog_file_obs = FileObservation( dog_file_obs = FileObservation(
where=["network", "nodes", pc.uuid, "file_system", "folders", "root", "files", "dog.png"] where=["network", "nodes", pc.hostname, "file_system", "folders", "root", "files", "dog.png"]
) )
assert dog_file_obs.observe(state) == {"health_status": 1} assert dog_file_obs.observe(state) == {"health_status": 1}
assert dog_file_obs.space == spaces.Dict({"health_status": spaces.Discrete(6)}) assert dog_file_obs.space == spaces.Dict({"health_status": spaces.Discrete(6)})