#2257: added common node attributes page + ability to set node operating state via config + tests
This commit is contained in:
35
docs/source/configuration/simulation/nodes/common/common.rst
Normal file
35
docs/source/configuration/simulation/nodes/common/common.rst
Normal file
@@ -0,0 +1,35 @@
|
||||
.. only:: comment
|
||||
|
||||
© Crown-owned copyright 2023, Defence Science and Technology Laboratory UK
|
||||
|
||||
.. _Node Attributes:
|
||||
|
||||
Common Attributes
|
||||
#################
|
||||
|
||||
Node Attributes
|
||||
===============
|
||||
|
||||
Attributes that are shared by all nodes.
|
||||
|
||||
.. include:: common_node_attributes.rst
|
||||
|
||||
.. _Network Node Attributes:
|
||||
|
||||
Network Node Attributes
|
||||
=======================
|
||||
|
||||
Attributes that are shared by nodes that inherit from :py:mod:`primaite.simulator.network.hardware.nodes.network.network_node.NetworkNode`
|
||||
|
||||
.. include:: common_host_node_attributes.rst
|
||||
|
||||
.. _Host Node Attributes:
|
||||
|
||||
Host Node Attributes
|
||||
====================
|
||||
|
||||
Attributes that are shared by nodes that inherit from :py:mod:`primaite.simulator.network.hardware.nodes.host.host_node.HostNode`
|
||||
|
||||
.. include:: common_host_node_attributes.rst
|
||||
|
||||
.. |NODE| replace:: node
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
© Crown-owned copyright 2023, Defence Science and Technology Laboratory UK
|
||||
|
||||
.. _common_host_node_attributes:
|
||||
|
||||
``ip_address``
|
||||
--------------
|
||||
|
||||
@@ -19,13 +21,6 @@ The subnet mask for the |NODE| to use.
|
||||
|
||||
The IP address that the |NODE| will use as the default gateway. Typically, this is the IP address of the closest router that the |NODE| is connected to.
|
||||
|
||||
``dns_server``
|
||||
--------------
|
||||
|
||||
Optional. Default value is ``None``
|
||||
|
||||
The IP address of the node which holds an instance of the :ref:`DNSServer`. Some applications may use a domain name e.g. the :ref:`WebBrowser`
|
||||
|
||||
.. include:: ../software/applications.rst
|
||||
|
||||
.. include:: ../software/services.rst
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
© Crown-owned copyright 2023, Defence Science and Technology Laboratory UK
|
||||
|
||||
.. _common_network_node_attributes:
|
||||
|
||||
``routes``
|
||||
----------
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
© Crown-owned copyright 2023, Defence Science and Technology Laboratory UK
|
||||
|
||||
.. _common_node_attributes:
|
||||
|
||||
``ref``
|
||||
-------
|
||||
|
||||
@@ -11,3 +13,43 @@ Human readable name used as reference for the |NODE|. Not used in code.
|
||||
------------
|
||||
|
||||
The hostname of the |NODE|. This will be used to reference the |NODE|.
|
||||
|
||||
``operating_state``
|
||||
-------------------
|
||||
|
||||
The initial operating state of the node.
|
||||
|
||||
Optional. Default value is ``ON``.
|
||||
|
||||
Options available are:
|
||||
|
||||
- ``ON``
|
||||
- ``OFF``
|
||||
- ``BOOTING``
|
||||
- ``SHUTTING_DOWN``
|
||||
|
||||
Note that YAML may assume non quoted ``ON`` and ``OFF`` as ``True`` and ``False`` respectively. To prevent this, use ``"ON"`` or ``"OFF"``
|
||||
|
||||
See :py:mod:`primaite.simulator.network.hardware.node_operating_state.NodeOperatingState`
|
||||
|
||||
|
||||
``dns_server``
|
||||
--------------
|
||||
|
||||
Optional. Default value is ``None``.
|
||||
|
||||
The IP address of the node which holds an instance of the :ref:`DNSServer`. Some applications may use a domain name e.g. the :ref:`WebBrowser`
|
||||
|
||||
``start_up_duration``
|
||||
---------------------
|
||||
|
||||
Optional. Default value is ``3``.
|
||||
|
||||
The number of time steps required to occur in order for the node to cycle from ``OFF`` to ``BOOTING_UP`` and then finally ``ON``.
|
||||
|
||||
``shut_down_duration``
|
||||
----------------------
|
||||
|
||||
Optional. Default value is ``3``.
|
||||
|
||||
The number of time steps required to occur in order for the node to cycle from ``ON`` to ``SHUTTING_DOWN`` and then finally ``OFF``.
|
||||
|
||||
@@ -12,34 +12,22 @@ complex, specialized hardware components inherit from and build upon.
|
||||
|
||||
The key elements defined in ``base.py`` are:
|
||||
|
||||
NetworkInterface
|
||||
================
|
||||
``NetworkInterface``
|
||||
====================
|
||||
|
||||
- Abstract base class for network interfaces like NICs. Defines common attributes like MAC address, speed, MTU.
|
||||
- Requires subclasses to implement ``enable()``, ``disable()``, ``send_frame()`` and ``receive_frame()``.
|
||||
- Provides basic state description and request handling capabilities.
|
||||
|
||||
Node
|
||||
====
|
||||
``Node``
|
||||
========
|
||||
The Node class stands as a central component in ``base.py``, acting as the superclass for all network nodes within a
|
||||
PrimAITE simulation.
|
||||
|
||||
|
||||
|
||||
Node Attributes
|
||||
---------------
|
||||
|
||||
|
||||
- **hostname**: The network hostname of the node.
|
||||
- **operating_state**: Indicates the current hardware state of the node.
|
||||
- **network_interfaces**: Maps interface names to NetworkInterface objects on the node.
|
||||
- **network_interface**: Maps port IDs to ``NetworkInterface`` objects on the node.
|
||||
- **dns_server**: Specifies DNS servers for domain name resolution.
|
||||
- **start_up_duration**: The time it takes for the node to become fully operational after being powered on.
|
||||
- **shut_down_duration**: The time required for the node to properly shut down.
|
||||
- **sys_log**: A system log for recording events related to the node.
|
||||
- **session_manager**: Manages user sessions within the node.
|
||||
- **software_manager**: Controls the installation and management of software and services on the node.
|
||||
See :ref:`Node Attributes`
|
||||
|
||||
.. _Node Start up and Shut down:
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@ Python
|
||||
data_manipulation_bot.configure(server_ip_address=IPv4Address("192.168.1.14"), payload="DELETE")
|
||||
data_manipulation_bot.run()
|
||||
|
||||
This would connect to the database service at 192.168.1.14, authenticate, and execute the SQL statement to drop the 'users' table.
|
||||
This would connect to the database service at 192.168.1.14, authenticate, and execute the SQL statement to delete database contents.
|
||||
|
||||
Example with ``DataManipulationAgent``
|
||||
""""""""""""""""""""""""""""""""""""""
|
||||
|
||||
@@ -24,12 +24,6 @@ Usage
|
||||
- Retrieve results in a dictionary.
|
||||
- Disconnect when finished.
|
||||
|
||||
To create database backups:
|
||||
|
||||
- Configure the backup server on the :ref:`DatabaseService` by providing the Backup server ``IPv4Address`` with ``configure_backup``
|
||||
- Create a backup using ``backup_database``. This fails if the backup server is not configured.
|
||||
- Restore a backup using ``restore_backup``. By default, this uses the database created via ``backup_database``.
|
||||
|
||||
Implementation
|
||||
==============
|
||||
|
||||
|
||||
@@ -13,4 +13,4 @@ The list of applications that are considered system software are:
|
||||
|
||||
- ``WebBrowser``
|
||||
|
||||
More info :py:mod:`primaite.simulator.network.hardware.nodes.host.host_node.SYSTEM_SOFTWARE`
|
||||
More info :py:mod:`primaite.simulator.network.hardware.nodes.host.host_node.HostNode.SYSTEM_SOFTWARE`
|
||||
|
||||
@@ -15,4 +15,4 @@ The list of services that are considered system software are:
|
||||
- ``FTPClient``
|
||||
- ``NTPClient``
|
||||
|
||||
More info :py:mod:`primaite.simulator.network.hardware.nodes.host.host_node.SYSTEM_SOFTWARE`
|
||||
More info :py:mod:`primaite.simulator.network.hardware.nodes.host.host_node.HostNode.SYSTEM_SOFTWARE`
|
||||
|
||||
@@ -10,7 +10,7 @@ Software
|
||||
Base Software
|
||||
-------------
|
||||
|
||||
All software which inherits ``IOSoftware`` installed on a node will not work unless the node has been turned on.
|
||||
Software which inherits ``IOSoftware`` installed on a node will not work unless the node has been turned on.
|
||||
|
||||
See :ref:`Node Start up and Shut down`
|
||||
|
||||
|
||||
@@ -234,7 +234,9 @@ class PrimaiteGame:
|
||||
subnet_mask=IPv4Address(node_cfg.get("subnet_mask", "255.255.255.0")),
|
||||
default_gateway=node_cfg["default_gateway"],
|
||||
dns_server=node_cfg.get("dns_server", None),
|
||||
operating_state=NodeOperatingState.ON,
|
||||
operating_state=NodeOperatingState.ON
|
||||
if not (p := node_cfg.get("operating_state"))
|
||||
else NodeOperatingState[p.upper()],
|
||||
)
|
||||
elif n_type == "server":
|
||||
new_node = Server(
|
||||
@@ -243,13 +245,17 @@ class PrimaiteGame:
|
||||
subnet_mask=IPv4Address(node_cfg.get("subnet_mask", "255.255.255.0")),
|
||||
default_gateway=node_cfg["default_gateway"],
|
||||
dns_server=node_cfg.get("dns_server", None),
|
||||
operating_state=NodeOperatingState.ON,
|
||||
operating_state=NodeOperatingState.ON
|
||||
if not (p := node_cfg.get("operating_state"))
|
||||
else NodeOperatingState[p.upper()],
|
||||
)
|
||||
elif n_type == "switch":
|
||||
new_node = Switch(
|
||||
hostname=node_cfg["hostname"],
|
||||
num_ports=int(node_cfg.get("num_ports", "8")),
|
||||
operating_state=NodeOperatingState.ON,
|
||||
operating_state=NodeOperatingState.ON
|
||||
if not (p := node_cfg.get("operating_state"))
|
||||
else NodeOperatingState[p.upper()],
|
||||
)
|
||||
elif n_type == "router":
|
||||
new_node = Router.from_config(node_cfg)
|
||||
@@ -359,7 +365,9 @@ class PrimaiteGame:
|
||||
new_node.shut_down_duration = 0
|
||||
|
||||
net.add_node(new_node)
|
||||
new_node.power_on()
|
||||
# run through the power on step if the node is to be turned on at the start
|
||||
if new_node.operating_state == NodeOperatingState.ON:
|
||||
new_node.power_on()
|
||||
game.ref_map_nodes[node_ref] = new_node.uuid
|
||||
|
||||
# set start up and shut down duration
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# flake8: noqa
|
||||
"""Core of the PrimAITE Simulator."""
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import Callable, ClassVar, Dict, List, Optional, Union
|
||||
from abc import abstractmethod
|
||||
from typing import Callable, Dict, List, Optional, Union
|
||||
from uuid import uuid4
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, Field
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from ipaddress import IPv4Address
|
||||
from typing import Any, Dict, Optional
|
||||
from typing import Any, ClassVar, Dict, Optional
|
||||
|
||||
from primaite import getLogger
|
||||
from primaite.simulator.network.hardware.base import IPWiredNetworkInterface, Link, Node
|
||||
@@ -253,17 +253,6 @@ class NIC(IPWiredNetworkInterface):
|
||||
return f"Port {self.port_num}: {self.mac_address}/{self.ip_address}"
|
||||
|
||||
|
||||
SYSTEM_SOFTWARE = {
|
||||
"HostARP": HostARP,
|
||||
"ICMP": ICMP,
|
||||
"DNSClient": DNSClient,
|
||||
"FTPClient": FTPClient,
|
||||
"NTPClient": NTPClient,
|
||||
"WebBrowser": WebBrowser,
|
||||
}
|
||||
"""List of system software that is automatically installed on nodes."""
|
||||
|
||||
|
||||
class HostNode(Node):
|
||||
"""
|
||||
Represents a host node in the network.
|
||||
@@ -308,6 +297,16 @@ class HostNode(Node):
|
||||
* Web Browser: Provides web browsing capabilities.
|
||||
"""
|
||||
|
||||
SYSTEM_SOFTWARE: ClassVar[Dict] = {
|
||||
"HostARP": HostARP,
|
||||
"ICMP": ICMP,
|
||||
"DNSClient": DNSClient,
|
||||
"FTPClient": FTPClient,
|
||||
"NTPClient": NTPClient,
|
||||
"WebBrowser": WebBrowser,
|
||||
}
|
||||
"""List of system software that is automatically installed on nodes."""
|
||||
|
||||
network_interfaces: Dict[str, NIC] = {}
|
||||
"The Network Interfaces on the node."
|
||||
network_interface: Dict[int, NIC] = {}
|
||||
@@ -324,7 +323,7 @@ class HostNode(Node):
|
||||
This method equips the host with essential network services and applications, preparing it for various
|
||||
network-related tasks and operations.
|
||||
"""
|
||||
for _, software_class in SYSTEM_SOFTWARE.items():
|
||||
for _, software_class in self.SYSTEM_SOFTWARE.items():
|
||||
self.software_manager.install(software_class)
|
||||
|
||||
super()._install_system_software()
|
||||
|
||||
@@ -12,6 +12,8 @@ from primaite.simulator.network.hardware.nodes.network.router import (
|
||||
RouterInterface,
|
||||
)
|
||||
from primaite.simulator.network.transmission.data_link_layer import Frame
|
||||
from primaite.simulator.network.transmission.network_layer import IPProtocol
|
||||
from primaite.simulator.network.transmission.transport_layer import Port
|
||||
from primaite.simulator.system.core.sys_log import SysLog
|
||||
from primaite.utils.validators import IPV4Address
|
||||
|
||||
@@ -479,7 +481,12 @@ class Firewall(Router):
|
||||
@classmethod
|
||||
def from_config(cls, cfg: dict) -> "Firewall":
|
||||
"""Create a firewall based on a config dict."""
|
||||
firewall = Firewall(hostname=cfg["hostname"], operating_state=NodeOperatingState.ON)
|
||||
firewall = Firewall(
|
||||
hostname=cfg["hostname"],
|
||||
operating_state=NodeOperatingState.ON
|
||||
if not (p := cfg.get("operating_state"))
|
||||
else NodeOperatingState[p.upper()],
|
||||
)
|
||||
if "ports" in cfg:
|
||||
internal_port = cfg["ports"]["internal_port"]
|
||||
external_port = cfg["ports"]["external_port"]
|
||||
@@ -505,34 +512,82 @@ class Firewall(Router):
|
||||
if "acl" in cfg:
|
||||
# acl rules for internal_inbound_acl
|
||||
if cfg["acl"]["internal_inbound_acl"]:
|
||||
firewall.internal_inbound_acl.max_acl_rules
|
||||
firewall.internal_inbound_acl._default_config = cfg["acl"]["internal_inbound_acl"]
|
||||
firewall.internal_inbound_acl._reset_rules_to_default()
|
||||
for r_num, r_cfg in cfg["acl"]["internal_inbound_acl"].items():
|
||||
firewall.internal_inbound_acl.add_rule(
|
||||
action=ACLAction[r_cfg["action"]],
|
||||
src_port=None if not (p := r_cfg.get("src_port")) else Port[p],
|
||||
dst_port=None if not (p := r_cfg.get("dst_port")) else Port[p],
|
||||
protocol=None if not (p := r_cfg.get("protocol")) else IPProtocol[p],
|
||||
src_ip_address=r_cfg.get("src_ip"),
|
||||
dst_ip_address=r_cfg.get("dst_ip"),
|
||||
position=r_num,
|
||||
)
|
||||
|
||||
# acl rules for internal_outbound_acl
|
||||
if cfg["acl"]["internal_outbound_acl"]:
|
||||
firewall.internal_outbound_acl._default_config = cfg["acl"]["internal_outbound_acl"]
|
||||
firewall.internal_outbound_acl._reset_rules_to_default()
|
||||
for r_num, r_cfg in cfg["acl"]["internal_outbound_acl"].items():
|
||||
firewall.internal_outbound_acl.add_rule(
|
||||
action=ACLAction[r_cfg["action"]],
|
||||
src_port=None if not (p := r_cfg.get("src_port")) else Port[p],
|
||||
dst_port=None if not (p := r_cfg.get("dst_port")) else Port[p],
|
||||
protocol=None if not (p := r_cfg.get("protocol")) else IPProtocol[p],
|
||||
src_ip_address=r_cfg.get("src_ip"),
|
||||
dst_ip_address=r_cfg.get("dst_ip"),
|
||||
position=r_num,
|
||||
)
|
||||
|
||||
# acl rules for dmz_inbound_acl
|
||||
if cfg["acl"]["dmz_inbound_acl"]:
|
||||
firewall.dmz_inbound_acl._default_config = cfg["acl"]["dmz_inbound_acl"]
|
||||
firewall.dmz_inbound_acl._reset_rules_to_default()
|
||||
for r_num, r_cfg in cfg["acl"]["dmz_inbound_acl"].items():
|
||||
firewall.dmz_inbound_acl.add_rule(
|
||||
action=ACLAction[r_cfg["action"]],
|
||||
src_port=None if not (p := r_cfg.get("src_port")) else Port[p],
|
||||
dst_port=None if not (p := r_cfg.get("dst_port")) else Port[p],
|
||||
protocol=None if not (p := r_cfg.get("protocol")) else IPProtocol[p],
|
||||
src_ip_address=r_cfg.get("src_ip"),
|
||||
dst_ip_address=r_cfg.get("dst_ip"),
|
||||
position=r_num,
|
||||
)
|
||||
|
||||
# acl rules for dmz_outbound_acl
|
||||
if cfg["acl"]["dmz_outbound_acl"]:
|
||||
firewall.dmz_outbound_acl._default_config = cfg["acl"]["dmz_outbound_acl"]
|
||||
firewall.dmz_outbound_acl._reset_rules_to_default()
|
||||
for r_num, r_cfg in cfg["acl"]["dmz_outbound_acl"].items():
|
||||
firewall.dmz_outbound_acl.add_rule(
|
||||
action=ACLAction[r_cfg["action"]],
|
||||
src_port=None if not (p := r_cfg.get("src_port")) else Port[p],
|
||||
dst_port=None if not (p := r_cfg.get("dst_port")) else Port[p],
|
||||
protocol=None if not (p := r_cfg.get("protocol")) else IPProtocol[p],
|
||||
src_ip_address=r_cfg.get("src_ip"),
|
||||
dst_ip_address=r_cfg.get("dst_ip"),
|
||||
position=r_num,
|
||||
)
|
||||
|
||||
# acl rules for external_inbound_acl
|
||||
if cfg["acl"]["external_inbound_acl"]:
|
||||
firewall.external_inbound_acl._default_config = cfg["acl"]["external_inbound_acl"]
|
||||
firewall.external_inbound_acl._reset_rules_to_default()
|
||||
for r_num, r_cfg in cfg["acl"]["external_inbound_acl"].items():
|
||||
firewall.external_inbound_acl.add_rule(
|
||||
action=ACLAction[r_cfg["action"]],
|
||||
src_port=None if not (p := r_cfg.get("src_port")) else Port[p],
|
||||
dst_port=None if not (p := r_cfg.get("dst_port")) else Port[p],
|
||||
protocol=None if not (p := r_cfg.get("protocol")) else IPProtocol[p],
|
||||
src_ip_address=r_cfg.get("src_ip"),
|
||||
dst_ip_address=r_cfg.get("dst_ip"),
|
||||
position=r_num,
|
||||
)
|
||||
|
||||
# acl rules for external_outbound_acl
|
||||
if cfg["acl"]["external_outbound_acl"]:
|
||||
firewall.external_outbound_acl._default_config = cfg["acl"]["external_outbound_acl"]
|
||||
firewall.external_outbound_acl._reset_rules_to_default()
|
||||
for r_num, r_cfg in cfg["acl"]["external_outbound_acl"].items():
|
||||
firewall.external_outbound_acl.add_rule(
|
||||
action=ACLAction[r_cfg["action"]],
|
||||
src_port=None if not (p := r_cfg.get("src_port")) else Port[p],
|
||||
dst_port=None if not (p := r_cfg.get("dst_port")) else Port[p],
|
||||
protocol=None if not (p := r_cfg.get("protocol")) else IPProtocol[p],
|
||||
src_ip_address=r_cfg.get("src_ip"),
|
||||
dst_ip_address=r_cfg.get("dst_ip"),
|
||||
position=r_num,
|
||||
)
|
||||
|
||||
if "routes" in cfg:
|
||||
for route in cfg.get("routes"):
|
||||
firewall.route_table.add_route(
|
||||
|
||||
@@ -1401,7 +1401,9 @@ class Router(NetworkNode):
|
||||
router = Router(
|
||||
hostname=cfg["hostname"],
|
||||
num_ports=int(cfg.get("num_ports", "5")),
|
||||
operating_state=NodeOperatingState.ON,
|
||||
operating_state=NodeOperatingState.ON
|
||||
if not (p := cfg.get("operating_state"))
|
||||
else NodeOperatingState[p.upper()],
|
||||
)
|
||||
if "ports" in cfg:
|
||||
for port_num, port_cfg in cfg["ports"].items():
|
||||
|
||||
@@ -141,6 +141,17 @@ simulation:
|
||||
default_gateway: 192.168.10.1
|
||||
dns_server: 192.168.1.10
|
||||
# pre installed services and applications
|
||||
- ref: client_3
|
||||
type: computer
|
||||
hostname: client_3
|
||||
ip_address: 192.168.10.23
|
||||
subnet_mask: 255.255.255.0
|
||||
default_gateway: 192.168.10.1
|
||||
dns_server: 192.168.1.10
|
||||
start_up_duration: 0
|
||||
shut_down_duration: 0
|
||||
operating_state: "OFF"
|
||||
# pre installed services and applications
|
||||
|
||||
links:
|
||||
- ref: switch_1___client_1
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
from primaite.config.load import example_config_path
|
||||
from primaite.simulator.network.container import Network
|
||||
from tests.integration_tests.configuration_file_parsing import DMZ_NETWORK, load_config
|
||||
from primaite.simulator.network.hardware.node_operating_state import NodeOperatingState
|
||||
from primaite.simulator.network.hardware.nodes.host.computer import Computer
|
||||
from tests.integration_tests.configuration_file_parsing import BASIC_CONFIG, DMZ_NETWORK, load_config
|
||||
|
||||
|
||||
def test_example_config():
|
||||
@@ -24,3 +26,19 @@ def test_dmz_config():
|
||||
assert len(network.routers) == 2 # 2 routers in network
|
||||
assert len(network.switches) == 3 # 3 switches in network
|
||||
assert len(network.servers) == 2 # 2 servers in network
|
||||
|
||||
|
||||
def test_basic_config():
|
||||
"""Test that the basic_switched_network config can be parsed properly."""
|
||||
game = load_config(BASIC_CONFIG)
|
||||
network: Network = game.simulation.network
|
||||
assert len(network.nodes) == 4 # 4 nodes in network
|
||||
|
||||
client_1: Computer = network.get_node_by_hostname("client_1")
|
||||
assert client_1.operating_state == NodeOperatingState.ON
|
||||
client_2: Computer = network.get_node_by_hostname("client_2")
|
||||
assert client_2.operating_state == NodeOperatingState.ON
|
||||
|
||||
# client 3 should not be online
|
||||
client_3: Computer = network.get_node_by_hostname("client_3")
|
||||
assert client_3.operating_state == NodeOperatingState.OFF
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
from ipaddress import IPv4Address
|
||||
from pathlib import Path
|
||||
from typing import Union
|
||||
|
||||
from primaite.game.game import APPLICATION_TYPES_MAPPING, SERVICE_TYPES_MAPPING
|
||||
import yaml
|
||||
|
||||
from primaite.config.load import example_config_path
|
||||
from primaite.game.agent.data_manipulation_bot import DataManipulationAgent
|
||||
from primaite.game.agent.interface import ProxyAgent, RandomAgent
|
||||
from primaite.game.game import APPLICATION_TYPES_MAPPING, PrimaiteGame, SERVICE_TYPES_MAPPING
|
||||
from primaite.simulator.network.container import Network
|
||||
from primaite.simulator.network.hardware.nodes.host.computer import Computer
|
||||
from primaite.simulator.system.applications.database_client import DatabaseClient
|
||||
from primaite.simulator.system.applications.red_applications.data_manipulation_bot import DataManipulationBot
|
||||
|
||||
Reference in New Issue
Block a user