Merge remote-tracking branch 'origin/dev' into feature/2085-dump_describe_state
This commit is contained in:
@@ -6,6 +6,9 @@ trigger:
|
||||
- bugfix/*
|
||||
- release/*
|
||||
|
||||
pr:
|
||||
autoCancel: true
|
||||
drafts: false
|
||||
parameters:
|
||||
# https://stackoverflow.com/a/70046417
|
||||
- name: matrix
|
||||
@@ -85,6 +88,33 @@ stages:
|
||||
primaite setup
|
||||
displayName: 'Perform PrimAITE Setup'
|
||||
|
||||
- task: UseDotNet@2
|
||||
displayName: 'Install dotnet dependencies'
|
||||
inputs:
|
||||
packageType: 'sdk'
|
||||
version: '2.1.x'
|
||||
|
||||
- script: |
|
||||
pytest -n auto
|
||||
displayName: 'Run tests'
|
||||
coverage run -m --source=primaite pytest -v -o junit_family=xunit2 --junitxml=junit/test-results.xml --cov-fail-under=80
|
||||
coverage xml -o coverage.xml -i
|
||||
coverage html -d htmlcov -i
|
||||
displayName: 'Run tests and code coverage'
|
||||
|
||||
- task: PublishTestResults@2
|
||||
condition: succeededOrFailed()
|
||||
inputs:
|
||||
testRunner: JUnit
|
||||
testResultsFiles: 'junit/**.xml'
|
||||
testRunTitle: 'Publish test results'
|
||||
|
||||
- publish: $(System.DefaultWorkingDirectory)/htmlcov/
|
||||
# publish the html report - so we can debug the coverage if needed
|
||||
condition: ${{ item.every_time }} # should only be run once
|
||||
artifact: coverage_report
|
||||
|
||||
- task: PublishCodeCoverageResults@2
|
||||
# publish the code coverage so it can be viewed in the run coverage page
|
||||
condition: ${{ item.every_time }} # should only be run once
|
||||
inputs:
|
||||
codeCoverageTool: Cobertura
|
||||
summaryFileLocation: '$(System.DefaultWorkingDirectory)/**/coverage.xml'
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -37,6 +37,7 @@ pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
junit/
|
||||
htmlcov/
|
||||
.tox/
|
||||
.nox/
|
||||
|
||||
@@ -1,13 +1,80 @@
|
||||
Primaite v3 config
|
||||
******************
|
||||
|
||||
PrimAITE uses a single configuration file to define a cybersecurity scenario. This includes the computer network and multiple agents. There are three main sections: training_config, game, and simulation.
|
||||
PrimAITE uses a single configuration file to define everything needed to train and evaluate an RL policy in a custom cybersecurity scenario. This includes the configuration of the network, the scripted or trained agents that interact with the network, as well as settings that define how to perform training in Stable Baselines 3 or Ray RLLib.
|
||||
The entire config is used by the ``PrimaiteSession`` object for users who wish to let PrimAITE handle the agent definition and training. If you wish to define custom agents and control the training loop yourself, you can use the config with the ``PrimaiteGame``, and ``PrimaiteGymEnv`` objects instead. That way, only the network configuration and agent setup parts of the config are used, and the training section is ignored.
|
||||
|
||||
The simulation section describes the simulated network environment with which the agetns interact.
|
||||
Configurable items
|
||||
==================
|
||||
|
||||
The game section describes the agents and their capabilities. Each agent has a unique type and is associated with a team (GREEN, RED, or BLUE). Each agent has a configurable observation space, action space, and reward function.
|
||||
``training_config``
|
||||
-------------------
|
||||
This section allows selecting which training framework and algorithm to use, and set some training hyperparameters.
|
||||
|
||||
The training_config section describes the training parameters for the learning agents. This includes the number of episodes, the number of steps per episode, and the number of steps before the agents start learning. The training_config section also describes the learning algorithm used by the agents. The learning algorithm is specified by the name of the algorithm and the hyperparameters for the algorithm. The hyperparameters are specific to each algorithm and are described in the documentation for each algorithm.
|
||||
``io_settings``
|
||||
---------------
|
||||
This section configures how the ``PrimaiteSession`` saves data.
|
||||
|
||||
.. only:: comment
|
||||
This needs a bit of refactoring so I haven't written extensive documentation about the config yet.
|
||||
``game``
|
||||
--------
|
||||
This section defines high-level settings that apply across the game, currently it's used to help shape the action and observation spaces by restricting which ports and internet protocols should be considered. Here, users can also set the maximum number of steps in an episode.
|
||||
|
||||
``agents``
|
||||
----------
|
||||
Agents can be scripted (deterministic and stochastic), or controlled by a reinforcement learning algorithm. Not to be confused with an RL agent, the term agent here is used to refer to an entity that sends requests to the simulated network. In this part of the config, each agent's action space, observation space, and reward function can be defined. All three are defined in a modular way.
|
||||
|
||||
**type**: Specifies which class should be used for the agent. ``ProxyAgent`` is used for agents that receive instructions from an RL algorithm. Scripted agents like ``RedDatabaseCorruptingAgent`` and ``GreenWebBrowsingAgent`` generate their own behaviour.
|
||||
|
||||
**team**: Specifies if the agent is malicious (RED), benign (GREEN), or defensive (BLUE). Currently this value is not used for anything.
|
||||
|
||||
**observation space:**
|
||||
* ``type``: selects which python class from the ``primaite.game.agent.observation`` module is used for the overall observation structure.
|
||||
* ``options``: allows configuring the chosen observation type. The ``UC2BlueObservation`` should be used for RL Agents.
|
||||
* ``num_services_per_node``, ``num_folders_per_node``, ``num_files_per_folder``, ``num_nics_per_node`` all define the shape of the observation space. The size and shape of the obs space must remain constant, but the number of files, folders, ACL rules, and other components can change within an episode. Therefore padding is performed and these options set the size of the obs space.
|
||||
* ``nodes``: list of nodes that will be present in this agent's observation space. The ``node_ref`` relates to the human-readable unique reference defined later in the ``simulation`` part of the config. Each node can also be configured with services, and files that should be monitored.
|
||||
* ``links``: list of links that will be present in this agent's observation space. The ``link_ref`` relates to the human-readable unique reference defined later in the ``simulation`` part of the config.
|
||||
* ``acl``: configure how the agent reads the access control list on the router in the simulation. ``router_node_ref`` is for selecting which router's ACL table should be used. ``ip_address_order`` sets the encoding of ip addresses as integers within the observation space.
|
||||
|
||||
**action space:**
|
||||
The action space is configured to be made up of individual action types. Once configured, the agent can select an action type and some optional action parameters at every step. For example: The ``NODE_SERVICE_SCAN`` action takes the parameters ``node_id`` and ``service_id``.
|
||||
|
||||
Description of configurable items:
|
||||
* ``action_list``: a list of action modules. The options are listed in the ``primaite.game.agent.actions`` module.
|
||||
* ``action_map``: (optional). Restricts the possible combinations of action type / action parameter values to reduce the overall size of the action space. By default, every possible combination of actions and parameters will be assigned an integer for the agent's ``MultiDiscrete`` action space. Instead, the ``action_map`` allows you to list the actions corresponding to each integer in the ``MultiDiscrete`` space.
|
||||
* ``options``: Options that apply too all action components.
|
||||
* ``nodes``: list the nodes that the agent can act on, the order of this list defines the mapping between nodes and ``node_id`` integers.
|
||||
* ``max_folders_per_node``, ``max_files_per_folder``, ``max_services_per_node``, ``max_nics_per_node``, ``max_acl_rules`` all are used to define the size of the action space.
|
||||
|
||||
**reward function:**
|
||||
Similar to action space, this is defined as a list of components.
|
||||
|
||||
Description of configurable items:
|
||||
* ``reward_components`` a list of reward components from the ``primaite.game.agent.reward`` module.
|
||||
* ``weight``: relative importance of this reward component. The total reward for a step is a weighted sum of all reward components.
|
||||
* ``options``: list of options passed to the reward component during initialisation, the exact options required depend on the reward component.
|
||||
|
||||
**agent_settings**:
|
||||
Settings passed to the agent during initialisation. These depend on the agent class.
|
||||
|
||||
``simulation``
|
||||
--------------
|
||||
In this section the network layout is defined. This part of the config follows a hierarchical structure. Almost every component defines a ``ref`` field which acts as a human-readable unique identifier, used by other parts of the config, such as agents.
|
||||
|
||||
At the top level of the network are ``nodes`` and ``links``.
|
||||
|
||||
**nodes:**
|
||||
* ``type``: one of ``router``, ``switch``, ``computer``, or ``server``, this affects what other sub-options should be defined.
|
||||
* ``hostname`` - a non-unique name used for logging and outputs.
|
||||
* ``num_ports`` (optional, routers and switches only): number of network interfaces present on the device.
|
||||
* ``ports`` (optional, routers and switches only): configuration for each network interface, including IP address and subnet mask.
|
||||
* ``acl`` (Router only): Define the ACL rules at each index of the ACL on the router. the possible options are: ``action`` (PERMIT or DENY), ``src_port``, ``dst_port``, ``protocol``, ``src_ip``, ``dst_ip``. Any options left blank default to none which usually means that it will apply across all options. For example leaving ``src_ip`` blank will apply the rule to all IP addresses.
|
||||
* ``services`` (computers and servers only): a list of services to install on the node. They must define a ``ref``, ``type``, and ``options`` that depend on which ``type`` was selected.
|
||||
* ``applications`` (computer and servers only): Similar to services. A list of application to install on the node.
|
||||
* ``nics`` (computers and servers only): If the node has multiple networking devices, the second, third, fourth, etc... must be defined here with an ``ip_address`` and ``subnet_mask``.
|
||||
|
||||
**links:**
|
||||
* ``ref``: unique identifier for this link
|
||||
* ``endpoint_a_ref``: Reference to the node at the first end of the link
|
||||
* ``endpoint_a_port``: The ethernet port or switch port index of the second node
|
||||
* ``endpoint_b_ref``: Reference to the node at the second end of the link
|
||||
* ``endpoint_b_port``: The ethernet port or switch port index on the second node
|
||||
|
||||
@@ -54,7 +54,7 @@ Example
|
||||
)
|
||||
network.connect(endpoint_b=client_1.ethernet_port[1], endpoint_a=switch_2.switch_ports[1])
|
||||
client_1.software_manager.install(DataManipulationBot)
|
||||
data_manipulation_bot: DataManipulationBot = client_1.software_manager.software["DataManipulationBot"]
|
||||
data_manipulation_bot: DataManipulationBot = client_1.software_manager.software.get("DataManipulationBot")
|
||||
data_manipulation_bot.configure(server_ip_address=IPv4Address("192.168.1.14"), payload="DELETE")
|
||||
data_manipulation_bot.run()
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ See :ref:`Node Start up and Shut down`
|
||||
|
||||
node.software_manager.install(WebServer)
|
||||
|
||||
web_server: WebServer = node.software_manager.software["WebServer"]
|
||||
web_server: WebServer = node.software_manager.software.get("WebServer")
|
||||
assert web_server.operating_state is ServiceOperatingState.RUNNING # service is immediately ran after install
|
||||
|
||||
node.power_off()
|
||||
|
||||
@@ -655,8 +655,8 @@ simulation:
|
||||
- ref: data_manipulation_bot
|
||||
type: DataManipulationBot
|
||||
options:
|
||||
port_scan_p_of_success: 0.1
|
||||
data_manipulation_p_of_success: 0.1
|
||||
port_scan_p_of_success: 0.8
|
||||
data_manipulation_p_of_success: 0.8
|
||||
payload: "DELETE"
|
||||
server_ip: 192.168.1.14
|
||||
services:
|
||||
|
||||
@@ -424,7 +424,7 @@ class NetworkACLAddRuleAction(AbstractAction):
|
||||
elif permission == 2:
|
||||
permission_str = "DENY"
|
||||
else:
|
||||
_LOGGER.warn(f"{self.__class__} received permission {permission}, expected 0 or 1.")
|
||||
_LOGGER.warning(f"{self.__class__} received permission {permission}, expected 0 or 1.")
|
||||
|
||||
if protocol_id == 0:
|
||||
return ["do_nothing"] # NOT SUPPORTED, JUST DO NOTHING IF WE COME ACROSS THIS
|
||||
|
||||
@@ -264,7 +264,7 @@ class FolderObservation(AbstractObservation):
|
||||
while len(self.files) > num_files_per_folder:
|
||||
truncated_file = self.files.pop()
|
||||
msg = f"Too many files in folder observation. Truncating file {truncated_file}"
|
||||
_LOGGER.warn(msg)
|
||||
_LOGGER.warning(msg)
|
||||
|
||||
self.default_observation = {
|
||||
"health_status": 0,
|
||||
@@ -438,7 +438,7 @@ class NodeObservation(AbstractObservation):
|
||||
while len(self.services) > num_services_per_node:
|
||||
truncated_service = self.services.pop()
|
||||
msg = f"Too many services in Node observation space for node. Truncating service {truncated_service.where}"
|
||||
_LOGGER.warn(msg)
|
||||
_LOGGER.warning(msg)
|
||||
# truncate service list
|
||||
|
||||
self.folders: List[FolderObservation] = folders
|
||||
@@ -448,7 +448,7 @@ class NodeObservation(AbstractObservation):
|
||||
while len(self.folders) > num_folders_per_node:
|
||||
truncated_folder = self.folders.pop()
|
||||
msg = f"Too many folders in Node observation for node. Truncating service {truncated_folder.where[-1]}"
|
||||
_LOGGER.warn(msg)
|
||||
_LOGGER.warning(msg)
|
||||
|
||||
self.nics: List[NicObservation] = nics
|
||||
while len(self.nics) < num_nics_per_node:
|
||||
@@ -456,7 +456,7 @@ class NodeObservation(AbstractObservation):
|
||||
while len(self.nics) > num_nics_per_node:
|
||||
truncated_nic = self.nics.pop()
|
||||
msg = f"Too many NICs in Node observation for node. Truncating service {truncated_nic.where[-1]}"
|
||||
_LOGGER.warn(msg)
|
||||
_LOGGER.warning(msg)
|
||||
|
||||
self.logon_status: bool = logon_status
|
||||
|
||||
|
||||
@@ -210,7 +210,7 @@ class WebServer404Penalty(AbstractReward):
|
||||
f"{cls.__name__} could not be initialised from config because node_ref and service_ref were not "
|
||||
"found in reward config."
|
||||
)
|
||||
_LOGGER.warn(msg)
|
||||
_LOGGER.warning(msg)
|
||||
return DummyReward() # TODO: should we error out with incorrect inputs? Probably!
|
||||
node_uuid = game.ref_map_nodes[node_ref]
|
||||
service_uuid = game.ref_map_services[service_ref]
|
||||
@@ -219,7 +219,7 @@ class WebServer404Penalty(AbstractReward):
|
||||
f"{cls.__name__} could not be initialised because node {node_ref} and service {service_ref} were not"
|
||||
" found in the simulator."
|
||||
)
|
||||
_LOGGER.warn(msg)
|
||||
_LOGGER.warning(msg)
|
||||
return DummyReward() # TODO: consider erroring here as well
|
||||
|
||||
return cls(node_uuid=node_uuid, service_uuid=service_uuid)
|
||||
@@ -238,7 +238,8 @@ class RewardFunction:
|
||||
"""Initialise the reward function object."""
|
||||
self.reward_components: List[Tuple[AbstractReward, float]] = []
|
||||
"attribute reward_components keeps track of reward components and the weights assigned to each."
|
||||
self.current_reward: float
|
||||
self.current_reward: float = 0.0
|
||||
self.total_reward: float = 0.0
|
||||
|
||||
def regsiter_component(self, component: AbstractReward, weight: float = 1.0) -> None:
|
||||
"""Add a reward component to the reward function.
|
||||
|
||||
@@ -125,6 +125,7 @@ class PrimaiteGame:
|
||||
for agent in self.agents:
|
||||
agent.update_observation(state)
|
||||
agent.update_reward(state)
|
||||
agent.reward_function.total_reward += agent.reward_function.current_reward
|
||||
|
||||
def apply_agent_actions(self) -> None:
|
||||
"""Apply all actions to simulation as requests."""
|
||||
@@ -155,6 +156,8 @@ class PrimaiteGame:
|
||||
self.step_counter = 0
|
||||
_LOGGER.debug(f"Resetting primaite game, episode = {self.episode_counter}")
|
||||
self.simulation.reset_component_for_episode(episode=self.episode_counter)
|
||||
for agent in self.agents:
|
||||
agent.reward_function.total_reward = 0.0
|
||||
|
||||
def close(self) -> None:
|
||||
"""Close the game, this will close the simulation."""
|
||||
@@ -240,7 +243,7 @@ class PrimaiteGame:
|
||||
position=r_num,
|
||||
)
|
||||
else:
|
||||
print("invalid node type")
|
||||
_LOGGER.warning(f"invalid node type {n_type} in config")
|
||||
if "services" in node_cfg:
|
||||
for service_cfg in node_cfg["services"]:
|
||||
new_service = None
|
||||
@@ -256,12 +259,12 @@ class PrimaiteGame:
|
||||
"FTPServer": FTPServer,
|
||||
}
|
||||
if service_type in service_types_mapping:
|
||||
print(f"installing {service_type} on node {new_node.hostname}")
|
||||
_LOGGER.debug(f"installing {service_type} on node {new_node.hostname}")
|
||||
new_node.software_manager.install(service_types_mapping[service_type])
|
||||
new_service = new_node.software_manager.software[service_type]
|
||||
game.ref_map_services[service_ref] = new_service.uuid
|
||||
else:
|
||||
print(f"service type not found {service_type}")
|
||||
_LOGGER.warning(f"service type not found {service_type}")
|
||||
# service-dependent options
|
||||
if service_type == "DatabaseClient":
|
||||
if "options" in service_cfg:
|
||||
@@ -295,7 +298,7 @@ class PrimaiteGame:
|
||||
new_application = new_node.software_manager.software[application_type]
|
||||
game.ref_map_applications[application_ref] = new_application.uuid
|
||||
else:
|
||||
print(f"application type not found {application_type}")
|
||||
_LOGGER.warning(f"application type not found {application_type}")
|
||||
|
||||
if application_type == "DataManipulationBot":
|
||||
if "options" in application_cfg:
|
||||
@@ -416,7 +419,7 @@ class PrimaiteGame:
|
||||
)
|
||||
game.agents.append(new_agent)
|
||||
else:
|
||||
print("agent type not found")
|
||||
_LOGGER.warning(f"agent type {agent_type} not found")
|
||||
|
||||
game.simulation.set_original_state()
|
||||
|
||||
|
||||
@@ -1,5 +1,21 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Train a Multi agent system using RLLIB\n",
|
||||
"\n",
|
||||
"This notebook will demonstrate how to use the `PrimaiteRayMARLEnv` to train a very basic system with two PPO agents."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"#### First, Import packages and read our config file."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
@@ -8,30 +24,28 @@
|
||||
"source": [
|
||||
"from primaite.game.game import PrimaiteGame\n",
|
||||
"import yaml\n",
|
||||
"from primaite.config.load import example_config_path\n",
|
||||
"\n",
|
||||
"from primaite.session.environment import PrimaiteRayEnv"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"with open('/home/cade/repos/PrimAITE/src/primaite/config/_package_data/example_config_2_rl_agents.yaml', 'r') as f:\n",
|
||||
" cfg = yaml.safe_load(f)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from primaite.session.environment import PrimaiteRayEnv\n",
|
||||
"from primaite import PRIMAITE_PATHS\n",
|
||||
"\n",
|
||||
"import ray\n",
|
||||
"from ray import air, tune\n",
|
||||
"from ray.rllib.algorithms.ppo import PPOConfig"
|
||||
"from ray.rllib.algorithms.ppo import PPOConfig\n",
|
||||
"from primaite.session.environment import PrimaiteRayMARLEnv\n",
|
||||
"\n",
|
||||
"# If you get an error saying this config file doesn't exist, you may need to run `primaite setup` in your command line\n",
|
||||
"# to copy the files to your user data path.\n",
|
||||
"with open(PRIMAITE_PATHS.user_config_path / 'example_config/example_config_2_rl_agents.yaml', 'r') as f:\n",
|
||||
" cfg = yaml.safe_load(f)\n",
|
||||
"\n",
|
||||
"ray.init(local_mode=True)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"#### Create a Ray algorithm config which accepts our two agents"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -40,13 +54,10 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from primaite.session.environment import PrimaiteRayMARLEnv\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"config = (\n",
|
||||
" PPOConfig()\n",
|
||||
" .multi_agent(\n",
|
||||
" policies={'defender_1','defender_2'},\n",
|
||||
" policies={'defender_1','defender_2'}, # These names are the same as the agents defined in the example config.\n",
|
||||
" policy_mapping_fn=lambda agent_id, episode, worker, **kw: agent_id,\n",
|
||||
" )\n",
|
||||
" .environment(env=PrimaiteRayMARLEnv, env_config={\"cfg\":cfg})#, disable_env_checking=True)\n",
|
||||
@@ -55,6 +66,14 @@
|
||||
" )\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"#### Set training parameters and start the training\n",
|
||||
"This example will save outputs to a default Ray directory and use mostly default settings."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
@@ -64,25 +83,11 @@
|
||||
"tune.Tuner(\n",
|
||||
" \"PPO\",\n",
|
||||
" run_config=air.RunConfig(\n",
|
||||
" stop={\"timesteps_total\": 511},\n",
|
||||
" stop={\"timesteps_total\": 512},\n",
|
||||
" ),\n",
|
||||
" param_space=config\n",
|
||||
").fit()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stderr",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"2023-12-01 14:53:13,421\tWARNING __init__.py:10 -- PG has/have been moved to `rllib_contrib` and will no longer be maintained by the RLlib team. You can still use it/them normally inside RLlib util Ray 2.8, but from Ray 2.9 on, all `rllib_contrib` algorithms will no longer be part of the core repo, and will therefore have to be installed separately with pinned dependencies for e.g. ray[rllib] and other packages! See https://github.com/ray-project/ray/tree/master/rllib_contrib#rllib-contrib for more information on the RLlib contrib effort.\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"## Train a Single agent system using RLLib\n",
|
||||
"This notebook will demonstrate how to use PrimaiteRayEnv to train a basic PPO agent."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from primaite.game.game import PrimaiteGame\n",
|
||||
"import yaml\n",
|
||||
@@ -22,86 +22,26 @@
|
||||
"from ray.rllib.algorithms import ppo\n",
|
||||
"from ray import air, tune\n",
|
||||
"import ray\n",
|
||||
"from ray.rllib.algorithms.ppo import PPOConfig"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from ray.rllib.algorithms.ppo import PPOConfig\n",
|
||||
"\n",
|
||||
"# If you get an error saying this config file doesn't exist, you may need to run `primaite setup` in your command line\n",
|
||||
"# to copy the files to your user data path.\n",
|
||||
"with open(example_config_path(), 'r') as f:\n",
|
||||
" cfg = yaml.safe_load(f)\n"
|
||||
" cfg = yaml.safe_load(f)\n",
|
||||
"\n",
|
||||
"ray.init(local_mode=True)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stderr",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"2023-12-01 14:53:16,276\tINFO worker.py:1673 -- Started a local Ray instance.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"application/vnd.jupyter.widget-view+json": {
|
||||
"model_id": "9a775bf48837443dbdc6a3da9e9831f5",
|
||||
"version_major": 2,
|
||||
"version_minor": 0
|
||||
},
|
||||
"text/html": [
|
||||
"<div class=\"lm-Widget p-Widget lm-Panel p-Panel jp-Cell-outputWrapper\">\n",
|
||||
" <div style=\"margin-left: 50px;display: flex;flex-direction: row;align-items: center\">\n",
|
||||
" <div class=\"jp-RenderedHTMLCommon\" style=\"display: flex; flex-direction: row;\">\n",
|
||||
" <svg viewBox=\"0 0 567 224\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" style=\"height: 3em;\">\n",
|
||||
" <g clip-path=\"url(#clip0_4338_178347)\">\n",
|
||||
" <path d=\"M341.29 165.561H355.29L330.13 129.051C345.63 123.991 354.21 112.051 354.21 94.2307C354.21 71.3707 338.72 58.1807 311.88 58.1807H271V165.561H283.27V131.661H311.8C314.25 131.661 316.71 131.501 319.01 131.351L341.25 165.561H341.29ZM283.29 119.851V70.0007H311.82C331.3 70.0007 342.34 78.2907 342.34 94.5507C342.34 111.271 331.34 119.861 311.82 119.861L283.29 119.851ZM451.4 138.411L463.4 165.561H476.74L428.74 58.1807H416L367.83 165.561H380.83L392.83 138.411H451.4ZM446.19 126.601H398L422 72.1407L446.24 126.601H446.19ZM526.11 128.741L566.91 58.1807H554.35L519.99 114.181L485.17 58.1807H472.44L514.01 129.181V165.541H526.13V128.741H526.11Z\" fill=\"var(--jp-ui-font-color0)\"/>\n",
|
||||
" <path d=\"M82.35 104.44C84.0187 97.8827 87.8248 92.0678 93.1671 87.9146C98.5094 83.7614 105.083 81.5067 111.85 81.5067C118.617 81.5067 125.191 83.7614 130.533 87.9146C135.875 92.0678 139.681 97.8827 141.35 104.44H163.75C164.476 101.562 165.622 98.8057 167.15 96.2605L127.45 56.5605C121.071 60.3522 113.526 61.6823 106.235 60.3005C98.9443 58.9187 92.4094 54.9203 87.8602 49.0574C83.3109 43.1946 81.0609 35.8714 81.5332 28.4656C82.0056 21.0599 85.1679 14.0819 90.4252 8.8446C95.6824 3.60726 102.672 0.471508 110.08 0.0272655C117.487 -0.416977 124.802 1.86091 130.647 6.4324C136.493 11.0039 140.467 17.5539 141.821 24.8501C143.175 32.1463 141.816 39.6859 138 46.0505L177.69 85.7505C182.31 82.9877 187.58 81.4995 192.962 81.4375C198.345 81.3755 203.648 82.742 208.33 85.3976C213.012 88.0532 216.907 91.9029 219.616 96.5544C222.326 101.206 223.753 106.492 223.753 111.875C223.753 117.258 222.326 122.545 219.616 127.197C216.907 131.848 213.012 135.698 208.33 138.353C203.648 141.009 198.345 142.375 192.962 142.313C187.58 142.251 182.31 140.763 177.69 138L138 177.7C141.808 184.071 143.155 191.614 141.79 198.91C140.424 206.205 136.44 212.75 130.585 217.313C124.731 221.875 117.412 224.141 110.004 223.683C102.596 223.226 95.6103 220.077 90.3621 214.828C85.1139 209.58 81.9647 202.595 81.5072 195.187C81.0497 187.779 83.3154 180.459 87.878 174.605C92.4405 168.751 98.9853 164.766 106.281 163.401C113.576 162.035 121.119 163.383 127.49 167.19L167.19 127.49C165.664 124.941 164.518 122.182 163.79 119.3H141.39C139.721 125.858 135.915 131.673 130.573 135.826C125.231 139.98 118.657 142.234 111.89 142.234C105.123 142.234 98.5494 139.98 93.2071 135.826C87.8648 131.673 84.0587 125.858 82.39 119.3H60C58.1878 126.495 53.8086 132.78 47.6863 136.971C41.5641 141.163 34.1211 142.972 26.7579 142.059C19.3947 141.146 12.6191 137.574 7.70605 132.014C2.79302 126.454 0.0813599 119.29 0.0813599 111.87C0.0813599 104.451 2.79302 97.2871 7.70605 91.7272C12.6191 86.1673 19.3947 82.5947 26.7579 81.6817C34.1211 80.7686 41.5641 82.5781 47.6863 86.7696C53.8086 90.9611 58.1878 97.2456 60 104.44H82.35ZM100.86 204.32C103.407 206.868 106.759 208.453 110.345 208.806C113.93 209.159 117.527 208.258 120.522 206.256C123.517 204.254 125.725 201.276 126.771 197.828C127.816 194.38 127.633 190.677 126.253 187.349C124.874 184.021 122.383 181.274 119.205 179.577C116.027 177.88 112.359 177.337 108.826 178.042C105.293 178.746 102.113 180.654 99.8291 183.44C97.5451 186.226 96.2979 189.718 96.3 193.32C96.2985 195.364 96.7006 197.388 97.4831 199.275C98.2656 201.163 99.4132 202.877 100.86 204.32ZM204.32 122.88C206.868 120.333 208.453 116.981 208.806 113.396C209.159 109.811 208.258 106.214 206.256 103.219C204.254 100.223 201.275 98.0151 197.827 96.97C194.38 95.9249 190.676 96.1077 187.348 97.4873C184.02 98.8669 181.274 101.358 179.577 104.536C177.879 107.714 177.337 111.382 178.041 114.915C178.746 118.448 180.653 121.627 183.439 123.911C186.226 126.195 189.717 127.443 193.32 127.44C195.364 127.443 197.388 127.042 199.275 126.259C201.163 125.476 202.878 124.328 204.32 122.88ZM122.88 19.4205C120.333 16.8729 116.981 15.2876 113.395 14.9347C109.81 14.5817 106.213 15.483 103.218 17.4849C100.223 19.4868 98.0146 22.4654 96.9696 25.9131C95.9245 29.3608 96.1073 33.0642 97.4869 36.3922C98.8665 39.7202 101.358 42.4668 104.535 44.1639C107.713 45.861 111.381 46.4036 114.914 45.6992C118.447 44.9949 121.627 43.0871 123.911 40.301C126.195 37.515 127.442 34.0231 127.44 30.4205C127.44 28.3772 127.038 26.3539 126.255 24.4664C125.473 22.5788 124.326 20.8642 122.88 19.4205ZM19.42 100.86C16.8725 103.408 15.2872 106.76 14.9342 110.345C14.5813 113.93 15.4826 117.527 17.4844 120.522C19.4863 123.518 22.4649 125.726 25.9127 126.771C29.3604 127.816 33.0638 127.633 36.3918 126.254C39.7198 124.874 42.4664 122.383 44.1635 119.205C45.8606 116.027 46.4032 112.359 45.6988 108.826C44.9944 105.293 43.0866 102.114 40.3006 99.8296C37.5145 97.5455 34.0227 96.2983 30.42 96.3005C26.2938 96.3018 22.337 97.9421 19.42 100.86ZM100.86 100.86C98.3125 103.408 96.7272 106.76 96.3742 110.345C96.0213 113.93 96.9226 117.527 98.9244 120.522C100.926 123.518 103.905 125.726 107.353 126.771C110.8 127.816 114.504 127.633 117.832 126.254C121.16 124.874 123.906 122.383 125.604 119.205C127.301 116.027 127.843 112.359 127.139 108.826C126.434 105.293 124.527 102.114 121.741 99.8296C118.955 97.5455 115.463 96.2983 111.86 96.3005C109.817 96.299 107.793 96.701 105.905 97.4835C104.018 98.2661 102.303 99.4136 100.86 100.86Z\" fill=\"#00AEEF\"/>\n",
|
||||
" </g>\n",
|
||||
" <defs>\n",
|
||||
" <clipPath id=\"clip0_4338_178347\">\n",
|
||||
" <rect width=\"566.93\" height=\"223.75\" fill=\"white\"/>\n",
|
||||
" </clipPath>\n",
|
||||
" </defs>\n",
|
||||
" </svg>\n",
|
||||
"</div>\n",
|
||||
"\n",
|
||||
" <table class=\"jp-RenderedHTMLCommon\" style=\"border-collapse: collapse;color: var(--jp-ui-font-color1);font-size: var(--jp-ui-font-size1);\">\n",
|
||||
" <tr>\n",
|
||||
" <td style=\"text-align: left\"><b>Python version:</b></td>\n",
|
||||
" <td style=\"text-align: left\"><b>3.10.12</b></td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <td style=\"text-align: left\"><b>Ray version:</b></td>\n",
|
||||
" <td style=\"text-align: left\"><b>2.8.0</b></td>\n",
|
||||
" </tr>\n",
|
||||
" \n",
|
||||
"</table>\n",
|
||||
"\n",
|
||||
" </div>\n",
|
||||
"</div>\n"
|
||||
],
|
||||
"text/plain": [
|
||||
"RayContext(dashboard_url='', python_version='3.10.12', ray_version='2.8.0', ray_commit='105355bd253d6538ed34d331f6a4bdf0e38ace3a', protocol_version=None)"
|
||||
]
|
||||
},
|
||||
"execution_count": 3,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"ray.init(local_mode=True)"
|
||||
"#### Create a Ray algorithm and pass it our config."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@@ -110,808 +50,23 @@
|
||||
"config = (\n",
|
||||
" PPOConfig()\n",
|
||||
" .environment(env=PrimaiteRayEnv, env_config=env_config, disable_env_checking=True)\n",
|
||||
" .rollouts(num_rollout_workers=0,)\n",
|
||||
" .rollouts(num_rollout_workers=0)\n",
|
||||
" .training(train_batch_size=128)\n",
|
||||
")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/html": [],
|
||||
"text/plain": [
|
||||
"<IPython.core.display.HTML object>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
},
|
||||
{
|
||||
"name": "stderr",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
":job_id:01000000\n",
|
||||
":task_name:bundle_reservation_check_func\n",
|
||||
":actor_name:PPO\n",
|
||||
"2023-12-01 14:53:17,868::ERROR::primaite.simulator.network.hardware.base::190::NIC 3e:e9:64:e8:cf:89/127.0.0.1 cannot be enabled as it is not connected to a Link\n",
|
||||
"2023-12-01 14:53:17,869::ERROR::primaite.simulator.network.hardware.base::190::NIC 74:17:08:49:f5:30/127.0.0.1 cannot be enabled as it is not connected to a Link\n",
|
||||
"2023-12-01 14:53:17,870::ERROR::primaite.simulator.network.hardware.base::190::NIC 36:ad:98:49:2d:a7/127.0.0.1 cannot be enabled as it is not connected to a Link\n",
|
||||
"2023-12-01 14:53:17,871::ERROR::primaite.simulator.network.hardware.base::190::NIC c4:0e:cf:36:55:de/127.0.0.1 cannot be enabled as it is not connected to a Link\n",
|
||||
"2023-12-01 14:53:17,872::ERROR::primaite.simulator.network.hardware.base::190::NIC ec:6e:b6:5c:8a:e7/127.0.0.1 cannot be enabled as it is not connected to a Link\n",
|
||||
"2023-12-01 14:53:17,875: Added node 1c94cb0c-b62c-43eb-b5d3-4a5d1937f845 to Network 07a10762-942f-409d-b36f-ea2ab7ddb136\n",
|
||||
"2023-12-01 14:53:17,878: Added node 3197ef0c-0ce8-4b63-bde8-91e7f95d59ef to Network 07a10762-942f-409d-b36f-ea2ab7ddb136\n",
|
||||
"2023-12-01 14:53:17,884: Added node 835b8e76-0b1e-4112-9897-0808a87fd9de to Network 07a10762-942f-409d-b36f-ea2ab7ddb136\n",
|
||||
"2023-12-01 14:53:17,888::WARNING::primaite.simulator.core::116::Overwriting request type scan.\n",
|
||||
"2023-12-01 14:53:17,889: Added service 6a19bda9-7f0e-4f77-a5bc-b473d3418df0 to node 7a31b3ca-b51d-4332-b9fb-ba5194ac5bae\n",
|
||||
"2023-12-01 14:53:17,890::WARNING::primaite.simulator.core::116::Overwriting request type scan.\n",
|
||||
"2023-12-01 14:53:17,891: Added service 6fc138ff-e698-4c4d-82ca-0aa990df6669 to node 7a31b3ca-b51d-4332-b9fb-ba5194ac5bae\n",
|
||||
"2023-12-01 14:53:17,893: Added application 601f573a-5480-492d-8508-4b1ccc45100f to node 7a31b3ca-b51d-4332-b9fb-ba5194ac5bae\n",
|
||||
"2023-12-01 14:53:17,895::ERROR::primaite.simulator.network.hardware.base::190::NIC fd:19:e4:d5:6e:c8/192.168.1.10 cannot be enabled as it is not connected to a Link\n",
|
||||
"2023-12-01 14:53:17,896::WARNING::primaite.simulator.core::116::Overwriting request type scan.\n",
|
||||
"2023-12-01 14:53:17,898: Added service 901a736f-8fd0-49e9-9369-ef1da8a6a5a4 to node 7a31b3ca-b51d-4332-b9fb-ba5194ac5bae\n",
|
||||
"2023-12-01 14:53:17,900::WARNING::primaite.simulator.core::116::Overwriting request type scan.\n",
|
||||
"2023-12-01 14:53:17,903: Added service e240939c-b017-4e67-b161-8e5d96cbe061 to node 7a31b3ca-b51d-4332-b9fb-ba5194ac5bae\n",
|
||||
"2023-12-01 14:53:17,905: Added application dada880f-ec1f-4ed3-a4b6-3f8c68a6c750 to node 7a31b3ca-b51d-4332-b9fb-ba5194ac5bae\n",
|
||||
"2023-12-01 14:53:17,906::WARNING::primaite.simulator.core::116::Overwriting request type scan.\n",
|
||||
"2023-12-01 14:53:17,908: Added service d2201c7b-418c-49f7-bed0-c93f520f0352 to node 7a31b3ca-b51d-4332-b9fb-ba5194ac5bae\n",
|
||||
"2023-12-01 14:53:17,909: Added node 7a31b3ca-b51d-4332-b9fb-ba5194ac5bae to Network 07a10762-942f-409d-b36f-ea2ab7ddb136\n",
|
||||
"2023-12-01 14:53:17,912::WARNING::primaite.simulator.core::116::Overwriting request type scan.\n",
|
||||
"2023-12-01 14:53:17,914: Added service 2c843f1e-643a-40d3-9477-8870926f49e8 to node 9b8bcb44-ec5a-42bc-a4a5-90d240f77036\n",
|
||||
"2023-12-01 14:53:17,916::WARNING::primaite.simulator.core::116::Overwriting request type scan.\n",
|
||||
"2023-12-01 14:53:17,918: Added service b52910ee-66d7-4006-8044-fb27a95cc00f to node 9b8bcb44-ec5a-42bc-a4a5-90d240f77036\n",
|
||||
"2023-12-01 14:53:17,920: Added application dd11b7fb-a31a-418d-bfdb-fb862c0c38b2 to node 9b8bcb44-ec5a-42bc-a4a5-90d240f77036\n",
|
||||
"2023-12-01 14:53:17,922::ERROR::primaite.simulator.network.hardware.base::190::NIC b9:01:34:d2:50:53/192.168.1.12 cannot be enabled as it is not connected to a Link\n",
|
||||
"2023-12-01 14:53:17,923::WARNING::primaite.simulator.core::116::Overwriting request type scan.\n",
|
||||
"2023-12-01 14:53:17,926: Added service a1d7a58a-df23-4ea0-934f-b4f397f252e5 to node 9b8bcb44-ec5a-42bc-a4a5-90d240f77036\n",
|
||||
"2023-12-01 14:53:17,927::WARNING::primaite.simulator.core::116::Overwriting request type scan.\n",
|
||||
"2023-12-01 14:53:17,928: Added service 742f59a4-369e-4a31-a95e-19adb9115cb7 to node 9b8bcb44-ec5a-42bc-a4a5-90d240f77036\n",
|
||||
"2023-12-01 14:53:17,930: Added application 5a93e02b-5485-46ad-9c61-4f32d4673ec3 to node 9b8bcb44-ec5a-42bc-a4a5-90d240f77036\n",
|
||||
"2023-12-01 14:53:17,934: Added application 040a27ae-8c65-47fd-a60b-7c72a46e7806 to node 9b8bcb44-ec5a-42bc-a4a5-90d240f77036\n",
|
||||
"2023-12-01 14:53:17,936::WARNING::primaite.simulator.core::116::Overwriting request type scan.\n",
|
||||
"2023-12-01 14:53:17,938: Added service f6241fbe-524e-4e94-8e94-232bcd8d0914 to node 9b8bcb44-ec5a-42bc-a4a5-90d240f77036\n",
|
||||
"2023-12-01 14:53:17,939: Added node 9b8bcb44-ec5a-42bc-a4a5-90d240f77036 to Network 07a10762-942f-409d-b36f-ea2ab7ddb136\n",
|
||||
"2023-12-01 14:53:17,941::WARNING::primaite.simulator.core::116::Overwriting request type scan.\n",
|
||||
"2023-12-01 14:53:17,942: Added service f69c460a-5385-4244-8582-508f806e52e4 to node 2f002450-027d-4791-832b-01327350d7e7\n",
|
||||
"2023-12-01 14:53:17,943::WARNING::primaite.simulator.core::116::Overwriting request type scan.\n",
|
||||
"2023-12-01 14:53:17,944: Added service f36088c4-0817-47a2-bd4d-1162fee46b63 to node 2f002450-027d-4791-832b-01327350d7e7\n",
|
||||
"2023-12-01 14:53:17,946: Added application 4de6ebfd-46ae-419f-b36e-3b2b079eff9d to node 2f002450-027d-4791-832b-01327350d7e7\n",
|
||||
"2023-12-01 14:53:17,949::ERROR::primaite.simulator.network.hardware.base::190::NIC 70:fb:95:ae:8b:e9/192.168.1.14 cannot be enabled as it is not connected to a Link\n",
|
||||
"2023-12-01 14:53:17,951::WARNING::primaite.simulator.core::116::Overwriting request type scan.\n",
|
||||
"2023-12-01 14:53:17,953: Added service 5a01c753-1c0b-4f9e-8cf9-bdab8e1151e7 to node 2f002450-027d-4791-832b-01327350d7e7\n",
|
||||
"2023-12-01 14:53:17,954::WARNING::primaite.simulator.core::116::Overwriting request type scan.\n",
|
||||
"2023-12-01 14:53:17,956: Added service 8f28720e-4374-4fe5-9b30-f2b3943691ff to node 2f002450-027d-4791-832b-01327350d7e7\n",
|
||||
"2023-12-01 14:53:17,957: Added application 500d5dc5-1bca-4904-8b2a-8d5f3c4db978 to node 2f002450-027d-4791-832b-01327350d7e7\n",
|
||||
"2023-12-01 14:53:17,958::WARNING::primaite.simulator.core::116::Overwriting request type scan.\n",
|
||||
"2023-12-01 14:53:17,960: Added service a5e5963e-c071-4715-9042-5e5887e26f3a to node 2f002450-027d-4791-832b-01327350d7e7\n",
|
||||
"2023-12-01 14:53:17,962::WARNING::primaite.simulator.core::116::Overwriting request type scan.\n",
|
||||
"2023-12-01 14:53:17,967: Added service 82dd1118-3e3c-4f72-8e62-3217e72b0360 to node 2f002450-027d-4791-832b-01327350d7e7\n",
|
||||
"2023-12-01 14:53:17,969: Added node 2f002450-027d-4791-832b-01327350d7e7 to Network 07a10762-942f-409d-b36f-ea2ab7ddb136\n",
|
||||
"2023-12-01 14:53:17,972::WARNING::primaite.simulator.core::116::Overwriting request type scan.\n",
|
||||
"2023-12-01 14:53:17,973: Added service d8d2c796-cae8-4d6b-acd1-76a30fb3dd87 to node 858361fa-1b42-4456-b184-59fa44b0c89b\n",
|
||||
"2023-12-01 14:53:17,974::WARNING::primaite.simulator.core::116::Overwriting request type scan.\n",
|
||||
"2023-12-01 14:53:17,975: Added service bd319940-2ad7-456b-88e9-a49b1c994edd to node 858361fa-1b42-4456-b184-59fa44b0c89b\n",
|
||||
"2023-12-01 14:53:17,977: Added application d30f9307-d8d5-41f0-b74d-94b878b3023a to node 858361fa-1b42-4456-b184-59fa44b0c89b\n",
|
||||
"2023-12-01 14:53:17,978::ERROR::primaite.simulator.network.hardware.base::190::NIC e8:c5:48:91:62:fe/192.168.1.16 cannot be enabled as it is not connected to a Link\n",
|
||||
"2023-12-01 14:53:17,980::WARNING::primaite.simulator.core::116::Overwriting request type scan.\n",
|
||||
"2023-12-01 14:53:17,983: Added service e926ebb1-6d91-4400-94f3-7dfab8e82eab to node 858361fa-1b42-4456-b184-59fa44b0c89b\n",
|
||||
"2023-12-01 14:53:17,985::WARNING::primaite.simulator.core::116::Overwriting request type scan.\n",
|
||||
"2023-12-01 14:53:17,987: Added service af73e5f5-c754-4936-9018-37ef69140ced to node 858361fa-1b42-4456-b184-59fa44b0c89b\n",
|
||||
"2023-12-01 14:53:17,988: Added application 13fd868b-e730-486f-ab83-e1bf2446e504 to node 858361fa-1b42-4456-b184-59fa44b0c89b\n",
|
||||
"2023-12-01 14:53:17,989::WARNING::primaite.simulator.core::116::Overwriting request type scan.\n",
|
||||
"2023-12-01 14:53:17,991: Added service ab453a9d-62dc-4437-b0dc-c9d587962a0b to node 858361fa-1b42-4456-b184-59fa44b0c89b\n",
|
||||
"2023-12-01 14:53:17,992: Added node 858361fa-1b42-4456-b184-59fa44b0c89b to Network 07a10762-942f-409d-b36f-ea2ab7ddb136\n",
|
||||
"2023-12-01 14:53:17,995::WARNING::primaite.simulator.core::116::Overwriting request type scan.\n",
|
||||
"2023-12-01 14:53:18,003: Added service d9b44dbd-f153-4f3c-b03d-b6441a917834 to node 7c47bb4e-deea-4c23-910d-6ba524f73bbc\n",
|
||||
"2023-12-01 14:53:18,005::WARNING::primaite.simulator.core::116::Overwriting request type scan.\n",
|
||||
"2023-12-01 14:53:18,006: Added service c3da251b-500a-40dd-8c25-e26a35b5b767 to node 7c47bb4e-deea-4c23-910d-6ba524f73bbc\n",
|
||||
"2023-12-01 14:53:18,008: Added application 8f692912-fb57-40bb-ad56-d38970d34430 to node 7c47bb4e-deea-4c23-910d-6ba524f73bbc\n",
|
||||
"2023-12-01 14:53:18,010::ERROR::primaite.simulator.network.hardware.base::190::NIC a3:59:d7:fe:28:08/192.168.1.110 cannot be enabled as it is not connected to a Link\n",
|
||||
"2023-12-01 14:53:18,011::WARNING::primaite.simulator.core::116::Overwriting request type scan.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
":job_id:01000000\n",
|
||||
":task_name:bundle_reservation_check_func\n",
|
||||
":actor_name:PPO\n",
|
||||
"installing DNSServer on node domain_controller\n",
|
||||
"installing DatabaseClient on node web_server\n",
|
||||
"installing WebServer on node web_server\n",
|
||||
"installing DatabaseService on node database_server\n",
|
||||
"installing FTPClient on node database_server\n",
|
||||
"installing FTPServer on node backup_server\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "stderr",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"2023-12-01 14:53:18,013: Added service be9a1ad7-252b-47c7-ae20-e8202cb890ab to node 7c47bb4e-deea-4c23-910d-6ba524f73bbc\n",
|
||||
"2023-12-01 14:53:18,020::WARNING::primaite.simulator.core::116::Overwriting request type scan.\n",
|
||||
"2023-12-01 14:53:18,022: Added service c5d5b514-cd30-4c7d-a4b7-b16fce71ccac to node 7c47bb4e-deea-4c23-910d-6ba524f73bbc\n",
|
||||
"2023-12-01 14:53:18,024: Added application 918b8a5e-e339-4cb1-bb8b-ca2f3ec34372 to node 7c47bb4e-deea-4c23-910d-6ba524f73bbc\n",
|
||||
"2023-12-01 14:53:18,026::ERROR::primaite.simulator.network.hardware.base::190::NIC c9:b5:db:9d:71:4d/192.168.10.110 cannot be enabled as it is not connected to a Link\n",
|
||||
"2023-12-01 14:53:18,027: Added node 7c47bb4e-deea-4c23-910d-6ba524f73bbc to Network 07a10762-942f-409d-b36f-ea2ab7ddb136\n",
|
||||
"2023-12-01 14:53:18,040::WARNING::primaite.simulator.core::116::Overwriting request type scan.\n",
|
||||
"2023-12-01 14:53:18,042: Added service 66ca1dd3-0997-427b-8663-402141122e75 to node fee76ed0-ed6a-4ee2-bf2a-27de9bbfa17f\n",
|
||||
"2023-12-01 14:53:18,044::WARNING::primaite.simulator.core::116::Overwriting request type scan.\n",
|
||||
"2023-12-01 14:53:18,045: Added service f87b344d-8a8e-4d9d-a341-df5d3bb538ba to node fee76ed0-ed6a-4ee2-bf2a-27de9bbfa17f\n",
|
||||
"2023-12-01 14:53:18,047: Added application ab20f1e3-e567-4d02-9e16-febcd57c2630 to node fee76ed0-ed6a-4ee2-bf2a-27de9bbfa17f\n",
|
||||
"2023-12-01 14:53:18,057::ERROR::primaite.simulator.network.hardware.base::190::NIC f5:2e:2d:55:76:d3/192.168.10.21 cannot be enabled as it is not connected to a Link\n",
|
||||
"2023-12-01 14:53:18,058::WARNING::primaite.simulator.core::116::Overwriting request type scan.\n",
|
||||
"2023-12-01 14:53:18,060: Added service 640815d4-878f-4dff-a607-08887b9045a7 to node fee76ed0-ed6a-4ee2-bf2a-27de9bbfa17f\n",
|
||||
"2023-12-01 14:53:18,061::WARNING::primaite.simulator.core::116::Overwriting request type scan.\n",
|
||||
"2023-12-01 14:53:18,063: Added service 655735a9-6db2-41df-b462-f8c14ea53e35 to node fee76ed0-ed6a-4ee2-bf2a-27de9bbfa17f\n",
|
||||
"2023-12-01 14:53:18,072: Added application 84fc60ba-b67e-4b72-86d1-d247fa7e31f7 to node fee76ed0-ed6a-4ee2-bf2a-27de9bbfa17f\n",
|
||||
"2023-12-01 14:53:18,074::WARNING::primaite.simulator.core::116::Overwriting request type scan.\n",
|
||||
"2023-12-01 14:53:18,075: Added service 8f83391f-a59b-4bdb-8fe7-7fe7e19bf1e9 to node fee76ed0-ed6a-4ee2-bf2a-27de9bbfa17f\n",
|
||||
"2023-12-01 14:53:18,077: Added application 75147ae5-cdce-4ac0-a884-fb9bd8f96387 to node fee76ed0-ed6a-4ee2-bf2a-27de9bbfa17f\n",
|
||||
"2023-12-01 14:53:18,078: Added node fee76ed0-ed6a-4ee2-bf2a-27de9bbfa17f to Network 07a10762-942f-409d-b36f-ea2ab7ddb136\n",
|
||||
"2023-12-01 14:53:18,084::WARNING::primaite.simulator.core::116::Overwriting request type scan.\n",
|
||||
"2023-12-01 14:53:18,086: Added service 02915c59-69e2-4248-9e46-16d627460448 to node d8a6abb1-8929-490f-a997-5e3dcb452027\n",
|
||||
"2023-12-01 14:53:18,087::WARNING::primaite.simulator.core::116::Overwriting request type scan.\n",
|
||||
"2023-12-01 14:53:18,088: Added service 3ec73168-2bad-41cd-b872-7747487410c5 to node d8a6abb1-8929-490f-a997-5e3dcb452027\n",
|
||||
"2023-12-01 14:53:18,089: Added application 2acc2c11-7eed-4382-b596-389a52b42915 to node d8a6abb1-8929-490f-a997-5e3dcb452027\n",
|
||||
"2023-12-01 14:53:18,090::ERROR::primaite.simulator.network.hardware.base::190::NIC 18:f5:a0:7f:c8:60/192.168.10.22 cannot be enabled as it is not connected to a Link\n",
|
||||
"2023-12-01 14:53:18,091::WARNING::primaite.simulator.core::116::Overwriting request type scan.\n",
|
||||
"2023-12-01 14:53:18,093: Added service 99ae3de9-6a18-45b7-b52e-929b2be8b69b to node d8a6abb1-8929-490f-a997-5e3dcb452027\n",
|
||||
"2023-12-01 14:53:18,093::WARNING::primaite.simulator.core::116::Overwriting request type scan.\n",
|
||||
"2023-12-01 14:53:18,095: Added service 80932931-e76e-4b98-8d05-3998f3a23a75 to node d8a6abb1-8929-490f-a997-5e3dcb452027\n",
|
||||
"2023-12-01 14:53:18,096: Added application 267775b8-36ad-4627-a5d3-dfd42ba5ecbf to node d8a6abb1-8929-490f-a997-5e3dcb452027\n",
|
||||
"2023-12-01 14:53:18,098::WARNING::primaite.simulator.core::116::Overwriting request type scan.\n",
|
||||
"2023-12-01 14:53:18,100: Added service b5c7f3cb-d928-433d-8b07-a6a778337c27 to node d8a6abb1-8929-490f-a997-5e3dcb452027\n",
|
||||
"2023-12-01 14:53:18,102: Added application a3f18b82-33be-4659-96cb-2f069c3a2aa4 to node d8a6abb1-8929-490f-a997-5e3dcb452027\n",
|
||||
"2023-12-01 14:53:18,103: Added node d8a6abb1-8929-490f-a997-5e3dcb452027 to Network 07a10762-942f-409d-b36f-ea2ab7ddb136\n",
|
||||
"2023-12-01 14:53:18,148::ERROR::primaite.simulator.network.hardware.base::190::NIC 36:ad:98:49:2d:a7/127.0.0.1 cannot be enabled as it is not connected to a Link\n",
|
||||
"2023-12-01 14:53:18,151::ERROR::primaite.simulator.network.hardware.base::190::NIC 36:ad:98:49:2d:a7/127.0.0.1 cannot be enabled as it is not connected to a Link\n",
|
||||
"2023-12-01 14:53:18,153::ERROR::primaite.simulator.network.hardware.base::190::NIC c4:0e:cf:36:55:de/127.0.0.1 cannot be enabled as it is not connected to a Link\n",
|
||||
"2023-12-01 14:53:18,154::ERROR::primaite.simulator.network.hardware.base::190::NIC c4:0e:cf:36:55:de/127.0.0.1 cannot be enabled as it is not connected to a Link\n",
|
||||
"2023-12-01 14:53:18,155::ERROR::primaite.simulator.network.hardware.base::190::NIC ec:6e:b6:5c:8a:e7/127.0.0.1 cannot be enabled as it is not connected to a Link\n",
|
||||
"2023-12-01 14:53:18,155::ERROR::primaite.simulator.network.hardware.base::190::NIC ec:6e:b6:5c:8a:e7/127.0.0.1 cannot be enabled as it is not connected to a Link\n",
|
||||
"2023-12-01 14:53:18,156::ERROR::primaite.simulator.network.hardware.base::190::NIC 36:ad:98:49:2d:a7/127.0.0.1 cannot be enabled as it is not connected to a Link\n",
|
||||
"2023-12-01 14:53:18,157::ERROR::primaite.simulator.network.hardware.base::190::NIC c4:0e:cf:36:55:de/127.0.0.1 cannot be enabled as it is not connected to a Link\n",
|
||||
"2023-12-01 14:53:18,159::ERROR::primaite.simulator.network.hardware.base::190::NIC ec:6e:b6:5c:8a:e7/127.0.0.1 cannot be enabled as it is not connected to a Link\n",
|
||||
"2023-12-01 14:53:18,163::ERROR::primaite.simulator.network.hardware.base::190::NIC 36:ad:98:49:2d:a7/127.0.0.1 cannot be enabled as it is not connected to a Link\n",
|
||||
"2023-12-01 14:53:18,165::ERROR::primaite.simulator.network.hardware.base::190::NIC c4:0e:cf:36:55:de/127.0.0.1 cannot be enabled as it is not connected to a Link\n",
|
||||
"2023-12-01 14:53:18,167::ERROR::primaite.simulator.network.hardware.base::190::NIC ec:6e:b6:5c:8a:e7/127.0.0.1 cannot be enabled as it is not connected to a Link\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"installing DNSClient on node client_1\n",
|
||||
"installing DNSClient on node client_2\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "stderr",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
":actor_name:PPO\n",
|
||||
"2023-12-01 14:53:18,581::ERROR::primaite.simulator.network.hardware.base::190::NIC 36:ad:98:49:2d:a7/127.0.0.1 cannot be enabled as it is not connected to a Link\n",
|
||||
"2023-12-01 14:53:18,582::ERROR::primaite.simulator.network.hardware.base::190::NIC 36:ad:98:49:2d:a7/127.0.0.1 cannot be enabled as it is not connected to a Link\n",
|
||||
"2023-12-01 14:53:18,583::ERROR::primaite.simulator.network.hardware.base::190::NIC c4:0e:cf:36:55:de/127.0.0.1 cannot be enabled as it is not connected to a Link\n",
|
||||
"2023-12-01 14:53:18,585::ERROR::primaite.simulator.network.hardware.base::190::NIC c4:0e:cf:36:55:de/127.0.0.1 cannot be enabled as it is not connected to a Link\n",
|
||||
"2023-12-01 14:53:18,586::ERROR::primaite.simulator.network.hardware.base::190::NIC ec:6e:b6:5c:8a:e7/127.0.0.1 cannot be enabled as it is not connected to a Link\n",
|
||||
"2023-12-01 14:53:18,588::ERROR::primaite.simulator.network.hardware.base::190::NIC ec:6e:b6:5c:8a:e7/127.0.0.1 cannot be enabled as it is not connected to a Link\n",
|
||||
"2023-12-01 14:53:18,590::ERROR::primaite.simulator.network.hardware.base::190::NIC 36:ad:98:49:2d:a7/127.0.0.1 cannot be enabled as it is not connected to a Link\n",
|
||||
"2023-12-01 14:53:18,591::ERROR::primaite.simulator.network.hardware.base::190::NIC c4:0e:cf:36:55:de/127.0.0.1 cannot be enabled as it is not connected to a Link\n",
|
||||
"2023-12-01 14:53:18,593::ERROR::primaite.simulator.network.hardware.base::190::NIC ec:6e:b6:5c:8a:e7/127.0.0.1 cannot be enabled as it is not connected to a Link\n",
|
||||
"2023-12-01 14:53:18,602::ERROR::primaite.simulator.network.hardware.base::190::NIC 36:ad:98:49:2d:a7/127.0.0.1 cannot be enabled as it is not connected to a Link\n",
|
||||
"2023-12-01 14:53:18,604::ERROR::primaite.simulator.network.hardware.base::190::NIC c4:0e:cf:36:55:de/127.0.0.1 cannot be enabled as it is not connected to a Link\n",
|
||||
"2023-12-01 14:53:18,604::ERROR::primaite.simulator.network.hardware.base::190::NIC ec:6e:b6:5c:8a:e7/127.0.0.1 cannot be enabled as it is not connected to a Link\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
":actor_name:PPO\n",
|
||||
"Episode: 1, Step: 1, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 2, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 3, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 4, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 5, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 6, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 7, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 8, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 9, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 10, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 11, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 12, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 13, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 14, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 15, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 16, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 17, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 18, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 19, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 20, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 21, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 22, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 23, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 24, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 25, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 26, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 27, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 28, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 29, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 30, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 31, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 32, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 33, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 34, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 35, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 36, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 37, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 38, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 39, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 40, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 41, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 42, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 43, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 44, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 45, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 46, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 47, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 48, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 49, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 50, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 51, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 52, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 53, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 54, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 55, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 56, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 57, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 58, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 59, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 60, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 61, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 62, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 63, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 64, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 65, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 66, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 67, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 68, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 69, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 70, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 71, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 72, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 73, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 74, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 75, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 76, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 77, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 78, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 79, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 80, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 81, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 82, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 83, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 84, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 85, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 86, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 87, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 88, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 89, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 90, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 91, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 92, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 93, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 94, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 95, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 96, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 97, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 98, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 99, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 100, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 101, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 102, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 103, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 104, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 105, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 106, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 107, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 108, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 109, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 110, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 111, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 112, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 113, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 114, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 115, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 116, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 117, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 118, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 119, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 120, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 121, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 122, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 123, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 124, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 125, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 126, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 127, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 128, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 129, Reward: 0.5\n",
|
||||
"<IPython.core.display.HTML object>\n",
|
||||
"Episode: 1, Step: 130, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 131, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 132, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 133, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 134, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 135, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 136, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 137, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 138, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 139, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 140, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 141, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 142, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 143, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 144, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 145, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 146, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 147, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 148, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 149, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 150, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 151, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 152, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 153, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 154, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 155, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 156, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 157, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 158, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 159, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 160, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 161, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 162, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 163, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 164, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 165, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 166, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 167, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 168, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 169, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 170, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 171, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 172, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 173, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 174, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 175, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 176, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 177, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 178, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 179, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 180, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 181, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 182, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 183, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 184, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 185, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 186, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 187, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 188, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 189, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 190, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 191, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 192, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 193, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 194, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 195, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 196, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 197, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 198, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 199, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 200, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 201, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 202, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 203, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 204, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 205, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 206, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 207, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 208, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 209, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 210, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 211, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 212, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 213, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 214, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 215, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 216, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 217, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 218, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 219, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 220, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 221, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 222, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 223, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 224, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 225, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 226, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 227, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 228, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 229, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 230, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 231, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 232, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 233, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 234, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 235, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 236, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 237, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 238, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 239, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 240, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 241, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 242, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 243, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 244, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 245, Reward: 0.5\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "stderr",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"2023-12-01 14:53:21,247::ERROR::primaite.simulator.network.hardware.base::190::NIC 36:ad:98:49:2d:a7/127.0.0.1 cannot be enabled as it is not connected to a Link\n",
|
||||
"2023-12-01 14:53:21,248::ERROR::primaite.simulator.network.hardware.base::190::NIC 36:ad:98:49:2d:a7/127.0.0.1 cannot be enabled as it is not connected to a Link\n",
|
||||
"2023-12-01 14:53:21,249::ERROR::primaite.simulator.network.hardware.base::190::NIC c4:0e:cf:36:55:de/127.0.0.1 cannot be enabled as it is not connected to a Link\n",
|
||||
"2023-12-01 14:53:21,251::ERROR::primaite.simulator.network.hardware.base::190::NIC c4:0e:cf:36:55:de/127.0.0.1 cannot be enabled as it is not connected to a Link\n",
|
||||
"2023-12-01 14:53:21,252::ERROR::primaite.simulator.network.hardware.base::190::NIC ec:6e:b6:5c:8a:e7/127.0.0.1 cannot be enabled as it is not connected to a Link\n",
|
||||
"2023-12-01 14:53:21,254::ERROR::primaite.simulator.network.hardware.base::190::NIC ec:6e:b6:5c:8a:e7/127.0.0.1 cannot be enabled as it is not connected to a Link\n",
|
||||
"2023-12-01 14:53:21,256::ERROR::primaite.simulator.network.hardware.base::190::NIC 36:ad:98:49:2d:a7/127.0.0.1 cannot be enabled as it is not connected to a Link\n",
|
||||
"2023-12-01 14:53:21,259::ERROR::primaite.simulator.network.hardware.base::190::NIC c4:0e:cf:36:55:de/127.0.0.1 cannot be enabled as it is not connected to a Link\n",
|
||||
"2023-12-01 14:53:21,262::ERROR::primaite.simulator.network.hardware.base::190::NIC ec:6e:b6:5c:8a:e7/127.0.0.1 cannot be enabled as it is not connected to a Link\n",
|
||||
"2023-12-01 14:53:21,292::ERROR::primaite.simulator.network.hardware.base::190::NIC 36:ad:98:49:2d:a7/127.0.0.1 cannot be enabled as it is not connected to a Link\n",
|
||||
"2023-12-01 14:53:21,293::ERROR::primaite.simulator.network.hardware.base::190::NIC c4:0e:cf:36:55:de/127.0.0.1 cannot be enabled as it is not connected to a Link\n",
|
||||
"2023-12-01 14:53:21,294::ERROR::primaite.simulator.network.hardware.base::190::NIC ec:6e:b6:5c:8a:e7/127.0.0.1 cannot be enabled as it is not connected to a Link\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Episode: 1, Step: 246, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 247, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 248, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 249, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 250, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 251, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 252, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 253, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 254, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 255, Reward: 0.5\n",
|
||||
"Episode: 1, Step: 256, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 1, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 2, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 3, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 4, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 5, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 6, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 7, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 8, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 9, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 10, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 11, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 12, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 13, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 14, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 15, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 16, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 17, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 18, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 19, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 20, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 21, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 22, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 23, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 24, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 25, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 26, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 27, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 28, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 29, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 30, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 31, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 32, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 33, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 34, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 35, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 36, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 37, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 38, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 39, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 40, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 41, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 42, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 43, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 44, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 45, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 46, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 47, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 48, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 49, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 50, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 51, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 52, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 53, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 54, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 55, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 56, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 57, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 58, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 59, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 60, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 61, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 62, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 63, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 64, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 65, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 66, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 67, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 68, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 69, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 70, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 71, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 72, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 73, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 74, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 75, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 76, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 77, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 78, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 79, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 80, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 81, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 82, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 83, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 84, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 85, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 86, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 87, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 88, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 89, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 90, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 91, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 92, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 93, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 94, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 95, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 96, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 97, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 98, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 99, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 100, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 101, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 102, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 103, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 104, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 105, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 106, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 107, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 108, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 109, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 110, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 111, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 112, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 113, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 114, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 115, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 116, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 117, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 118, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 119, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 120, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 121, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 122, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 123, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 124, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 125, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 126, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 127, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 128, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 129, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 130, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 131, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 132, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 133, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 134, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 135, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 136, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 137, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 138, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 139, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 140, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 141, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 142, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 143, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 144, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 145, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 146, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 147, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 148, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 149, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 150, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 151, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 152, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 153, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 154, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 155, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 156, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 157, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 158, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 159, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 160, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 161, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 162, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 163, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 164, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 165, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 166, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 167, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 168, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 169, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 170, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 171, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 172, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 173, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 174, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 175, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 176, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 177, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 178, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 179, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 180, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 181, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 182, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 183, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 184, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 185, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 186, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 187, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 188, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 189, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 190, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 191, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 192, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 193, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 194, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 195, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 196, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 197, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 198, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 199, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 200, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 201, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 202, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 203, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 204, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 205, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 206, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 207, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 208, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 209, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 210, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 211, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 212, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 213, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 214, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 215, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 216, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 217, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 218, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 219, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 220, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 221, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 222, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 223, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 224, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 225, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 226, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 227, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 228, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 229, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 230, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 231, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 232, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 233, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 234, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 235, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 236, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 237, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 238, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 239, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 240, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 241, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 242, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 243, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 244, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 245, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 246, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 247, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 248, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 249, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 250, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 251, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 252, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 253, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 254, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 255, Reward: 0.5\n",
|
||||
"Episode: 2, Step: 256, Reward: 0.5\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "stderr",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"2023-12-01 14:53:24,371::ERROR::primaite.simulator.network.hardware.base::190::NIC 36:ad:98:49:2d:a7/127.0.0.1 cannot be enabled as it is not connected to a Link\n",
|
||||
"2023-12-01 14:53:24,373::ERROR::primaite.simulator.network.hardware.base::190::NIC 36:ad:98:49:2d:a7/127.0.0.1 cannot be enabled as it is not connected to a Link\n",
|
||||
"2023-12-01 14:53:24,375::ERROR::primaite.simulator.network.hardware.base::190::NIC c4:0e:cf:36:55:de/127.0.0.1 cannot be enabled as it is not connected to a Link\n",
|
||||
"2023-12-01 14:53:24,375::ERROR::primaite.simulator.network.hardware.base::190::NIC c4:0e:cf:36:55:de/127.0.0.1 cannot be enabled as it is not connected to a Link\n",
|
||||
"2023-12-01 14:53:24,376::ERROR::primaite.simulator.network.hardware.base::190::NIC ec:6e:b6:5c:8a:e7/127.0.0.1 cannot be enabled as it is not connected to a Link\n",
|
||||
"2023-12-01 14:53:24,377::ERROR::primaite.simulator.network.hardware.base::190::NIC ec:6e:b6:5c:8a:e7/127.0.0.1 cannot be enabled as it is not connected to a Link\n",
|
||||
"2023-12-01 14:53:24,379::ERROR::primaite.simulator.network.hardware.base::190::NIC 36:ad:98:49:2d:a7/127.0.0.1 cannot be enabled as it is not connected to a Link\n",
|
||||
"2023-12-01 14:53:24,380::ERROR::primaite.simulator.network.hardware.base::190::NIC c4:0e:cf:36:55:de/127.0.0.1 cannot be enabled as it is not connected to a Link\n",
|
||||
"2023-12-01 14:53:24,381::ERROR::primaite.simulator.network.hardware.base::190::NIC ec:6e:b6:5c:8a:e7/127.0.0.1 cannot be enabled as it is not connected to a Link\n",
|
||||
"2023-12-01 14:53:24,402::ERROR::primaite.simulator.network.hardware.base::190::NIC 36:ad:98:49:2d:a7/127.0.0.1 cannot be enabled as it is not connected to a Link\n",
|
||||
"2023-12-01 14:53:24,404::ERROR::primaite.simulator.network.hardware.base::190::NIC c4:0e:cf:36:55:de/127.0.0.1 cannot be enabled as it is not connected to a Link\n",
|
||||
"2023-12-01 14:53:24,406::ERROR::primaite.simulator.network.hardware.base::190::NIC ec:6e:b6:5c:8a:e7/127.0.0.1 cannot be enabled as it is not connected to a Link\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Episode: 3, Step: 1, Reward: 0.5\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "stderr",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"2023-12-01 14:53:24,878\tINFO storage.py:563 -- Checkpoint successfully created at: Checkpoint(filesystem=local, path=/home/cade/ray_results/PPO_2023-12-01_14-53-17/PPO_PrimaiteRayEnv_5cbc4_00000_0_2023-12-01_14-53-17/checkpoint_000000)\n",
|
||||
"2023-12-01 14:53:25,098\tINFO tune.py:1047 -- Total run time: 7.37 seconds (7.31 seconds for the tuning loop).\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"<IPython.core.display.HTML object>\n",
|
||||
"<IPython.core.display.HTML object>\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"ResultGrid<[\n",
|
||||
" Result(\n",
|
||||
" metrics={'custom_metrics': {}, 'episode_media': {}, 'info': {'learner': {'__all__': {'num_agent_steps_trained': 128.0, 'num_env_steps_trained': 128.0, 'total_loss': 9.403312460581462}, 'default_policy': {'total_loss': 9.403312460581462, 'policy_loss': -0.06894568807135025, 'vf_loss': 9.469796816507975, 'vf_loss_unclipped': 416.65203653971355, 'vf_explained_var': 0.0007335106531778971, 'entropy': 3.864323592185974, 'mean_kl_loss': 0.012305201259247648, 'default_optimizer_lr': 4.999999999999999e-05, 'curr_lr': 5e-05, 'curr_entropy_coeff': 0.0, 'curr_kl_coeff': 0.20000000298023224}}, 'num_env_steps_sampled': 512, 'num_env_steps_trained': 0, 'num_agent_steps_sampled': 512, 'num_agent_steps_trained': 0}, 'sampler_results': {'episode_reward_max': 128.0, 'episode_reward_min': 128.0, 'episode_reward_mean': 128.0, 'episode_len_mean': 256.0, 'episode_media': {}, 'episodes_this_iter': 1, 'policy_reward_min': {}, 'policy_reward_max': {}, 'policy_reward_mean': {}, 'custom_metrics': {}, 'hist_stats': {'episode_reward': [128.0, 128.0], 'episode_lengths': [256, 256]}, 'sampler_perf': {'mean_raw_obs_processing_ms': 0.8607522543689299, 'mean_inference_ms': 2.1271821797748984, 'mean_action_processing_ms': 0.15329866429338604, 'mean_env_wait_ms': 6.184263571370873, 'mean_env_render_ms': 0.0}, 'num_faulty_episodes': 0, 'connector_metrics': {'ObsPreprocessorConnector_ms': 0.010561943054199219, 'StateBufferConnector_ms': 0.004971027374267578, 'ViewRequirementAgentConnector_ms': 0.29495954513549805}}, 'episode_reward_max': 128.0, 'episode_reward_min': 128.0, 'episode_reward_mean': 128.0, 'episode_len_mean': 256.0, 'episodes_this_iter': 1, 'policy_reward_min': {}, 'policy_reward_max': {}, 'policy_reward_mean': {}, 'hist_stats': {'episode_reward': [128.0, 128.0], 'episode_lengths': [256, 256]}, 'sampler_perf': {'mean_raw_obs_processing_ms': 0.8607522543689299, 'mean_inference_ms': 2.1271821797748984, 'mean_action_processing_ms': 0.15329866429338604, 'mean_env_wait_ms': 6.184263571370873, 'mean_env_render_ms': 0.0}, 'num_faulty_episodes': 0, 'connector_metrics': {'ObsPreprocessorConnector_ms': 0.010561943054199219, 'StateBufferConnector_ms': 0.004971027374267578, 'ViewRequirementAgentConnector_ms': 0.29495954513549805}, 'num_healthy_workers': 0, 'num_in_flight_async_reqs': 0, 'num_remote_worker_restarts': 0, 'num_agent_steps_sampled': 512, 'num_agent_steps_trained': 0, 'num_env_steps_sampled': 512, 'num_env_steps_trained': 0, 'num_env_steps_sampled_this_iter': 128, 'num_env_steps_trained_this_iter': 0, 'num_env_steps_sampled_throughput_per_sec': 85.63165451744611, 'num_env_steps_trained_throughput_per_sec': 0.0, 'num_steps_trained_this_iter': 0, 'agent_timesteps_total': 512, 'timers': {'training_iteration_time_ms': 1530.574, 'sample_time_ms': 1196.582, 'synch_weights_time_ms': 1.912}, 'counters': {'num_env_steps_sampled': 512, 'num_env_steps_trained': 0, 'num_agent_steps_sampled': 512, 'num_agent_steps_trained': 0}, 'perf': {'cpu_util_percent': 55.25, 'ram_util_percent': 58.8}},\n",
|
||||
" path='/home/cade/ray_results/PPO_2023-12-01_14-53-17/PPO_PrimaiteRayEnv_5cbc4_00000_0_2023-12-01_14-53-17',\n",
|
||||
" filesystem='local',\n",
|
||||
" checkpoint=Checkpoint(filesystem=local, path=/home/cade/ray_results/PPO_2023-12-01_14-53-17/PPO_PrimaiteRayEnv_5cbc4_00000_0_2023-12-01_14-53-17/checkpoint_000000)\n",
|
||||
" )\n",
|
||||
"]>"
|
||||
]
|
||||
},
|
||||
"execution_count": 5,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"#### Set training parameters and start the training"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"tune.Tuner(\n",
|
||||
" \"PPO\",\n",
|
||||
|
||||
@@ -62,6 +62,10 @@ class PrimaiteGymEnv(gymnasium.Env):
|
||||
|
||||
def reset(self, seed: Optional[int] = None) -> Tuple[ObsType, Dict[str, Any]]:
|
||||
"""Reset the environment."""
|
||||
print(
|
||||
f"Resetting environment, episode {self.game.episode_counter}, "
|
||||
f"avg. reward: {self.game.rl_agents[0].reward_function.total_reward}"
|
||||
)
|
||||
self.game.reset()
|
||||
state = self.game.get_sim_state()
|
||||
self.game.update_agents(state)
|
||||
|
||||
@@ -62,6 +62,7 @@ class PrimaiteSession:
|
||||
|
||||
def start_session(self) -> None:
|
||||
"""Commence the training/eval session."""
|
||||
print("Starting Primaite Session")
|
||||
self.mode = SessionMode.TRAIN
|
||||
n_learn_episodes = self.training_options.n_learn_episodes
|
||||
n_eval_episodes = self.training_options.n_eval_episodes
|
||||
|
||||
@@ -113,7 +113,7 @@ class RequestManager(BaseModel):
|
||||
"""
|
||||
if name in self.request_types:
|
||||
msg = f"Overwriting request type {name}."
|
||||
_LOGGER.warn(msg)
|
||||
_LOGGER.debug(msg)
|
||||
|
||||
self.request_types[name] = request_type
|
||||
|
||||
@@ -252,6 +252,6 @@ class SimComponent(BaseModel):
|
||||
def parent(self, new_parent: Union["SimComponent", None]) -> None:
|
||||
if self._parent and new_parent:
|
||||
msg = f"Overwriting parent of {self.uuid}. Old parent: {self._parent.uuid}, New parent: {new_parent.uuid}"
|
||||
_LOGGER.warn(msg)
|
||||
_LOGGER.warning(msg)
|
||||
raise RuntimeWarning(msg)
|
||||
self._parent = new_parent
|
||||
|
||||
@@ -72,7 +72,7 @@ class Account(SimComponent):
|
||||
"num_group_changes": self.num_group_changes,
|
||||
"username": self.username,
|
||||
"password": self.password,
|
||||
"account_type": self.account_type.name,
|
||||
"account_type": self.account_type.value,
|
||||
"enabled": self.enabled,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -53,7 +53,10 @@ class FileSystem(SimComponent):
|
||||
original_folder_uuids = self._original_state["original_folder_uuids"]
|
||||
for uuid in original_folder_uuids:
|
||||
if uuid in self.deleted_folders:
|
||||
self.folders[uuid] = self.deleted_folders.pop(uuid)
|
||||
folder = self.deleted_folders[uuid]
|
||||
self.deleted_folders.pop(uuid)
|
||||
self.folders[uuid] = folder
|
||||
self._folders_by_name[folder.name] = folder
|
||||
|
||||
# Clear any other deleted folders that aren't original (have been created by agent)
|
||||
self.deleted_folders.clear()
|
||||
@@ -62,7 +65,9 @@ class FileSystem(SimComponent):
|
||||
current_folder_uuids = list(self.folders.keys())
|
||||
for uuid in current_folder_uuids:
|
||||
if uuid not in original_folder_uuids:
|
||||
folder = self.folders[uuid]
|
||||
self.folders.pop(uuid)
|
||||
self._folders_by_name.pop(folder.name)
|
||||
|
||||
# Now reset all remaining folders
|
||||
for folder in self.folders.values():
|
||||
|
||||
@@ -75,7 +75,10 @@ class Folder(FileSystemItemABC):
|
||||
original_file_uuids = self._original_state["original_file_uuids"]
|
||||
for uuid in original_file_uuids:
|
||||
if uuid in self.deleted_files:
|
||||
self.files[uuid] = self.deleted_files.pop(uuid)
|
||||
file = self.deleted_files[uuid]
|
||||
self.deleted_files.pop(uuid)
|
||||
self.files[uuid] = file
|
||||
self._files_by_name[file.name] = file
|
||||
|
||||
# Clear any other deleted files that aren't original (have been created by agent)
|
||||
self.deleted_files.clear()
|
||||
@@ -84,7 +87,9 @@ class Folder(FileSystemItemABC):
|
||||
current_file_uuids = list(self.files.keys())
|
||||
for uuid in current_file_uuids:
|
||||
if uuid not in original_file_uuids:
|
||||
file = self.files[uuid]
|
||||
self.files.pop(uuid)
|
||||
self._files_by_name.pop(file.name)
|
||||
|
||||
# Now reset all remaining files
|
||||
for file in self.files.values():
|
||||
|
||||
@@ -220,7 +220,7 @@ class Network(SimComponent):
|
||||
self._node_id_map[len(self.nodes)] = node
|
||||
node.parent = self
|
||||
self._nx_graph.add_node(node.hostname)
|
||||
_LOGGER.info(f"Added node {node.uuid} to Network {self.uuid}")
|
||||
_LOGGER.debug(f"Added node {node.uuid} to Network {self.uuid}")
|
||||
self._node_request_manager.add_request(name=node.uuid, request_type=RequestType(func=node._request_manager))
|
||||
|
||||
def get_node_by_hostname(self, hostname: str) -> Optional[Node]:
|
||||
|
||||
@@ -181,13 +181,13 @@ class NIC(SimComponent):
|
||||
if self.enabled:
|
||||
return
|
||||
if not self._connected_node:
|
||||
_LOGGER.error(f"NIC {self} cannot be enabled as it is not connected to a Node")
|
||||
_LOGGER.debug(f"NIC {self} cannot be enabled as it is not connected to a Node")
|
||||
return
|
||||
if self._connected_node.operating_state != NodeOperatingState.ON:
|
||||
self._connected_node.sys_log.error(f"NIC {self} cannot be enabled as the endpoint is not turned on")
|
||||
return
|
||||
if not self._connected_link:
|
||||
_LOGGER.error(f"NIC {self} cannot be enabled as it is not connected to a Link")
|
||||
_LOGGER.debug(f"NIC {self} cannot be enabled as it is not connected to a Link")
|
||||
return
|
||||
|
||||
self.enabled = True
|
||||
|
||||
@@ -51,14 +51,22 @@ def client_server_routed() -> Network:
|
||||
|
||||
# Client 1
|
||||
client_1 = Computer(
|
||||
hostname="client_1", ip_address="192.168.2.2", subnet_mask="255.255.255.0", default_gateway="192.168.2.1"
|
||||
hostname="client_1",
|
||||
ip_address="192.168.2.2",
|
||||
subnet_mask="255.255.255.0",
|
||||
default_gateway="192.168.2.1",
|
||||
operating_state=NodeOperatingState.ON,
|
||||
)
|
||||
client_1.power_on()
|
||||
network.connect(endpoint_b=client_1.ethernet_port[1], endpoint_a=switch_2.switch_ports[1])
|
||||
|
||||
# Server 1
|
||||
server_1 = Server(
|
||||
hostname="server_1", ip_address="192.168.1.2", subnet_mask="255.255.255.0", default_gateway="192.168.1.1"
|
||||
hostname="server_1",
|
||||
ip_address="192.168.1.2",
|
||||
subnet_mask="255.255.255.0",
|
||||
default_gateway="192.168.1.1",
|
||||
operating_state=NodeOperatingState.ON,
|
||||
)
|
||||
server_1.power_on()
|
||||
network.connect(endpoint_b=server_1.ethernet_port[1], endpoint_a=switch_1.switch_ports[1])
|
||||
@@ -139,7 +147,7 @@ def arcd_uc2_network() -> Network:
|
||||
client_1.power_on()
|
||||
network.connect(endpoint_b=client_1.ethernet_port[1], endpoint_a=switch_2.switch_ports[1])
|
||||
client_1.software_manager.install(DataManipulationBot)
|
||||
db_manipulation_bot: DataManipulationBot = client_1.software_manager.software["DataManipulationBot"]
|
||||
db_manipulation_bot: DataManipulationBot = client_1.software_manager.software.get("DataManipulationBot")
|
||||
db_manipulation_bot.configure(
|
||||
server_ip_address=IPv4Address("192.168.1.14"),
|
||||
payload="DELETE",
|
||||
@@ -157,7 +165,7 @@ def arcd_uc2_network() -> Network:
|
||||
operating_state=NodeOperatingState.ON,
|
||||
)
|
||||
client_2.power_on()
|
||||
web_browser = client_2.software_manager.software["WebBrowser"]
|
||||
web_browser = client_2.software_manager.software.get("WebBrowser")
|
||||
web_browser.target_url = "http://arcd.com/users/"
|
||||
network.connect(endpoint_b=client_2.ethernet_port[1], endpoint_a=switch_2.switch_ports[2])
|
||||
|
||||
@@ -241,7 +249,7 @@ def arcd_uc2_network() -> Network:
|
||||
# noqa
|
||||
]
|
||||
database_server.software_manager.install(DatabaseService)
|
||||
database_service: DatabaseService = database_server.software_manager.software["DatabaseService"] # noqa
|
||||
database_service: DatabaseService = database_server.software_manager.software.get("DatabaseService") # noqa
|
||||
database_service.start()
|
||||
database_service.configure_backup(backup_server=IPv4Address("192.168.1.16"))
|
||||
database_service._process_sql(ddl, None) # noqa
|
||||
@@ -260,7 +268,7 @@ def arcd_uc2_network() -> Network:
|
||||
web_server.power_on()
|
||||
web_server.software_manager.install(DatabaseClient)
|
||||
|
||||
database_client: DatabaseClient = web_server.software_manager.software["DatabaseClient"]
|
||||
database_client: DatabaseClient = web_server.software_manager.software.get("DatabaseClient")
|
||||
database_client.configure(server_ip_address=IPv4Address("192.168.1.14"))
|
||||
network.connect(endpoint_b=web_server.ethernet_port[1], endpoint_a=switch_1.switch_ports[2])
|
||||
database_client.run()
|
||||
@@ -269,7 +277,7 @@ def arcd_uc2_network() -> Network:
|
||||
web_server.software_manager.install(WebServer)
|
||||
|
||||
# register the web_server to a domain
|
||||
dns_server_service: DNSServer = domain_controller.software_manager.software["DNSServer"] # noqa
|
||||
dns_server_service: DNSServer = domain_controller.software_manager.software.get("DNSServer") # noqa
|
||||
dns_server_service.dns_register("arcd.com", web_server.ip_address)
|
||||
|
||||
# Backup Server
|
||||
|
||||
@@ -5,6 +5,8 @@ def convert_bytes_to_megabits(B: Union[int, float]) -> float: # noqa - Keep it
|
||||
"""
|
||||
Convert Bytes (file size) to Megabits (data transfer).
|
||||
|
||||
Technically Mebibits - but for simplicity sake, we'll call it megabit
|
||||
|
||||
:param B: The file size in Bytes.
|
||||
:return: File bits to transfer in Megabits.
|
||||
"""
|
||||
|
||||
@@ -73,7 +73,8 @@ class DatabaseClient(Application):
|
||||
|
||||
if not self.connected:
|
||||
return self._connect(self.server_ip_address, self.server_password)
|
||||
return False
|
||||
# already connected
|
||||
return True
|
||||
|
||||
def _connect(
|
||||
self, server_ip_address: IPv4Address, password: Optional[str] = None, is_reattempt: bool = False
|
||||
@@ -107,7 +108,7 @@ class DatabaseClient(Application):
|
||||
|
||||
def disconnect(self):
|
||||
"""Disconnect from the Database Service."""
|
||||
if self.connected and self.operating_state.RUNNING:
|
||||
if self.connected and self.operating_state is ApplicationOperatingState.RUNNING:
|
||||
software_manager: SoftwareManager = self.software_manager
|
||||
software_manager.send_payload_to_session_manager(
|
||||
payload={"type": "disconnect"}, dest_ip_address=self.server_ip_address, dest_port=self.port
|
||||
@@ -186,6 +187,9 @@ class DatabaseClient(Application):
|
||||
:param session_id: The session id the payload relates to.
|
||||
:return: True.
|
||||
"""
|
||||
if not self._can_perform_action():
|
||||
return False
|
||||
|
||||
if isinstance(payload, dict) and payload.get("type"):
|
||||
if payload["type"] == "connect_response":
|
||||
self.connected = payload["response"] == True
|
||||
|
||||
@@ -99,7 +99,7 @@ class WebBrowser(Application):
|
||||
return False
|
||||
|
||||
# get the IP address of the domain name via DNS
|
||||
dns_client: DNSClient = self.software_manager.software["DNSClient"]
|
||||
dns_client: DNSClient = self.software_manager.software.get("DNSClient")
|
||||
domain_exists = dns_client.check_domain_exists(target_domain=parsed_url.hostname)
|
||||
|
||||
# if domain does not exist, the request fails
|
||||
|
||||
@@ -80,7 +80,7 @@ class DatabaseService(Service):
|
||||
return False
|
||||
|
||||
software_manager: SoftwareManager = self.software_manager
|
||||
ftp_client_service: FTPClient = software_manager.software["FTPClient"]
|
||||
ftp_client_service: FTPClient = software_manager.software.get("FTPClient")
|
||||
|
||||
# send backup copy of database file to FTP server
|
||||
response = ftp_client_service.send_file(
|
||||
@@ -104,7 +104,7 @@ class DatabaseService(Service):
|
||||
return False
|
||||
|
||||
software_manager: SoftwareManager = self.software_manager
|
||||
ftp_client_service: FTPClient = software_manager.software["FTPClient"]
|
||||
ftp_client_service: FTPClient = software_manager.software.get("FTPClient")
|
||||
|
||||
# retrieve backup file from backup server
|
||||
response = ftp_client_service.request_file(
|
||||
|
||||
@@ -8,7 +8,6 @@ from primaite.simulator.network.transmission.network_layer import IPProtocol
|
||||
from primaite.simulator.network.transmission.transport_layer import Port
|
||||
from primaite.simulator.system.core.software_manager import SoftwareManager
|
||||
from primaite.simulator.system.services.ftp.ftp_service import FTPServiceABC
|
||||
from primaite.simulator.system.services.service import ServiceOperatingState
|
||||
|
||||
_LOGGER = getLogger(__name__)
|
||||
|
||||
@@ -53,8 +52,7 @@ class FTPClient(FTPServiceABC):
|
||||
:type: session_id: Optional[str]
|
||||
"""
|
||||
# if client service is down, return error
|
||||
if self.operating_state != ServiceOperatingState.RUNNING:
|
||||
self.sys_log.error("FTP Client is not running")
|
||||
if not self._can_perform_action():
|
||||
payload.status_code = FTPStatusCode.ERROR
|
||||
return payload
|
||||
|
||||
@@ -81,8 +79,7 @@ class FTPClient(FTPServiceABC):
|
||||
:type: is_reattempt: Optional[bool]
|
||||
"""
|
||||
# make sure the service is running before attempting
|
||||
if self.operating_state != ServiceOperatingState.RUNNING:
|
||||
self.sys_log.error(f"FTPClient not running for {self.sys_log.hostname}")
|
||||
if not self._can_perform_action():
|
||||
return False
|
||||
|
||||
# normally FTP will choose a random port for the transfer, but using the FTP command port will do for now
|
||||
@@ -282,8 +279,11 @@ class FTPClient(FTPServiceABC):
|
||||
This helps prevent an FTP request loop - FTP client and servers can exist on
|
||||
the same node.
|
||||
"""
|
||||
if not self._can_perform_action():
|
||||
return False
|
||||
|
||||
if payload.status_code is None:
|
||||
self.sys_log.error(f"FTP Server could not be found - Error Code: {payload.status_code.value}")
|
||||
self.sys_log.error(f"FTP Server could not be found - Error Code: {FTPStatusCode.NOT_FOUND.value}")
|
||||
return False
|
||||
|
||||
self.sys_log.info(f"{self.name}: Received FTP Response {payload.ftp_command.name} {payload.status_code.value}")
|
||||
|
||||
@@ -6,7 +6,6 @@ from primaite.simulator.network.protocols.ftp import FTPCommand, FTPPacket, FTPS
|
||||
from primaite.simulator.network.transmission.network_layer import IPProtocol
|
||||
from primaite.simulator.network.transmission.transport_layer import Port
|
||||
from primaite.simulator.system.services.ftp.ftp_service import FTPServiceABC
|
||||
from primaite.simulator.system.services.service import ServiceOperatingState
|
||||
|
||||
_LOGGER = getLogger(__name__)
|
||||
|
||||
@@ -58,8 +57,7 @@ class FTPServer(FTPServiceABC):
|
||||
payload.status_code = FTPStatusCode.ERROR
|
||||
|
||||
# if server service is down, return error
|
||||
if self.operating_state != ServiceOperatingState.RUNNING:
|
||||
self.sys_log.error("FTP Server not running")
|
||||
if not self._can_perform_action():
|
||||
return payload
|
||||
|
||||
self.sys_log.info(f"{self.name}: Received FTP {payload.ftp_command.name} {payload.ftp_command_args}")
|
||||
@@ -95,6 +93,9 @@ class FTPServer(FTPServiceABC):
|
||||
self.sys_log.error(f"{payload} is not an FTP packet")
|
||||
return False
|
||||
|
||||
if not super().receive(payload=payload, session_id=session_id, **kwargs):
|
||||
return False
|
||||
|
||||
"""
|
||||
Ignore ftp payload if status code is defined.
|
||||
|
||||
@@ -102,9 +103,6 @@ class FTPServer(FTPServiceABC):
|
||||
prevents an FTP request loop - FTP client and servers can exist on
|
||||
the same node.
|
||||
"""
|
||||
if not super().receive(payload=payload, session_id=session_id, **kwargs):
|
||||
return False
|
||||
|
||||
if payload.status_code is not None:
|
||||
return False
|
||||
|
||||
|
||||
@@ -119,7 +119,7 @@ class WebServer(Service):
|
||||
|
||||
if path.startswith("users"):
|
||||
# get data from DatabaseServer
|
||||
db_client: DatabaseClient = self.software_manager.software["DatabaseClient"]
|
||||
db_client: DatabaseClient = self.software_manager.software.get("DatabaseClient")
|
||||
# get all users
|
||||
if db_client.query("SELECT"):
|
||||
# query succeeded
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, Union
|
||||
from typing import Any, Dict, Tuple, Union
|
||||
|
||||
import pytest
|
||||
import yaml
|
||||
@@ -12,6 +12,11 @@ from primaite.session.session import PrimaiteSession
|
||||
# from primaite.environment.primaite_env import Primaite
|
||||
# from primaite.primaite_session import PrimaiteSession
|
||||
from primaite.simulator.network.container import Network
|
||||
from primaite.simulator.network.hardware.node_operating_state import NodeOperatingState
|
||||
from primaite.simulator.network.hardware.nodes.computer import Computer
|
||||
from primaite.simulator.network.hardware.nodes.router import ACLAction, Router
|
||||
from primaite.simulator.network.hardware.nodes.server import Server
|
||||
from primaite.simulator.network.hardware.nodes.switch import Switch
|
||||
from primaite.simulator.network.networks import arcd_uc2_network
|
||||
from primaite.simulator.network.transmission.network_layer import IPProtocol
|
||||
from primaite.simulator.network.transmission.transport_layer import Port
|
||||
@@ -29,7 +34,7 @@ from primaite import PRIMAITE_PATHS
|
||||
|
||||
# PrimAITE v3 stuff
|
||||
from primaite.simulator.file_system.file_system import FileSystem
|
||||
from primaite.simulator.network.hardware.base import Node
|
||||
from primaite.simulator.network.hardware.base import Link, Node
|
||||
|
||||
|
||||
class TestService(Service):
|
||||
@@ -122,3 +127,110 @@ def temp_primaite_session(request, monkeypatch) -> TempPrimaiteSession:
|
||||
monkeypatch.setattr(PRIMAITE_PATHS, "user_sessions_path", temp_user_sessions_path())
|
||||
config_path = request.param[0]
|
||||
return TempPrimaiteSession.from_config(config_path=config_path)
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def client_server() -> Tuple[Computer, Server]:
|
||||
# Create Computer
|
||||
computer: Computer = Computer(
|
||||
hostname="test_computer",
|
||||
ip_address="192.168.0.1",
|
||||
subnet_mask="255.255.255.0",
|
||||
default_gateway="192.168.1.1",
|
||||
operating_state=NodeOperatingState.ON,
|
||||
)
|
||||
|
||||
# Create Server
|
||||
server = Server(
|
||||
hostname="server", ip_address="192.168.0.2", subnet_mask="255.255.255.0", operating_state=NodeOperatingState.ON
|
||||
)
|
||||
|
||||
# Connect Computer and Server
|
||||
computer_nic = computer.nics[next(iter(computer.nics))]
|
||||
server_nic = server.nics[next(iter(server.nics))]
|
||||
link = Link(endpoint_a=computer_nic, endpoint_b=server_nic)
|
||||
|
||||
# Should be linked
|
||||
assert link.is_up
|
||||
|
||||
return computer, server
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def example_network() -> Network:
|
||||
"""
|
||||
Create the network used for testing.
|
||||
|
||||
Should only contain the nodes and links.
|
||||
This would act as the base network and services and applications are installed in the relevant test file,
|
||||
|
||||
-------------- --------------
|
||||
| client_1 |----- ----| server_1 |
|
||||
-------------- | -------------- -------------- -------------- | --------------
|
||||
------| switch_1 |------| router_1 |------| switch_2 |------
|
||||
-------------- | -------------- -------------- -------------- | --------------
|
||||
| client_2 |---- ----| server_2 |
|
||||
-------------- --------------
|
||||
"""
|
||||
network = Network()
|
||||
|
||||
# Router 1
|
||||
router_1 = Router(hostname="router_1", num_ports=5, operating_state=NodeOperatingState.ON)
|
||||
router_1.configure_port(port=1, ip_address="192.168.1.1", subnet_mask="255.255.255.0")
|
||||
router_1.configure_port(port=2, ip_address="192.168.10.1", subnet_mask="255.255.255.0")
|
||||
|
||||
# Switch 1
|
||||
switch_1 = Switch(hostname="switch_1", num_ports=8, operating_state=NodeOperatingState.ON)
|
||||
network.connect(endpoint_a=router_1.ethernet_ports[1], endpoint_b=switch_1.switch_ports[8])
|
||||
router_1.enable_port(1)
|
||||
|
||||
# Switch 2
|
||||
switch_2 = Switch(hostname="switch_2", num_ports=8, operating_state=NodeOperatingState.ON)
|
||||
network.connect(endpoint_a=router_1.ethernet_ports[2], endpoint_b=switch_2.switch_ports[8])
|
||||
router_1.enable_port(2)
|
||||
|
||||
# Client 1
|
||||
client_1 = Computer(
|
||||
hostname="client_1",
|
||||
ip_address="192.168.10.21",
|
||||
subnet_mask="255.255.255.0",
|
||||
default_gateway="192.168.10.1",
|
||||
operating_state=NodeOperatingState.ON,
|
||||
)
|
||||
network.connect(endpoint_b=client_1.ethernet_port[1], endpoint_a=switch_2.switch_ports[1])
|
||||
|
||||
# Client 2
|
||||
client_2 = Computer(
|
||||
hostname="client_2",
|
||||
ip_address="192.168.10.22",
|
||||
subnet_mask="255.255.255.0",
|
||||
default_gateway="192.168.10.1",
|
||||
operating_state=NodeOperatingState.ON,
|
||||
)
|
||||
network.connect(endpoint_b=client_2.ethernet_port[1], endpoint_a=switch_2.switch_ports[2])
|
||||
|
||||
# Domain Controller
|
||||
server_1 = Server(
|
||||
hostname="server_1",
|
||||
ip_address="192.168.1.10",
|
||||
subnet_mask="255.255.255.0",
|
||||
default_gateway="192.168.1.1",
|
||||
operating_state=NodeOperatingState.ON,
|
||||
)
|
||||
|
||||
network.connect(endpoint_b=server_1.ethernet_port[1], endpoint_a=switch_1.switch_ports[1])
|
||||
|
||||
# Database Server
|
||||
server_2 = Server(
|
||||
hostname="server_2",
|
||||
ip_address="192.168.1.14",
|
||||
subnet_mask="255.255.255.0",
|
||||
default_gateway="192.168.1.1",
|
||||
operating_state=NodeOperatingState.ON,
|
||||
)
|
||||
network.connect(endpoint_b=server_2.ethernet_port[1], endpoint_a=switch_1.switch_ports[2])
|
||||
|
||||
router_1.acl.add_rule(action=ACLAction.PERMIT, src_port=Port.ARP, dst_port=Port.ARP, position=22)
|
||||
router_1.acl.add_rule(action=ACLAction.PERMIT, protocol=IPProtocol.ICMP, position=23)
|
||||
|
||||
return network
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
import yaml
|
||||
from stable_baselines3 import PPO
|
||||
|
||||
@@ -10,6 +11,7 @@ from primaite.game.game import PrimaiteGame
|
||||
from primaite.session.environment import PrimaiteGymEnv
|
||||
|
||||
|
||||
# @pytest.mark.skip(reason="no way of currently testing this")
|
||||
def test_sb3_compatibility():
|
||||
"""Test that the Gymnasium environment can be used with an SB3 agent."""
|
||||
with open(example_config_path(), "r") as f:
|
||||
|
||||
@@ -11,6 +11,7 @@ MISCONFIGURED_PATH = TEST_ASSETS_ROOT / "configs/bad_primaite_session.yaml"
|
||||
MULTI_AGENT_PATH = TEST_ASSETS_ROOT / "configs/multi_agent_session.yaml"
|
||||
|
||||
|
||||
# @pytest.mark.skip(reason="no way of currently testing this")
|
||||
class TestPrimaiteSession:
|
||||
@pytest.mark.parametrize("temp_primaite_session", [[CFG_PATH]], indirect=True)
|
||||
def test_creating_session(self, temp_primaite_session):
|
||||
|
||||
@@ -8,13 +8,13 @@ from primaite.simulator.system.services.red_services.data_manipulation_bot impor
|
||||
def test_data_manipulation(uc2_network):
|
||||
"""Tests the UC2 data manipulation scenario end-to-end. Is a work in progress."""
|
||||
client_1: Computer = uc2_network.get_node_by_hostname("client_1")
|
||||
db_manipulation_bot: DataManipulationBot = client_1.software_manager.software["DataManipulationBot"]
|
||||
db_manipulation_bot: DataManipulationBot = client_1.software_manager.software.get("DataManipulationBot")
|
||||
|
||||
database_server: Server = uc2_network.get_node_by_hostname("database_server")
|
||||
db_service: DatabaseService = database_server.software_manager.software["DatabaseService"]
|
||||
db_service: DatabaseService = database_server.software_manager.software.get("DatabaseService")
|
||||
|
||||
web_server: Server = uc2_network.get_node_by_hostname("web_server")
|
||||
db_client: DatabaseClient = web_server.software_manager.software["DatabaseClient"]
|
||||
db_client: DatabaseClient = web_server.software_manager.software.get("DatabaseClient")
|
||||
|
||||
db_service.backup_database()
|
||||
|
||||
|
||||
@@ -16,3 +16,9 @@ def test_link_up():
|
||||
assert nic_a.enabled
|
||||
assert nic_b.enabled
|
||||
assert link.is_up
|
||||
|
||||
|
||||
def test_ping_between_computer_and_server(client_server):
|
||||
computer, server = client_server
|
||||
|
||||
assert computer.ping(target_ip_address=server.nics[next(iter(server.nics))].ip_address)
|
||||
|
||||
@@ -2,6 +2,28 @@ import pytest
|
||||
|
||||
from primaite.simulator.network.container import Network
|
||||
from primaite.simulator.network.hardware.base import NIC, Node
|
||||
from primaite.simulator.network.hardware.nodes.computer import Computer
|
||||
from primaite.simulator.network.hardware.nodes.server import Server
|
||||
from primaite.simulator.network.networks import client_server_routed
|
||||
|
||||
|
||||
def test_network(example_network):
|
||||
network: Network = example_network
|
||||
client_1: Computer = network.get_node_by_hostname("client_1")
|
||||
client_2: Computer = network.get_node_by_hostname("client_2")
|
||||
server_1: Server = network.get_node_by_hostname("server_1")
|
||||
server_2: Server = network.get_node_by_hostname("server_2")
|
||||
|
||||
assert client_1.ping(client_2.ethernet_port[1].ip_address)
|
||||
assert client_2.ping(client_1.ethernet_port[1].ip_address)
|
||||
|
||||
assert server_1.ping(server_2.ethernet_port[1].ip_address)
|
||||
assert server_2.ping(server_1.ethernet_port[1].ip_address)
|
||||
|
||||
assert client_1.ping(server_1.ethernet_port[1].ip_address)
|
||||
assert client_2.ping(server_1.ethernet_port[1].ip_address)
|
||||
assert client_1.ping(server_2.ethernet_port[1].ip_address)
|
||||
assert client_2.ping(server_2.ethernet_port[1].ip_address)
|
||||
|
||||
|
||||
def test_adding_removing_nodes():
|
||||
|
||||
@@ -18,7 +18,7 @@ def populated_node(application_class) -> Tuple[Application, Computer]:
|
||||
)
|
||||
computer.software_manager.install(application_class)
|
||||
|
||||
app = computer.software_manager.software["TestApplication"]
|
||||
app = computer.software_manager.software.get("TestApplication")
|
||||
app.run()
|
||||
|
||||
return app, computer
|
||||
@@ -35,7 +35,7 @@ def test_service_on_offline_node(application_class):
|
||||
)
|
||||
computer.software_manager.install(application_class)
|
||||
|
||||
app: Application = computer.software_manager.software["TestApplication"]
|
||||
app: Application = computer.software_manager.software.get("TestApplication")
|
||||
|
||||
computer.power_off()
|
||||
|
||||
|
||||
@@ -10,10 +10,10 @@ from primaite.simulator.system.services.service import ServiceOperatingState
|
||||
|
||||
def test_database_client_server_connection(uc2_network):
|
||||
web_server: Server = uc2_network.get_node_by_hostname("web_server")
|
||||
db_client: DatabaseClient = web_server.software_manager.software["DatabaseClient"]
|
||||
db_client: DatabaseClient = web_server.software_manager.software.get("DatabaseClient")
|
||||
|
||||
db_server: Server = uc2_network.get_node_by_hostname("database_server")
|
||||
db_service: DatabaseService = db_server.software_manager.software["DatabaseService"]
|
||||
db_service: DatabaseService = db_server.software_manager.software.get("DatabaseService")
|
||||
|
||||
assert len(db_service.connections) == 1
|
||||
|
||||
@@ -23,10 +23,10 @@ def test_database_client_server_connection(uc2_network):
|
||||
|
||||
def test_database_client_server_correct_password(uc2_network):
|
||||
web_server: Server = uc2_network.get_node_by_hostname("web_server")
|
||||
db_client: DatabaseClient = web_server.software_manager.software["DatabaseClient"]
|
||||
db_client: DatabaseClient = web_server.software_manager.software.get("DatabaseClient")
|
||||
|
||||
db_server: Server = uc2_network.get_node_by_hostname("database_server")
|
||||
db_service: DatabaseService = db_server.software_manager.software["DatabaseService"]
|
||||
db_service: DatabaseService = db_server.software_manager.software.get("DatabaseService")
|
||||
|
||||
db_client.disconnect()
|
||||
|
||||
@@ -40,10 +40,10 @@ def test_database_client_server_correct_password(uc2_network):
|
||||
|
||||
def test_database_client_server_incorrect_password(uc2_network):
|
||||
web_server: Server = uc2_network.get_node_by_hostname("web_server")
|
||||
db_client: DatabaseClient = web_server.software_manager.software["DatabaseClient"]
|
||||
db_client: DatabaseClient = web_server.software_manager.software.get("DatabaseClient")
|
||||
|
||||
db_server: Server = uc2_network.get_node_by_hostname("database_server")
|
||||
db_service: DatabaseService = db_server.software_manager.software["DatabaseService"]
|
||||
db_service: DatabaseService = db_server.software_manager.software.get("DatabaseService")
|
||||
|
||||
db_client.disconnect()
|
||||
db_client.configure(server_ip_address=IPv4Address("192.168.1.14"), server_password="54321")
|
||||
@@ -56,7 +56,7 @@ def test_database_client_server_incorrect_password(uc2_network):
|
||||
def test_database_client_query(uc2_network):
|
||||
"""Tests DB query across the network returns HTTP status 200 and date."""
|
||||
web_server: Server = uc2_network.get_node_by_hostname("web_server")
|
||||
db_client: DatabaseClient = web_server.software_manager.software["DatabaseClient"]
|
||||
db_client: DatabaseClient = web_server.software_manager.software.get("DatabaseClient")
|
||||
|
||||
assert db_client.connected
|
||||
|
||||
@@ -66,13 +66,13 @@ def test_database_client_query(uc2_network):
|
||||
def test_create_database_backup(uc2_network):
|
||||
"""Run the backup_database method and check if the FTP server has the relevant file."""
|
||||
db_server: Server = uc2_network.get_node_by_hostname("database_server")
|
||||
db_service: DatabaseService = db_server.software_manager.software["DatabaseService"]
|
||||
db_service: DatabaseService = db_server.software_manager.software.get("DatabaseService")
|
||||
|
||||
# back up should be created
|
||||
assert db_service.backup_database() is True
|
||||
|
||||
backup_server: Server = uc2_network.get_node_by_hostname("backup_server")
|
||||
ftp_server: FTPServer = backup_server.software_manager.software["FTPServer"]
|
||||
ftp_server: FTPServer = backup_server.software_manager.software.get("FTPServer")
|
||||
|
||||
# backup file should exist in the backup server
|
||||
assert ftp_server.file_system.get_file(folder_name=db_service.uuid, file_name="database.db") is not None
|
||||
@@ -81,7 +81,7 @@ def test_create_database_backup(uc2_network):
|
||||
def test_restore_backup(uc2_network):
|
||||
"""Run the restore_backup method and check if the backup is properly restored."""
|
||||
db_server: Server = uc2_network.get_node_by_hostname("database_server")
|
||||
db_service: DatabaseService = db_server.software_manager.software["DatabaseService"]
|
||||
db_service: DatabaseService = db_server.software_manager.software.get("DatabaseService")
|
||||
|
||||
# create a back up
|
||||
assert db_service.backup_database() is True
|
||||
@@ -100,13 +100,13 @@ def test_restore_backup(uc2_network):
|
||||
def test_database_client_cannot_query_offline_database_server(uc2_network):
|
||||
"""Tests DB query across the network returns HTTP status 404 when db server is offline."""
|
||||
db_server: Server = uc2_network.get_node_by_hostname("database_server")
|
||||
db_service: DatabaseService = db_server.software_manager.software["DatabaseService"]
|
||||
db_service: DatabaseService = db_server.software_manager.software.get("DatabaseService")
|
||||
|
||||
assert db_server.operating_state is NodeOperatingState.ON
|
||||
assert db_service.operating_state is ServiceOperatingState.RUNNING
|
||||
|
||||
web_server: Server = uc2_network.get_node_by_hostname("web_server")
|
||||
db_client: DatabaseClient = web_server.software_manager.software["DatabaseClient"]
|
||||
db_client: DatabaseClient = web_server.software_manager.software.get("DatabaseClient")
|
||||
assert db_client.connected
|
||||
|
||||
assert db_client.query("SELECT") is True
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
from ipaddress import IPv4Address
|
||||
from typing import Tuple
|
||||
|
||||
import pytest
|
||||
|
||||
from primaite.simulator.network.hardware.node_operating_state import NodeOperatingState
|
||||
from primaite.simulator.network.hardware.nodes.computer import Computer
|
||||
from primaite.simulator.network.hardware.nodes.server import Server
|
||||
@@ -6,12 +11,31 @@ from primaite.simulator.system.services.dns.dns_server import DNSServer
|
||||
from primaite.simulator.system.services.service import ServiceOperatingState
|
||||
|
||||
|
||||
def test_dns_client_server(uc2_network):
|
||||
client_1: Computer = uc2_network.get_node_by_hostname("client_1")
|
||||
domain_controller: Server = uc2_network.get_node_by_hostname("domain_controller")
|
||||
@pytest.fixture(scope="function")
|
||||
def dns_client_and_dns_server(client_server) -> Tuple[DNSClient, Computer, DNSServer, Server]:
|
||||
computer, server = client_server
|
||||
|
||||
dns_client: DNSClient = client_1.software_manager.software["DNSClient"]
|
||||
dns_server: DNSServer = domain_controller.software_manager.software["DNSServer"]
|
||||
# Install DNS Client on computer
|
||||
computer.software_manager.install(DNSClient)
|
||||
dns_client: DNSClient = computer.software_manager.software.get("DNSClient")
|
||||
dns_client.start()
|
||||
# set server as DNS Server
|
||||
dns_client.dns_server = IPv4Address(server.nics.get(next(iter(server.nics))).ip_address)
|
||||
|
||||
# Install DNS Server on server
|
||||
server.software_manager.install(DNSServer)
|
||||
dns_server: DNSServer = server.software_manager.software.get("DNSServer")
|
||||
dns_server.start()
|
||||
# register arcd.com as a domain
|
||||
dns_server.dns_register(
|
||||
domain_name="arcd.com", domain_ip_address=IPv4Address(server.nics.get(next(iter(server.nics))).ip_address)
|
||||
)
|
||||
|
||||
return dns_client, computer, dns_server, server
|
||||
|
||||
|
||||
def test_dns_client_server(dns_client_and_dns_server):
|
||||
dns_client, computer, dns_server, server = dns_client_and_dns_server
|
||||
|
||||
assert dns_client.operating_state == ServiceOperatingState.RUNNING
|
||||
assert dns_server.operating_state == ServiceOperatingState.RUNNING
|
||||
@@ -29,12 +53,8 @@ def test_dns_client_server(uc2_network):
|
||||
assert len(dns_client.dns_cache) == 1
|
||||
|
||||
|
||||
def test_dns_client_requests_offline_dns_server(uc2_network):
|
||||
client_1: Computer = uc2_network.get_node_by_hostname("client_1")
|
||||
domain_controller: Server = uc2_network.get_node_by_hostname("domain_controller")
|
||||
|
||||
dns_client: DNSClient = client_1.software_manager.software["DNSClient"]
|
||||
dns_server: DNSServer = domain_controller.software_manager.software["DNSServer"]
|
||||
def test_dns_client_requests_offline_dns_server(dns_client_and_dns_server):
|
||||
dns_client, computer, dns_server, server = dns_client_and_dns_server
|
||||
|
||||
assert dns_client.operating_state == ServiceOperatingState.RUNNING
|
||||
assert dns_server.operating_state == ServiceOperatingState.RUNNING
|
||||
@@ -48,12 +68,12 @@ def test_dns_client_requests_offline_dns_server(uc2_network):
|
||||
assert len(dns_client.dns_cache) == 1
|
||||
dns_client.dns_cache = {}
|
||||
|
||||
domain_controller.power_off()
|
||||
server.power_off()
|
||||
|
||||
for i in range(domain_controller.shut_down_duration + 1):
|
||||
uc2_network.apply_timestep(timestep=i)
|
||||
for i in range(server.shut_down_duration + 1):
|
||||
server.apply_timestep(timestep=i)
|
||||
|
||||
assert domain_controller.operating_state == NodeOperatingState.OFF
|
||||
assert server.operating_state == NodeOperatingState.OFF
|
||||
assert dns_server.operating_state == ServiceOperatingState.STOPPED
|
||||
|
||||
# this time it should not cache because dns server is not online
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
from ipaddress import IPv4Address
|
||||
from typing import Tuple
|
||||
|
||||
import pytest
|
||||
|
||||
from primaite.simulator.network.hardware.nodes.computer import Computer
|
||||
from primaite.simulator.network.hardware.nodes.server import Server
|
||||
@@ -7,18 +10,31 @@ from primaite.simulator.system.services.ftp.ftp_server import FTPServer
|
||||
from primaite.simulator.system.services.service import ServiceOperatingState
|
||||
|
||||
|
||||
def test_ftp_client_store_file_in_server(uc2_network):
|
||||
@pytest.fixture(scope="function")
|
||||
def ftp_client_and_ftp_server(client_server) -> Tuple[FTPClient, Computer, FTPServer, Server]:
|
||||
computer, server = client_server
|
||||
|
||||
# Install FTP Client service on computer
|
||||
computer.software_manager.install(FTPClient)
|
||||
ftp_client: FTPClient = computer.software_manager.software.get("FTPClient")
|
||||
ftp_client.start()
|
||||
|
||||
# Install FTP Server service on server
|
||||
server.software_manager.install(FTPServer)
|
||||
ftp_server: FTPServer = server.software_manager.software.get("FTPServer")
|
||||
ftp_server.start()
|
||||
|
||||
return ftp_client, computer, ftp_server, server
|
||||
|
||||
|
||||
def test_ftp_client_store_file_in_server(ftp_client_and_ftp_server):
|
||||
"""
|
||||
Test checks to see if the client is able to store files in the backup server.
|
||||
"""
|
||||
client_1: Computer = uc2_network.get_node_by_hostname("client_1")
|
||||
backup_server: Server = uc2_network.get_node_by_hostname("backup_server")
|
||||
|
||||
ftp_client: FTPClient = client_1.software_manager.software["FTPClient"]
|
||||
ftp_server_service: FTPServer = backup_server.software_manager.software["FTPServer"]
|
||||
ftp_client, computer, ftp_server, server = ftp_client_and_ftp_server
|
||||
|
||||
assert ftp_client.operating_state == ServiceOperatingState.RUNNING
|
||||
assert ftp_server_service.operating_state == ServiceOperatingState.RUNNING
|
||||
assert ftp_server.operating_state == ServiceOperatingState.RUNNING
|
||||
|
||||
# create file on ftp client
|
||||
ftp_client.file_system.create_file(file_name="test_file.txt")
|
||||
@@ -28,61 +44,53 @@ def test_ftp_client_store_file_in_server(uc2_network):
|
||||
src_file_name="test_file.txt",
|
||||
dest_folder_name="client_1_backup",
|
||||
dest_file_name="test_file.txt",
|
||||
dest_ip_address=backup_server.nics.get(next(iter(backup_server.nics))).ip_address,
|
||||
dest_ip_address=server.nics.get(next(iter(server.nics))).ip_address,
|
||||
)
|
||||
|
||||
assert ftp_server_service.file_system.get_file(folder_name="client_1_backup", file_name="test_file.txt")
|
||||
assert ftp_server.file_system.get_file(folder_name="client_1_backup", file_name="test_file.txt")
|
||||
|
||||
|
||||
def test_ftp_client_retrieve_file_from_server(uc2_network):
|
||||
def test_ftp_client_retrieve_file_from_server(ftp_client_and_ftp_server):
|
||||
"""
|
||||
Test checks to see if the client is able to retrieve files from the backup server.
|
||||
"""
|
||||
client_1: Computer = uc2_network.get_node_by_hostname("client_1")
|
||||
backup_server: Server = uc2_network.get_node_by_hostname("backup_server")
|
||||
|
||||
ftp_client: FTPClient = client_1.software_manager.software["FTPClient"]
|
||||
ftp_server_service: FTPServer = backup_server.software_manager.software["FTPServer"]
|
||||
ftp_client, computer, ftp_server, server = ftp_client_and_ftp_server
|
||||
|
||||
assert ftp_client.operating_state == ServiceOperatingState.RUNNING
|
||||
assert ftp_server_service.operating_state == ServiceOperatingState.RUNNING
|
||||
assert ftp_server.operating_state == ServiceOperatingState.RUNNING
|
||||
|
||||
# create file on ftp server
|
||||
ftp_server_service.file_system.create_file(file_name="test_file.txt", folder_name="file_share")
|
||||
ftp_server.file_system.create_file(file_name="test_file.txt", folder_name="file_share")
|
||||
|
||||
assert ftp_client.request_file(
|
||||
src_folder_name="file_share",
|
||||
src_file_name="test_file.txt",
|
||||
dest_folder_name="downloads",
|
||||
dest_file_name="test_file.txt",
|
||||
dest_ip_address=backup_server.nics.get(next(iter(backup_server.nics))).ip_address,
|
||||
dest_ip_address=server.nics.get(next(iter(server.nics))).ip_address,
|
||||
)
|
||||
|
||||
# client should have retrieved the file
|
||||
assert ftp_client.file_system.get_file(folder_name="downloads", file_name="test_file.txt")
|
||||
|
||||
|
||||
def test_ftp_client_tries_to_connect_to_offline_server(uc2_network):
|
||||
def test_ftp_client_tries_to_connect_to_offline_server(ftp_client_and_ftp_server):
|
||||
"""Test checks to make sure that the client can't do anything when the server is offline."""
|
||||
client_1: Computer = uc2_network.get_node_by_hostname("client_1")
|
||||
backup_server: Server = uc2_network.get_node_by_hostname("backup_server")
|
||||
|
||||
ftp_client: FTPClient = client_1.software_manager.software["FTPClient"]
|
||||
ftp_server_service: FTPServer = backup_server.software_manager.software["FTPServer"]
|
||||
ftp_client, computer, ftp_server, server = ftp_client_and_ftp_server
|
||||
|
||||
assert ftp_client.operating_state == ServiceOperatingState.RUNNING
|
||||
assert ftp_server_service.operating_state == ServiceOperatingState.RUNNING
|
||||
assert ftp_server.operating_state == ServiceOperatingState.RUNNING
|
||||
|
||||
# create file on ftp server
|
||||
ftp_server_service.file_system.create_file(file_name="test_file.txt", folder_name="file_share")
|
||||
ftp_server.file_system.create_file(file_name="test_file.txt", folder_name="file_share")
|
||||
|
||||
backup_server.power_off()
|
||||
server.power_off()
|
||||
|
||||
for i in range(backup_server.shut_down_duration + 1):
|
||||
uc2_network.apply_timestep(timestep=i)
|
||||
for i in range(server.shut_down_duration + 1):
|
||||
server.apply_timestep(timestep=i)
|
||||
|
||||
assert ftp_client.operating_state == ServiceOperatingState.RUNNING
|
||||
assert ftp_server_service.operating_state == ServiceOperatingState.STOPPED
|
||||
assert ftp_server.operating_state == ServiceOperatingState.STOPPED
|
||||
|
||||
assert (
|
||||
ftp_client.request_file(
|
||||
@@ -90,7 +98,7 @@ def test_ftp_client_tries_to_connect_to_offline_server(uc2_network):
|
||||
src_file_name="test_file.txt",
|
||||
dest_folder_name="downloads",
|
||||
dest_file_name="test_file.txt",
|
||||
dest_ip_address=backup_server.nics.get(next(iter(backup_server.nics))).ip_address,
|
||||
dest_ip_address=server.nics.get(next(iter(server.nics))).ip_address,
|
||||
)
|
||||
is False
|
||||
)
|
||||
|
||||
@@ -17,7 +17,7 @@ def populated_node(
|
||||
)
|
||||
server.software_manager.install(service_class)
|
||||
|
||||
service = server.software_manager.software["TestService"]
|
||||
service = server.software_manager.software.get("TestService")
|
||||
service.start()
|
||||
|
||||
return server, service
|
||||
@@ -34,7 +34,7 @@ def test_service_on_offline_node(service_class):
|
||||
)
|
||||
computer.software_manager.install(service_class)
|
||||
|
||||
service: Service = computer.software_manager.software["TestService"]
|
||||
service: Service = computer.software_manager.software.get("TestService")
|
||||
|
||||
computer.power_off()
|
||||
|
||||
|
||||
@@ -1,104 +1,118 @@
|
||||
from typing import Tuple
|
||||
|
||||
import pytest
|
||||
|
||||
from primaite.simulator.network.hardware.node_operating_state import NodeOperatingState
|
||||
from primaite.simulator.network.hardware.nodes.computer import Computer
|
||||
from primaite.simulator.network.hardware.nodes.server import Server
|
||||
from primaite.simulator.network.protocols.http import HttpStatusCode
|
||||
from primaite.simulator.system.applications.application import ApplicationOperatingState
|
||||
from primaite.simulator.system.applications.web_browser import WebBrowser
|
||||
from primaite.simulator.system.services.dns.dns_client import DNSClient
|
||||
from primaite.simulator.system.services.dns.dns_server import DNSServer
|
||||
from primaite.simulator.system.services.web_server.web_server import WebServer
|
||||
|
||||
|
||||
def test_web_page_home_page(uc2_network):
|
||||
"""Test to see if the browser is able to open the main page of the web server."""
|
||||
client_1: Computer = uc2_network.get_node_by_hostname("client_1")
|
||||
web_client: WebBrowser = client_1.software_manager.software["WebBrowser"]
|
||||
web_client.run()
|
||||
web_client.target_url = "http://arcd.com/"
|
||||
assert web_client.operating_state == ApplicationOperatingState.RUNNING
|
||||
@pytest.fixture(scope="function")
|
||||
def web_client_and_web_server(client_server) -> Tuple[WebBrowser, Computer, WebServer, Server]:
|
||||
computer, server = client_server
|
||||
|
||||
assert web_client.get_webpage() is True
|
||||
# Install Web Browser on computer
|
||||
computer.software_manager.install(WebBrowser)
|
||||
web_browser: WebBrowser = computer.software_manager.software.get("WebBrowser")
|
||||
web_browser.run()
|
||||
|
||||
# latest reponse should have status code 200
|
||||
assert web_client.latest_response is not None
|
||||
assert web_client.latest_response.status_code == HttpStatusCode.OK
|
||||
# Install DNS Client service on computer
|
||||
computer.software_manager.install(DNSClient)
|
||||
dns_client: DNSClient = computer.software_manager.software.get("DNSClient")
|
||||
# set dns server
|
||||
dns_client.dns_server = server.nics[next(iter(server.nics))].ip_address
|
||||
|
||||
# Install Web Server service on server
|
||||
server.software_manager.install(WebServer)
|
||||
web_server_service: WebServer = server.software_manager.software.get("WebServer")
|
||||
web_server_service.start()
|
||||
|
||||
# Install DNS Server service on server
|
||||
server.software_manager.install(DNSServer)
|
||||
dns_server: DNSServer = server.software_manager.software.get("DNSServer")
|
||||
# register arcd.com to DNS
|
||||
dns_server.dns_register(domain_name="arcd.com", domain_ip_address=server.nics[next(iter(server.nics))].ip_address)
|
||||
|
||||
return web_browser, computer, web_server_service, server
|
||||
|
||||
|
||||
def test_web_page_get_users_page_request_with_domain_name(uc2_network):
|
||||
def test_web_page_get_users_page_request_with_domain_name(web_client_and_web_server):
|
||||
"""Test to see if the client can handle requests with domain names"""
|
||||
client_1: Computer = uc2_network.get_node_by_hostname("client_1")
|
||||
web_client: WebBrowser = client_1.software_manager.software["WebBrowser"]
|
||||
web_client.run()
|
||||
assert web_client.operating_state == ApplicationOperatingState.RUNNING
|
||||
web_client.target_url = "http://arcd.com/users/"
|
||||
web_browser_app, computer, web_server_service, server = web_client_and_web_server
|
||||
|
||||
assert web_client.get_webpage() is True
|
||||
web_server_ip = server.nics.get(next(iter(server.nics))).ip_address
|
||||
web_browser_app.target_url = f"http://arcd.com/"
|
||||
assert web_browser_app.operating_state == ApplicationOperatingState.RUNNING
|
||||
|
||||
assert web_browser_app.get_webpage() is True
|
||||
|
||||
# latest response should have status code 200
|
||||
assert web_client.latest_response is not None
|
||||
assert web_client.latest_response.status_code == HttpStatusCode.OK
|
||||
assert web_browser_app.latest_response is not None
|
||||
assert web_browser_app.latest_response.status_code == HttpStatusCode.OK
|
||||
|
||||
|
||||
def test_web_page_get_users_page_request_with_ip_address(uc2_network):
|
||||
def test_web_page_get_users_page_request_with_ip_address(web_client_and_web_server):
|
||||
"""Test to see if the client can handle requests that use ip_address."""
|
||||
client_1: Computer = uc2_network.get_node_by_hostname("client_1")
|
||||
web_client: WebBrowser = client_1.software_manager.software["WebBrowser"]
|
||||
web_client.run()
|
||||
web_browser_app, computer, web_server_service, server = web_client_and_web_server
|
||||
|
||||
web_server: Server = uc2_network.get_node_by_hostname("web_server")
|
||||
web_server_ip = server.nics.get(next(iter(server.nics))).ip_address
|
||||
web_browser_app.target_url = f"http://{web_server_ip}/"
|
||||
assert web_browser_app.operating_state == ApplicationOperatingState.RUNNING
|
||||
|
||||
web_server_ip = web_server.nics.get(next(iter(web_server.nics))).ip_address
|
||||
web_client.target_url = f"http://{web_server_ip}/users/"
|
||||
assert web_client.operating_state == ApplicationOperatingState.RUNNING
|
||||
|
||||
assert web_client.get_webpage() is True
|
||||
assert web_browser_app.get_webpage() is True
|
||||
|
||||
# latest response should have status code 200
|
||||
assert web_client.latest_response is not None
|
||||
assert web_client.latest_response.status_code == HttpStatusCode.OK
|
||||
assert web_browser_app.latest_response is not None
|
||||
assert web_browser_app.latest_response.status_code == HttpStatusCode.OK
|
||||
|
||||
|
||||
def test_web_page_request_from_shut_down_server(uc2_network):
|
||||
def test_web_page_request_from_shut_down_server(web_client_and_web_server):
|
||||
"""Test to see that the web server does not respond when the server is off."""
|
||||
client_1: Computer = uc2_network.get_node_by_hostname("client_1")
|
||||
web_client: WebBrowser = client_1.software_manager.software["WebBrowser"]
|
||||
web_client.run()
|
||||
web_browser_app, computer, web_server_service, server = web_client_and_web_server
|
||||
|
||||
web_server: Server = uc2_network.get_node_by_hostname("web_server")
|
||||
web_server_ip = server.nics.get(next(iter(server.nics))).ip_address
|
||||
web_browser_app.target_url = f"http://arcd.com/"
|
||||
assert web_browser_app.operating_state == ApplicationOperatingState.RUNNING
|
||||
|
||||
assert web_client.operating_state == ApplicationOperatingState.RUNNING
|
||||
|
||||
assert web_client.get_webpage("http://arcd.com/users/") is True
|
||||
assert web_browser_app.get_webpage() is True
|
||||
|
||||
# latest response should have status code 200
|
||||
assert web_client.latest_response.status_code == HttpStatusCode.OK
|
||||
assert web_browser_app.latest_response is not None
|
||||
assert web_browser_app.latest_response.status_code == HttpStatusCode.OK
|
||||
|
||||
web_server.power_off()
|
||||
server.power_off()
|
||||
|
||||
for i in range(web_server.shut_down_duration + 1):
|
||||
uc2_network.apply_timestep(timestep=i)
|
||||
server.power_off()
|
||||
|
||||
for i in range(server.shut_down_duration + 1):
|
||||
server.apply_timestep(timestep=i)
|
||||
|
||||
# node should be off
|
||||
assert web_server.operating_state is NodeOperatingState.OFF
|
||||
assert server.operating_state is NodeOperatingState.OFF
|
||||
|
||||
assert web_client.get_webpage("http://arcd.com/users/") is False
|
||||
assert web_client.latest_response.status_code == HttpStatusCode.NOT_FOUND
|
||||
assert web_browser_app.get_webpage() is False
|
||||
assert web_browser_app.latest_response.status_code == HttpStatusCode.NOT_FOUND
|
||||
|
||||
|
||||
def test_web_page_request_from_closed_web_browser(uc2_network):
|
||||
client_1: Computer = uc2_network.get_node_by_hostname("client_1")
|
||||
web_client: WebBrowser = client_1.software_manager.software["WebBrowser"]
|
||||
web_client.run()
|
||||
def test_web_page_request_from_closed_web_browser(web_client_and_web_server):
|
||||
web_browser_app, computer, web_server_service, server = web_client_and_web_server
|
||||
|
||||
web_server: Server = uc2_network.get_node_by_hostname("web_server")
|
||||
|
||||
assert web_client.operating_state == ApplicationOperatingState.RUNNING
|
||||
|
||||
assert web_client.get_webpage("http://arcd.com/users/") is True
|
||||
assert web_browser_app.operating_state == ApplicationOperatingState.RUNNING
|
||||
web_browser_app.target_url = f"http://arcd.com/"
|
||||
assert web_browser_app.get_webpage() is True
|
||||
|
||||
# latest response should have status code 200
|
||||
assert web_client.latest_response.status_code == HttpStatusCode.OK
|
||||
assert web_browser_app.latest_response.status_code == HttpStatusCode.OK
|
||||
|
||||
web_client.close()
|
||||
web_browser_app.close()
|
||||
|
||||
# node should be off
|
||||
assert web_client.operating_state is ApplicationOperatingState.CLOSED
|
||||
assert web_browser_app.operating_state is ApplicationOperatingState.CLOSED
|
||||
|
||||
assert web_client.get_webpage("http://arcd.com/users/") is False
|
||||
assert web_browser_app.get_webpage() is False
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
from ipaddress import IPv4Address
|
||||
from typing import Tuple
|
||||
|
||||
import pytest
|
||||
|
||||
from primaite.simulator.network.hardware.base import Link
|
||||
from primaite.simulator.network.hardware.node_operating_state import NodeOperatingState
|
||||
from primaite.simulator.network.hardware.nodes.computer import Computer
|
||||
from primaite.simulator.network.hardware.nodes.router import ACLAction, Router
|
||||
from primaite.simulator.network.hardware.nodes.server import Server
|
||||
from primaite.simulator.network.transmission.transport_layer import Port
|
||||
from primaite.simulator.system.applications.database_client import DatabaseClient
|
||||
from primaite.simulator.system.applications.web_browser import WebBrowser
|
||||
from primaite.simulator.system.services.database.database_service import DatabaseService
|
||||
from primaite.simulator.system.services.dns.dns_client import DNSClient
|
||||
from primaite.simulator.system.services.dns.dns_server import DNSServer
|
||||
from primaite.simulator.system.services.web_server.web_server import WebServer
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def web_client_web_server_database(example_network) -> Tuple[Computer, Server, Server]:
|
||||
# add rules to network router
|
||||
router_1: Router = example_network.get_node_by_hostname("router_1")
|
||||
router_1.acl.add_rule(
|
||||
action=ACLAction.PERMIT, src_port=Port.POSTGRES_SERVER, dst_port=Port.POSTGRES_SERVER, position=0
|
||||
)
|
||||
|
||||
# Allow DNS requests
|
||||
router_1.acl.add_rule(action=ACLAction.PERMIT, src_port=Port.DNS, dst_port=Port.DNS, position=1)
|
||||
|
||||
# Allow FTP requests
|
||||
router_1.acl.add_rule(action=ACLAction.PERMIT, src_port=Port.FTP, dst_port=Port.FTP, position=2)
|
||||
|
||||
# Open port 80 for web server
|
||||
router_1.acl.add_rule(action=ACLAction.PERMIT, src_port=Port.HTTP, dst_port=Port.HTTP, position=3)
|
||||
|
||||
# Create Computer
|
||||
computer: Computer = example_network.get_node_by_hostname("client_1")
|
||||
|
||||
# Create Web Server
|
||||
web_server: Server = example_network.get_node_by_hostname("server_1")
|
||||
|
||||
# Create Database Server
|
||||
db_server = example_network.get_node_by_hostname("server_2")
|
||||
|
||||
# Get the NICs
|
||||
computer_nic = computer.nics[next(iter(computer.nics))]
|
||||
server_nic = web_server.nics[next(iter(web_server.nics))]
|
||||
db_server_nic = db_server.nics[next(iter(db_server.nics))]
|
||||
|
||||
# Connect Computer and Server
|
||||
link_computer_server = Link(endpoint_a=computer_nic, endpoint_b=server_nic)
|
||||
# Should be linked
|
||||
assert link_computer_server.is_up
|
||||
|
||||
# Connect database server and web server
|
||||
link_server_db = Link(endpoint_a=server_nic, endpoint_b=db_server_nic)
|
||||
# Should be linked
|
||||
assert link_computer_server.is_up
|
||||
assert link_server_db.is_up
|
||||
|
||||
# Install DatabaseService on db server
|
||||
db_server.software_manager.install(DatabaseService)
|
||||
db_service: DatabaseService = db_server.software_manager.software.get("DatabaseService")
|
||||
db_service.start()
|
||||
|
||||
# Install Web Browser on computer
|
||||
computer.software_manager.install(WebBrowser)
|
||||
web_browser: WebBrowser = computer.software_manager.software.get("WebBrowser")
|
||||
web_browser.target_url = "http://arcd.com/users/"
|
||||
web_browser.run()
|
||||
|
||||
# Install DNS Client service on computer
|
||||
computer.software_manager.install(DNSClient)
|
||||
dns_client: DNSClient = computer.software_manager.software.get("DNSClient")
|
||||
# set dns server
|
||||
dns_client.dns_server = web_server.nics[next(iter(web_server.nics))].ip_address
|
||||
|
||||
# Install Web Server service on web server
|
||||
web_server.software_manager.install(WebServer)
|
||||
web_server_service: WebServer = web_server.software_manager.software.get("WebServer")
|
||||
web_server_service.start()
|
||||
|
||||
# Install DNS Server service on web server
|
||||
web_server.software_manager.install(DNSServer)
|
||||
dns_server: DNSServer = web_server.software_manager.software.get("DNSServer")
|
||||
# register arcd.com to DNS
|
||||
dns_server.dns_register(
|
||||
domain_name="arcd.com", domain_ip_address=web_server.nics[next(iter(web_server.nics))].ip_address
|
||||
)
|
||||
|
||||
# Install DatabaseClient service on web server
|
||||
web_server.software_manager.install(DatabaseClient)
|
||||
db_client: DatabaseClient = web_server.software_manager.software.get("DatabaseClient")
|
||||
db_client.server_ip_address = IPv4Address(db_server_nic.ip_address) # set IP address of Database Server
|
||||
db_client.run()
|
||||
assert dns_client.check_domain_exists("arcd.com")
|
||||
assert db_client.connect()
|
||||
|
||||
return computer, web_server, db_server
|
||||
|
||||
|
||||
def test_web_client_requests_users(web_client_web_server_database):
|
||||
computer, web_server, db_server = web_client_web_server_database
|
||||
|
||||
web_browser: WebBrowser = computer.software_manager.software.get("WebBrowser")
|
||||
|
||||
assert web_browser.get_webpage()
|
||||
@@ -1,18 +1,140 @@
|
||||
"""Test the account module of the simulator."""
|
||||
import pytest
|
||||
|
||||
from primaite.simulator.domain.account import Account, AccountType
|
||||
|
||||
|
||||
def test_account_serialise():
|
||||
@pytest.fixture(scope="function")
|
||||
def account() -> Account:
|
||||
acct = Account(username="Jake", password="totally_hashed_password", account_type=AccountType.USER)
|
||||
acct.set_original_state()
|
||||
return acct
|
||||
|
||||
|
||||
def test_original_state(account):
|
||||
"""Test the original state - see if it resets properly"""
|
||||
account.log_on()
|
||||
account.log_off()
|
||||
account.disable()
|
||||
|
||||
state = account.describe_state()
|
||||
assert state["num_logons"] is 1
|
||||
assert state["num_logoffs"] is 1
|
||||
assert state["num_group_changes"] is 0
|
||||
assert state["username"] is "Jake"
|
||||
assert state["password"] is "totally_hashed_password"
|
||||
assert state["account_type"] is AccountType.USER.value
|
||||
assert state["enabled"] is False
|
||||
|
||||
account.reset_component_for_episode(episode=1)
|
||||
state = account.describe_state()
|
||||
assert state["num_logons"] is 0
|
||||
assert state["num_logoffs"] is 0
|
||||
assert state["num_group_changes"] is 0
|
||||
assert state["username"] is "Jake"
|
||||
assert state["password"] is "totally_hashed_password"
|
||||
assert state["account_type"] is AccountType.USER.value
|
||||
assert state["enabled"] is True
|
||||
|
||||
account.log_on()
|
||||
account.log_off()
|
||||
account.disable()
|
||||
account.set_original_state()
|
||||
|
||||
account.log_on()
|
||||
state = account.describe_state()
|
||||
assert state["num_logons"] is 2
|
||||
|
||||
account.reset_component_for_episode(episode=2)
|
||||
state = account.describe_state()
|
||||
assert state["num_logons"] is 1
|
||||
assert state["num_logoffs"] is 1
|
||||
assert state["num_group_changes"] is 0
|
||||
assert state["username"] is "Jake"
|
||||
assert state["password"] is "totally_hashed_password"
|
||||
assert state["account_type"] is AccountType.USER.value
|
||||
assert state["enabled"] is False
|
||||
|
||||
|
||||
def test_enable(account):
|
||||
"""Should enable the account."""
|
||||
account.enabled = False
|
||||
account.enable()
|
||||
assert account.enabled is True
|
||||
|
||||
|
||||
def test_disable(account):
|
||||
"""Should disable the account."""
|
||||
account.enabled = True
|
||||
account.disable()
|
||||
assert account.enabled is False
|
||||
|
||||
|
||||
def test_log_on_increments(account):
|
||||
"""Should increase the log on value by 1."""
|
||||
account.num_logons = 0
|
||||
account.log_on()
|
||||
assert account.num_logons is 1
|
||||
|
||||
|
||||
def test_log_off_increments(account):
|
||||
"""Should increase the log on value by 1."""
|
||||
account.num_logoffs = 0
|
||||
account.log_off()
|
||||
assert account.num_logoffs is 1
|
||||
|
||||
|
||||
def test_account_serialise(account):
|
||||
"""Test that an account can be serialised. If pydantic throws error then this test fails."""
|
||||
acct = Account(username="Jake", password="JakePass1!", account_type=AccountType.USER)
|
||||
serialised = acct.model_dump_json()
|
||||
serialised = account.model_dump_json()
|
||||
print(serialised)
|
||||
|
||||
|
||||
def test_account_deserialise():
|
||||
def test_account_deserialise(account):
|
||||
"""Test that an account can be deserialised. The test fails if pydantic throws an error."""
|
||||
acct_json = (
|
||||
'{"uuid":"dfb2bcaa-d3a1-48fd-af3f-c943354622b4","num_logons":0,"num_logoffs":0,"num_group_changes":0,'
|
||||
'"username":"Jake","password":"JakePass1!","account_type":2,"status":2,"request_manager":null}'
|
||||
'"username":"Jake","password":"totally_hashed_password","account_type":2,"status":2,"request_manager":null}'
|
||||
)
|
||||
acct = Account.model_validate_json(acct_json)
|
||||
assert Account.model_validate_json(acct_json)
|
||||
|
||||
|
||||
def test_describe_state(account):
|
||||
state = account.describe_state()
|
||||
assert state["num_logons"] is 0
|
||||
assert state["num_logoffs"] is 0
|
||||
assert state["num_group_changes"] is 0
|
||||
assert state["username"] is "Jake"
|
||||
assert state["password"] is "totally_hashed_password"
|
||||
assert state["account_type"] is AccountType.USER.value
|
||||
assert state["enabled"] is True
|
||||
|
||||
account.log_on()
|
||||
state = account.describe_state()
|
||||
assert state["num_logons"] is 1
|
||||
assert state["num_logoffs"] is 0
|
||||
assert state["num_group_changes"] is 0
|
||||
assert state["username"] is "Jake"
|
||||
assert state["password"] is "totally_hashed_password"
|
||||
assert state["account_type"] is AccountType.USER.value
|
||||
assert state["enabled"] is True
|
||||
|
||||
account.log_off()
|
||||
state = account.describe_state()
|
||||
assert state["num_logons"] is 1
|
||||
assert state["num_logoffs"] is 1
|
||||
assert state["num_group_changes"] is 0
|
||||
assert state["username"] is "Jake"
|
||||
assert state["password"] is "totally_hashed_password"
|
||||
assert state["account_type"] is AccountType.USER.value
|
||||
assert state["enabled"] is True
|
||||
|
||||
account.disable()
|
||||
state = account.describe_state()
|
||||
assert state["num_logons"] is 1
|
||||
assert state["num_logoffs"] is 1
|
||||
assert state["num_group_changes"] is 0
|
||||
assert state["username"] is "Jake"
|
||||
assert state["password"] is "totally_hashed_password"
|
||||
assert state["account_type"] is AccountType.USER.value
|
||||
assert state["enabled"] is False
|
||||
|
||||
@@ -185,6 +185,38 @@ def test_get_file(file_system):
|
||||
file_system.show(full=True)
|
||||
|
||||
|
||||
def test_reset_file_system(file_system):
|
||||
# file and folder that existed originally
|
||||
file_system.create_file(file_name="test_file.zip")
|
||||
file_system.create_folder(folder_name="test_folder")
|
||||
file_system.set_original_state()
|
||||
|
||||
# create a new file
|
||||
file_system.create_file(file_name="new_file.txt")
|
||||
|
||||
# create a new folder
|
||||
file_system.create_folder(folder_name="new_folder")
|
||||
|
||||
# delete the file that existed originally
|
||||
file_system.delete_file(folder_name="root", file_name="test_file.zip")
|
||||
assert file_system.get_file(folder_name="root", file_name="test_file.zip") is None
|
||||
|
||||
# delete the folder that existed originally
|
||||
file_system.delete_folder(folder_name="test_folder")
|
||||
assert file_system.get_folder(folder_name="test_folder") is None
|
||||
|
||||
# reset
|
||||
file_system.reset_component_for_episode(episode=1)
|
||||
|
||||
# deleted original file and folder should be back
|
||||
assert file_system.get_file(folder_name="root", file_name="test_file.zip")
|
||||
assert file_system.get_folder(folder_name="test_folder")
|
||||
|
||||
# new file and folder should be removed
|
||||
assert file_system.get_file(folder_name="root", file_name="new_file.txt") is None
|
||||
assert file_system.get_folder(folder_name="new_folder") is None
|
||||
|
||||
|
||||
@pytest.mark.skip(reason="Skipping until we tackle serialisation")
|
||||
def test_serialisation(file_system):
|
||||
"""Test to check that the object serialisation works correctly."""
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import pytest
|
||||
|
||||
from primaite.simulator.network.hardware.node_operating_state import NodeOperatingState
|
||||
from primaite.simulator.network.hardware.nodes.switch import Switch
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def switch() -> Switch:
|
||||
switch: Switch = Switch(hostname="switch_1", num_ports=8, operating_state=NodeOperatingState.ON)
|
||||
switch.show()
|
||||
return switch
|
||||
|
||||
|
||||
def test_describe_state(switch):
|
||||
state = switch.describe_state()
|
||||
assert len(state.get("ports")) is 8
|
||||
assert state.get("num_ports") is 8
|
||||
@@ -3,6 +3,66 @@ import json
|
||||
import pytest
|
||||
|
||||
from primaite.simulator.network.container import Network
|
||||
from primaite.simulator.network.hardware.base import Link, Node
|
||||
from primaite.simulator.network.hardware.node_operating_state import NodeOperatingState
|
||||
from primaite.simulator.network.hardware.nodes.computer import Computer
|
||||
from primaite.simulator.system.applications.database_client import DatabaseClient
|
||||
from primaite.simulator.system.services.database.database_service import DatabaseService
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def network(example_network) -> Network:
|
||||
assert len(example_network.routers) is 1
|
||||
assert len(example_network.switches) is 2
|
||||
assert len(example_network.computers) is 2
|
||||
assert len(example_network.servers) is 2
|
||||
|
||||
example_network.set_original_state()
|
||||
example_network.show()
|
||||
|
||||
return example_network
|
||||
|
||||
|
||||
def test_describe_state(network):
|
||||
"""Test that describe state works."""
|
||||
state = network.describe_state()
|
||||
|
||||
assert len(state["nodes"]) is 7
|
||||
assert len(state["links"]) is 6
|
||||
|
||||
|
||||
def test_reset_network(network):
|
||||
"""
|
||||
Test that the network is properly reset.
|
||||
|
||||
TODO: make sure that once implemented - any installed/uninstalled services, processes, apps,
|
||||
etc are also removed/reinstalled
|
||||
|
||||
"""
|
||||
state_before = network.describe_state()
|
||||
|
||||
client_1: Computer = network.get_node_by_hostname("client_1")
|
||||
server_1: Computer = network.get_node_by_hostname("server_1")
|
||||
|
||||
assert client_1.operating_state is NodeOperatingState.ON
|
||||
assert server_1.operating_state is NodeOperatingState.ON
|
||||
|
||||
client_1.power_off()
|
||||
assert client_1.operating_state is NodeOperatingState.SHUTTING_DOWN
|
||||
|
||||
server_1.power_off()
|
||||
assert server_1.operating_state is NodeOperatingState.SHUTTING_DOWN
|
||||
|
||||
assert network.describe_state() != state_before
|
||||
|
||||
network.reset_component_for_episode(episode=1)
|
||||
|
||||
assert client_1.operating_state is NodeOperatingState.ON
|
||||
assert server_1.operating_state is NodeOperatingState.ON
|
||||
|
||||
assert json.dumps(network.describe_state(), sort_keys=True, indent=2) == json.dumps(
|
||||
state_before, sort_keys=True, indent=2
|
||||
)
|
||||
|
||||
|
||||
def test_creating_container():
|
||||
@@ -10,11 +70,50 @@ def test_creating_container():
|
||||
net = Network()
|
||||
assert net.nodes == {}
|
||||
assert net.links == {}
|
||||
net.show()
|
||||
|
||||
|
||||
@pytest.mark.skip(reason="Skipping until we tackle serialisation")
|
||||
def test_describe_state():
|
||||
"""Check that we can describe network state without raising errors, and that the result is JSON serialisable."""
|
||||
net = Network()
|
||||
state = net.describe_state()
|
||||
json.dumps(state) # if this function call raises an error, the test fails, state was not JSON-serialisable
|
||||
def test_apply_timestep_to_nodes(network):
|
||||
"""Calling apply_timestep on the network should apply to the nodes within it."""
|
||||
client_1: Computer = network.get_node_by_hostname("client_1")
|
||||
assert client_1.operating_state is NodeOperatingState.ON
|
||||
|
||||
client_1.power_off()
|
||||
assert client_1.operating_state is NodeOperatingState.SHUTTING_DOWN
|
||||
|
||||
for i in range(client_1.shut_down_duration + 1):
|
||||
network.apply_timestep(timestep=i)
|
||||
|
||||
assert client_1.operating_state is NodeOperatingState.OFF
|
||||
|
||||
network.apply_timestep(client_1.shut_down_duration + 2)
|
||||
assert client_1.operating_state is NodeOperatingState.OFF
|
||||
|
||||
|
||||
def test_removing_node_that_does_not_exist(network):
|
||||
"""Node that does not exist on network should not affect existing nodes."""
|
||||
assert len(network.nodes) is 7
|
||||
|
||||
network.remove_node(Node(hostname="new_node"))
|
||||
assert len(network.nodes) is 7
|
||||
|
||||
|
||||
def test_remove_node(network):
|
||||
"""Remove node should remove the correct node."""
|
||||
assert len(network.nodes) is 7
|
||||
|
||||
client_1: Computer = network.get_node_by_hostname("client_1")
|
||||
network.remove_node(client_1)
|
||||
|
||||
assert network.get_node_by_hostname("client_1") is None
|
||||
assert len(network.nodes) is 6
|
||||
|
||||
|
||||
def test_remove_link(network):
|
||||
"""Remove link should remove the correct link."""
|
||||
assert len(network.links) is 6
|
||||
link: Link = network.links.get(next(iter(network.links)))
|
||||
|
||||
network.remove_link(link)
|
||||
assert len(network.links) is 5
|
||||
assert network.links.get(link.uuid) is None
|
||||
|
||||
11
tests/unit_tests/_primaite/_simulator/_network/test_utils.py
Normal file
11
tests/unit_tests/_primaite/_simulator/_network/test_utils.py
Normal file
@@ -0,0 +1,11 @@
|
||||
from primaite.simulator.network.utils import convert_bytes_to_megabits, convert_megabits_to_bytes
|
||||
|
||||
|
||||
def test_convert_bytes_to_megabits():
|
||||
assert round(convert_bytes_to_megabits(B=131072), 5) == float(1)
|
||||
assert round(convert_bytes_to_megabits(B=69420), 5) == float(0.52963)
|
||||
|
||||
|
||||
def test_convert_megabits_to_bytes():
|
||||
assert round(convert_megabits_to_bytes(Mbits=1), 5) == float(131072)
|
||||
assert round(convert_megabits_to_bytes(Mbits=float(0.52963)), 5) == float(69419.66336)
|
||||
@@ -0,0 +1,122 @@
|
||||
from ipaddress import IPv4Address
|
||||
from typing import Tuple, Union
|
||||
|
||||
import pytest
|
||||
|
||||
from primaite.simulator.network.hardware.node_operating_state import NodeOperatingState
|
||||
from primaite.simulator.network.hardware.nodes.computer import Computer
|
||||
from primaite.simulator.system.applications.application import ApplicationOperatingState
|
||||
from primaite.simulator.system.applications.database_client import DatabaseClient
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def database_client_on_computer() -> Tuple[DatabaseClient, Computer]:
|
||||
computer = Computer(
|
||||
hostname="db_node", ip_address="192.168.0.1", subnet_mask="255.255.255.0", operating_state=NodeOperatingState.ON
|
||||
)
|
||||
computer.software_manager.install(DatabaseClient)
|
||||
|
||||
database_client: DatabaseClient = computer.software_manager.software.get("DatabaseClient")
|
||||
database_client.configure(server_ip_address=IPv4Address("192.168.0.1"))
|
||||
database_client.run()
|
||||
return database_client, computer
|
||||
|
||||
|
||||
def test_creation(database_client_on_computer):
|
||||
database_client, computer = database_client_on_computer
|
||||
database_client.describe_state()
|
||||
|
||||
|
||||
def test_connect_when_client_is_closed(database_client_on_computer):
|
||||
"""Database client should not connect when it is not running."""
|
||||
database_client, computer = database_client_on_computer
|
||||
|
||||
database_client.close()
|
||||
assert database_client.operating_state is ApplicationOperatingState.CLOSED
|
||||
|
||||
assert database_client.connect() is False
|
||||
|
||||
|
||||
def test_connect_to_database_fails_on_reattempt(database_client_on_computer):
|
||||
"""Database client should return False when the attempt to connect fails."""
|
||||
database_client, computer = database_client_on_computer
|
||||
|
||||
database_client.connected = False
|
||||
assert database_client._connect(server_ip_address=IPv4Address("192.168.0.1"), is_reattempt=True) is False
|
||||
|
||||
|
||||
def test_disconnect_when_client_is_closed(database_client_on_computer):
|
||||
"""Database client disconnect should not do anything when it is not running."""
|
||||
database_client, computer = database_client_on_computer
|
||||
|
||||
database_client.connected = True
|
||||
assert database_client.server_ip_address is not None
|
||||
|
||||
database_client.close()
|
||||
assert database_client.operating_state is ApplicationOperatingState.CLOSED
|
||||
|
||||
database_client.disconnect()
|
||||
|
||||
assert database_client.connected is True
|
||||
assert database_client.server_ip_address is not None
|
||||
|
||||
|
||||
def test_disconnect(database_client_on_computer):
|
||||
"""Database client should set connected to False and remove the database server ip address."""
|
||||
database_client, computer = database_client_on_computer
|
||||
|
||||
database_client.connected = True
|
||||
|
||||
assert database_client.operating_state is ApplicationOperatingState.RUNNING
|
||||
assert database_client.server_ip_address is not None
|
||||
|
||||
database_client.disconnect()
|
||||
|
||||
assert database_client.connected is False
|
||||
assert database_client.server_ip_address is None
|
||||
|
||||
|
||||
def test_query_when_client_is_closed(database_client_on_computer):
|
||||
"""Database client should return False when it is not running."""
|
||||
database_client, computer = database_client_on_computer
|
||||
|
||||
database_client.close()
|
||||
assert database_client.operating_state is ApplicationOperatingState.CLOSED
|
||||
|
||||
assert database_client.query(sql="test") is False
|
||||
|
||||
|
||||
def test_query_failed_reattempt(database_client_on_computer):
|
||||
"""Database client query should return False if the reattempt fails."""
|
||||
database_client, computer = database_client_on_computer
|
||||
|
||||
def return_false():
|
||||
return False
|
||||
|
||||
database_client.connect = return_false
|
||||
|
||||
database_client.connected = False
|
||||
assert database_client.query(sql="test", is_reattempt=True) is False
|
||||
|
||||
|
||||
def test_query_fail_to_connect(database_client_on_computer):
|
||||
"""Database client query should return False if the connect attempt fails."""
|
||||
database_client, computer = database_client_on_computer
|
||||
|
||||
def return_false():
|
||||
return False
|
||||
|
||||
database_client.connect = return_false
|
||||
database_client.connected = False
|
||||
|
||||
assert database_client.query(sql="test") is False
|
||||
|
||||
|
||||
def test_client_receives_response_when_closed(database_client_on_computer):
|
||||
"""Database client receive should return False when it is closed."""
|
||||
database_client, computer = database_client_on_computer
|
||||
|
||||
database_client.close()
|
||||
assert database_client.operating_state is ApplicationOperatingState.CLOSED
|
||||
|
||||
database_client.receive(payload={}, session_id="")
|
||||
@@ -1,39 +1,66 @@
|
||||
from typing import Tuple
|
||||
|
||||
import pytest
|
||||
|
||||
from primaite.simulator.network.hardware.node_operating_state import NodeOperatingState
|
||||
from primaite.simulator.network.hardware.nodes.computer import Computer
|
||||
from primaite.simulator.network.protocols.http import HttpResponsePacket, HttpStatusCode
|
||||
from primaite.simulator.network.transmission.network_layer import IPProtocol
|
||||
from primaite.simulator.network.transmission.transport_layer import Port
|
||||
from primaite.simulator.system.applications.application import ApplicationOperatingState
|
||||
from primaite.simulator.system.applications.web_browser import WebBrowser
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def web_client() -> Computer:
|
||||
node = Computer(
|
||||
hostname="web_client", ip_address="192.168.1.11", subnet_mask="255.255.255.0", default_gateway="192.168.1.1"
|
||||
def web_browser() -> WebBrowser:
|
||||
computer = Computer(
|
||||
hostname="web_client",
|
||||
ip_address="192.168.1.11",
|
||||
subnet_mask="255.255.255.0",
|
||||
default_gateway="192.168.1.1",
|
||||
operating_state=NodeOperatingState.ON,
|
||||
)
|
||||
return node
|
||||
# Web Browser should be pre-installed in computer
|
||||
web_browser: WebBrowser = computer.software_manager.software.get("WebBrowser")
|
||||
web_browser.run()
|
||||
assert web_browser.operating_state is ApplicationOperatingState.RUNNING
|
||||
return web_browser
|
||||
|
||||
|
||||
def test_create_web_client(web_client):
|
||||
assert web_client is not None
|
||||
web_browser: WebBrowser = web_client.software_manager.software["WebBrowser"]
|
||||
def test_create_web_client():
|
||||
computer = Computer(
|
||||
hostname="web_client",
|
||||
ip_address="192.168.1.11",
|
||||
subnet_mask="255.255.255.0",
|
||||
default_gateway="192.168.1.1",
|
||||
operating_state=NodeOperatingState.ON,
|
||||
)
|
||||
# Web Browser should be pre-installed in computer
|
||||
web_browser: WebBrowser = computer.software_manager.software.get("WebBrowser")
|
||||
assert web_browser.name is "WebBrowser"
|
||||
assert web_browser.port is Port.HTTP
|
||||
assert web_browser.protocol is IPProtocol.TCP
|
||||
|
||||
|
||||
def test_receive_invalid_payload(web_client):
|
||||
web_browser: WebBrowser = web_client.software_manager.software["WebBrowser"]
|
||||
|
||||
def test_receive_invalid_payload(web_browser):
|
||||
assert web_browser.receive(payload={}) is False
|
||||
|
||||
|
||||
def test_receive_payload(web_client):
|
||||
def test_receive_payload(web_browser):
|
||||
payload = HttpResponsePacket(status_code=HttpStatusCode.OK)
|
||||
web_browser: WebBrowser = web_client.software_manager.software["WebBrowser"]
|
||||
assert web_browser.latest_response is None
|
||||
|
||||
web_browser.receive(payload=payload)
|
||||
|
||||
assert web_browser.latest_response is not None
|
||||
|
||||
|
||||
def test_invalid_target_url(web_browser):
|
||||
# none value target url
|
||||
web_browser.target_url = None
|
||||
assert web_browser.get_webpage() is False
|
||||
|
||||
|
||||
def test_non_existent_target_url(web_browser):
|
||||
web_browser.target_url = "http://192.168.255.255"
|
||||
assert web_browser.get_webpage() is False
|
||||
|
||||
@@ -19,11 +19,11 @@ def dm_client() -> Node:
|
||||
|
||||
@pytest.fixture
|
||||
def dm_bot(dm_client) -> DataManipulationBot:
|
||||
return dm_client.software_manager.software["DataManipulationBot"]
|
||||
return dm_client.software_manager.software.get("DataManipulationBot")
|
||||
|
||||
|
||||
def test_create_dm_bot(dm_client):
|
||||
data_manipulation_bot: DataManipulationBot = dm_client.software_manager.software["DataManipulationBot"]
|
||||
data_manipulation_bot: DataManipulationBot = dm_client.software_manager.software.get("DataManipulationBot")
|
||||
|
||||
assert data_manipulation_bot.name == "DataManipulationBot"
|
||||
assert data_manipulation_bot.port == Port.POSTGRES_SERVER
|
||||
|
||||
@@ -8,7 +8,7 @@ from primaite.simulator.system.services.database.database_service import Databas
|
||||
def database_server() -> Node:
|
||||
node = Node(hostname="db_node")
|
||||
node.software_manager.install(DatabaseService)
|
||||
node.software_manager.software["DatabaseService"].start()
|
||||
node.software_manager.software.get("DatabaseService").start()
|
||||
return node
|
||||
|
||||
|
||||
|
||||
@@ -5,28 +5,13 @@ import pytest
|
||||
from primaite.simulator.network.hardware.base import Node
|
||||
from primaite.simulator.network.hardware.node_operating_state import NodeOperatingState
|
||||
from primaite.simulator.network.hardware.nodes.computer import Computer
|
||||
from primaite.simulator.network.hardware.nodes.server import Server
|
||||
from primaite.simulator.network.protocols.dns import DNSPacket, DNSReply, DNSRequest
|
||||
from primaite.simulator.network.transmission.network_layer import IPProtocol
|
||||
from primaite.simulator.network.transmission.transport_layer import Port
|
||||
from primaite.simulator.system.services.dns.dns_client import DNSClient
|
||||
from primaite.simulator.system.services.dns.dns_server import DNSServer
|
||||
from primaite.simulator.system.services.service import ServiceOperatingState
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def dns_server() -> Node:
|
||||
node = Server(
|
||||
hostname="dns_server",
|
||||
ip_address="192.168.1.10",
|
||||
subnet_mask="255.255.255.0",
|
||||
default_gateway="192.168.1.1",
|
||||
operating_state=NodeOperatingState.ON,
|
||||
)
|
||||
node.software_manager.install(software_class=DNSServer)
|
||||
return node
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def dns_client() -> Node:
|
||||
node = Computer(
|
||||
@@ -39,24 +24,16 @@ def dns_client() -> Node:
|
||||
return node
|
||||
|
||||
|
||||
def test_create_dns_server(dns_server):
|
||||
assert dns_server is not None
|
||||
dns_server_service: DNSServer = dns_server.software_manager.software["DNSServer"]
|
||||
assert dns_server_service.name is "DNSServer"
|
||||
assert dns_server_service.port is Port.DNS
|
||||
assert dns_server_service.protocol is IPProtocol.TCP
|
||||
|
||||
|
||||
def test_create_dns_client(dns_client):
|
||||
assert dns_client is not None
|
||||
dns_client_service: DNSClient = dns_client.software_manager.software["DNSClient"]
|
||||
dns_client_service: DNSClient = dns_client.software_manager.software.get("DNSClient")
|
||||
assert dns_client_service.name is "DNSClient"
|
||||
assert dns_client_service.port is Port.DNS
|
||||
assert dns_client_service.protocol is IPProtocol.TCP
|
||||
|
||||
|
||||
def test_dns_client_add_domain_to_cache_when_not_running(dns_client):
|
||||
dns_client_service: DNSClient = dns_client.software_manager.software["DNSClient"]
|
||||
dns_client_service: DNSClient = dns_client.software_manager.software.get("DNSClient")
|
||||
assert dns_client.operating_state is NodeOperatingState.OFF
|
||||
assert dns_client_service.operating_state is ServiceOperatingState.STOPPED
|
||||
|
||||
@@ -69,7 +46,7 @@ def test_dns_client_add_domain_to_cache_when_not_running(dns_client):
|
||||
|
||||
def test_dns_client_check_domain_exists_when_not_running(dns_client):
|
||||
dns_client.operating_state = NodeOperatingState.ON
|
||||
dns_client_service: DNSClient = dns_client.software_manager.software["DNSClient"]
|
||||
dns_client_service: DNSClient = dns_client.software_manager.software.get("DNSClient")
|
||||
dns_client_service.start()
|
||||
|
||||
assert dns_client.operating_state is NodeOperatingState.ON
|
||||
@@ -93,22 +70,10 @@ def test_dns_client_check_domain_exists_when_not_running(dns_client):
|
||||
assert dns_client_service.check_domain_exists("test.com") is False
|
||||
|
||||
|
||||
def test_dns_server_domain_name_registration(dns_server):
|
||||
"""Test to check if the domain name registration works."""
|
||||
dns_server_service: DNSServer = dns_server.software_manager.software["DNSServer"]
|
||||
|
||||
# register the web server in the domain controller
|
||||
dns_server_service.dns_register(domain_name="real-domain.com", domain_ip_address=IPv4Address("192.168.1.12"))
|
||||
|
||||
# return none for an unknown domain
|
||||
assert dns_server_service.dns_lookup("fake-domain.com") is None
|
||||
assert dns_server_service.dns_lookup("real-domain.com") is not None
|
||||
|
||||
|
||||
def test_dns_client_check_domain_in_cache(dns_client):
|
||||
"""Test to make sure that the check_domain_in_cache returns the correct values."""
|
||||
dns_client.operating_state = NodeOperatingState.ON
|
||||
dns_client_service: DNSClient = dns_client.software_manager.software["DNSClient"]
|
||||
dns_client_service: DNSClient = dns_client.software_manager.software.get("DNSClient")
|
||||
dns_client_service.start()
|
||||
|
||||
# add a domain to the dns client cache
|
||||
@@ -118,29 +83,9 @@ def test_dns_client_check_domain_in_cache(dns_client):
|
||||
assert dns_client_service.check_domain_exists("real-domain.com") is True
|
||||
|
||||
|
||||
def test_dns_server_receive(dns_server):
|
||||
"""Test to make sure that the DNS Server correctly responds to a DNS Client request."""
|
||||
dns_server_service: DNSServer = dns_server.software_manager.software["DNSServer"]
|
||||
|
||||
# register the web server in the domain controller
|
||||
dns_server_service.dns_register(domain_name="real-domain.com", domain_ip_address=IPv4Address("192.168.1.12"))
|
||||
|
||||
assert (
|
||||
dns_server_service.receive(payload=DNSPacket(dns_request=DNSRequest(domain_name_request="fake-domain.com")))
|
||||
is False
|
||||
)
|
||||
|
||||
assert (
|
||||
dns_server_service.receive(payload=DNSPacket(dns_request=DNSRequest(domain_name_request="real-domain.com")))
|
||||
is True
|
||||
)
|
||||
|
||||
dns_server_service.show()
|
||||
|
||||
|
||||
def test_dns_client_receive(dns_client):
|
||||
"""Test to make sure the DNS Client knows how to deal with request responses."""
|
||||
dns_client_service: DNSClient = dns_client.software_manager.software["DNSClient"]
|
||||
dns_client_service: DNSClient = dns_client.software_manager.software.get("DNSClient")
|
||||
|
||||
dns_client_service.receive(
|
||||
payload=DNSPacket(
|
||||
@@ -151,3 +96,9 @@ def test_dns_client_receive(dns_client):
|
||||
|
||||
# domain name should be saved to cache
|
||||
assert dns_client_service.dns_cache["real-domain.com"] == IPv4Address("192.168.1.12")
|
||||
|
||||
|
||||
def test_dns_client_receive_non_dns_payload(dns_client):
|
||||
dns_client_service: DNSClient = dns_client.software_manager.software.get("DNSClient")
|
||||
|
||||
assert dns_client_service.receive(payload=None) is False
|
||||
@@ -0,0 +1,64 @@
|
||||
from ipaddress import IPv4Address
|
||||
|
||||
import pytest
|
||||
|
||||
from primaite.simulator.network.hardware.base import Node
|
||||
from primaite.simulator.network.hardware.node_operating_state import NodeOperatingState
|
||||
from primaite.simulator.network.hardware.nodes.server import Server
|
||||
from primaite.simulator.network.protocols.dns import DNSPacket, DNSRequest
|
||||
from primaite.simulator.network.transmission.network_layer import IPProtocol
|
||||
from primaite.simulator.network.transmission.transport_layer import Port
|
||||
from primaite.simulator.system.services.dns.dns_server import DNSServer
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def dns_server() -> Node:
|
||||
node = Server(
|
||||
hostname="dns_server",
|
||||
ip_address="192.168.1.10",
|
||||
subnet_mask="255.255.255.0",
|
||||
default_gateway="192.168.1.1",
|
||||
operating_state=NodeOperatingState.ON,
|
||||
)
|
||||
node.software_manager.install(software_class=DNSServer)
|
||||
return node
|
||||
|
||||
|
||||
def test_create_dns_server(dns_server):
|
||||
assert dns_server is not None
|
||||
dns_server_service: DNSServer = dns_server.software_manager.software.get("DNSServer")
|
||||
assert dns_server_service.name is "DNSServer"
|
||||
assert dns_server_service.port is Port.DNS
|
||||
assert dns_server_service.protocol is IPProtocol.TCP
|
||||
|
||||
|
||||
def test_dns_server_domain_name_registration(dns_server):
|
||||
"""Test to check if the domain name registration works."""
|
||||
dns_server_service: DNSServer = dns_server.software_manager.software.get("DNSServer")
|
||||
|
||||
# register the web server in the domain controller
|
||||
dns_server_service.dns_register(domain_name="real-domain.com", domain_ip_address=IPv4Address("192.168.1.12"))
|
||||
|
||||
# return none for an unknown domain
|
||||
assert dns_server_service.dns_lookup("fake-domain.com") is None
|
||||
assert dns_server_service.dns_lookup("real-domain.com") is not None
|
||||
|
||||
|
||||
def test_dns_server_receive(dns_server):
|
||||
"""Test to make sure that the DNS Server correctly responds to a DNS Client request."""
|
||||
dns_server_service: DNSServer = dns_server.software_manager.software.get("DNSServer")
|
||||
|
||||
# register the web server in the domain controller
|
||||
dns_server_service.dns_register(domain_name="real-domain.com", domain_ip_address=IPv4Address("192.168.1.12"))
|
||||
|
||||
assert (
|
||||
dns_server_service.receive(payload=DNSPacket(dns_request=DNSRequest(domain_name_request="fake-domain.com")))
|
||||
is False
|
||||
)
|
||||
|
||||
assert (
|
||||
dns_server_service.receive(payload=DNSPacket(dns_request=DNSRequest(domain_name_request="real-domain.com")))
|
||||
is True
|
||||
)
|
||||
|
||||
dns_server_service.show()
|
||||
@@ -0,0 +1,122 @@
|
||||
from ipaddress import IPv4Address
|
||||
|
||||
import pytest
|
||||
|
||||
from primaite.simulator.network.hardware.base import Node
|
||||
from primaite.simulator.network.hardware.node_operating_state import NodeOperatingState
|
||||
from primaite.simulator.network.hardware.nodes.computer import Computer
|
||||
from primaite.simulator.network.protocols.ftp import FTPCommand, FTPPacket, FTPStatusCode
|
||||
from primaite.simulator.network.transmission.network_layer import IPProtocol
|
||||
from primaite.simulator.network.transmission.transport_layer import Port
|
||||
from primaite.simulator.system.services.ftp.ftp_client import FTPClient
|
||||
from primaite.simulator.system.services.service import ServiceOperatingState
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def ftp_client() -> Node:
|
||||
node = Computer(
|
||||
hostname="ftp_client",
|
||||
ip_address="192.168.1.11",
|
||||
subnet_mask="255.255.255.0",
|
||||
default_gateway="192.168.1.1",
|
||||
operating_state=NodeOperatingState.ON,
|
||||
)
|
||||
return node
|
||||
|
||||
|
||||
def test_create_ftp_client(ftp_client):
|
||||
assert ftp_client is not None
|
||||
ftp_client_service: FTPClient = ftp_client.software_manager.software.get("FTPClient")
|
||||
assert ftp_client_service.name is "FTPClient"
|
||||
assert ftp_client_service.port is Port.FTP
|
||||
assert ftp_client_service.protocol is IPProtocol.TCP
|
||||
|
||||
|
||||
def test_ftp_client_store_file(ftp_client):
|
||||
"""Test to make sure the FTP Client knows how to deal with request responses."""
|
||||
assert ftp_client.file_system.get_file(folder_name="downloads", file_name="file.txt") is None
|
||||
|
||||
response: FTPPacket = FTPPacket(
|
||||
ftp_command=FTPCommand.STOR,
|
||||
ftp_command_args={
|
||||
"dest_folder_name": "downloads",
|
||||
"dest_file_name": "file.txt",
|
||||
"file_size": 24,
|
||||
},
|
||||
packet_payload_size=24,
|
||||
status_code=FTPStatusCode.OK,
|
||||
)
|
||||
|
||||
ftp_client_service: FTPClient = ftp_client.software_manager.software.get("FTPClient")
|
||||
ftp_client_service.receive(response)
|
||||
|
||||
assert ftp_client.file_system.get_file(folder_name="downloads", file_name="file.txt")
|
||||
|
||||
|
||||
def test_ftp_should_not_process_commands_if_service_not_running(ftp_client):
|
||||
"""Method _process_ftp_command should return false if service is not running."""
|
||||
payload: FTPPacket = FTPPacket(
|
||||
ftp_command=FTPCommand.PORT,
|
||||
ftp_command_args=Port.FTP,
|
||||
status_code=FTPStatusCode.OK,
|
||||
)
|
||||
|
||||
ftp_client_service: FTPClient = ftp_client.software_manager.software.get("FTPClient")
|
||||
ftp_client_service.stop()
|
||||
assert ftp_client_service.operating_state is ServiceOperatingState.STOPPED
|
||||
assert ftp_client_service._process_ftp_command(payload=payload).status_code is FTPStatusCode.ERROR
|
||||
|
||||
|
||||
def test_ftp_tries_to_senf_file__that_does_not_exist(ftp_client):
|
||||
"""Method send_file should return false if no file to send."""
|
||||
assert ftp_client.file_system.get_file(folder_name="root", file_name="test.txt") is None
|
||||
|
||||
ftp_client_service: FTPClient = ftp_client.software_manager.software.get("FTPClient")
|
||||
assert ftp_client_service.operating_state is ServiceOperatingState.RUNNING
|
||||
assert (
|
||||
ftp_client_service.send_file(
|
||||
dest_ip_address=IPv4Address("192.168.1.1"),
|
||||
src_folder_name="root",
|
||||
src_file_name="test.txt",
|
||||
dest_folder_name="root",
|
||||
dest_file_name="text.txt",
|
||||
)
|
||||
is False
|
||||
)
|
||||
|
||||
|
||||
def test_offline_ftp_client_receives_request(ftp_client):
|
||||
"""Receive should return false if the node the ftp client is installed on is offline."""
|
||||
ftp_client_service: FTPClient = ftp_client.software_manager.software.get("FTPClient")
|
||||
ftp_client.power_off()
|
||||
|
||||
for i in range(ftp_client.shut_down_duration + 1):
|
||||
ftp_client.apply_timestep(timestep=i)
|
||||
|
||||
assert ftp_client.operating_state is NodeOperatingState.OFF
|
||||
assert ftp_client_service.operating_state is ServiceOperatingState.STOPPED
|
||||
|
||||
payload: FTPPacket = FTPPacket(
|
||||
ftp_command=FTPCommand.PORT,
|
||||
ftp_command_args=Port.FTP,
|
||||
status_code=FTPStatusCode.OK,
|
||||
)
|
||||
|
||||
assert ftp_client_service.receive(payload=payload) is False
|
||||
|
||||
|
||||
def test_receive_should_fail_if_payload_is_not_ftp(ftp_client):
|
||||
"""Receive should return false if the node the ftp client is installed on is not an FTPPacket."""
|
||||
ftp_client_service: FTPClient = ftp_client.software_manager.software.get("FTPClient")
|
||||
assert ftp_client_service.receive(payload=None) is False
|
||||
|
||||
|
||||
def test_receive_should_ignore_payload_with_none_status_code(ftp_client):
|
||||
"""Receive should ignore payload with no set status code to prevent infinite send/receive loops."""
|
||||
payload: FTPPacket = FTPPacket(
|
||||
ftp_command=FTPCommand.PORT,
|
||||
ftp_command_args=Port.FTP,
|
||||
status_code=None,
|
||||
)
|
||||
ftp_client_service: FTPClient = ftp_client.software_manager.software.get("FTPClient")
|
||||
assert ftp_client_service.receive(payload=payload) is False
|
||||
@@ -1,16 +1,13 @@
|
||||
from ipaddress import IPv4Address
|
||||
|
||||
import pytest
|
||||
|
||||
from primaite.simulator.network.hardware.base import Node
|
||||
from primaite.simulator.network.hardware.node_operating_state import NodeOperatingState
|
||||
from primaite.simulator.network.hardware.nodes.computer import Computer
|
||||
from primaite.simulator.network.hardware.nodes.server import Server
|
||||
from primaite.simulator.network.protocols.ftp import FTPCommand, FTPPacket, FTPStatusCode
|
||||
from primaite.simulator.network.transmission.network_layer import IPProtocol
|
||||
from primaite.simulator.network.transmission.transport_layer import Port
|
||||
from primaite.simulator.system.services.ftp.ftp_client import FTPClient
|
||||
from primaite.simulator.system.services.ftp.ftp_server import FTPServer
|
||||
from primaite.simulator.system.services.service import ServiceOperatingState
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
@@ -26,34 +23,14 @@ def ftp_server() -> Node:
|
||||
return node
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def ftp_client() -> Node:
|
||||
node = Computer(
|
||||
hostname="ftp_client",
|
||||
ip_address="192.168.1.11",
|
||||
subnet_mask="255.255.255.0",
|
||||
default_gateway="192.168.1.1",
|
||||
operating_state=NodeOperatingState.ON,
|
||||
)
|
||||
return node
|
||||
|
||||
|
||||
def test_create_ftp_server(ftp_server):
|
||||
assert ftp_server is not None
|
||||
ftp_server_service: FTPServer = ftp_server.software_manager.software["FTPServer"]
|
||||
ftp_server_service: FTPServer = ftp_server.software_manager.software.get("FTPServer")
|
||||
assert ftp_server_service.name is "FTPServer"
|
||||
assert ftp_server_service.port is Port.FTP
|
||||
assert ftp_server_service.protocol is IPProtocol.TCP
|
||||
|
||||
|
||||
def test_create_ftp_client(ftp_client):
|
||||
assert ftp_client is not None
|
||||
ftp_client_service: FTPClient = ftp_client.software_manager.software["FTPClient"]
|
||||
assert ftp_client_service.name is "FTPClient"
|
||||
assert ftp_client_service.port is Port.FTP
|
||||
assert ftp_client_service.protocol is IPProtocol.TCP
|
||||
|
||||
|
||||
def test_ftp_server_store_file(ftp_server):
|
||||
"""Test to make sure the FTP Server knows how to deal with request responses."""
|
||||
assert ftp_server.file_system.get_file(folder_name="downloads", file_name="file.txt") is None
|
||||
@@ -68,16 +45,34 @@ def test_ftp_server_store_file(ftp_server):
|
||||
packet_payload_size=24,
|
||||
)
|
||||
|
||||
ftp_server_service: FTPServer = ftp_server.software_manager.software["FTPServer"]
|
||||
ftp_server_service: FTPServer = ftp_server.software_manager.software.get("FTPServer")
|
||||
ftp_server_service.receive(response)
|
||||
|
||||
assert ftp_server.file_system.get_file(folder_name="downloads", file_name="file.txt")
|
||||
|
||||
|
||||
def test_ftp_client_store_file(ftp_client):
|
||||
"""Test to make sure the FTP Client knows how to deal with request responses."""
|
||||
assert ftp_client.file_system.get_file(folder_name="downloads", file_name="file.txt") is None
|
||||
def test_ftp_server_should_send_error_if_port_arg_is_invalid(ftp_server):
|
||||
"""Should fail if the port command receives an invalid port."""
|
||||
payload: FTPPacket = FTPPacket(
|
||||
ftp_command=FTPCommand.PORT,
|
||||
ftp_command_args=None,
|
||||
packet_payload_size=24,
|
||||
)
|
||||
|
||||
ftp_server_service: FTPServer = ftp_server.software_manager.software.get("FTPServer")
|
||||
assert ftp_server_service._process_ftp_command(payload=payload).status_code is FTPStatusCode.ERROR
|
||||
|
||||
|
||||
def test_ftp_server_receives_non_ftp_packet(ftp_server):
|
||||
"""Receive should return false if the service receives a non ftp packet."""
|
||||
response: FTPPacket = None
|
||||
|
||||
ftp_server_service: FTPServer = ftp_server.software_manager.software.get("FTPServer")
|
||||
assert ftp_server_service.receive(response) is False
|
||||
|
||||
|
||||
def test_offline_ftp_server_receives_request(ftp_server):
|
||||
"""Receive should return false if the service is stopped."""
|
||||
response: FTPPacket = FTPPacket(
|
||||
ftp_command=FTPCommand.STOR,
|
||||
ftp_command_args={
|
||||
@@ -86,10 +81,9 @@ def test_ftp_client_store_file(ftp_client):
|
||||
"file_size": 24,
|
||||
},
|
||||
packet_payload_size=24,
|
||||
status_code=FTPStatusCode.OK,
|
||||
)
|
||||
|
||||
ftp_client_service: FTPClient = ftp_client.software_manager.software["FTPClient"]
|
||||
ftp_client_service.receive(response)
|
||||
|
||||
assert ftp_client.file_system.get_file(folder_name="downloads", file_name="file.txt")
|
||||
ftp_server_service: FTPServer = ftp_server.software_manager.software.get("FTPServer")
|
||||
ftp_server_service.stop()
|
||||
assert ftp_server_service.operating_state is ServiceOperatingState.STOPPED
|
||||
assert ftp_server_service.receive(response) is False
|
||||
@@ -18,13 +18,13 @@ def web_server() -> Server:
|
||||
hostname="web_server", ip_address="192.168.1.10", subnet_mask="255.255.255.0", default_gateway="192.168.1.1"
|
||||
)
|
||||
node.software_manager.install(software_class=WebServer)
|
||||
node.software_manager.software["WebServer"].start()
|
||||
node.software_manager.software.get("WebServer").start()
|
||||
return node
|
||||
|
||||
|
||||
def test_create_web_server(web_server):
|
||||
assert web_server is not None
|
||||
web_server_service: WebServer = web_server.software_manager.software["WebServer"]
|
||||
web_server_service: WebServer = web_server.software_manager.software.get("WebServer")
|
||||
assert web_server_service.name is "WebServer"
|
||||
assert web_server_service.port is Port.HTTP
|
||||
assert web_server_service.protocol is IPProtocol.TCP
|
||||
@@ -33,7 +33,7 @@ def test_create_web_server(web_server):
|
||||
def test_handling_get_request_not_found_path(web_server):
|
||||
payload = HttpRequestPacket(request_method=HttpRequestMethod.GET, request_url="http://domain.com/fake-path")
|
||||
|
||||
web_server_service: WebServer = web_server.software_manager.software["WebServer"]
|
||||
web_server_service: WebServer = web_server.software_manager.software.get("WebServer")
|
||||
|
||||
response: HttpResponsePacket = web_server_service._handle_get_request(payload=payload)
|
||||
assert response.status_code == HttpStatusCode.NOT_FOUND
|
||||
@@ -42,7 +42,7 @@ def test_handling_get_request_not_found_path(web_server):
|
||||
def test_handling_get_request_home_page(web_server):
|
||||
payload = HttpRequestPacket(request_method=HttpRequestMethod.GET, request_url="http://domain.com/")
|
||||
|
||||
web_server_service: WebServer = web_server.software_manager.software["WebServer"]
|
||||
web_server_service: WebServer = web_server.software_manager.software.get("WebServer")
|
||||
|
||||
response: HttpResponsePacket = web_server_service._handle_get_request(payload=payload)
|
||||
assert response.status_code == HttpStatusCode.OK
|
||||
@@ -51,7 +51,7 @@ def test_handling_get_request_home_page(web_server):
|
||||
def test_process_http_request_get(web_server):
|
||||
payload = HttpRequestPacket(request_method=HttpRequestMethod.GET, request_url="http://domain.com/")
|
||||
|
||||
web_server_service: WebServer = web_server.software_manager.software["WebServer"]
|
||||
web_server_service: WebServer = web_server.software_manager.software.get("WebServer")
|
||||
|
||||
assert web_server_service._process_http_request(payload=payload) is True
|
||||
|
||||
@@ -59,6 +59,6 @@ def test_process_http_request_get(web_server):
|
||||
def test_process_http_request_method_not_allowed(web_server):
|
||||
payload = HttpRequestPacket(request_method=HttpRequestMethod.DELETE, request_url="http://domain.com/")
|
||||
|
||||
web_server_service: WebServer = web_server.software_manager.software["WebServer"]
|
||||
web_server_service: WebServer = web_server.software_manager.software.get("WebServer")
|
||||
|
||||
assert web_server_service._process_http_request(payload=payload) is False
|
||||
|
||||
Reference in New Issue
Block a user