From 1613bbe27afece0621614b1931daae38848c24e4 Mon Sep 17 00:00:00 2001 From: Marek Wolan Date: Wed, 23 Aug 2023 14:41:30 +0100 Subject: [PATCH 01/10] Add methods for adding/removing nodes form network --- .../notebooks/create-simulation.ipynb | 200 +++--------------- src/primaite/simulator/core.py | 22 ++ src/primaite/simulator/network/container.py | 47 +++- 3 files changed, 93 insertions(+), 176 deletions(-) diff --git a/src/primaite/notebooks/create-simulation.ipynb b/src/primaite/notebooks/create-simulation.ipynb index b0a140a1..11d41356 100644 --- a/src/primaite/notebooks/create-simulation.ipynb +++ b/src/primaite/notebooks/create-simulation.ipynb @@ -18,7 +18,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -36,26 +36,12 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'uuid': '5304ed6d-de4c-408c-ae24-ada32852d196',\n", - " 'network': {'uuid': 'fa17dfe8-81a1-4c7f-8c5b-8c2d3b1e8756',\n", - " 'nodes': {},\n", - " 'links': {}},\n", - " 'domain': {'uuid': '320cbb83-eb1b-4911-a4f0-fc46d8038a8a', 'accounts': {}}}" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "my_sim = Simulation()\n", + "net = my_sim.network\n", "my_sim.describe_state()" ] }, @@ -68,7 +54,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -77,17 +63,14 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ "my_pc = Node(hostname=\"primaite_pc\",)\n", + "net.add_node(my_pc)\n", "my_server = Node(hostname=\"google_server\")\n", - "\n", - "# TODO: when there is a proper function for adding nodes, use it instead of manually adding.\n", - "\n", - "my_sim.network.nodes[my_pc.uuid] = my_pc\n", - "my_sim.network.nodes[my_server.uuid] = my_server\n" + "net.add_node(my_server)\n" ] }, { @@ -99,7 +82,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -108,22 +91,12 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2023-08-20 18:42:51,310: NIC 5c:b6:26:c0:86:61/130.1.1.1 connected to Link 5c:b6:26:c0:86:61/130.1.1.1<-->01:ef:b1:a3:24:72\n", - "2023-08-20 18:42:51,311: SwitchPort 01:ef:b1:a3:24:72 connected to Link 5c:b6:26:c0:86:61/130.1.1.1<-->01:ef:b1:a3:24:72\n", - "2023-08-20 18:42:51,314: NIC f6:de:1e:63:8e:7f/130.1.1.2 connected to Link f6:de:1e:63:8e:7f/130.1.1.2<-->30:9e:c8:d4:5d:f3\n", - "2023-08-20 18:42:51,315: SwitchPort 30:9e:c8:d4:5d:f3 connected to Link f6:de:1e:63:8e:7f/130.1.1.2<-->30:9e:c8:d4:5d:f3\n" - ] - } - ], + "outputs": [], "source": [ "my_swtich = Switch(hostname=\"switch1\", num_ports=12)\n", + "net.add_node(my_swtich)\n", "\n", "pc_nic = NIC(ip_address=\"130.1.1.1\", gateway=\"130.1.1.255\", subnet_mask=\"255.255.255.0\")\n", "my_pc.connect_nic(pc_nic)\n", @@ -149,7 +122,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -159,7 +132,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -169,20 +142,9 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "FileSystemFile(uuid='253e4606-0f6d-4e57-8db0-6fa7e331ecea', name='favicon.ico', size=40.0, file_type=, action_manager=None)" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "my_server_folder = my_server.file_system.create_folder(\"static\")\n", "my_server.file_system.create_file(\"favicon.ico\", file_type=FileSystemFileType.PNG)" @@ -197,7 +159,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -213,7 +175,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -222,7 +184,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -238,7 +200,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -247,7 +209,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -264,130 +226,18 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'uuid': '5304ed6d-de4c-408c-ae24-ada32852d196',\n", - " 'network': {'uuid': 'fa17dfe8-81a1-4c7f-8c5b-8c2d3b1e8756',\n", - " 'nodes': {'1fa46446-6681-4e25-a3ba-c4c2cc564630': {'uuid': '1fa46446-6681-4e25-a3ba-c4c2cc564630',\n", - " 'hostname': 'primaite_pc',\n", - " 'operating_state': 0,\n", - " 'NICs': {'09ca02eb-7733-492c-9eff-f0d6b6ebeeda': {'uuid': '09ca02eb-7733-492c-9eff-f0d6b6ebeeda',\n", - " 'ip_adress': '130.1.1.1',\n", - " 'subnet_mask': '255.255.255.0',\n", - " 'gateway': '130.1.1.255',\n", - " 'mac_address': '5c:b6:26:c0:86:61',\n", - " 'speed': 100,\n", - " 'mtu': 1500,\n", - " 'wake_on_lan': False,\n", - " 'dns_servers': [],\n", - " 'enabled': False}},\n", - " 'file_system': {'uuid': '8b533e31-04e9-4838-839d-0656ace3e57a',\n", - " 'folders': {'b450c223-872c-4fe0-90cc-9da80973eaad': {'uuid': 'b450c223-872c-4fe0-90cc-9da80973eaad',\n", - " 'name': 'downloads',\n", - " 'size': 1000.0,\n", - " 'files': {'8160e685-a76f-4171-8a12-3d6b32a9ea16': {'uuid': '8160e685-a76f-4171-8a12-3d6b32a9ea16',\n", - " 'name': 'firefox_installer.zip',\n", - " 'size': 1000.0,\n", - " 'file_type': 'ZIP'}},\n", - " 'is_quarantined': False}}},\n", - " 'applications': {'c82f1064-f35e-466b-88ae-3f61ba0e5161': {'uuid': 'c82f1064-f35e-466b-88ae-3f61ba0e5161',\n", - " 'health_state': 'GOOD',\n", - " 'health_state_red_view': 'GOOD',\n", - " 'criticality': 'MEDIUM',\n", - " 'patching_count': 0,\n", - " 'scanning_count': 0,\n", - " 'revealed_to_red': False,\n", - " 'installing_count': 0,\n", - " 'max_sessions': 1,\n", - " 'tcp': True,\n", - " 'udp': True,\n", - " 'ports': ['HTTP'],\n", - " 'opearting_state': 'RUNNING',\n", - " 'execution_control_status': 'manual',\n", - " 'num_executions': 0,\n", - " 'groups': []}},\n", - " 'services': {},\n", - " 'process': {}},\n", - " '7f637689-6f91-4026-a685-48a9067f03e8': {'uuid': '7f637689-6f91-4026-a685-48a9067f03e8',\n", - " 'hostname': 'google_server',\n", - " 'operating_state': 0,\n", - " 'NICs': {'1abc7272-c516-4463-bd07-1a3cefe39313': {'uuid': '1abc7272-c516-4463-bd07-1a3cefe39313',\n", - " 'ip_adress': '130.1.1.2',\n", - " 'subnet_mask': '255.255.255.0',\n", - " 'gateway': '130.1.1.255',\n", - " 'mac_address': 'f6:de:1e:63:8e:7f',\n", - " 'speed': 100,\n", - " 'mtu': 1500,\n", - " 'wake_on_lan': False,\n", - " 'dns_servers': [],\n", - " 'enabled': False}},\n", - " 'file_system': {'uuid': 'ac9a6643-8349-4f7a-98c7-a1a9f97ce123',\n", - " 'folders': {'befa5d92-0878-4da2-9dac-f993c0b4a554': {'uuid': 'befa5d92-0878-4da2-9dac-f993c0b4a554',\n", - " 'name': 'static',\n", - " 'size': 0,\n", - " 'files': {},\n", - " 'is_quarantined': False},\n", - " '27383b5e-8884-4ec0-bb50-a5d43e460dfa': {'uuid': '27383b5e-8884-4ec0-bb50-a5d43e460dfa',\n", - " 'name': 'root',\n", - " 'size': 40.0,\n", - " 'files': {'253e4606-0f6d-4e57-8db0-6fa7e331ecea': {'uuid': '253e4606-0f6d-4e57-8db0-6fa7e331ecea',\n", - " 'name': 'favicon.ico',\n", - " 'size': 40.0,\n", - " 'file_type': 'PNG'}},\n", - " 'is_quarantined': False}}},\n", - " 'applications': {},\n", - " 'services': {},\n", - " 'process': {}}},\n", - " 'links': {'a449b1ff-50d9-4342-861e-44f2d4dfef37': {'uuid': 'a449b1ff-50d9-4342-861e-44f2d4dfef37',\n", - " 'endpoint_a': '09ca02eb-7733-492c-9eff-f0d6b6ebeeda',\n", - " 'endpoint_b': 'ee4557d9-a309-45dd-a6e0-5b572cc70ee5',\n", - " 'bandwidth': 100.0,\n", - " 'current_load': 0.0},\n", - " 'ebd7687b-ec69-4f1b-b2ba-86669aa95723': {'uuid': 'ebd7687b-ec69-4f1b-b2ba-86669aa95723',\n", - " 'endpoint_a': '1abc7272-c516-4463-bd07-1a3cefe39313',\n", - " 'endpoint_b': 'dc26b764-a07e-486a-99a4-798c8e0c187a',\n", - " 'bandwidth': 100.0,\n", - " 'current_load': 0.0}}},\n", - " 'domain': {'uuid': '320cbb83-eb1b-4911-a4f0-fc46d8038a8a',\n", - " 'accounts': {'5fdcfb66-84f3-4f0f-a3a7-d0cb0e1a5d51': {'uuid': '5fdcfb66-84f3-4f0f-a3a7-d0cb0e1a5d51',\n", - " 'num_logons': 0,\n", - " 'num_logoffs': 0,\n", - " 'num_group_changes': 0,\n", - " 'username': 'admin',\n", - " 'password': 'admin12',\n", - " 'account_type': 'USER',\n", - " 'enabled': True}}}}" - ] - }, - "execution_count": 15, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "my_sim.describe_state()" ] }, { "cell_type": "code", - "execution_count": 16, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'{\"uuid\": \"5304ed6d-de4c-408c-ae24-ada32852d196\", \"network\": {\"uuid\": \"fa17dfe8-81a1-4c7f-8c5b-8c2d3b1e8756\", \"nodes\": {\"1fa46446-6681-4e25-a3ba-c4c2cc564630\": {\"uuid\": \"1fa46446-6681-4e25-a3ba-c4c2cc564630\", \"hostname\": \"primaite_pc\", \"operating_state\": 0, \"NICs\": {\"09ca02eb-7733-492c-9eff-f0d6b6ebeeda\": {\"uuid\": \"09ca02eb-7733-492c-9eff-f0d6b6ebeeda\", \"ip_adress\": \"130.1.1.1\", \"subnet_mask\": \"255.255.255.0\", \"gateway\": \"130.1.1.255\", \"mac_address\": \"5c:b6:26:c0:86:61\", \"speed\": 100, \"mtu\": 1500, \"wake_on_lan\": false, \"dns_servers\": [], \"enabled\": false}}, \"file_system\": {\"uuid\": \"8b533e31-04e9-4838-839d-0656ace3e57a\", \"folders\": {\"b450c223-872c-4fe0-90cc-9da80973eaad\": {\"uuid\": \"b450c223-872c-4fe0-90cc-9da80973eaad\", \"name\": \"downloads\", \"size\": 1000.0, \"files\": {\"8160e685-a76f-4171-8a12-3d6b32a9ea16\": {\"uuid\": \"8160e685-a76f-4171-8a12-3d6b32a9ea16\", \"name\": \"firefox_installer.zip\", \"size\": 1000.0, \"file_type\": \"ZIP\"}}, \"is_quarantined\": false}}}, \"applications\": {\"c82f1064-f35e-466b-88ae-3f61ba0e5161\": {\"uuid\": \"c82f1064-f35e-466b-88ae-3f61ba0e5161\", \"health_state\": \"GOOD\", \"health_state_red_view\": \"GOOD\", \"criticality\": \"MEDIUM\", \"patching_count\": 0, \"scanning_count\": 0, \"revealed_to_red\": false, \"installing_count\": 0, \"max_sessions\": 1, \"tcp\": true, \"udp\": true, \"ports\": [\"HTTP\"], \"opearting_state\": \"RUNNING\", \"execution_control_status\": \"manual\", \"num_executions\": 0, \"groups\": []}}, \"services\": {}, \"process\": {}}, \"7f637689-6f91-4026-a685-48a9067f03e8\": {\"uuid\": \"7f637689-6f91-4026-a685-48a9067f03e8\", \"hostname\": \"google_server\", \"operating_state\": 0, \"NICs\": {\"1abc7272-c516-4463-bd07-1a3cefe39313\": {\"uuid\": \"1abc7272-c516-4463-bd07-1a3cefe39313\", \"ip_adress\": \"130.1.1.2\", \"subnet_mask\": \"255.255.255.0\", \"gateway\": \"130.1.1.255\", \"mac_address\": \"f6:de:1e:63:8e:7f\", \"speed\": 100, \"mtu\": 1500, \"wake_on_lan\": false, \"dns_servers\": [], \"enabled\": false}}, \"file_system\": {\"uuid\": \"ac9a6643-8349-4f7a-98c7-a1a9f97ce123\", \"folders\": {\"befa5d92-0878-4da2-9dac-f993c0b4a554\": {\"uuid\": \"befa5d92-0878-4da2-9dac-f993c0b4a554\", \"name\": \"static\", \"size\": 0, \"files\": {}, \"is_quarantined\": false}, \"27383b5e-8884-4ec0-bb50-a5d43e460dfa\": {\"uuid\": \"27383b5e-8884-4ec0-bb50-a5d43e460dfa\", \"name\": \"root\", \"size\": 40.0, \"files\": {\"253e4606-0f6d-4e57-8db0-6fa7e331ecea\": {\"uuid\": \"253e4606-0f6d-4e57-8db0-6fa7e331ecea\", \"name\": \"favicon.ico\", \"size\": 40.0, \"file_type\": \"PNG\"}}, \"is_quarantined\": false}}}, \"applications\": {}, \"services\": {}, \"process\": {}}}, \"links\": {\"a449b1ff-50d9-4342-861e-44f2d4dfef37\": {\"uuid\": \"a449b1ff-50d9-4342-861e-44f2d4dfef37\", \"endpoint_a\": \"09ca02eb-7733-492c-9eff-f0d6b6ebeeda\", \"endpoint_b\": \"ee4557d9-a309-45dd-a6e0-5b572cc70ee5\", \"bandwidth\": 100.0, \"current_load\": 0.0}, \"ebd7687b-ec69-4f1b-b2ba-86669aa95723\": {\"uuid\": \"ebd7687b-ec69-4f1b-b2ba-86669aa95723\", \"endpoint_a\": \"1abc7272-c516-4463-bd07-1a3cefe39313\", \"endpoint_b\": \"dc26b764-a07e-486a-99a4-798c8e0c187a\", \"bandwidth\": 100.0, \"current_load\": 0.0}}}, \"domain\": {\"uuid\": \"320cbb83-eb1b-4911-a4f0-fc46d8038a8a\", \"accounts\": {\"5fdcfb66-84f3-4f0f-a3a7-d0cb0e1a5d51\": {\"uuid\": \"5fdcfb66-84f3-4f0f-a3a7-d0cb0e1a5d51\", \"num_logons\": 0, \"num_logoffs\": 0, \"num_group_changes\": 0, \"username\": \"admin\", \"password\": \"admin12\", \"account_type\": \"USER\", \"enabled\": true}}}}'" - ] - }, - "execution_count": 16, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "import json\n", "json.dumps(my_sim.describe_state())" diff --git a/src/primaite/simulator/core.py b/src/primaite/simulator/core.py index 2c802c0f..63120ecf 100644 --- a/src/primaite/simulator/core.py +++ b/src/primaite/simulator/core.py @@ -137,6 +137,7 @@ class SimComponent(BaseModel): kwargs["uuid"] = str(uuid4()) super().__init__(**kwargs) self.action_manager: Optional[ActionManager] = None + self._parent: Optional["SimComponent"] = None @abstractmethod def describe_state(self) -> Dict: @@ -187,3 +188,24 @@ class SimComponent(BaseModel): Override this method with anything that needs to happen within the component for it to be reset. """ pass + + @property + def parent(self) -> "SimComponent": + """Reference to the parent object which manages this object. + + :return: Parent object. + :rtype: SimComponent + """ + return self._parent + + @parent.setter + def parent(self, new_parent: "SimComponent") -> None: + if self._parent: + msg = f"Overwriting parent of {self}, {self._parent} with {new_parent}" + _LOGGER.warn(msg) + raise RuntimeWarning(msg) + self._parent = new_parent + + @parent.deleter + def parent(self) -> None: + self._parent = None diff --git a/src/primaite/simulator/network/container.py b/src/primaite/simulator/network/container.py index f89ed2d3..be2a3bbb 100644 --- a/src/primaite/simulator/network/container.py +++ b/src/primaite/simulator/network/container.py @@ -1,8 +1,11 @@ -from typing import Dict +from typing import Any, Dict +from primaite import getLogger from primaite.simulator.core import Action, ActionManager, AllowAllValidator, SimComponent from primaite.simulator.network.hardware.base import Link, Node +_LOGGER = getLogger(__name__) + class NetworkContainer(SimComponent): """Top level container object representing the physical network.""" @@ -40,3 +43,45 @@ class NetworkContainer(SimComponent): } ) return state + + def add_node(self, node: Node) -> None: + """ + Add an existing node to the network. + + :param node: Node instance that the network should keep track of. + :type node: Node + """ + if node in self: + _LOGGER.warning(f"Can't add node {node}. It is already in the network.") + self.nodes[node.uuid] = node + node.parent = self + + def remove_node(self, node: Node) -> None: + """ + Remove a node from the network. + + :param node: Node instance that is currently part of the network that should be removed. + :type node: Node + """ + if node not in self: + _LOGGER.warning(f"Can't remove node {node}. It's not in the network.") + del self.nodes[node.uuid] + del node.parent # misleading? + + def connect_nodes(self, node1: Node, node2: Node) -> None: + """TODO.""" + # I think we should not be forcing users to add and remove individual links. + # Clearly if a link exists between two nodes in the network, then the link is also part of the network. + # I'm just not sure how we ought to handle link creation as it requires an unoccupied network device on the node + raise NotImplementedError + + def disconnect_nodes(self, node1: Node, node2: Node) -> None: + """TODO.""" + raise NotImplementedError + + def __contains__(self, item: Any) -> bool: + if isinstance(item, Node): + return item.uuid in self.nodes + elif isinstance(item, Link): + return item.uuid in self.links + raise TypeError("") From 72b019287aef95c014a36b5e1764aba208da7ff6 Mon Sep 17 00:00:00 2001 From: Marek Wolan Date: Wed, 23 Aug 2023 14:41:59 +0100 Subject: [PATCH 02/10] Add scratch notebook to gitignore. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 60f5f54c..ff86b65f 100644 --- a/.gitignore +++ b/.gitignore @@ -150,3 +150,4 @@ src/primaite/outputs/ # benchmark session outputs benchmark/output +src/primaite/notebooks/scratch.ipynb From a82ffb974717273963482d9162579538dac2ffb8 Mon Sep 17 00:00:00 2001 From: Marek Wolan Date: Wed, 23 Aug 2023 15:44:23 +0100 Subject: [PATCH 03/10] Add notebook outputs back into src control --- .../notebooks/create-simulation.ipynb | 254 ++++++++++++++++-- 1 file changed, 233 insertions(+), 21 deletions(-) diff --git a/src/primaite/notebooks/create-simulation.ipynb b/src/primaite/notebooks/create-simulation.ipynb index 11d41356..e3e7dfb7 100644 --- a/src/primaite/notebooks/create-simulation.ipynb +++ b/src/primaite/notebooks/create-simulation.ipynb @@ -18,7 +18,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "metadata": {}, "outputs": [], "source": [ @@ -36,9 +36,24 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "{'uuid': '95929b6a-1ce4-4c94-966c-6d3246d7caf9',\n", + " 'network': {'uuid': '4b41398e-d768-47c5-80cf-4278cfc35a24',\n", + " 'nodes': {},\n", + " 'links': {}},\n", + " 'domain': {'uuid': '15920e15-6cd1-4a93-b6af-acbcc6f6468e', 'accounts': {}}}" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "my_sim = Simulation()\n", "net = my_sim.network\n", @@ -54,7 +69,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "metadata": {}, "outputs": [], "source": [ @@ -63,7 +78,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "metadata": {}, "outputs": [], "source": [ @@ -82,7 +97,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "metadata": {}, "outputs": [], "source": [ @@ -91,9 +106,20 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2023-08-23 15:44:02,059: NIC 1b:8f:94:4f:46:99/130.1.1.1 connected to Link 1b:8f:94:4f:46:99/130.1.1.1<-->ad:3c:77:44:98:27\n", + "2023-08-23 15:44:02,062: SwitchPort ad:3c:77:44:98:27 connected to Link 1b:8f:94:4f:46:99/130.1.1.1<-->ad:3c:77:44:98:27\n", + "2023-08-23 15:44:02,064: NIC 50:f4:6b:9b:a8:74/130.1.1.2 connected to Link 50:f4:6b:9b:a8:74/130.1.1.2<-->fd:b1:68:f9:8f:eb\n", + "2023-08-23 15:44:02,065: SwitchPort fd:b1:68:f9:8f:eb connected to Link 50:f4:6b:9b:a8:74/130.1.1.2<-->fd:b1:68:f9:8f:eb\n" + ] + } + ], "source": [ "my_swtich = Switch(hostname=\"switch1\", num_ports=12)\n", "net.add_node(my_swtich)\n", @@ -122,7 +148,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "metadata": {}, "outputs": [], "source": [ @@ -132,7 +158,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 8, "metadata": {}, "outputs": [], "source": [ @@ -142,9 +168,20 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 9, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "FileSystemFile(uuid='f45bffd7-4aa1-4f6f-81ba-85e746abd28b', name='favicon.ico', size=40.0, file_type=, action_manager=None)" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "my_server_folder = my_server.file_system.create_folder(\"static\")\n", "my_server.file_system.create_file(\"favicon.ico\", file_type=FileSystemFileType.PNG)" @@ -159,7 +196,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 10, "metadata": {}, "outputs": [], "source": [ @@ -175,7 +212,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 11, "metadata": {}, "outputs": [], "source": [ @@ -184,7 +221,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 12, "metadata": {}, "outputs": [], "source": [ @@ -200,7 +237,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 13, "metadata": {}, "outputs": [], "source": [ @@ -209,7 +246,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 14, "metadata": {}, "outputs": [], "source": [ @@ -226,18 +263,193 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 15, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "{'uuid': '95929b6a-1ce4-4c94-966c-6d3246d7caf9',\n", + " 'network': {'uuid': '4b41398e-d768-47c5-80cf-4278cfc35a24',\n", + " 'nodes': {'1599c08e-a101-41a7-a86a-4176660c4270': {'uuid': '1599c08e-a101-41a7-a86a-4176660c4270',\n", + " 'hostname': 'primaite_pc',\n", + " 'operating_state': 0,\n", + " 'NICs': {'ab09d298-ac44-40ef-b950-b4ca6268d482': {'uuid': 'ab09d298-ac44-40ef-b950-b4ca6268d482',\n", + " 'ip_adress': '130.1.1.1',\n", + " 'subnet_mask': '255.255.255.0',\n", + " 'gateway': '130.1.1.255',\n", + " 'mac_address': '1b:8f:94:4f:46:99',\n", + " 'speed': 100,\n", + " 'mtu': 1500,\n", + " 'wake_on_lan': False,\n", + " 'dns_servers': [],\n", + " 'enabled': False}},\n", + " 'file_system': {'uuid': '92120387-14cb-426c-98f2-64d64a85f560',\n", + " 'folders': {'6a11bd03-bc59-4da9-8474-639fcb72b9be': {'uuid': '6a11bd03-bc59-4da9-8474-639fcb72b9be',\n", + " 'name': 'downloads',\n", + " 'size': 1000.0,\n", + " 'files': {'194b2029-4723-4cff-b6d7-e647e4fb687d': {'uuid': '194b2029-4723-4cff-b6d7-e647e4fb687d',\n", + " 'name': 'firefox_installer.zip',\n", + " 'size': 1000.0,\n", + " 'file_type': 'ZIP'}},\n", + " 'is_quarantined': False}}},\n", + " 'applications': {'ae49273b-f581-44e7-ae8c-18cc766158e8': {'uuid': 'ae49273b-f581-44e7-ae8c-18cc766158e8',\n", + " 'health_state': 'GOOD',\n", + " 'health_state_red_view': 'GOOD',\n", + " 'criticality': 'MEDIUM',\n", + " 'patching_count': 0,\n", + " 'scanning_count': 0,\n", + " 'revealed_to_red': False,\n", + " 'installing_count': 0,\n", + " 'max_sessions': 1,\n", + " 'tcp': True,\n", + " 'udp': True,\n", + " 'ports': ['HTTP'],\n", + " 'opearting_state': 'RUNNING',\n", + " 'execution_control_status': 'manual',\n", + " 'num_executions': 0,\n", + " 'groups': []}},\n", + " 'services': {},\n", + " 'process': {}},\n", + " '7231c745-e186-47a2-8f69-006033b38b8f': {'uuid': '7231c745-e186-47a2-8f69-006033b38b8f',\n", + " 'hostname': 'google_server',\n", + " 'operating_state': 0,\n", + " 'NICs': {'d138788b-2a8e-4c5c-aa5d-b5c28758a78a': {'uuid': 'd138788b-2a8e-4c5c-aa5d-b5c28758a78a',\n", + " 'ip_adress': '130.1.1.2',\n", + " 'subnet_mask': '255.255.255.0',\n", + " 'gateway': '130.1.1.255',\n", + " 'mac_address': '50:f4:6b:9b:a8:74',\n", + " 'speed': 100,\n", + " 'mtu': 1500,\n", + " 'wake_on_lan': False,\n", + " 'dns_servers': [],\n", + " 'enabled': False}},\n", + " 'file_system': {'uuid': '85f1d50c-ded7-4160-9a11-1305ab25934b',\n", + " 'folders': {'86c2666e-31da-46a9-a267-4dc87e2620f9': {'uuid': '86c2666e-31da-46a9-a267-4dc87e2620f9',\n", + " 'name': 'static',\n", + " 'size': 0,\n", + " 'files': {},\n", + " 'is_quarantined': False},\n", + " '1a4479df-6f52-428c-b7b9-c026ab24d2a3': {'uuid': '1a4479df-6f52-428c-b7b9-c026ab24d2a3',\n", + " 'name': 'root',\n", + " 'size': 40.0,\n", + " 'files': {'f45bffd7-4aa1-4f6f-81ba-85e746abd28b': {'uuid': 'f45bffd7-4aa1-4f6f-81ba-85e746abd28b',\n", + " 'name': 'favicon.ico',\n", + " 'size': 40.0,\n", + " 'file_type': 'PNG'}},\n", + " 'is_quarantined': False}}},\n", + " 'applications': {},\n", + " 'services': {},\n", + " 'process': {}},\n", + " '384bab1c-aa23-49cf-9c4e-caababcf30a0': {'uuid': '384bab1c-aa23-49cf-9c4e-caababcf30a0',\n", + " 'num_ports': 12,\n", + " 'ports': {1: {'uuid': 'e64847dd-6f19-4f5e-b473-4f9098ca4b9c',\n", + " 'mac_address': 'ad:3c:77:44:98:27',\n", + " 'speed': 100,\n", + " 'mtu': 1500,\n", + " 'enabled': False},\n", + " 2: {'uuid': 'd65f815d-dc28-4313-a4f0-b918bb026e7c',\n", + " 'mac_address': 'fd:b1:68:f9:8f:eb',\n", + " 'speed': 100,\n", + " 'mtu': 1500,\n", + " 'enabled': False},\n", + " 3: {'uuid': '8e1d8783-80af-4aad-bc1e-0c5f1d28b9a1',\n", + " 'mac_address': 'bb:ba:58:26:52:2d',\n", + " 'speed': 100,\n", + " 'mtu': 1500,\n", + " 'enabled': False},\n", + " 4: {'uuid': '3cde63c0-38e4-4faa-88ba-3a958118e2b3',\n", + " 'mac_address': '69:bc:6f:e1:30:32',\n", + " 'speed': 100,\n", + " 'mtu': 1500,\n", + " 'enabled': False},\n", + " 5: {'uuid': '37e49743-1723-4b0e-a1e5-61d76e230c08',\n", + " 'mac_address': 'd3:a0:8b:92:25:11',\n", + " 'speed': 100,\n", + " 'mtu': 1500,\n", + " 'enabled': False},\n", + " 6: {'uuid': '3bf0c0c4-27f6-4a90-8279-1f713b46f4bf',\n", + " 'mac_address': '48:88:7c:71:0a:c0',\n", + " 'speed': 100,\n", + " 'mtu': 1500,\n", + " 'enabled': False},\n", + " 7: {'uuid': '40b0ba34-9e70-448a-8fdf-836a5a71ed8f',\n", + " 'mac_address': '24:81:03:09:c0:be',\n", + " 'speed': 100,\n", + " 'mtu': 1500,\n", + " 'enabled': False},\n", + " 8: {'uuid': 'cd23d94b-84b8-441c-bd95-4e310682a095',\n", + " 'mac_address': '27:18:c5:47:fd:82',\n", + " 'speed': 100,\n", + " 'mtu': 1500,\n", + " 'enabled': False},\n", + " 9: {'uuid': '608eb5bd-7875-4b64-a6f8-794e6283a305',\n", + " 'mac_address': '03:dd:34:d2:56:1c',\n", + " 'speed': 100,\n", + " 'mtu': 1500,\n", + " 'enabled': False},\n", + " 10: {'uuid': '4acb48c6-74be-40d3-b706-64c06c55720b',\n", + " 'mac_address': 'a3:55:83:af:b7:6b',\n", + " 'speed': 100,\n", + " 'mtu': 1500,\n", + " 'enabled': False},\n", + " 11: {'uuid': '73e989b5-3c2c-4035-8191-47220ea5ca43',\n", + " 'mac_address': '4f:60:84:21:50:6d',\n", + " 'speed': 100,\n", + " 'mtu': 1500,\n", + " 'enabled': False},\n", + " 12: {'uuid': '961ff733-a07c-433b-9433-8418a3761120',\n", + " 'mac_address': '7a:26:02:14:8d:da',\n", + " 'speed': 100,\n", + " 'mtu': 1500,\n", + " 'enabled': False}},\n", + " 'mac_address_table': {}}},\n", + " 'links': {'67df55f4-c485-4eed-a4dc-fe6f96f6b2f3': {'uuid': '67df55f4-c485-4eed-a4dc-fe6f96f6b2f3',\n", + " 'endpoint_a': 'ab09d298-ac44-40ef-b950-b4ca6268d482',\n", + " 'endpoint_b': 'e64847dd-6f19-4f5e-b473-4f9098ca4b9c',\n", + " 'bandwidth': 100.0,\n", + " 'current_load': 0.0},\n", + " '4fdb61da-7cc9-43ea-9ee6-7d9853deff72': {'uuid': '4fdb61da-7cc9-43ea-9ee6-7d9853deff72',\n", + " 'endpoint_a': 'd138788b-2a8e-4c5c-aa5d-b5c28758a78a',\n", + " 'endpoint_b': 'd65f815d-dc28-4313-a4f0-b918bb026e7c',\n", + " 'bandwidth': 100.0,\n", + " 'current_load': 0.0}}},\n", + " 'domain': {'uuid': '15920e15-6cd1-4a93-b6af-acbcc6f6468e',\n", + " 'accounts': {'d7f5bd32-5071-4bec-a111-a9f4e1aca45a': {'uuid': 'd7f5bd32-5071-4bec-a111-a9f4e1aca45a',\n", + " 'num_logons': 0,\n", + " 'num_logoffs': 0,\n", + " 'num_group_changes': 0,\n", + " 'username': 'admin',\n", + " 'password': 'admin12',\n", + " 'account_type': 'USER',\n", + " 'enabled': True}}}}" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "my_sim.describe_state()" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 16, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "'{\"uuid\": \"95929b6a-1ce4-4c94-966c-6d3246d7caf9\", \"network\": {\"uuid\": \"4b41398e-d768-47c5-80cf-4278cfc35a24\", \"nodes\": {\"1599c08e-a101-41a7-a86a-4176660c4270\": {\"uuid\": \"1599c08e-a101-41a7-a86a-4176660c4270\", \"hostname\": \"primaite_pc\", \"operating_state\": 0, \"NICs\": {\"ab09d298-ac44-40ef-b950-b4ca6268d482\": {\"uuid\": \"ab09d298-ac44-40ef-b950-b4ca6268d482\", \"ip_adress\": \"130.1.1.1\", \"subnet_mask\": \"255.255.255.0\", \"gateway\": \"130.1.1.255\", \"mac_address\": \"1b:8f:94:4f:46:99\", \"speed\": 100, \"mtu\": 1500, \"wake_on_lan\": false, \"dns_servers\": [], \"enabled\": false}}, \"file_system\": {\"uuid\": \"92120387-14cb-426c-98f2-64d64a85f560\", \"folders\": {\"6a11bd03-bc59-4da9-8474-639fcb72b9be\": {\"uuid\": \"6a11bd03-bc59-4da9-8474-639fcb72b9be\", \"name\": \"downloads\", \"size\": 1000.0, \"files\": {\"194b2029-4723-4cff-b6d7-e647e4fb687d\": {\"uuid\": \"194b2029-4723-4cff-b6d7-e647e4fb687d\", \"name\": \"firefox_installer.zip\", \"size\": 1000.0, \"file_type\": \"ZIP\"}}, \"is_quarantined\": false}}}, \"applications\": {\"ae49273b-f581-44e7-ae8c-18cc766158e8\": {\"uuid\": \"ae49273b-f581-44e7-ae8c-18cc766158e8\", \"health_state\": \"GOOD\", \"health_state_red_view\": \"GOOD\", \"criticality\": \"MEDIUM\", \"patching_count\": 0, \"scanning_count\": 0, \"revealed_to_red\": false, \"installing_count\": 0, \"max_sessions\": 1, \"tcp\": true, \"udp\": true, \"ports\": [\"HTTP\"], \"opearting_state\": \"RUNNING\", \"execution_control_status\": \"manual\", \"num_executions\": 0, \"groups\": []}}, \"services\": {}, \"process\": {}}, \"7231c745-e186-47a2-8f69-006033b38b8f\": {\"uuid\": \"7231c745-e186-47a2-8f69-006033b38b8f\", \"hostname\": \"google_server\", \"operating_state\": 0, \"NICs\": {\"d138788b-2a8e-4c5c-aa5d-b5c28758a78a\": {\"uuid\": \"d138788b-2a8e-4c5c-aa5d-b5c28758a78a\", \"ip_adress\": \"130.1.1.2\", \"subnet_mask\": \"255.255.255.0\", \"gateway\": \"130.1.1.255\", \"mac_address\": \"50:f4:6b:9b:a8:74\", \"speed\": 100, \"mtu\": 1500, \"wake_on_lan\": false, \"dns_servers\": [], \"enabled\": false}}, \"file_system\": {\"uuid\": \"85f1d50c-ded7-4160-9a11-1305ab25934b\", \"folders\": {\"86c2666e-31da-46a9-a267-4dc87e2620f9\": {\"uuid\": \"86c2666e-31da-46a9-a267-4dc87e2620f9\", \"name\": \"static\", \"size\": 0, \"files\": {}, \"is_quarantined\": false}, \"1a4479df-6f52-428c-b7b9-c026ab24d2a3\": {\"uuid\": \"1a4479df-6f52-428c-b7b9-c026ab24d2a3\", \"name\": \"root\", \"size\": 40.0, \"files\": {\"f45bffd7-4aa1-4f6f-81ba-85e746abd28b\": {\"uuid\": \"f45bffd7-4aa1-4f6f-81ba-85e746abd28b\", \"name\": \"favicon.ico\", \"size\": 40.0, \"file_type\": \"PNG\"}}, \"is_quarantined\": false}}}, \"applications\": {}, \"services\": {}, \"process\": {}}, \"384bab1c-aa23-49cf-9c4e-caababcf30a0\": {\"uuid\": \"384bab1c-aa23-49cf-9c4e-caababcf30a0\", \"num_ports\": 12, \"ports\": {\"1\": {\"uuid\": \"e64847dd-6f19-4f5e-b473-4f9098ca4b9c\", \"mac_address\": \"ad:3c:77:44:98:27\", \"speed\": 100, \"mtu\": 1500, \"enabled\": false}, \"2\": {\"uuid\": \"d65f815d-dc28-4313-a4f0-b918bb026e7c\", \"mac_address\": \"fd:b1:68:f9:8f:eb\", \"speed\": 100, \"mtu\": 1500, \"enabled\": false}, \"3\": {\"uuid\": \"8e1d8783-80af-4aad-bc1e-0c5f1d28b9a1\", \"mac_address\": \"bb:ba:58:26:52:2d\", \"speed\": 100, \"mtu\": 1500, \"enabled\": false}, \"4\": {\"uuid\": \"3cde63c0-38e4-4faa-88ba-3a958118e2b3\", \"mac_address\": \"69:bc:6f:e1:30:32\", \"speed\": 100, \"mtu\": 1500, \"enabled\": false}, \"5\": {\"uuid\": \"37e49743-1723-4b0e-a1e5-61d76e230c08\", \"mac_address\": \"d3:a0:8b:92:25:11\", \"speed\": 100, \"mtu\": 1500, \"enabled\": false}, \"6\": {\"uuid\": \"3bf0c0c4-27f6-4a90-8279-1f713b46f4bf\", \"mac_address\": \"48:88:7c:71:0a:c0\", \"speed\": 100, \"mtu\": 1500, \"enabled\": false}, \"7\": {\"uuid\": \"40b0ba34-9e70-448a-8fdf-836a5a71ed8f\", \"mac_address\": \"24:81:03:09:c0:be\", \"speed\": 100, \"mtu\": 1500, \"enabled\": false}, \"8\": {\"uuid\": \"cd23d94b-84b8-441c-bd95-4e310682a095\", \"mac_address\": \"27:18:c5:47:fd:82\", \"speed\": 100, \"mtu\": 1500, \"enabled\": false}, \"9\": {\"uuid\": \"608eb5bd-7875-4b64-a6f8-794e6283a305\", \"mac_address\": \"03:dd:34:d2:56:1c\", \"speed\": 100, \"mtu\": 1500, \"enabled\": false}, \"10\": {\"uuid\": \"4acb48c6-74be-40d3-b706-64c06c55720b\", \"mac_address\": \"a3:55:83:af:b7:6b\", \"speed\": 100, \"mtu\": 1500, \"enabled\": false}, \"11\": {\"uuid\": \"73e989b5-3c2c-4035-8191-47220ea5ca43\", \"mac_address\": \"4f:60:84:21:50:6d\", \"speed\": 100, \"mtu\": 1500, \"enabled\": false}, \"12\": {\"uuid\": \"961ff733-a07c-433b-9433-8418a3761120\", \"mac_address\": \"7a:26:02:14:8d:da\", \"speed\": 100, \"mtu\": 1500, \"enabled\": false}}, \"mac_address_table\": {}}}, \"links\": {\"67df55f4-c485-4eed-a4dc-fe6f96f6b2f3\": {\"uuid\": \"67df55f4-c485-4eed-a4dc-fe6f96f6b2f3\", \"endpoint_a\": \"ab09d298-ac44-40ef-b950-b4ca6268d482\", \"endpoint_b\": \"e64847dd-6f19-4f5e-b473-4f9098ca4b9c\", \"bandwidth\": 100.0, \"current_load\": 0.0}, \"4fdb61da-7cc9-43ea-9ee6-7d9853deff72\": {\"uuid\": \"4fdb61da-7cc9-43ea-9ee6-7d9853deff72\", \"endpoint_a\": \"d138788b-2a8e-4c5c-aa5d-b5c28758a78a\", \"endpoint_b\": \"d65f815d-dc28-4313-a4f0-b918bb026e7c\", \"bandwidth\": 100.0, \"current_load\": 0.0}}}, \"domain\": {\"uuid\": \"15920e15-6cd1-4a93-b6af-acbcc6f6468e\", \"accounts\": {\"d7f5bd32-5071-4bec-a111-a9f4e1aca45a\": {\"uuid\": \"d7f5bd32-5071-4bec-a111-a9f4e1aca45a\", \"num_logons\": 0, \"num_logoffs\": 0, \"num_group_changes\": 0, \"username\": \"admin\", \"password\": \"admin12\", \"account_type\": \"USER\", \"enabled\": true}}}}'" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "import json\n", "json.dumps(my_sim.describe_state())" From 4077eb3a5cfabbfe9800a2249a0a733e160a5a7c Mon Sep 17 00:00:00 2001 From: Marek Wolan Date: Thu, 24 Aug 2023 10:26:17 +0100 Subject: [PATCH 04/10] Add tests for network node adding/removal --- src/primaite/simulator/network/container.py | 8 +++- .../network/test_network_creation.py | 38 +++++++++++++++++++ .../_simulator/_network/test_container.py | 16 ++++++++ 3 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 tests/integration_tests/network/test_network_creation.py create mode 100644 tests/unit_tests/_primaite/_simulator/_network/test_container.py diff --git a/src/primaite/simulator/network/container.py b/src/primaite/simulator/network/container.py index be2a3bbb..5d7e6a47 100644 --- a/src/primaite/simulator/network/container.py +++ b/src/primaite/simulator/network/container.py @@ -52,7 +52,9 @@ class NetworkContainer(SimComponent): :type node: Node """ if node in self: - _LOGGER.warning(f"Can't add node {node}. It is already in the network.") + msg = f"Can't add node {node}. It is already in the network." + _LOGGER.warning(msg) + raise RuntimeWarning(msg) self.nodes[node.uuid] = node node.parent = self @@ -64,7 +66,9 @@ class NetworkContainer(SimComponent): :type node: Node """ if node not in self: - _LOGGER.warning(f"Can't remove node {node}. It's not in the network.") + msg = f"Can't remove node {node}. It's not in the network." + _LOGGER.warning(msg) + raise RuntimeWarning(msg) del self.nodes[node.uuid] del node.parent # misleading? diff --git a/tests/integration_tests/network/test_network_creation.py b/tests/integration_tests/network/test_network_creation.py new file mode 100644 index 00000000..482c188d --- /dev/null +++ b/tests/integration_tests/network/test_network_creation.py @@ -0,0 +1,38 @@ +import pytest + +from primaite.simulator.network.container import NetworkContainer +from primaite.simulator.network.hardware.base import Node + + +def test_adding_removing_nodes(): + """Check that we can create and add a node to a network.""" + net = NetworkContainer() + n1 = Node(hostname="computer") + net.add_node(n1) + assert n1.parent is net + assert n1 in net + + net.remove_node(n1) + assert n1.parent is None + assert n1 not in net + + +def test_readding_node(): + """Check that warning is raised when readding a node.""" + net = NetworkContainer() + n1 = Node(hostname="computer") + net.add_node(n1) + with pytest.raises(RuntimeWarning): + net.add_node(n1) + assert n1.parent is net + assert n1 in net + + +def test_removing_nonexistent_node(): + """Check that warning is raised when trying to remove a node that is not in the network.""" + net = NetworkContainer() + n1 = Node(hostname="computer") + with pytest.raises(RuntimeWarning): + net.remove_node(n1) + assert n1.parent is None + assert n1 not in net diff --git a/tests/unit_tests/_primaite/_simulator/_network/test_container.py b/tests/unit_tests/_primaite/_simulator/_network/test_container.py new file mode 100644 index 00000000..2492dc87 --- /dev/null +++ b/tests/unit_tests/_primaite/_simulator/_network/test_container.py @@ -0,0 +1,16 @@ +import json + +from primaite.simulator.network.container import NetworkContainer + + +def test_creating_container(): + """Check that we can create a network container""" + net = NetworkContainer() + assert net.nodes and net.links + + +def test_describe_state(): + """Check that we can describe network state without raising errors, and that the result is JSON serialisable.""" + net = NetworkContainer() + state = net.describe_state() + json.dumps(state) # if this function call raises an error, the test fails, state was not JSON-serialisable From f38b423886e45dbf5422a1326f5402e453e99034 Mon Sep 17 00:00:00 2001 From: Marek Wolan Date: Thu, 24 Aug 2023 10:27:30 +0100 Subject: [PATCH 05/10] Update comment --- src/primaite/simulator/network/container.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/primaite/simulator/network/container.py b/src/primaite/simulator/network/container.py index 5d7e6a47..db782744 100644 --- a/src/primaite/simulator/network/container.py +++ b/src/primaite/simulator/network/container.py @@ -76,7 +76,7 @@ class NetworkContainer(SimComponent): """TODO.""" # I think we should not be forcing users to add and remove individual links. # Clearly if a link exists between two nodes in the network, then the link is also part of the network. - # I'm just not sure how we ought to handle link creation as it requires an unoccupied network device on the node + # I'm just not sure how we ought to handle link creation as it requires an unoccupied interface on the node. raise NotImplementedError def disconnect_nodes(self, node1: Node, node2: Node) -> None: From a818de8f0133fcd5c1eb37b2b12cb83dcb9b3c73 Mon Sep 17 00:00:00 2001 From: Marek Wolan Date: Thu, 24 Aug 2023 12:40:00 +0100 Subject: [PATCH 06/10] Add ability to connect nodes via the network. --- src/primaite/simulator/network/container.py | 48 ++++++++++++++----- .../simulator/network/hardware/base.py | 2 + .../network/test_network_creation.py | 46 +++++++++++++++++- 3 files changed, 84 insertions(+), 12 deletions(-) diff --git a/src/primaite/simulator/network/container.py b/src/primaite/simulator/network/container.py index db782744..432356b8 100644 --- a/src/primaite/simulator/network/container.py +++ b/src/primaite/simulator/network/container.py @@ -1,8 +1,8 @@ -from typing import Any, Dict +from typing import Any, Dict, Union from primaite import getLogger from primaite.simulator.core import Action, ActionManager, AllowAllValidator, SimComponent -from primaite.simulator.network.hardware.base import Link, Node +from primaite.simulator.network.hardware.base import Link, NIC, Node, SwitchPort _LOGGER = getLogger(__name__) @@ -72,16 +72,42 @@ class NetworkContainer(SimComponent): del self.nodes[node.uuid] del node.parent # misleading? - def connect_nodes(self, node1: Node, node2: Node) -> None: - """TODO.""" - # I think we should not be forcing users to add and remove individual links. - # Clearly if a link exists between two nodes in the network, then the link is also part of the network. - # I'm just not sure how we ought to handle link creation as it requires an unoccupied interface on the node. - raise NotImplementedError + def connect_nodes(self, endpoint_a: Union[NIC, SwitchPort], endpoint_b: Union[NIC, SwitchPort], **kwargs) -> None: + """Connect two nodes on the network by creating a link between an NIC/SwitchPort of each one. - def disconnect_nodes(self, node1: Node, node2: Node) -> None: - """TODO.""" - raise NotImplementedError + :param endpoint_a: The endpoint to which to connect the link on the first node + :type endpoint_a: Union[NIC, SwitchPort] + :param endpoint_b: The endpoint to which to connct the link on the second node + :type endpoint_b: Union[NIC, SwitchPort] + :raises RuntimeError: _description_ + """ + node_a = endpoint_a.parent + node_b = endpoint_b.parent + msg = "" + if node_a not in self: + msg = f"Cannot create a link to {endpoint_a} because the node is not in the network." + if node_b not in self: + msg = f"Cannot create a link to {endpoint_b} because the node is not in the network." + if node_a is node_b: + msg = f"Cannot link {endpoint_a} to {endpoint_b} because they belong to the same node." + if msg: + _LOGGER.error(msg) + raise RuntimeError(msg) + + link = Link(endpoint_a=endpoint_a, endpoint_b=endpoint_b, **kwargs) + self.links[link.uuid] = link + link.parent = self + + def remove_link(self, link: Link) -> None: + """Disconnect a link from the network. + + :param link: The link to be removed + :type link: Link + """ + link.endpoint_a.disconnect_link() + link.endpoint_b.disconnect_link() + del self.links[link.uuid] + del link.parent def __contains__(self, item: Any) -> bool: if isinstance(item, Node): diff --git a/src/primaite/simulator/network/hardware/base.py b/src/primaite/simulator/network/hardware/base.py index 28e7693a..5b49f008 100644 --- a/src/primaite/simulator/network/hardware/base.py +++ b/src/primaite/simulator/network/hardware/base.py @@ -918,6 +918,7 @@ class Node(SimComponent): if nic.uuid not in self.nics: self.nics[nic.uuid] = nic nic.connected_node = self + nic.parent = self self.sys_log.info(f"Connected NIC {nic}") if self.operating_state == NodeOperatingState.ON: nic.enable() @@ -938,6 +939,7 @@ class Node(SimComponent): nic = self.nics.get(nic) if nic or nic.uuid in self.nics: self.nics.pop(nic.uuid) + del nic.parent nic.disable() self.sys_log.info(f"Disconnected NIC {nic}") else: diff --git a/tests/integration_tests/network/test_network_creation.py b/tests/integration_tests/network/test_network_creation.py index 482c188d..0ee827be 100644 --- a/tests/integration_tests/network/test_network_creation.py +++ b/tests/integration_tests/network/test_network_creation.py @@ -1,7 +1,7 @@ import pytest from primaite.simulator.network.container import NetworkContainer -from primaite.simulator.network.hardware.base import Node +from primaite.simulator.network.hardware.base import NIC, Node def test_adding_removing_nodes(): @@ -36,3 +36,47 @@ def test_removing_nonexistent_node(): net.remove_node(n1) assert n1.parent is None assert n1 not in net + + +def test_connecting_nodes(): + """Check that two nodes on the network can be connected.""" + net = NetworkContainer() + n1 = Node(hostname="computer") + n1_nic = NIC(ip_address="120.30.0.1", gateway="192.168.0.1", subnet_mask="255.255.255.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(n2) + + net.connect_nodes(n1.nics[n1_nic.uuid], n2.nics[n2_nic.uuid], bandwidth=30) + + assert len(net.links) == 1 + link = list(net.links.values())[0] + assert link in net + assert link.parent is net + + +def test_connecting_node_to_itself(): + net = NetworkContainer() + node = Node(hostname="computer") + nic1 = NIC(ip_address="120.30.0.1", gateway="192.168.0.1", subnet_mask="255.255.255.0") + node.connect_nic(nic1) + 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) + + with pytest.raises(RuntimeError): + net.connect_nodes(node.nics[nic1.uuid], node.nics[nic2.uuid], bandwidth=30) + + assert node in net + assert nic1.connected_link is None + assert nic2.connected_link is None + assert len(net.links) == 0 + + +def test_disconnecting_nodes(): + ... From 7058c7e9a89e1462d924c0b578f92fb789a051b5 Mon Sep 17 00:00:00 2001 From: Marek Wolan Date: Thu, 24 Aug 2023 12:41:46 +0100 Subject: [PATCH 07/10] Rename networkcontainer to network --- src/primaite/simulator/network/container.py | 2 +- src/primaite/simulator/sim_container.py | 6 +++--- .../network/test_network_creation.py | 12 ++++++------ .../_primaite/_simulator/_network/test_container.py | 6 +++--- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/primaite/simulator/network/container.py b/src/primaite/simulator/network/container.py index 432356b8..0612069c 100644 --- a/src/primaite/simulator/network/container.py +++ b/src/primaite/simulator/network/container.py @@ -7,7 +7,7 @@ from primaite.simulator.network.hardware.base import Link, NIC, Node, SwitchPort _LOGGER = getLogger(__name__) -class NetworkContainer(SimComponent): +class Network(SimComponent): """Top level container object representing the physical network.""" nodes: Dict[str, Node] = {} diff --git a/src/primaite/simulator/sim_container.py b/src/primaite/simulator/sim_container.py index 50fe412c..319defe4 100644 --- a/src/primaite/simulator/sim_container.py +++ b/src/primaite/simulator/sim_container.py @@ -2,19 +2,19 @@ from typing import Dict from primaite.simulator.core import Action, ActionManager, AllowAllValidator, SimComponent from primaite.simulator.domain.controller import DomainController -from primaite.simulator.network.container import NetworkContainer +from primaite.simulator.network.container import Network class Simulation(SimComponent): """Top-level simulation object which holds a reference to all other parts of the simulation.""" - network: NetworkContainer + network: Network domain: DomainController def __init__(self, **kwargs): """Initialise the Simulation.""" if not kwargs.get("network"): - kwargs["network"] = NetworkContainer() + kwargs["network"] = Network() if not kwargs.get("domain"): kwargs["domain"] = DomainController() diff --git a/tests/integration_tests/network/test_network_creation.py b/tests/integration_tests/network/test_network_creation.py index 0ee827be..70b48806 100644 --- a/tests/integration_tests/network/test_network_creation.py +++ b/tests/integration_tests/network/test_network_creation.py @@ -1,12 +1,12 @@ import pytest -from primaite.simulator.network.container import NetworkContainer +from primaite.simulator.network.container import Network from primaite.simulator.network.hardware.base import NIC, Node def test_adding_removing_nodes(): """Check that we can create and add a node to a network.""" - net = NetworkContainer() + net = Network() n1 = Node(hostname="computer") net.add_node(n1) assert n1.parent is net @@ -19,7 +19,7 @@ def test_adding_removing_nodes(): def test_readding_node(): """Check that warning is raised when readding a node.""" - net = NetworkContainer() + net = Network() n1 = Node(hostname="computer") net.add_node(n1) with pytest.raises(RuntimeWarning): @@ -30,7 +30,7 @@ def test_readding_node(): def test_removing_nonexistent_node(): """Check that warning is raised when trying to remove a node that is not in the network.""" - net = NetworkContainer() + net = Network() n1 = Node(hostname="computer") with pytest.raises(RuntimeWarning): net.remove_node(n1) @@ -40,7 +40,7 @@ def test_removing_nonexistent_node(): def test_connecting_nodes(): """Check that two nodes on the network can be connected.""" - net = NetworkContainer() + net = Network() n1 = Node(hostname="computer") n1_nic = NIC(ip_address="120.30.0.1", gateway="192.168.0.1", subnet_mask="255.255.255.0") n1.connect_nic(n1_nic) @@ -60,7 +60,7 @@ def test_connecting_nodes(): def test_connecting_node_to_itself(): - net = NetworkContainer() + net = Network() node = Node(hostname="computer") nic1 = NIC(ip_address="120.30.0.1", gateway="192.168.0.1", subnet_mask="255.255.255.0") node.connect_nic(nic1) diff --git a/tests/unit_tests/_primaite/_simulator/_network/test_container.py b/tests/unit_tests/_primaite/_simulator/_network/test_container.py index 2492dc87..5fc308cc 100644 --- a/tests/unit_tests/_primaite/_simulator/_network/test_container.py +++ b/tests/unit_tests/_primaite/_simulator/_network/test_container.py @@ -1,16 +1,16 @@ import json -from primaite.simulator.network.container import NetworkContainer +from primaite.simulator.network.container import Network def test_creating_container(): """Check that we can create a network container""" - net = NetworkContainer() + net = Network() assert net.nodes and net.links def test_describe_state(): """Check that we can describe network state without raising errors, and that the result is JSON serialisable.""" - net = NetworkContainer() + net = Network() state = net.describe_state() json.dumps(state) # if this function call raises an error, the test fails, state was not JSON-serialisable From 78008e3c6e80199bd5116455e8afb1f2ccecf15b Mon Sep 17 00:00:00 2001 From: Marek Wolan Date: Thu, 24 Aug 2023 12:52:38 +0100 Subject: [PATCH 08/10] Fix container test --- .../unit_tests/_primaite/_simulator/_network/test_container.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/unit_tests/_primaite/_simulator/_network/test_container.py b/tests/unit_tests/_primaite/_simulator/_network/test_container.py index 5fc308cc..290e7cc3 100644 --- a/tests/unit_tests/_primaite/_simulator/_network/test_container.py +++ b/tests/unit_tests/_primaite/_simulator/_network/test_container.py @@ -6,7 +6,8 @@ from primaite.simulator.network.container import Network def test_creating_container(): """Check that we can create a network container""" net = Network() - assert net.nodes and net.links + assert net.nodes == {} + assert net.links == {} def test_describe_state(): From fec44aef53e25b2ac1a83e851f92a5c212a5daef Mon Sep 17 00:00:00 2001 From: Marek Wolan Date: Thu, 24 Aug 2023 13:03:16 +0100 Subject: [PATCH 09/10] Rename connect_nodes to connect and fix minor bug --- src/primaite/simulator/network/container.py | 2 +- src/primaite/simulator/network/hardware/base.py | 1 + tests/integration_tests/network/test_network_creation.py | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/primaite/simulator/network/container.py b/src/primaite/simulator/network/container.py index 0612069c..1c03358c 100644 --- a/src/primaite/simulator/network/container.py +++ b/src/primaite/simulator/network/container.py @@ -72,7 +72,7 @@ class Network(SimComponent): del self.nodes[node.uuid] del node.parent # misleading? - def connect_nodes(self, endpoint_a: Union[NIC, SwitchPort], endpoint_b: Union[NIC, SwitchPort], **kwargs) -> None: + def connect(self, endpoint_a: Union[NIC, SwitchPort], endpoint_b: Union[NIC, SwitchPort], **kwargs) -> None: """Connect two nodes on the network by creating a link between an NIC/SwitchPort of each one. :param endpoint_a: The endpoint to which to connect the link on the first node diff --git a/src/primaite/simulator/network/hardware/base.py b/src/primaite/simulator/network/hardware/base.py index 5b49f008..fe3b5b15 100644 --- a/src/primaite/simulator/network/hardware/base.py +++ b/src/primaite/simulator/network/hardware/base.py @@ -1011,6 +1011,7 @@ class Switch(Node): self.switch_ports = {i: SwitchPort() for i in range(1, self.num_ports + 1)} for port_num, port in self.switch_ports.items(): port.connected_node = self + port.parent = self port.port_num = port_num def show(self): diff --git a/tests/integration_tests/network/test_network_creation.py b/tests/integration_tests/network/test_network_creation.py index 70b48806..418f5e5f 100644 --- a/tests/integration_tests/network/test_network_creation.py +++ b/tests/integration_tests/network/test_network_creation.py @@ -51,7 +51,7 @@ def test_connecting_nodes(): net.add_node(n1) net.add_node(n2) - net.connect_nodes(n1.nics[n1_nic.uuid], n2.nics[n2_nic.uuid], bandwidth=30) + net.connect(n1.nics[n1_nic.uuid], n2.nics[n2_nic.uuid], bandwidth=30) assert len(net.links) == 1 link = list(net.links.values())[0] @@ -70,7 +70,7 @@ def test_connecting_node_to_itself(): net.add_node(node) with pytest.raises(RuntimeError): - net.connect_nodes(node.nics[nic1.uuid], node.nics[nic2.uuid], bandwidth=30) + net.connect(node.nics[nic1.uuid], node.nics[nic2.uuid], bandwidth=30) assert node in net assert nic1.connected_link is None From 05bb0f295b25973a0776d0ab4b7e65c6767ce93f Mon Sep 17 00:00:00 2001 From: Marek Wolan Date: Thu, 24 Aug 2023 13:06:45 +0100 Subject: [PATCH 10/10] Update notebook tutorial on creating a simulation --- .../notebooks/create-simulation.ipynb | 123 +++++++++--------- 1 file changed, 60 insertions(+), 63 deletions(-) diff --git a/src/primaite/notebooks/create-simulation.ipynb b/src/primaite/notebooks/create-simulation.ipynb index e3e7dfb7..baf7bd2c 100644 --- a/src/primaite/notebooks/create-simulation.ipynb +++ b/src/primaite/notebooks/create-simulation.ipynb @@ -42,11 +42,11 @@ { "data": { "text/plain": [ - "{'uuid': '95929b6a-1ce4-4c94-966c-6d3246d7caf9',\n", - " 'network': {'uuid': '4b41398e-d768-47c5-80cf-4278cfc35a24',\n", + "{'uuid': '2ef348c6-32e5-4c5c-83b7-3b82d0b6123b',\n", + " 'network': {'uuid': 'dd2d1a02-d461-4505-8bbd-fd0681750175',\n", " 'nodes': {},\n", " 'links': {}},\n", - " 'domain': {'uuid': '15920e15-6cd1-4a93-b6af-acbcc6f6468e', 'accounts': {}}}" + " 'domain': {'uuid': 'ae0423ee-51fa-41e7-be80-c642b39707f6', 'accounts': {}}}" ] }, "execution_count": 2, @@ -113,10 +113,10 @@ "name": "stderr", "output_type": "stream", "text": [ - "2023-08-23 15:44:02,059: NIC 1b:8f:94:4f:46:99/130.1.1.1 connected to Link 1b:8f:94:4f:46:99/130.1.1.1<-->ad:3c:77:44:98:27\n", - "2023-08-23 15:44:02,062: SwitchPort ad:3c:77:44:98:27 connected to Link 1b:8f:94:4f:46:99/130.1.1.1<-->ad:3c:77:44:98:27\n", - "2023-08-23 15:44:02,064: NIC 50:f4:6b:9b:a8:74/130.1.1.2 connected to Link 50:f4:6b:9b:a8:74/130.1.1.2<-->fd:b1:68:f9:8f:eb\n", - "2023-08-23 15:44:02,065: SwitchPort fd:b1:68:f9:8f:eb connected to Link 50:f4:6b:9b:a8:74/130.1.1.2<-->fd:b1:68:f9:8f:eb\n" + "2023-08-24 13:06:28,617: NIC cc:be:ec:43:a6:4c/130.1.1.1 connected to Link cc:be:ec:43:a6:4c/130.1.1.1<-->79:2b:4a:70:c3:50\n", + "2023-08-24 13:06:28,618: SwitchPort 79:2b:4a:70:c3:50 connected to Link cc:be:ec:43:a6:4c/130.1.1.1<-->79:2b:4a:70:c3:50\n", + "2023-08-24 13:06:28,619: NIC c2:1e:48:e1:a4:ad/130.1.1.2 connected to Link c2:1e:48:e1:a4:ad/130.1.1.2<-->1a:2d:12:38:80:2f\n", + "2023-08-24 13:06:28,620: SwitchPort 1a:2d:12:38:80:2f connected to Link c2:1e:48:e1:a4:ad/130.1.1.2<-->1a:2d:12:38:80:2f\n" ] } ], @@ -132,11 +132,8 @@ "my_server.connect_nic(server_nic)\n", "\n", "\n", - "pc_to_switch = Link(endpoint_a=pc_nic, endpoint_b=my_swtich.switch_ports[1])\n", - "server_to_swtich = Link(endpoint_a=server_nic, endpoint_b=my_swtich.switch_ports[2])\n", - "\n", - "my_sim.network.links[pc_to_switch.uuid] = pc_to_switch\n", - "my_sim.network.links[server_to_swtich.uuid] = server_to_swtich" + "net.connect(pc_nic, my_swtich.switch_ports[1])\n", + "net.connect(server_nic, my_swtich.switch_ports[2])\n" ] }, { @@ -174,7 +171,7 @@ { "data": { "text/plain": [ - "FileSystemFile(uuid='f45bffd7-4aa1-4f6f-81ba-85e746abd28b', name='favicon.ico', size=40.0, file_type=, action_manager=None)" + "FileSystemFile(uuid='7d56a563-ecc0-4011-8c97-240dd6c885c0', name='favicon.ico', size=40.0, file_type=, action_manager=None)" ] }, "execution_count": 9, @@ -269,31 +266,31 @@ { "data": { "text/plain": [ - "{'uuid': '95929b6a-1ce4-4c94-966c-6d3246d7caf9',\n", - " 'network': {'uuid': '4b41398e-d768-47c5-80cf-4278cfc35a24',\n", - " 'nodes': {'1599c08e-a101-41a7-a86a-4176660c4270': {'uuid': '1599c08e-a101-41a7-a86a-4176660c4270',\n", + "{'uuid': '2ef348c6-32e5-4c5c-83b7-3b82d0b6123b',\n", + " 'network': {'uuid': 'dd2d1a02-d461-4505-8bbd-fd0681750175',\n", + " 'nodes': {'2f03b32b-7290-4921-8670-faebe4a19d63': {'uuid': '2f03b32b-7290-4921-8670-faebe4a19d63',\n", " 'hostname': 'primaite_pc',\n", " 'operating_state': 0,\n", - " 'NICs': {'ab09d298-ac44-40ef-b950-b4ca6268d482': {'uuid': 'ab09d298-ac44-40ef-b950-b4ca6268d482',\n", + " 'NICs': {'e07e2a7f-b09f-4bd8-8e92-cffbf1f2270b': {'uuid': 'e07e2a7f-b09f-4bd8-8e92-cffbf1f2270b',\n", " 'ip_adress': '130.1.1.1',\n", " 'subnet_mask': '255.255.255.0',\n", " 'gateway': '130.1.1.255',\n", - " 'mac_address': '1b:8f:94:4f:46:99',\n", + " 'mac_address': 'cc:be:ec:43:a6:4c',\n", " 'speed': 100,\n", " 'mtu': 1500,\n", " 'wake_on_lan': False,\n", " 'dns_servers': [],\n", " 'enabled': False}},\n", - " 'file_system': {'uuid': '92120387-14cb-426c-98f2-64d64a85f560',\n", - " 'folders': {'6a11bd03-bc59-4da9-8474-639fcb72b9be': {'uuid': '6a11bd03-bc59-4da9-8474-639fcb72b9be',\n", + " 'file_system': {'uuid': '0b7206af-3e0a-41b0-8115-ae9e0dbbcd81',\n", + " 'folders': {'c161bc7c-9abd-4666-9b49-2745fdb65ebe': {'uuid': 'c161bc7c-9abd-4666-9b49-2745fdb65ebe',\n", " 'name': 'downloads',\n", " 'size': 1000.0,\n", - " 'files': {'194b2029-4723-4cff-b6d7-e647e4fb687d': {'uuid': '194b2029-4723-4cff-b6d7-e647e4fb687d',\n", + " 'files': {'f807d777-d167-4f37-9f9b-ced634af6ed5': {'uuid': 'f807d777-d167-4f37-9f9b-ced634af6ed5',\n", " 'name': 'firefox_installer.zip',\n", " 'size': 1000.0,\n", " 'file_type': 'ZIP'}},\n", " 'is_quarantined': False}}},\n", - " 'applications': {'ae49273b-f581-44e7-ae8c-18cc766158e8': {'uuid': 'ae49273b-f581-44e7-ae8c-18cc766158e8',\n", + " 'applications': {'ea466b2f-1ed5-49fd-9579-44852bff684d': {'uuid': 'ea466b2f-1ed5-49fd-9579-44852bff684d',\n", " 'health_state': 'GOOD',\n", " 'health_state_red_view': 'GOOD',\n", " 'criticality': 'MEDIUM',\n", @@ -311,29 +308,29 @@ " 'groups': []}},\n", " 'services': {},\n", " 'process': {}},\n", - " '7231c745-e186-47a2-8f69-006033b38b8f': {'uuid': '7231c745-e186-47a2-8f69-006033b38b8f',\n", + " 'e9afc0bc-fb21-48a3-9868-2ede6a3181dc': {'uuid': 'e9afc0bc-fb21-48a3-9868-2ede6a3181dc',\n", " 'hostname': 'google_server',\n", " 'operating_state': 0,\n", - " 'NICs': {'d138788b-2a8e-4c5c-aa5d-b5c28758a78a': {'uuid': 'd138788b-2a8e-4c5c-aa5d-b5c28758a78a',\n", + " 'NICs': {'956ce240-8fb3-4fde-8635-ac4ea601a582': {'uuid': '956ce240-8fb3-4fde-8635-ac4ea601a582',\n", " 'ip_adress': '130.1.1.2',\n", " 'subnet_mask': '255.255.255.0',\n", " 'gateway': '130.1.1.255',\n", - " 'mac_address': '50:f4:6b:9b:a8:74',\n", + " 'mac_address': 'c2:1e:48:e1:a4:ad',\n", " 'speed': 100,\n", " 'mtu': 1500,\n", " 'wake_on_lan': False,\n", " 'dns_servers': [],\n", " 'enabled': False}},\n", - " 'file_system': {'uuid': '85f1d50c-ded7-4160-9a11-1305ab25934b',\n", - " 'folders': {'86c2666e-31da-46a9-a267-4dc87e2620f9': {'uuid': '86c2666e-31da-46a9-a267-4dc87e2620f9',\n", + " 'file_system': {'uuid': 'c3f99c30-b493-4fb6-b13e-d2005d851b59',\n", + " 'folders': {'869eda49-21f2-4fc1-8681-78725cdd5c70': {'uuid': '869eda49-21f2-4fc1-8681-78725cdd5c70',\n", " 'name': 'static',\n", " 'size': 0,\n", " 'files': {},\n", " 'is_quarantined': False},\n", - " '1a4479df-6f52-428c-b7b9-c026ab24d2a3': {'uuid': '1a4479df-6f52-428c-b7b9-c026ab24d2a3',\n", + " '9fbe0e41-0d6a-4142-9c73-9c0de2dbde6e': {'uuid': '9fbe0e41-0d6a-4142-9c73-9c0de2dbde6e',\n", " 'name': 'root',\n", " 'size': 40.0,\n", - " 'files': {'f45bffd7-4aa1-4f6f-81ba-85e746abd28b': {'uuid': 'f45bffd7-4aa1-4f6f-81ba-85e746abd28b',\n", + " 'files': {'7d56a563-ecc0-4011-8c97-240dd6c885c0': {'uuid': '7d56a563-ecc0-4011-8c97-240dd6c885c0',\n", " 'name': 'favicon.ico',\n", " 'size': 40.0,\n", " 'file_type': 'PNG'}},\n", @@ -341,81 +338,81 @@ " 'applications': {},\n", " 'services': {},\n", " 'process': {}},\n", - " '384bab1c-aa23-49cf-9c4e-caababcf30a0': {'uuid': '384bab1c-aa23-49cf-9c4e-caababcf30a0',\n", + " '47814452-ef47-4e6b-9087-796c438d4698': {'uuid': '47814452-ef47-4e6b-9087-796c438d4698',\n", " 'num_ports': 12,\n", - " 'ports': {1: {'uuid': 'e64847dd-6f19-4f5e-b473-4f9098ca4b9c',\n", - " 'mac_address': 'ad:3c:77:44:98:27',\n", + " 'ports': {1: {'uuid': 'b76fe86f-bb92-4346-8e83-217a2fb0bc67',\n", + " 'mac_address': '79:2b:4a:70:c3:50',\n", " 'speed': 100,\n", " 'mtu': 1500,\n", " 'enabled': False},\n", - " 2: {'uuid': 'd65f815d-dc28-4313-a4f0-b918bb026e7c',\n", - " 'mac_address': 'fd:b1:68:f9:8f:eb',\n", + " 2: {'uuid': '6f8fc6e7-76a4-441a-b7af-441edbdcc6ac',\n", + " 'mac_address': '1a:2d:12:38:80:2f',\n", " 'speed': 100,\n", " 'mtu': 1500,\n", " 'enabled': False},\n", - " 3: {'uuid': '8e1d8783-80af-4aad-bc1e-0c5f1d28b9a1',\n", - " 'mac_address': 'bb:ba:58:26:52:2d',\n", + " 3: {'uuid': '1aa75a3c-01f1-4293-9894-5396fa412690',\n", + " 'mac_address': 'd1:7b:36:c1:82:c1',\n", " 'speed': 100,\n", " 'mtu': 1500,\n", " 'enabled': False},\n", - " 4: {'uuid': '3cde63c0-38e4-4faa-88ba-3a958118e2b3',\n", - " 'mac_address': '69:bc:6f:e1:30:32',\n", + " 4: {'uuid': 'fe6c9f44-59d5-403e-973a-6f19fce7b9b9',\n", + " 'mac_address': 'e3:6b:cc:0c:98:9b',\n", " 'speed': 100,\n", " 'mtu': 1500,\n", " 'enabled': False},\n", - " 5: {'uuid': '37e49743-1723-4b0e-a1e5-61d76e230c08',\n", - " 'mac_address': 'd3:a0:8b:92:25:11',\n", + " 5: {'uuid': 'e9e83e37-8537-4884-98a6-87017540078f',\n", + " 'mac_address': '32:09:c0:4a:f1:20',\n", " 'speed': 100,\n", " 'mtu': 1500,\n", " 'enabled': False},\n", - " 6: {'uuid': '3bf0c0c4-27f6-4a90-8279-1f713b46f4bf',\n", - " 'mac_address': '48:88:7c:71:0a:c0',\n", + " 6: {'uuid': '747f2cd3-8902-4da8-8829-b0b53fe79735',\n", + " 'mac_address': 'e8:20:0b:04:b8:76',\n", " 'speed': 100,\n", " 'mtu': 1500,\n", " 'enabled': False},\n", - " 7: {'uuid': '40b0ba34-9e70-448a-8fdf-836a5a71ed8f',\n", - " 'mac_address': '24:81:03:09:c0:be',\n", + " 7: {'uuid': '88ed129e-0ddb-4d29-ba3c-58d81efe240e',\n", + " 'mac_address': '7f:b4:f4:2e:b6:71',\n", " 'speed': 100,\n", " 'mtu': 1500,\n", " 'enabled': False},\n", - " 8: {'uuid': 'cd23d94b-84b8-441c-bd95-4e310682a095',\n", - " 'mac_address': '27:18:c5:47:fd:82',\n", + " 8: {'uuid': '6c1a4c3c-25d8-46f6-98a8-54073d0ca0d3',\n", + " 'mac_address': 'f6:22:2d:24:b9:71',\n", " 'speed': 100,\n", " 'mtu': 1500,\n", " 'enabled': False},\n", - " 9: {'uuid': '608eb5bd-7875-4b64-a6f8-794e6283a305',\n", - " 'mac_address': '03:dd:34:d2:56:1c',\n", + " 9: {'uuid': 'b2bfc006-6a6b-4701-a75a-27954592d429',\n", + " 'mac_address': 'b6:a5:92:a5:aa:1b',\n", " 'speed': 100,\n", " 'mtu': 1500,\n", " 'enabled': False},\n", - " 10: {'uuid': '4acb48c6-74be-40d3-b706-64c06c55720b',\n", - " 'mac_address': 'a3:55:83:af:b7:6b',\n", + " 10: {'uuid': '3c607386-87a2-4d0b-ac04-449416ca5b1f',\n", + " 'mac_address': 'b3:75:7d:ce:88:0a',\n", " 'speed': 100,\n", " 'mtu': 1500,\n", " 'enabled': False},\n", - " 11: {'uuid': '73e989b5-3c2c-4035-8191-47220ea5ca43',\n", - " 'mac_address': '4f:60:84:21:50:6d',\n", + " 11: {'uuid': '590002c8-27fa-4c31-b17b-7b89dbf8cdf8',\n", + " 'mac_address': 'c0:25:a6:64:52:8e',\n", " 'speed': 100,\n", " 'mtu': 1500,\n", " 'enabled': False},\n", - " 12: {'uuid': '961ff733-a07c-433b-9433-8418a3761120',\n", - " 'mac_address': '7a:26:02:14:8d:da',\n", + " 12: {'uuid': 'b7e25eed-547a-4c17-8cb9-8b976ce4bbd9',\n", + " 'mac_address': '98:50:96:47:ca:bc',\n", " 'speed': 100,\n", " 'mtu': 1500,\n", " 'enabled': False}},\n", " 'mac_address_table': {}}},\n", - " 'links': {'67df55f4-c485-4eed-a4dc-fe6f96f6b2f3': {'uuid': '67df55f4-c485-4eed-a4dc-fe6f96f6b2f3',\n", - " 'endpoint_a': 'ab09d298-ac44-40ef-b950-b4ca6268d482',\n", - " 'endpoint_b': 'e64847dd-6f19-4f5e-b473-4f9098ca4b9c',\n", + " 'links': {'a51a4435-20ae-43cf-a151-26e824968b3d': {'uuid': 'a51a4435-20ae-43cf-a151-26e824968b3d',\n", + " 'endpoint_a': 'e07e2a7f-b09f-4bd8-8e92-cffbf1f2270b',\n", + " 'endpoint_b': 'b76fe86f-bb92-4346-8e83-217a2fb0bc67',\n", " 'bandwidth': 100.0,\n", " 'current_load': 0.0},\n", - " '4fdb61da-7cc9-43ea-9ee6-7d9853deff72': {'uuid': '4fdb61da-7cc9-43ea-9ee6-7d9853deff72',\n", - " 'endpoint_a': 'd138788b-2a8e-4c5c-aa5d-b5c28758a78a',\n", - " 'endpoint_b': 'd65f815d-dc28-4313-a4f0-b918bb026e7c',\n", + " 'ae3486e5-f78e-4092-96d1-d7e8176f2b7d': {'uuid': 'ae3486e5-f78e-4092-96d1-d7e8176f2b7d',\n", + " 'endpoint_a': '956ce240-8fb3-4fde-8635-ac4ea601a582',\n", + " 'endpoint_b': '6f8fc6e7-76a4-441a-b7af-441edbdcc6ac',\n", " 'bandwidth': 100.0,\n", " 'current_load': 0.0}}},\n", - " 'domain': {'uuid': '15920e15-6cd1-4a93-b6af-acbcc6f6468e',\n", - " 'accounts': {'d7f5bd32-5071-4bec-a111-a9f4e1aca45a': {'uuid': 'd7f5bd32-5071-4bec-a111-a9f4e1aca45a',\n", + " 'domain': {'uuid': 'ae0423ee-51fa-41e7-be80-c642b39707f6',\n", + " 'accounts': {'917eda28-9a67-4449-bddd-87e2141a3162': {'uuid': '917eda28-9a67-4449-bddd-87e2141a3162',\n", " 'num_logons': 0,\n", " 'num_logoffs': 0,\n", " 'num_group_changes': 0,\n", @@ -442,7 +439,7 @@ { "data": { "text/plain": [ - "'{\"uuid\": \"95929b6a-1ce4-4c94-966c-6d3246d7caf9\", \"network\": {\"uuid\": \"4b41398e-d768-47c5-80cf-4278cfc35a24\", \"nodes\": {\"1599c08e-a101-41a7-a86a-4176660c4270\": {\"uuid\": \"1599c08e-a101-41a7-a86a-4176660c4270\", \"hostname\": \"primaite_pc\", \"operating_state\": 0, \"NICs\": {\"ab09d298-ac44-40ef-b950-b4ca6268d482\": {\"uuid\": \"ab09d298-ac44-40ef-b950-b4ca6268d482\", \"ip_adress\": \"130.1.1.1\", \"subnet_mask\": \"255.255.255.0\", \"gateway\": \"130.1.1.255\", \"mac_address\": \"1b:8f:94:4f:46:99\", \"speed\": 100, \"mtu\": 1500, \"wake_on_lan\": false, \"dns_servers\": [], \"enabled\": false}}, \"file_system\": {\"uuid\": \"92120387-14cb-426c-98f2-64d64a85f560\", \"folders\": {\"6a11bd03-bc59-4da9-8474-639fcb72b9be\": {\"uuid\": \"6a11bd03-bc59-4da9-8474-639fcb72b9be\", \"name\": \"downloads\", \"size\": 1000.0, \"files\": {\"194b2029-4723-4cff-b6d7-e647e4fb687d\": {\"uuid\": \"194b2029-4723-4cff-b6d7-e647e4fb687d\", \"name\": \"firefox_installer.zip\", \"size\": 1000.0, \"file_type\": \"ZIP\"}}, \"is_quarantined\": false}}}, \"applications\": {\"ae49273b-f581-44e7-ae8c-18cc766158e8\": {\"uuid\": \"ae49273b-f581-44e7-ae8c-18cc766158e8\", \"health_state\": \"GOOD\", \"health_state_red_view\": \"GOOD\", \"criticality\": \"MEDIUM\", \"patching_count\": 0, \"scanning_count\": 0, \"revealed_to_red\": false, \"installing_count\": 0, \"max_sessions\": 1, \"tcp\": true, \"udp\": true, \"ports\": [\"HTTP\"], \"opearting_state\": \"RUNNING\", \"execution_control_status\": \"manual\", \"num_executions\": 0, \"groups\": []}}, \"services\": {}, \"process\": {}}, \"7231c745-e186-47a2-8f69-006033b38b8f\": {\"uuid\": \"7231c745-e186-47a2-8f69-006033b38b8f\", \"hostname\": \"google_server\", \"operating_state\": 0, \"NICs\": {\"d138788b-2a8e-4c5c-aa5d-b5c28758a78a\": {\"uuid\": \"d138788b-2a8e-4c5c-aa5d-b5c28758a78a\", \"ip_adress\": \"130.1.1.2\", \"subnet_mask\": \"255.255.255.0\", \"gateway\": \"130.1.1.255\", \"mac_address\": \"50:f4:6b:9b:a8:74\", \"speed\": 100, \"mtu\": 1500, \"wake_on_lan\": false, \"dns_servers\": [], \"enabled\": false}}, \"file_system\": {\"uuid\": \"85f1d50c-ded7-4160-9a11-1305ab25934b\", \"folders\": {\"86c2666e-31da-46a9-a267-4dc87e2620f9\": {\"uuid\": \"86c2666e-31da-46a9-a267-4dc87e2620f9\", \"name\": \"static\", \"size\": 0, \"files\": {}, \"is_quarantined\": false}, \"1a4479df-6f52-428c-b7b9-c026ab24d2a3\": {\"uuid\": \"1a4479df-6f52-428c-b7b9-c026ab24d2a3\", \"name\": \"root\", \"size\": 40.0, \"files\": {\"f45bffd7-4aa1-4f6f-81ba-85e746abd28b\": {\"uuid\": \"f45bffd7-4aa1-4f6f-81ba-85e746abd28b\", \"name\": \"favicon.ico\", \"size\": 40.0, \"file_type\": \"PNG\"}}, \"is_quarantined\": false}}}, \"applications\": {}, \"services\": {}, \"process\": {}}, \"384bab1c-aa23-49cf-9c4e-caababcf30a0\": {\"uuid\": \"384bab1c-aa23-49cf-9c4e-caababcf30a0\", \"num_ports\": 12, \"ports\": {\"1\": {\"uuid\": \"e64847dd-6f19-4f5e-b473-4f9098ca4b9c\", \"mac_address\": \"ad:3c:77:44:98:27\", \"speed\": 100, \"mtu\": 1500, \"enabled\": false}, \"2\": {\"uuid\": \"d65f815d-dc28-4313-a4f0-b918bb026e7c\", \"mac_address\": \"fd:b1:68:f9:8f:eb\", \"speed\": 100, \"mtu\": 1500, \"enabled\": false}, \"3\": {\"uuid\": \"8e1d8783-80af-4aad-bc1e-0c5f1d28b9a1\", \"mac_address\": \"bb:ba:58:26:52:2d\", \"speed\": 100, \"mtu\": 1500, \"enabled\": false}, \"4\": {\"uuid\": \"3cde63c0-38e4-4faa-88ba-3a958118e2b3\", \"mac_address\": \"69:bc:6f:e1:30:32\", \"speed\": 100, \"mtu\": 1500, \"enabled\": false}, \"5\": {\"uuid\": \"37e49743-1723-4b0e-a1e5-61d76e230c08\", \"mac_address\": \"d3:a0:8b:92:25:11\", \"speed\": 100, \"mtu\": 1500, \"enabled\": false}, \"6\": {\"uuid\": \"3bf0c0c4-27f6-4a90-8279-1f713b46f4bf\", \"mac_address\": \"48:88:7c:71:0a:c0\", \"speed\": 100, \"mtu\": 1500, \"enabled\": false}, \"7\": {\"uuid\": \"40b0ba34-9e70-448a-8fdf-836a5a71ed8f\", \"mac_address\": \"24:81:03:09:c0:be\", \"speed\": 100, \"mtu\": 1500, \"enabled\": false}, \"8\": {\"uuid\": \"cd23d94b-84b8-441c-bd95-4e310682a095\", \"mac_address\": \"27:18:c5:47:fd:82\", \"speed\": 100, \"mtu\": 1500, \"enabled\": false}, \"9\": {\"uuid\": \"608eb5bd-7875-4b64-a6f8-794e6283a305\", \"mac_address\": \"03:dd:34:d2:56:1c\", \"speed\": 100, \"mtu\": 1500, \"enabled\": false}, \"10\": {\"uuid\": \"4acb48c6-74be-40d3-b706-64c06c55720b\", \"mac_address\": \"a3:55:83:af:b7:6b\", \"speed\": 100, \"mtu\": 1500, \"enabled\": false}, \"11\": {\"uuid\": \"73e989b5-3c2c-4035-8191-47220ea5ca43\", \"mac_address\": \"4f:60:84:21:50:6d\", \"speed\": 100, \"mtu\": 1500, \"enabled\": false}, \"12\": {\"uuid\": \"961ff733-a07c-433b-9433-8418a3761120\", \"mac_address\": \"7a:26:02:14:8d:da\", \"speed\": 100, \"mtu\": 1500, \"enabled\": false}}, \"mac_address_table\": {}}}, \"links\": {\"67df55f4-c485-4eed-a4dc-fe6f96f6b2f3\": {\"uuid\": \"67df55f4-c485-4eed-a4dc-fe6f96f6b2f3\", \"endpoint_a\": \"ab09d298-ac44-40ef-b950-b4ca6268d482\", \"endpoint_b\": \"e64847dd-6f19-4f5e-b473-4f9098ca4b9c\", \"bandwidth\": 100.0, \"current_load\": 0.0}, \"4fdb61da-7cc9-43ea-9ee6-7d9853deff72\": {\"uuid\": \"4fdb61da-7cc9-43ea-9ee6-7d9853deff72\", \"endpoint_a\": \"d138788b-2a8e-4c5c-aa5d-b5c28758a78a\", \"endpoint_b\": \"d65f815d-dc28-4313-a4f0-b918bb026e7c\", \"bandwidth\": 100.0, \"current_load\": 0.0}}}, \"domain\": {\"uuid\": \"15920e15-6cd1-4a93-b6af-acbcc6f6468e\", \"accounts\": {\"d7f5bd32-5071-4bec-a111-a9f4e1aca45a\": {\"uuid\": \"d7f5bd32-5071-4bec-a111-a9f4e1aca45a\", \"num_logons\": 0, \"num_logoffs\": 0, \"num_group_changes\": 0, \"username\": \"admin\", \"password\": \"admin12\", \"account_type\": \"USER\", \"enabled\": true}}}}'" + "'{\"uuid\": \"2ef348c6-32e5-4c5c-83b7-3b82d0b6123b\", \"network\": {\"uuid\": \"dd2d1a02-d461-4505-8bbd-fd0681750175\", \"nodes\": {\"2f03b32b-7290-4921-8670-faebe4a19d63\": {\"uuid\": \"2f03b32b-7290-4921-8670-faebe4a19d63\", \"hostname\": \"primaite_pc\", \"operating_state\": 0, \"NICs\": {\"e07e2a7f-b09f-4bd8-8e92-cffbf1f2270b\": {\"uuid\": \"e07e2a7f-b09f-4bd8-8e92-cffbf1f2270b\", \"ip_adress\": \"130.1.1.1\", \"subnet_mask\": \"255.255.255.0\", \"gateway\": \"130.1.1.255\", \"mac_address\": \"cc:be:ec:43:a6:4c\", \"speed\": 100, \"mtu\": 1500, \"wake_on_lan\": false, \"dns_servers\": [], \"enabled\": false}}, \"file_system\": {\"uuid\": \"0b7206af-3e0a-41b0-8115-ae9e0dbbcd81\", \"folders\": {\"c161bc7c-9abd-4666-9b49-2745fdb65ebe\": {\"uuid\": \"c161bc7c-9abd-4666-9b49-2745fdb65ebe\", \"name\": \"downloads\", \"size\": 1000.0, \"files\": {\"f807d777-d167-4f37-9f9b-ced634af6ed5\": {\"uuid\": \"f807d777-d167-4f37-9f9b-ced634af6ed5\", \"name\": \"firefox_installer.zip\", \"size\": 1000.0, \"file_type\": \"ZIP\"}}, \"is_quarantined\": false}}}, \"applications\": {\"ea466b2f-1ed5-49fd-9579-44852bff684d\": {\"uuid\": \"ea466b2f-1ed5-49fd-9579-44852bff684d\", \"health_state\": \"GOOD\", \"health_state_red_view\": \"GOOD\", \"criticality\": \"MEDIUM\", \"patching_count\": 0, \"scanning_count\": 0, \"revealed_to_red\": false, \"installing_count\": 0, \"max_sessions\": 1, \"tcp\": true, \"udp\": true, \"ports\": [\"HTTP\"], \"opearting_state\": \"RUNNING\", \"execution_control_status\": \"manual\", \"num_executions\": 0, \"groups\": []}}, \"services\": {}, \"process\": {}}, \"e9afc0bc-fb21-48a3-9868-2ede6a3181dc\": {\"uuid\": \"e9afc0bc-fb21-48a3-9868-2ede6a3181dc\", \"hostname\": \"google_server\", \"operating_state\": 0, \"NICs\": {\"956ce240-8fb3-4fde-8635-ac4ea601a582\": {\"uuid\": \"956ce240-8fb3-4fde-8635-ac4ea601a582\", \"ip_adress\": \"130.1.1.2\", \"subnet_mask\": \"255.255.255.0\", \"gateway\": \"130.1.1.255\", \"mac_address\": \"c2:1e:48:e1:a4:ad\", \"speed\": 100, \"mtu\": 1500, \"wake_on_lan\": false, \"dns_servers\": [], \"enabled\": false}}, \"file_system\": {\"uuid\": \"c3f99c30-b493-4fb6-b13e-d2005d851b59\", \"folders\": {\"869eda49-21f2-4fc1-8681-78725cdd5c70\": {\"uuid\": \"869eda49-21f2-4fc1-8681-78725cdd5c70\", \"name\": \"static\", \"size\": 0, \"files\": {}, \"is_quarantined\": false}, \"9fbe0e41-0d6a-4142-9c73-9c0de2dbde6e\": {\"uuid\": \"9fbe0e41-0d6a-4142-9c73-9c0de2dbde6e\", \"name\": \"root\", \"size\": 40.0, \"files\": {\"7d56a563-ecc0-4011-8c97-240dd6c885c0\": {\"uuid\": \"7d56a563-ecc0-4011-8c97-240dd6c885c0\", \"name\": \"favicon.ico\", \"size\": 40.0, \"file_type\": \"PNG\"}}, \"is_quarantined\": false}}}, \"applications\": {}, \"services\": {}, \"process\": {}}, \"47814452-ef47-4e6b-9087-796c438d4698\": {\"uuid\": \"47814452-ef47-4e6b-9087-796c438d4698\", \"num_ports\": 12, \"ports\": {\"1\": {\"uuid\": \"b76fe86f-bb92-4346-8e83-217a2fb0bc67\", \"mac_address\": \"79:2b:4a:70:c3:50\", \"speed\": 100, \"mtu\": 1500, \"enabled\": false}, \"2\": {\"uuid\": \"6f8fc6e7-76a4-441a-b7af-441edbdcc6ac\", \"mac_address\": \"1a:2d:12:38:80:2f\", \"speed\": 100, \"mtu\": 1500, \"enabled\": false}, \"3\": {\"uuid\": \"1aa75a3c-01f1-4293-9894-5396fa412690\", \"mac_address\": \"d1:7b:36:c1:82:c1\", \"speed\": 100, \"mtu\": 1500, \"enabled\": false}, \"4\": {\"uuid\": \"fe6c9f44-59d5-403e-973a-6f19fce7b9b9\", \"mac_address\": \"e3:6b:cc:0c:98:9b\", \"speed\": 100, \"mtu\": 1500, \"enabled\": false}, \"5\": {\"uuid\": \"e9e83e37-8537-4884-98a6-87017540078f\", \"mac_address\": \"32:09:c0:4a:f1:20\", \"speed\": 100, \"mtu\": 1500, \"enabled\": false}, \"6\": {\"uuid\": \"747f2cd3-8902-4da8-8829-b0b53fe79735\", \"mac_address\": \"e8:20:0b:04:b8:76\", \"speed\": 100, \"mtu\": 1500, \"enabled\": false}, \"7\": {\"uuid\": \"88ed129e-0ddb-4d29-ba3c-58d81efe240e\", \"mac_address\": \"7f:b4:f4:2e:b6:71\", \"speed\": 100, \"mtu\": 1500, \"enabled\": false}, \"8\": {\"uuid\": \"6c1a4c3c-25d8-46f6-98a8-54073d0ca0d3\", \"mac_address\": \"f6:22:2d:24:b9:71\", \"speed\": 100, \"mtu\": 1500, \"enabled\": false}, \"9\": {\"uuid\": \"b2bfc006-6a6b-4701-a75a-27954592d429\", \"mac_address\": \"b6:a5:92:a5:aa:1b\", \"speed\": 100, \"mtu\": 1500, \"enabled\": false}, \"10\": {\"uuid\": \"3c607386-87a2-4d0b-ac04-449416ca5b1f\", \"mac_address\": \"b3:75:7d:ce:88:0a\", \"speed\": 100, \"mtu\": 1500, \"enabled\": false}, \"11\": {\"uuid\": \"590002c8-27fa-4c31-b17b-7b89dbf8cdf8\", \"mac_address\": \"c0:25:a6:64:52:8e\", \"speed\": 100, \"mtu\": 1500, \"enabled\": false}, \"12\": {\"uuid\": \"b7e25eed-547a-4c17-8cb9-8b976ce4bbd9\", \"mac_address\": \"98:50:96:47:ca:bc\", \"speed\": 100, \"mtu\": 1500, \"enabled\": false}}, \"mac_address_table\": {}}}, \"links\": {\"a51a4435-20ae-43cf-a151-26e824968b3d\": {\"uuid\": \"a51a4435-20ae-43cf-a151-26e824968b3d\", \"endpoint_a\": \"e07e2a7f-b09f-4bd8-8e92-cffbf1f2270b\", \"endpoint_b\": \"b76fe86f-bb92-4346-8e83-217a2fb0bc67\", \"bandwidth\": 100.0, \"current_load\": 0.0}, \"ae3486e5-f78e-4092-96d1-d7e8176f2b7d\": {\"uuid\": \"ae3486e5-f78e-4092-96d1-d7e8176f2b7d\", \"endpoint_a\": \"956ce240-8fb3-4fde-8635-ac4ea601a582\", \"endpoint_b\": \"6f8fc6e7-76a4-441a-b7af-441edbdcc6ac\", \"bandwidth\": 100.0, \"current_load\": 0.0}}}, \"domain\": {\"uuid\": \"ae0423ee-51fa-41e7-be80-c642b39707f6\", \"accounts\": {\"917eda28-9a67-4449-bddd-87e2141a3162\": {\"uuid\": \"917eda28-9a67-4449-bddd-87e2141a3162\", \"num_logons\": 0, \"num_logoffs\": 0, \"num_group_changes\": 0, \"username\": \"admin\", \"password\": \"admin12\", \"account_type\": \"USER\", \"enabled\": true}}}}'" ] }, "execution_count": 16,