diff --git a/simulation-system/libs/csle-common/tests/test_ossec_ids_controller.py b/simulation-system/libs/csle-common/tests/test_ossec_ids_controller.py new file mode 100644 index 000000000..ee7eb70e0 --- /dev/null +++ b/simulation-system/libs/csle-common/tests/test_ossec_ids_controller.py @@ -0,0 +1,459 @@ +import pytest +import logging +import csle_common.constants.constants as constants +from unittest.mock import patch, MagicMock +from csle_common.dao.emulation_config.emulation_env_config import EmulationEnvConfig +from csle_common.controllers.ossec_ids_controller import ( + OSSECIDSController, +) + + +class TestOssecIdsSuite: + """ + Test suite for ossec_ids_controller + """ + + @pytest.fixture(autouse=True) + def emulation_env_config_setup(self) -> None: + """ + Set up emulation environment configuration + + :return: None + """ + # setup container configurations + emulation_env_config = MagicMock(spec=EmulationEnvConfig) + container1 = MagicMock() + container1.physical_host_ip = "192.168.1.10" + container1.docker_gw_bridge_ip = "172.17.0.1" + container1.name = "container-1" + + container2 = MagicMock() + container2.physical_host_ip = "192.168.1.10" + container2.docker_gw_bridge_ip = "172.17.0.2" + container2.name = "container-2" + + container3 = MagicMock() + container3.physical_host_ip = "192.168.1.11" + container3.docker_gw_bridge_ip = "172.17.0.3" + container3.name = "container-3" + + containers_config = MagicMock() + emulation_env_config.containers_config = containers_config + emulation_env_config.containers_config.containers = [ + container1, + container2, + container3, + ] + + ossec_ids_manager_config = MagicMock() + emulation_env_config.ossec_ids_manager_config = ossec_ids_manager_config + emulation_env_config.ossec_ids_manager_config.ossec_ids_manager_port = 1515 + self.emulation_env_config = emulation_env_config + self.logger = MagicMock(spec=logging.Logger) + + @patch( + "csle_common.controllers.ossec_ids_controller.OSSECIDSController.stop_ossec_ids" + ) + def test_stop_ossec_idses(self, mock_stop_ossec_ids) -> None: + """ + Test the method for stopping the OSSEC IDSes + + :param mock_stop_ossec_ids: mock stop_ossec_ids + + :return: None + """ + constants.CONTAINER_IMAGES = MagicMock() # type: ignore + constants.CONTAINER_IMAGES.OSSEC_IDS_IMAGES = ["container-1", "container-2"] + physical_host_ip = "192.168.1.10" + OSSECIDSController.stop_ossec_idses( + emulation_env_config=self.emulation_env_config, + physical_host_ip=physical_host_ip, + ) + assert mock_stop_ossec_ids.call_count == 2 + + @patch( + "csle_common.controllers.ossec_ids_controller.OSSECIDSController.start_ossec_ids" + ) + def test_start_ossec_idses(self, mock_start_ossec_ids) -> None: + """ + Test the method for starting the OSSEC IDSes + + :param mock_start_ossec_ids: mock start_ossec_ids + + :return: None + """ + constants.CONTAINER_IMAGES = MagicMock() # type: ignore + constants.CONTAINER_IMAGES.OSSEC_IDS_IMAGES = ["container-1", "container-2"] + physical_server_ip = "192.168.1.10" + OSSECIDSController.start_ossec_idses( + emulation_env_config=self.emulation_env_config, + physical_server_ip=physical_server_ip, + logger=self.logger, + ) + self.logger.info.assert_any_call("Starting the OSSEC IDS on ip: 172.17.0.1") + self.logger.info.assert_any_call("Starting the OSSEC IDS on ip: 172.17.0.2") + assert mock_start_ossec_ids.call_count == 2 + + @patch( + "csle_common.controllers.ossec_ids_controller.OSSECIDSController.start_ossec_ids_manager" + ) + @patch( + "csle_common.controllers.ossec_ids_controller.OSSECIDSController.get_ossec_ids_monitor_thread_status_by_ip_and_port" + ) + @patch("grpc.insecure_channel") + @patch("csle_common.controllers.ossec_ids_controller.Logger") + def test_start_ossec_ids( + self, + mock_logger, + mock_insecure_channel, + mock_get_monitor_status, + mock_start_manager, + ) -> None: + """ + Test the method for starting a OSSEC IDS with a specific IP + + :param mock_logger: mock logger + :param mock_insecure_channel: mock insecure_channel + :param mock_get_monitor_status: mock get_monitor_status + :param mock_start_manager: mock start_manager + + :return: None + """ + mock_get_monitor_status.return_value.ossec_ids_running = False + mock_channel = MagicMock() + mock_insecure_channel.return_value.__enter__.return_value = mock_channel + ip = "192.168.1.10" + OSSECIDSController.start_ossec_ids( + emulation_env_config=self.emulation_env_config, ip=ip + ) + mock_start_manager.assert_called_once_with( + emulation_env_config=self.emulation_env_config, ip=ip + ) + mock_get_monitor_status.assert_called_once_with(port=1515, ip=ip) + mock_insecure_channel.assert_called_once_with( + f"{ip}:1515", options=constants.GRPC_SERVERS.GRPC_OPTIONS + ) + mock_logger.__call__().get_logger().info.assert_called_once_with( + f"Starting OSSEC IDS on {ip}." + ) + + @patch( + "csle_common.controllers.ossec_ids_controller.OSSECIDSController.start_ossec_ids_manager" + ) + @patch( + "csle_common.controllers.ossec_ids_controller.OSSECIDSController.get_ossec_ids_monitor_thread_status_by_ip_and_port" + ) + @patch("grpc.insecure_channel") + def test_stop_ossec_ids( + self, mock_insecure_channel, mock_get_monitor_status, mock_start_manager + ) -> None: + """ + Test the method for stopping a OSSEC IDS with a specific IP + + :param mock_insecure_channel: mock insecure_channel + :param mock_get_monitor_status: mock get_monitor_status + :param mock_start_manager: mock start_manager + + :return: None + """ + mock_get_monitor_status.return_value.ossec_ids_running = True + mock_channel = MagicMock() + mock_insecure_channel.return_value.__enter__.return_value = mock_channel + ip = "192.168.1.10" + OSSECIDSController.start_ossec_ids( + emulation_env_config=self.emulation_env_config, ip=ip + ) + mock_start_manager.assert_called_once_with( + emulation_env_config=self.emulation_env_config, ip=ip + ) + mock_get_monitor_status.assert_called_once_with(port=1515, ip=ip) + + @patch( + "csle_common.controllers.ossec_ids_controller.OSSECIDSController.start_ossec_ids_manager" + ) + def test_start_ossec_idses_managers(self, mock_start_manager) -> None: + """ + Test the method for starting OSSEC IDS managers + + :param mock_start_manager: mock start_manager + + :return: None + """ + constants.CONTAINER_IMAGES = MagicMock() # type: ignore + constants.CONTAINER_IMAGES.OSSEC_IDS_IMAGES = ["container-1", "container-2"] + physical_server_ip = "192.168.1.10" + OSSECIDSController.start_ossec_idses_managers( + emulation_env_config=self.emulation_env_config, + physical_server_ip=physical_server_ip, + ) + assert mock_start_manager.call_count == 2 + + @patch("csle_common.util.emulation_util.EmulationUtil.connect_admin") + @patch("csle_common.util.emulation_util.EmulationUtil.execute_ssh_cmd") + def test_start_ossec_ids_manager( + self, mock_execute_ssh_cmd, mock_connect_admin + ) -> None: + """ + Test method for starting the OSSEC IDS manager on a specific container + + :param mock_execute_ssh_cmd: mock execute_ssh_cmd + :param mock_connect_admin: mock connect_admin + + :return: None + """ + ip = "192.168.1.10" + mock_execute_ssh_cmd.return_value = ("ossec_ids_manager running", "", 0) + OSSECIDSController.start_ossec_ids_manager( + emulation_env_config=self.emulation_env_config, ip=ip + ) + mock_execute_ssh_cmd.assert_called() + mock_connect_admin.assert_called() + + @patch( + "csle_common.controllers.ossec_ids_controller.OSSECIDSController.stop_ossec_ids_manager" + ) + def test_stop_ossec_idses_managers(self, mock_stop_manager) -> None: + """ + Test method for stopping ossec ids managers + + :param mock_stop_manager: mock stop_manager + + :return: None + """ + constants.CONTAINER_IMAGES = MagicMock() # type: ignore + constants.CONTAINER_IMAGES.OSSEC_IDS_IMAGES = ["container-1", "container-2"] + physical_server_ip = "192.168.1.10" + OSSECIDSController.stop_ossec_idses_managers( + emulation_env_config=self.emulation_env_config, + physical_server_ip=physical_server_ip, + ) + assert mock_stop_manager.call_count == 2 + + @patch("csle_common.util.emulation_util.EmulationUtil.connect_admin") + @patch("csle_common.util.emulation_util.EmulationUtil.execute_ssh_cmd") + def test_stop_ossec_ids_manager( + self, mock_execute_ssh_cmd, mock_connect_admin + ) -> None: + """ + Test method for stopping the OSSEC IDS manager on a specific container + + :param mock_execute_ssh_cmd: mock execute_ssh_cmd + :param mock_connect_admin: mock connect_admin + + :return: None + """ + ip = "192.168.1.10" + mock_execute_ssh_cmd.return_value = ("ossec_ids_manager running", "", 0) + OSSECIDSController.stop_ossec_ids_manager( + emulation_env_config=self.emulation_env_config, ip=ip + ) + mock_execute_ssh_cmd.assert_called() + mock_connect_admin.assert_called() + + """@patch("csle_common.controllers.ossec_ids_controller.OSSECIDSController.start_ossec_ids_monitor_thread") + def test_start_ossec_idses_monitor_threads(self, mock_start_monitor) -> None: + constants.CONTAINER_IMAGES = MagicMock() + constants.CONTAINER_IMAGES.OSSEC_IDS_IMAGES = ["container-1", "container-2"] + physical_server_ip = "192.168.1.10" + OSSECIDSController.start_ossec_idses_monitor_threads(emulation_env_config=self.emulation_env_config,physical_server_ip=physical_server_ip,logger=self.logger) + assert mock_start_monitor.call_count == 2""" + + @patch( + "csle_common.controllers.ossec_ids_controller.OSSECIDSController.start_ossec_ids_manager" + ) + @patch( + "csle_common.controllers.ossec_ids_controller.OSSECIDSController.get_ossec_ids_monitor_thread_status_by_ip_and_port" + ) + @patch("grpc.insecure_channel") + def test_start_ossec_ids_monitor_thread( + self, mock_insecure_channel, mock_get_monitor_status, mock_start_manager + ) -> None: + """ + A method that sends a request to the OSSECIDSManager on a specific IP to start + to start the IDS manager and the monitor thread + + :param mock_insecure_channel: mock insecure_channel + :param mock_get_monitor_status: mock get_monitor_status + :param mock_start_manager: mock start_manager + + :return: None + """ + mock_get_monitor_status.return_value.ossec_ids_running = False + mock_channel = MagicMock() + mock_insecure_channel.return_value.__enter__.return_value = mock_channel + ip = "192.168.1.10" + OSSECIDSController.start_ossec_ids_monitor_thread( + emulation_env_config=self.emulation_env_config, ip=ip + ) + mock_start_manager.assert_called_once_with( + emulation_env_config=self.emulation_env_config, ip=ip + ) + mock_get_monitor_status.assert_called_once_with(port=1515, ip=ip) + + @patch( + "csle_common.controllers.ossec_ids_controller.OSSECIDSController.stop_ossec_ids_monitor_thread" + ) + def test_stop_ossec_ids_monitor_threads(self, mock_stop_monitor) -> None: + """ + Test a method that sends a request to the OSSECIDSManager on every container that runs + an IDS to stop the monitor threads + + :param mock_stop_monitor: _description_ + :type mock_stop_monitor: _type_ + """ + constants.CONTAINER_IMAGES = MagicMock() # type: ignore + constants.CONTAINER_IMAGES.OSSEC_IDS_IMAGES = ["container-1", "container-2"] + physical_server_ip = "192.168.1.10" + OSSECIDSController.stop_ossec_idses_monitor_threads( + emulation_env_config=self.emulation_env_config, + physical_server_ip=physical_server_ip, + ) + assert mock_stop_monitor.call_count == 2 + + @patch( + "csle_common.controllers.ossec_ids_controller.OSSECIDSController.start_ossec_ids_manager" + ) + def test_stop_ossec_ids_monitor_thread(self, mock_start_manager) -> None: + """ + Test a method that sends a request to the OSSECIDSManager for a specific IP to stop the monitor thread + + :param mock_start_manager: mock start_manager + + :return: None + """ + ip = "192.168.1.10" + OSSECIDSController.start_ossec_ids_monitor_thread( + emulation_env_config=self.emulation_env_config, ip=ip + ) + mock_start_manager.assert_called_once_with( + emulation_env_config=self.emulation_env_config, ip=ip + ) + + @patch( + "csle_common.controllers.ossec_ids_controller.OSSECIDSController.start_ossec_idses_managers" + ) + def test_get_ossec_idses_monitor_threads_statuses( + self, mock_start_managers + ) -> None: + """ + Test a method that sends a request to the OSSECIDSManager on every container to get the status of the + IDS monitor thread + + :param mock_start_manager: mock start_manager + + :return: None + """ + physical_server_ip = "192.168.1.10" + constants.CONTAINER_IMAGES = MagicMock() # type: ignore + constants.CONTAINER_IMAGES.OSSEC_IDS_IMAGES = ["container-1", "container-2"] + OSSECIDSController.get_ossec_idses_monitor_threads_statuses( + emulation_env_config=self.emulation_env_config, + physical_server_ip=physical_server_ip, + ) + mock_start_managers.assert_called_once_with( + emulation_env_config=self.emulation_env_config, + physical_server_ip=physical_server_ip, + ) + + def test_get_ossec_idses_managers_ips(self) -> None: + """ + Tests a method that extracts the IPS of the OSSEC IDS managers in a given emulation + + :return: None + """ + constants.CONTAINER_IMAGES = MagicMock() # type: ignore + constants.CONTAINER_IMAGES.OSSEC_IDS_IMAGES = ["container-1", "container-2"] + ips = OSSECIDSController.get_ossec_idses_managers_ips( + emulation_env_config=self.emulation_env_config + ) + assert ips == ["172.17.0.1", "172.17.0.2"] + + def test_get_ossec_idses_managers_ports(self) -> None: + """ + Tests a method that extracts the ports of the OSSEC IDS managers in a given emulation + + :return: None + """ + constants.CONTAINER_IMAGES = MagicMock() # type: ignore + constants.CONTAINER_IMAGES.OSSEC_IDS_IMAGES = ["container-1", "container-2"] + ports = OSSECIDSController.get_ossec_idses_managers_ports( + emulation_env_config=self.emulation_env_config + ) + assert ports == [1515, 1515] + + @patch("grpc.insecure_channel") + def test_get_ossec_ids_monitor_thread_status_by_ip_and_port( + self, mock_insecure_channel + ) -> None: + """ + Tests a method that sends a request to the OSSECIDSManager with a specific port and ip + to get the status of the IDS monitor thread + + :param mock_insecure_channel: mock insecure_channel + + :return: None + """ + port = 1515 + ip = "192.168.1.100" + mock_channel = MagicMock() + mock_insecure_channel.return_value.__enter__.return_value = mock_channel + OSSECIDSController.get_ossec_ids_monitor_thread_status_by_ip_and_port( + port=port, ip=ip + ) + mock_insecure_channel.assert_called_once_with( + f"{ip}:{port}", options=constants.GRPC_SERVERS.GRPC_OPTIONS + ) + + @patch( + "csle_common.controllers.ossec_ids_controller.OSSECIDSController.get_ossec_idses_managers_ips" + ) + @patch( + "csle_common.controllers.ossec_ids_controller.OSSECIDSController.get_ossec_idses_managers_ports" + ) + @patch( + "csle_common.controllers.ossec_ids_controller.OSSECIDSController.get_ossec_ids_monitor_thread_status_by_ip_and_port" + ) + @patch("csle_common.util.emulation_util.EmulationUtil.physical_ip_match") + @patch( + "csle_collector.ossec_ids_manager.ossec_ids_manager_util.OSSecManagerUtil.ossec_ids_monitor_dto_empty" + ) + def test_get_ossec_managers_info( + self, + mock_ossec_dto_empty, + mock_physical_ip_match, + mock_get_status, + mock_get_ports, + mock_get_ips, + ) -> None: + """ + Tests the method that extracts the information of the OSSEC IDS managers for a given emulation + + :param mock_ossec_dto_empty: mock ossec_dto_empty + :param mock_physical_ip_match: mock physical_ip_match + :param mock_get_status: mock get_status + :param mock_get_ports: mock get_ports + :param mock_get_ips: mock get_ips + + :retun: None + """ + emulation_env_config = self.emulation_env_config + emulation_env_config.execution_id = "test_execution_id" + emulation_env_config.name = "test_emulation_name" + emulation_env_config.ossec_ids_manager_config.ossec_ids_manager_port = 1515 + active_ips = ["192.168.1.10", "192.168.1.11"] + physical_host_ip = "192.168.1.1" + logger = self.logger + mock_get_ips.return_value = ["192.168.1.10", "192.168.1.12"] + mock_get_ports.return_value = [1515, 1515] + mock_status_1 = MagicMock() + mock_get_status.side_effect = [mock_status_1, Exception("Test Exception")] + mock_physical_ip_match.side_effect = [True, True] + mock_ossec_dto_empty.return_value = MagicMock() + OSSECIDSController.get_ossec_managers_info( + emulation_env_config, active_ips, logger, physical_host_ip + ) + mock_get_ips.assert_called_once_with(emulation_env_config=emulation_env_config) + mock_get_ports.assert_called_once_with( + emulation_env_config=emulation_env_config + ) + assert mock_get_status.call_count == 1 diff --git a/simulation-system/libs/csle-common/tests/test_ovs_controller.py b/simulation-system/libs/csle-common/tests/test_ovs_controller.py new file mode 100644 index 000000000..a05dfc1fe --- /dev/null +++ b/simulation-system/libs/csle-common/tests/test_ovs_controller.py @@ -0,0 +1,82 @@ +import pytest +import logging +from unittest.mock import patch, MagicMock +import csle_common.constants.constants as constants +from csle_common.controllers.ovs_controller import ( + OVSController, +) +from csle_common.dao.emulation_config.containers_config import ContainersConfig + + +class TestOVSControllerSuite: + """ + Test suite for OVS controller + """ + + @pytest.fixture + def mock_containers_config(self): + """ + Test method that sets up OVS switches on containers + + :return: None + """ + container1 = MagicMock() + container1.physical_host_ip = "192.168.1.1" + container1.name = "ovs_container1" + container1.get_full_name.return_value = "container1" + container1.ips_and_networks = [ + ("192.168.1.100", MagicMock(interface="eth0", bitmask="255.255.255.0")) + ] + + container2 = MagicMock() + container2.physical_host_ip = "192.168.1.2" + container2.name = "ovs_container2" + container2.get_full_name.return_value = "container2" + container2.ips_and_networks = [ + ("192.168.1.101", MagicMock(interface="eth0", bitmask="255.255.255.0")) + ] + containers_config = MagicMock(spec=ContainersConfig) + containers_config.containers = [container1, container2] + return containers_config + + @patch("subprocess.Popen") + @patch("time.sleep") + def test_create_virtual_switches_on_container( + self, mock_sleep, mock_popen, mock_containers_config + ) -> None: + """ + Test method that aplies the OVS configuration on the OVS switches + + :param mock_sleep: mock_sleep + :param mock_popen: mock_popen + :param mock_containers_config: mock_containers_config + """ + logger = MagicMock() + physical_server_ip = "192.168.1.1" + constants.CONTAINER_IMAGES.OVS_IMAGES = ["ovs_container1"] + OVSController.create_virtual_switches_on_container( + mock_containers_config, physical_server_ip, logger + ) + mock_popen.assert_called() + assert mock_sleep.call_count == 5 + + @patch("csle_common.util.emulation_util.EmulationUtil.connect_admin") + @patch("csle_common.util.emulation_util.EmulationUtil.execute_ssh_cmd") + def test_apply_ovs_config(self, mock_execute_ssh_cmd, mock_connect_admin) -> None: + emulation_env_config = MagicMock() + ovs_switch_config = MagicMock() + ovs_switch_config.container_name = "ovs_container_1" + ovs_switch_config.physical_host_ip = "192.168.1.1" + ovs_switch_config.docker_gw_bridge_ip = "192.168.1.3" + emulation_env_config.ovs_switch_config = ovs_switch_config + emulation_env_config.ovs_switch_config.switch_configs = [ovs_switch_config] + emulation_env_config.connections = {"192.168.1.3": MagicMock()} + physical_server_ip = "192.168.1.2" + logger = MagicMock(spec=logging.Logger) + OVSController.apply_ovs_config( + emulation_env_config=emulation_env_config, + physical_server_ip=physical_server_ip, + logger=logger, + ) + mock_connect_admin.assert_not_called() + mock_execute_ssh_cmd.assert_not_called() diff --git a/simulation-system/libs/csle-common/tests/test_resource_constraints_controller.py b/simulation-system/libs/csle-common/tests/test_resource_constraints_controller.py new file mode 100644 index 000000000..e4c11e2f7 --- /dev/null +++ b/simulation-system/libs/csle-common/tests/test_resource_constraints_controller.py @@ -0,0 +1,87 @@ +import subprocess +from unittest.mock import patch, MagicMock +from csle_common.controllers.resource_constraints_controller import ( + ResourceConstraintsController, +) + + +class TestResourceConstraintsControllerSuite: + """ + Test suite for ResourceConstraintsController + """ + + @patch("csle_common.util.emulation_util.EmulationUtil.connect_admin") + @patch("csle_common.util.emulation_util.EmulationUtil.disconnect_admin") + @patch("csle_common.util.emulation_util.EmulationUtil.execute_ssh_cmd") + @patch("subprocess.Popen") + def test_apply_resource_constraints( + self, + mock_popen, + mock_execute_ssh_cmd, + mock_disconnect_admin, + mock_connect_admin, + ) -> None: + """ + Test the method that creates users in an emulation environment according to a specified users-configuration + + + :param mock_popen: mock_popen + :param mock_execute_ssh_cmd: mock_execute_ssh_cmd + :param mock_disconnect_admin: mock_disconnect_admin + :param mock_connect_admin: mock_connect_admin + + :return: None + """ + emulation_env_config = MagicMock() + network_config = MagicMock() + network_config.interface = "eth0" + network_config.packet_delay_ms = 10 + network_config.packet_delay_jitter_ms = 5 + network_config.packet_delay_distribution = "normal" + network_config.loss_gemodel_p = 0.1 + network_config.loss_gemodel_r = 0.1 + network_config.loss_gemodel_h = 0.9 + network_config.loss_gemodel_k = 0.9 + network_config.packet_duplicate_percentage = 0.1 + network_config.packet_duplicate_correlation_percentage = 0.1 + network_config.packet_corrupt_percentage = 0.1 + network_config.packet_reorder_percentage = 0.1 + network_config.packet_reorder_correlation_percentage = 0.1 + network_config.packet_reorder_gap = 5 + network_config.rate_limit_mbit = 10 + network_config.limit_packets_queue = 100 + + node_resource_config = MagicMock() + node_resource_config.physical_host_ip = "192.168.1.1" + node_resource_config.docker_gw_bridge_ip = "192.168.1.2" + node_resource_config.container_name = "container_1" + node_resource_config.available_memory_gb = 2 + node_resource_config.num_cpus = 1 + node_resource_config.ips_and_network_configs = [("192.168.1.2", network_config)] + + emulation_env_config.resources_config.node_resources_configurations = [ + node_resource_config + ] + emulation_env_config.kafka_config.resources = node_resource_config + emulation_env_config.sdn_controller_config.resources = node_resource_config + emulation_env_config.connections = {"192.168.1.2": MagicMock()} + physical_server_ip = "192.168.1.1" + mock_execute_ssh_cmd.return_value = ("output", "error", 0) + logger = MagicMock() + ResourceConstraintsController.apply_resource_constraints( + emulation_env_config=emulation_env_config, + physical_server_ip=physical_server_ip, + logger=logger, + ) + mock_connect_admin.assert_any_call( + emulation_env_config=emulation_env_config, ip="192.168.1.2" + ) + expected_docker_update_cmd = "docker update --memory=2G --cpus=1 container_1" + mock_popen.assert_any_call( + expected_docker_update_cmd, + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + shell=True, + ) + mock_execute_ssh_cmd.assert_called() + mock_disconnect_admin.assert_any_call(emulation_env_config=emulation_env_config)