Loading src/opticalcentralizedattackdetector/service/OpticalCentralizedAttackDetectorServiceServicerImpl.py +11 −11 Original line number Diff line number Diff line Loading @@ -35,18 +35,18 @@ INFLUXDB_HOSTNAME = os.environ.get("INFLUXDB_HOSTNAME") INFLUXDB_USER = os.environ.get("INFLUXDB_USER") INFLUXDB_PASSWORD = os.environ.get("INFLUXDB_PASSWORD") INFLUXDB_DATABASE = os.environ.get("INFLUXDB_DATABASE") context_client: ContextClient = ContextClient(address=CONTEXT_SERVICE_ADDRESS, port=CONTEXT_GRPC_SERVICE_PORT) influxdb_client: InfluxDBClient = InfluxDBClient(host=MONITORING_SERVICE_ADDRESS, port=8086, username=INFLUXDB_USER, password=INFLUXDB_PASSWORD, database=INFLUXDB_DATABASE) monitoring_client: MonitoringClient = MonitoringClient(server=MONITORING_SERVICE_ADDRESS, port=MONITORING_GRPC_SERVICE_PORT) dbscanserving_client: DbscanServingClient = DbscanServingClient(address=INFERENCE_SERVICE_ADDRESS, port=DBSCANSERVING_GRPC_SERVICE_PORT) service_client: ServiceClient = ServiceClient(SERVICE_SERVICE_ADDRESS, SERVICE_GRPC_SERVICE_PORT) attack_mitigator_client: OpticalAttackMitigatorClient = OpticalAttackMitigatorClient(address=ATTACK_MITIGATOR_SERVICE_ADDRESS, port=ATTACK_MITIGATOR_GRPC_SERVICE_PORT) class OpticalCentralizedAttackDetectorServiceServicerImpl(OpticalCentralizedAttackDetectorServiceServicer): def __init__(self): LOGGER.debug('Creating Servicer...') self.context_client: ContextClient = ContextClient(address=CONTEXT_SERVICE_ADDRESS, port=CONTEXT_GRPC_SERVICE_PORT) self.monitoring_client: MonitoringClient = MonitoringClient(server=MONITORING_SERVICE_ADDRESS, port=MONITORING_GRPC_SERVICE_PORT) self.service_client: ServiceClient = ServiceClient(SERVICE_SERVICE_ADDRESS, SERVICE_GRPC_SERVICE_PORT) self.influxdb_client: InfluxDBClient = InfluxDBClient(host=MONITORING_SERVICE_ADDRESS, port=8086, username=INFLUXDB_USER, password=INFLUXDB_PASSWORD, database=INFLUXDB_DATABASE) self.dbscanserving_client: DbscanServingClient = DbscanServingClient(address=INFERENCE_SERVICE_ADDRESS, port=DBSCANSERVING_GRPC_SERVICE_PORT) self.attack_mitigator_client: OpticalAttackMitigatorClient = OpticalAttackMitigatorClient(address=ATTACK_MITIGATOR_SERVICE_ADDRESS, port=ATTACK_MITIGATOR_GRPC_SERVICE_PORT) LOGGER.debug('Servicer Created') @safe_and_metered_rpc_method(METRICS, LOGGER) Loading @@ -58,18 +58,18 @@ class OpticalCentralizedAttackDetectorServiceServicerImpl(OpticalCentralizedAtta # retrieve list with current contexts # import pdb; pdb.set_trace() context_ids: ContextIdList = self.context_client.ListContextIds(Empty()) context_ids: ContextIdList = context_client.ListContextIds(Empty()) # for each context, retrieve list of current services services = [] for context_id in context_ids.context_ids: context_services: ServiceIdList = self.context_client.ListServices(context_id) context_services: ServiceIdList = context_client.ListServices(context_id) for service in context_services.services: services.append(service) # get monitoring data for each of the current services results = self.influxdb_client.query('select * from samples;') results = influxdb_client.query('select * from samples;') for service in services: for endpoint in service.service_endpoint_ids: Loading Loading @@ -107,12 +107,12 @@ class OpticalCentralizedAttackDetectorServiceServicerImpl(OpticalCentralizedAtta grpc_sample.features.append(random.uniform(5000., 6000.)) request.samples.append(grpc_sample) response: DetectionResponse = self.dbscanserving_client.Detect(request) response: DetectionResponse = dbscanserving_client.Detect(request) if -1 in response.cluster_indices: # attack detected attack = AttackDescription() attack.cs_id.uuid = service.service_id.service_uuid.uuid response: AttackResponse = self.attack_mitigator_client.NotifyAttack(attack) response: AttackResponse = attack_mitigator_client.NotifyAttack(attack) # if attack is detected, run the attack mitigator return Empty() Loading src/opticalcentralizedattackdetector/tests/example_objects.py 0 → 100644 +201 −0 Original line number Diff line number Diff line from copy import deepcopy from common.Constants import DEFAULT_CONTEXT_UUID, DEFAULT_TOPOLOGY_UUID from context.proto.context_pb2 import ( ConfigActionEnum, DeviceDriverEnum, DeviceOperationalStatusEnum, ServiceStatusEnum, ServiceTypeEnum) # Some example objects to be used by the tests # Helper methods def config_rule(action, resource_key, resource_value): return {'action': action, 'resource_key': resource_key, 'resource_value': resource_value} def endpoint_id(topology_id, device_id, endpoint_uuid): return {'topology_id': deepcopy(topology_id), 'device_id': deepcopy(device_id), 'endpoint_uuid': {'uuid': endpoint_uuid}} def endpoint(topology_id, device_id, endpoint_uuid, endpoint_type): return {'endpoint_id': endpoint_id(topology_id, device_id, endpoint_uuid), 'endpoint_type': endpoint_type} ## use "deepcopy" to prevent propagating forced changes during tests CONTEXT_ID = {'context_uuid': {'uuid': DEFAULT_CONTEXT_UUID}} CONTEXT = { 'context_id': deepcopy(CONTEXT_ID), 'topology_ids': [], 'service_ids': [], } CONTEXT_ID_2 = {'context_uuid': {'uuid': 'test'}} CONTEXT_2 = { 'context_id': deepcopy(CONTEXT_ID_2), 'topology_ids': [], 'service_ids': [], } TOPOLOGY_ID = { 'context_id': deepcopy(CONTEXT_ID), 'topology_uuid': {'uuid': DEFAULT_TOPOLOGY_UUID}, } TOPOLOGY = { 'topology_id': deepcopy(TOPOLOGY_ID), 'device_ids': [], 'link_ids': [], } DEVICE1_UUID = 'DEV1' DEVICE1_ID = {'device_uuid': {'uuid': DEVICE1_UUID}} DEVICE1 = { 'device_id': deepcopy(DEVICE1_ID), 'device_type': 'packet-router', 'device_config': {'config_rules': [ config_rule(ConfigActionEnum.CONFIGACTION_SET, 'dev/rsrc1/value', 'value1'), config_rule(ConfigActionEnum.CONFIGACTION_SET, 'dev/rsrc2/value', 'value2'), config_rule(ConfigActionEnum.CONFIGACTION_SET, 'dev/rsrc3/value', 'value3'), ]}, 'device_operational_status': DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_ENABLED, 'device_drivers': [DeviceDriverEnum.DEVICEDRIVER_OPENCONFIG, DeviceDriverEnum.DEVICEDRIVER_P4], 'device_endpoints': [ endpoint(TOPOLOGY_ID, DEVICE1_ID, 'EP2', 'port-packet-100G'), endpoint(TOPOLOGY_ID, DEVICE1_ID, 'EP3', 'port-packet-100G'), endpoint(TOPOLOGY_ID, DEVICE1_ID, 'EP100', 'port-packet-10G'), ], } DEVICE2_UUID = 'DEV2' DEVICE2_ID = {'device_uuid': {'uuid': DEVICE2_UUID}} DEVICE2 = { 'device_id': deepcopy(DEVICE2_ID), 'device_type': 'packet-router', 'device_config': {'config_rules': [ config_rule(ConfigActionEnum.CONFIGACTION_SET, 'dev/rsrc1/value', 'value4'), config_rule(ConfigActionEnum.CONFIGACTION_SET, 'dev/rsrc2/value', 'value5'), config_rule(ConfigActionEnum.CONFIGACTION_SET, 'dev/rsrc3/value', 'value6'), ]}, 'device_operational_status': DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_ENABLED, 'device_drivers': [DeviceDriverEnum.DEVICEDRIVER_OPENCONFIG, DeviceDriverEnum.DEVICEDRIVER_P4], 'device_endpoints': [ endpoint(TOPOLOGY_ID, DEVICE2_ID, 'EP1', 'port-packet-100G'), endpoint(TOPOLOGY_ID, DEVICE2_ID, 'EP3', 'port-packet-100G'), endpoint(TOPOLOGY_ID, DEVICE2_ID, 'EP100', 'port-packet-10G'), ], } DEVICE3_UUID = 'DEV3' DEVICE3_ID = {'device_uuid': {'uuid': DEVICE3_UUID}} DEVICE3 = { 'device_id': deepcopy(DEVICE3_ID), 'device_type': 'packet-router', 'device_config': {'config_rules': [ config_rule(ConfigActionEnum.CONFIGACTION_SET, 'dev/rsrc1/value', 'value4'), config_rule(ConfigActionEnum.CONFIGACTION_SET, 'dev/rsrc2/value', 'value5'), config_rule(ConfigActionEnum.CONFIGACTION_SET, 'dev/rsrc3/value', 'value6'), ]}, 'device_operational_status': DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_ENABLED, 'device_drivers': [DeviceDriverEnum.DEVICEDRIVER_OPENCONFIG, DeviceDriverEnum.DEVICEDRIVER_P4], 'device_endpoints': [ endpoint(TOPOLOGY_ID, DEVICE3_ID, 'EP1', 'port-packet-100G'), endpoint(TOPOLOGY_ID, DEVICE3_ID, 'EP2', 'port-packet-100G'), endpoint(TOPOLOGY_ID, DEVICE3_ID, 'EP100', 'port-packet-10G'), ], } LINK_DEV1_DEV2_UUID = 'DEV1/EP2 ==> DEV2/EP1' LINK_DEV1_DEV2_ID = {'link_uuid': {'uuid': LINK_DEV1_DEV2_UUID}} LINK_DEV1_DEV2 = { 'link_id': deepcopy(LINK_DEV1_DEV2_ID), 'link_endpoint_ids' : [ endpoint_id(TOPOLOGY_ID, DEVICE1_ID, 'EP2'), endpoint_id(TOPOLOGY_ID, DEVICE2_ID, 'EP1'), ] } LINK_DEV2_DEV3_UUID = 'DEV2/EP3 ==> DEV3/EP2' LINK_DEV2_DEV3_ID = {'link_uuid': {'uuid': LINK_DEV2_DEV3_UUID}} LINK_DEV2_DEV3 = { 'link_id': deepcopy(LINK_DEV2_DEV3_ID), 'link_endpoint_ids' : [ endpoint_id(TOPOLOGY_ID, DEVICE2_ID, 'EP3'), endpoint_id(TOPOLOGY_ID, DEVICE3_ID, 'EP2'), ] } LINK_DEV1_DEV3_UUID = 'DEV1/EP3 ==> DEV3/EP1' LINK_DEV1_DEV3_ID = {'link_uuid': {'uuid': LINK_DEV1_DEV3_UUID}} LINK_DEV1_DEV3 = { 'link_id': deepcopy(LINK_DEV1_DEV3_ID), 'link_endpoint_ids' : [ endpoint_id(TOPOLOGY_ID, DEVICE1_ID, 'EP3'), endpoint_id(TOPOLOGY_ID, DEVICE3_ID, 'EP1'), ] } SERVICE_DEV1_DEV2_UUID = 'SVC:DEV1/EP100-DEV2/EP100' SERVICE_DEV1_DEV2_ID = { 'context_id': deepcopy(CONTEXT_ID), 'service_uuid': {'uuid': SERVICE_DEV1_DEV2_UUID}, } SERVICE_DEV1_DEV2 = { 'service_id': deepcopy(SERVICE_DEV1_DEV2_ID), 'service_type': ServiceTypeEnum.SERVICETYPE_L3NM, 'service_endpoint_ids' : [ endpoint_id(TOPOLOGY_ID, DEVICE1_ID, 'EP100'), endpoint_id(TOPOLOGY_ID, DEVICE2_ID, 'EP100'), ], 'service_constraints': [ {'constraint_type': 'latency_ms', 'constraint_value': '15.2'}, {'constraint_type': 'jitter_us', 'constraint_value': '1.2'}, ], 'service_status': {'service_status': ServiceStatusEnum.SERVICESTATUS_ACTIVE}, 'service_config': {'config_rules': [ config_rule(ConfigActionEnum.CONFIGACTION_SET, 'svc/rsrc1/value', 'value7'), config_rule(ConfigActionEnum.CONFIGACTION_SET, 'svc/rsrc2/value', 'value8'), config_rule(ConfigActionEnum.CONFIGACTION_SET, 'svc/rsrc3/value', 'value9'), ]}, } SERVICE_DEV1_DEV3_UUID = 'SVC:DEV1/EP100-DEV3/EP100' SERVICE_DEV1_DEV3_ID = { 'context_id': deepcopy(CONTEXT_ID), 'service_uuid': {'uuid': SERVICE_DEV1_DEV3_UUID}, } SERVICE_DEV1_DEV3 = { 'service_id': deepcopy(SERVICE_DEV1_DEV3_ID), 'service_type': ServiceTypeEnum.SERVICETYPE_L3NM, 'service_endpoint_ids' : [ endpoint_id(TOPOLOGY_ID, DEVICE1_ID, 'EP100'), endpoint_id(TOPOLOGY_ID, DEVICE3_ID, 'EP100'), ], 'service_constraints': [ {'constraint_type': 'latency_ms', 'constraint_value': '5.8'}, {'constraint_type': 'jitter_us', 'constraint_value': '0.1'}, ], 'service_status': {'service_status': ServiceStatusEnum.SERVICESTATUS_ACTIVE}, 'service_config': {'config_rules': [ config_rule(ConfigActionEnum.CONFIGACTION_SET, 'svc/rsrc1/value', 'value7'), config_rule(ConfigActionEnum.CONFIGACTION_SET, 'svc/rsrc2/value', 'value8'), config_rule(ConfigActionEnum.CONFIGACTION_SET, 'svc/rsrc3/value', 'value9'), ]}, } SERVICE_DEV2_DEV3_UUID = 'SVC:DEV2/EP100-DEV3/EP100' SERVICE_DEV2_DEV3_ID = { 'context_id': deepcopy(CONTEXT_ID), 'service_uuid': {'uuid': SERVICE_DEV2_DEV3_UUID}, } SERVICE_DEV2_DEV3 = { 'service_id': deepcopy(SERVICE_DEV2_DEV3_ID), 'service_type': ServiceTypeEnum.SERVICETYPE_L3NM, 'service_endpoint_ids' : [ endpoint_id(TOPOLOGY_ID, DEVICE2_ID, 'EP100'), endpoint_id(TOPOLOGY_ID, DEVICE3_ID, 'EP100'), ], 'service_constraints': [ {'constraint_type': 'latency_ms', 'constraint_value': '23.1'}, {'constraint_type': 'jitter_us', 'constraint_value': '3.4'}, ], 'service_status': {'service_status': ServiceStatusEnum.SERVICESTATUS_ACTIVE}, 'service_config': {'config_rules': [ config_rule(ConfigActionEnum.CONFIGACTION_SET, 'svc/rsrc1/value', 'value7'), config_rule(ConfigActionEnum.CONFIGACTION_SET, 'svc/rsrc2/value', 'value8'), config_rule(ConfigActionEnum.CONFIGACTION_SET, 'svc/rsrc3/value', 'value9'), ]}, } src/opticalcentralizedattackdetector/tests/test_unitary.py +139 −4 Original line number Diff line number Diff line import logging, pytest from unittest.mock import patch from opticalcentralizedattackdetector.Config import GRPC_SERVICE_PORT, GRPC_MAX_WORKERS, GRPC_GRACE_PERIOD from opticalcentralizedattackdetector.client.OpticalCentralizedAttackDetectorClient import OpticalCentralizedAttackDetectorClient from opticalcentralizedattackdetector.proto.context_pb2 import Empty, Service from opticalcentralizedattackdetector.proto.context_pb2 import ContextIdList, ContextId, Empty, Service, ContextId, ServiceList from opticalcentralizedattackdetector.proto.monitoring_pb2 import Kpi, KpiList from opticalcentralizedattackdetector.service.OpticalCentralizedAttackDetectorService import OpticalCentralizedAttackDetectorService from .example_objects import CONTEXT_ID, CONTEXT_ID_2, SERVICE_DEV1_DEV2 port = 10000 + GRPC_SERVICE_PORT # avoid privileged ports Loading @@ -14,9 +16,17 @@ LOGGER.setLevel(logging.DEBUG) def optical_centralized_attack_detector_service(): _service = OpticalCentralizedAttackDetectorService( port=port, max_workers=GRPC_MAX_WORKERS, grace_period=GRPC_GRACE_PERIOD) # mocker_context_client = mock.patch('opticalcentralizedattackdetector.service.OpticalCentralizedAttackDetectorServiceServicerImpl.context_client') # mocker_context_client.start() # mocker_influx_db = mock.patch('opticalcentralizedattackdetector.service.OpticalCentralizedAttackDetectorServiceServicerImpl.influxdb_client') # mocker_influx_db.start() _service.start() yield _service _service.stop() # mocker_context_client.stop() # mocker_influx_db.stop() @pytest.fixture(scope='session') def optical_centralized_attack_detector_client(optical_centralized_attack_detector_service): Loading @@ -28,10 +38,135 @@ def test_notify_service_update(optical_centralized_attack_detector_client: Optic service = Service() optical_centralized_attack_detector_client.NotifyServiceUpdate(service) def test_detect_attack(optical_centralized_attack_detector_client: OpticalCentralizedAttackDetectorClient): def test_detect_attack_no_contexts(optical_centralized_attack_detector_client: OpticalCentralizedAttackDetectorClient): with patch('opticalcentralizedattackdetector.service.OpticalCentralizedAttackDetectorServiceServicerImpl.context_client') as context, \ patch('opticalcentralizedattackdetector.service.OpticalCentralizedAttackDetectorServiceServicerImpl.influxdb_client') as influxdb: request = Empty() optical_centralized_attack_detector_client.DetectAttack(request) context.ListContextIds.assert_called_once() influxdb.query.assert_called_once() context.ListServices.assert_not_called() def test_detect_attack_with_context(optical_centralized_attack_detector_client: OpticalCentralizedAttackDetectorClient,): with patch('opticalcentralizedattackdetector.service.OpticalCentralizedAttackDetectorServiceServicerImpl.context_client') as context, \ patch('opticalcentralizedattackdetector.service.OpticalCentralizedAttackDetectorServiceServicerImpl.influxdb_client') as influxdb: # setting up the mock cid_list = ContextIdList() cid_list.context_ids.append(ContextId(**CONTEXT_ID)) context.ListContextIds.return_value = cid_list # making the test request = Empty() optical_centralized_attack_detector_client.DetectAttack(request) # checking behavior context.ListContextIds.assert_called_once() context.ListServices.assert_called_with(cid_list.context_ids[0]) influxdb.query.assert_called_once() def test_detect_attack_with_contexts(optical_centralized_attack_detector_client: OpticalCentralizedAttackDetectorClient,): with patch('opticalcentralizedattackdetector.service.OpticalCentralizedAttackDetectorServiceServicerImpl.context_client') as context, \ patch('opticalcentralizedattackdetector.service.OpticalCentralizedAttackDetectorServiceServicerImpl.influxdb_client') as influxdb: # setting up the mock cid_list = ContextIdList() cid_list.context_ids.append(ContextId(**CONTEXT_ID)) cid_list.context_ids.append(ContextId(**CONTEXT_ID_2)) context.ListContextIds.return_value = cid_list # making the test request = Empty() optical_centralized_attack_detector_client.DetectAttack(request) # checking behavior context.ListContextIds.assert_called_once() context.ListServices.assert_any_call(cid_list.context_ids[0]) context.ListServices.assert_any_call(cid_list.context_ids[1]) influxdb.query.assert_called_once() def test_detect_attack_with_service(optical_centralized_attack_detector_client: OpticalCentralizedAttackDetectorClient,): with patch('opticalcentralizedattackdetector.service.OpticalCentralizedAttackDetectorServiceServicerImpl.context_client') as context, \ patch('opticalcentralizedattackdetector.service.OpticalCentralizedAttackDetectorServiceServicerImpl.influxdb_client') as influxdb, \ patch('opticalcentralizedattackdetector.service.OpticalCentralizedAttackDetectorServiceServicerImpl.dbscanserving_client') as dbscan: # setting up the mock cid_list = ContextIdList() cid_list.context_ids.append(ContextId(**CONTEXT_ID)) context.ListContextIds.return_value = cid_list service_list = ServiceList() service_list.services.append(Service(**SERVICE_DEV1_DEV2)) context.ListServices.return_value = service_list influxdb.query.return_value.get_points.return_value = [(1, 2), (3, 4)] # making the test request = Empty() optical_centralized_attack_detector_client.DetectAttack(request) # checking behavior context.ListContextIds.assert_called_once() context.ListServices.assert_called_with(cid_list.context_ids[0]) influxdb.query.assert_called_once() dbscan.Detect.assert_called() def test_detect_attack_no_attack(optical_centralized_attack_detector_client: OpticalCentralizedAttackDetectorClient,): with patch('opticalcentralizedattackdetector.service.OpticalCentralizedAttackDetectorServiceServicerImpl.context_client') as context, \ patch('opticalcentralizedattackdetector.service.OpticalCentralizedAttackDetectorServiceServicerImpl.influxdb_client') as influxdb, \ patch('opticalcentralizedattackdetector.service.OpticalCentralizedAttackDetectorServiceServicerImpl.dbscanserving_client') as dbscan, \ patch('opticalcentralizedattackdetector.service.OpticalCentralizedAttackDetectorServiceServicerImpl.attack_mitigator_client') as mitigator: # setting up the mock cid_list = ContextIdList() cid_list.context_ids.append(ContextId(**CONTEXT_ID)) context.ListContextIds.return_value = cid_list service_list = ServiceList() service_list.services.append(Service(**SERVICE_DEV1_DEV2)) context.ListServices.return_value = service_list # dbscan.Detect.return_value = object() dbscan.Detect.return_value.cluster_indices = [0, 1, 2, 3, 4, 5] # making the test request = Empty() optical_centralized_attack_detector_client.DetectAttack(request) # checking behavior context.ListContextIds.assert_called_once() context.ListServices.assert_called_with(cid_list.context_ids[0]) influxdb.query.assert_called_once() dbscan.Detect.assert_called() mitigator.NotifyAttack.assert_not_called() def test_detect_attack_with_attack(optical_centralized_attack_detector_client: OpticalCentralizedAttackDetectorClient,): with patch('opticalcentralizedattackdetector.service.OpticalCentralizedAttackDetectorServiceServicerImpl.context_client') as context, \ patch('opticalcentralizedattackdetector.service.OpticalCentralizedAttackDetectorServiceServicerImpl.influxdb_client') as influxdb, \ patch('opticalcentralizedattackdetector.service.OpticalCentralizedAttackDetectorServiceServicerImpl.dbscanserving_client') as dbscan, \ patch('opticalcentralizedattackdetector.service.OpticalCentralizedAttackDetectorServiceServicerImpl.attack_mitigator_client') as mitigator: # setting up the mock cid_list = ContextIdList() cid_list.context_ids.append(ContextId(**CONTEXT_ID)) context.ListContextIds.return_value = cid_list service_list = ServiceList() service_list.services.append(Service(**SERVICE_DEV1_DEV2)) context.ListServices.return_value = service_list # dbscan.Detect.return_value = object() dbscan.Detect.return_value.cluster_indices = [0, 1, 2, 3, 4, -1] # making the test request = Empty() optical_centralized_attack_detector_client.DetectAttack(request) # checking behavior context.ListContextIds.assert_called_once() context.ListServices.assert_called_with(cid_list.context_ids[0]) influxdb.query.assert_called_once() dbscan.Detect.assert_called() mitigator.NotifyAttack.assert_called() def test_report_summarized_kpi(optical_centralized_attack_detector_client: OpticalCentralizedAttackDetectorClient): kpi_list = KpiList() optical_centralized_attack_detector_client.ReportSummarizedKpi(kpi_list) Loading Loading
src/opticalcentralizedattackdetector/service/OpticalCentralizedAttackDetectorServiceServicerImpl.py +11 −11 Original line number Diff line number Diff line Loading @@ -35,18 +35,18 @@ INFLUXDB_HOSTNAME = os.environ.get("INFLUXDB_HOSTNAME") INFLUXDB_USER = os.environ.get("INFLUXDB_USER") INFLUXDB_PASSWORD = os.environ.get("INFLUXDB_PASSWORD") INFLUXDB_DATABASE = os.environ.get("INFLUXDB_DATABASE") context_client: ContextClient = ContextClient(address=CONTEXT_SERVICE_ADDRESS, port=CONTEXT_GRPC_SERVICE_PORT) influxdb_client: InfluxDBClient = InfluxDBClient(host=MONITORING_SERVICE_ADDRESS, port=8086, username=INFLUXDB_USER, password=INFLUXDB_PASSWORD, database=INFLUXDB_DATABASE) monitoring_client: MonitoringClient = MonitoringClient(server=MONITORING_SERVICE_ADDRESS, port=MONITORING_GRPC_SERVICE_PORT) dbscanserving_client: DbscanServingClient = DbscanServingClient(address=INFERENCE_SERVICE_ADDRESS, port=DBSCANSERVING_GRPC_SERVICE_PORT) service_client: ServiceClient = ServiceClient(SERVICE_SERVICE_ADDRESS, SERVICE_GRPC_SERVICE_PORT) attack_mitigator_client: OpticalAttackMitigatorClient = OpticalAttackMitigatorClient(address=ATTACK_MITIGATOR_SERVICE_ADDRESS, port=ATTACK_MITIGATOR_GRPC_SERVICE_PORT) class OpticalCentralizedAttackDetectorServiceServicerImpl(OpticalCentralizedAttackDetectorServiceServicer): def __init__(self): LOGGER.debug('Creating Servicer...') self.context_client: ContextClient = ContextClient(address=CONTEXT_SERVICE_ADDRESS, port=CONTEXT_GRPC_SERVICE_PORT) self.monitoring_client: MonitoringClient = MonitoringClient(server=MONITORING_SERVICE_ADDRESS, port=MONITORING_GRPC_SERVICE_PORT) self.service_client: ServiceClient = ServiceClient(SERVICE_SERVICE_ADDRESS, SERVICE_GRPC_SERVICE_PORT) self.influxdb_client: InfluxDBClient = InfluxDBClient(host=MONITORING_SERVICE_ADDRESS, port=8086, username=INFLUXDB_USER, password=INFLUXDB_PASSWORD, database=INFLUXDB_DATABASE) self.dbscanserving_client: DbscanServingClient = DbscanServingClient(address=INFERENCE_SERVICE_ADDRESS, port=DBSCANSERVING_GRPC_SERVICE_PORT) self.attack_mitigator_client: OpticalAttackMitigatorClient = OpticalAttackMitigatorClient(address=ATTACK_MITIGATOR_SERVICE_ADDRESS, port=ATTACK_MITIGATOR_GRPC_SERVICE_PORT) LOGGER.debug('Servicer Created') @safe_and_metered_rpc_method(METRICS, LOGGER) Loading @@ -58,18 +58,18 @@ class OpticalCentralizedAttackDetectorServiceServicerImpl(OpticalCentralizedAtta # retrieve list with current contexts # import pdb; pdb.set_trace() context_ids: ContextIdList = self.context_client.ListContextIds(Empty()) context_ids: ContextIdList = context_client.ListContextIds(Empty()) # for each context, retrieve list of current services services = [] for context_id in context_ids.context_ids: context_services: ServiceIdList = self.context_client.ListServices(context_id) context_services: ServiceIdList = context_client.ListServices(context_id) for service in context_services.services: services.append(service) # get monitoring data for each of the current services results = self.influxdb_client.query('select * from samples;') results = influxdb_client.query('select * from samples;') for service in services: for endpoint in service.service_endpoint_ids: Loading Loading @@ -107,12 +107,12 @@ class OpticalCentralizedAttackDetectorServiceServicerImpl(OpticalCentralizedAtta grpc_sample.features.append(random.uniform(5000., 6000.)) request.samples.append(grpc_sample) response: DetectionResponse = self.dbscanserving_client.Detect(request) response: DetectionResponse = dbscanserving_client.Detect(request) if -1 in response.cluster_indices: # attack detected attack = AttackDescription() attack.cs_id.uuid = service.service_id.service_uuid.uuid response: AttackResponse = self.attack_mitigator_client.NotifyAttack(attack) response: AttackResponse = attack_mitigator_client.NotifyAttack(attack) # if attack is detected, run the attack mitigator return Empty() Loading
src/opticalcentralizedattackdetector/tests/example_objects.py 0 → 100644 +201 −0 Original line number Diff line number Diff line from copy import deepcopy from common.Constants import DEFAULT_CONTEXT_UUID, DEFAULT_TOPOLOGY_UUID from context.proto.context_pb2 import ( ConfigActionEnum, DeviceDriverEnum, DeviceOperationalStatusEnum, ServiceStatusEnum, ServiceTypeEnum) # Some example objects to be used by the tests # Helper methods def config_rule(action, resource_key, resource_value): return {'action': action, 'resource_key': resource_key, 'resource_value': resource_value} def endpoint_id(topology_id, device_id, endpoint_uuid): return {'topology_id': deepcopy(topology_id), 'device_id': deepcopy(device_id), 'endpoint_uuid': {'uuid': endpoint_uuid}} def endpoint(topology_id, device_id, endpoint_uuid, endpoint_type): return {'endpoint_id': endpoint_id(topology_id, device_id, endpoint_uuid), 'endpoint_type': endpoint_type} ## use "deepcopy" to prevent propagating forced changes during tests CONTEXT_ID = {'context_uuid': {'uuid': DEFAULT_CONTEXT_UUID}} CONTEXT = { 'context_id': deepcopy(CONTEXT_ID), 'topology_ids': [], 'service_ids': [], } CONTEXT_ID_2 = {'context_uuid': {'uuid': 'test'}} CONTEXT_2 = { 'context_id': deepcopy(CONTEXT_ID_2), 'topology_ids': [], 'service_ids': [], } TOPOLOGY_ID = { 'context_id': deepcopy(CONTEXT_ID), 'topology_uuid': {'uuid': DEFAULT_TOPOLOGY_UUID}, } TOPOLOGY = { 'topology_id': deepcopy(TOPOLOGY_ID), 'device_ids': [], 'link_ids': [], } DEVICE1_UUID = 'DEV1' DEVICE1_ID = {'device_uuid': {'uuid': DEVICE1_UUID}} DEVICE1 = { 'device_id': deepcopy(DEVICE1_ID), 'device_type': 'packet-router', 'device_config': {'config_rules': [ config_rule(ConfigActionEnum.CONFIGACTION_SET, 'dev/rsrc1/value', 'value1'), config_rule(ConfigActionEnum.CONFIGACTION_SET, 'dev/rsrc2/value', 'value2'), config_rule(ConfigActionEnum.CONFIGACTION_SET, 'dev/rsrc3/value', 'value3'), ]}, 'device_operational_status': DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_ENABLED, 'device_drivers': [DeviceDriverEnum.DEVICEDRIVER_OPENCONFIG, DeviceDriverEnum.DEVICEDRIVER_P4], 'device_endpoints': [ endpoint(TOPOLOGY_ID, DEVICE1_ID, 'EP2', 'port-packet-100G'), endpoint(TOPOLOGY_ID, DEVICE1_ID, 'EP3', 'port-packet-100G'), endpoint(TOPOLOGY_ID, DEVICE1_ID, 'EP100', 'port-packet-10G'), ], } DEVICE2_UUID = 'DEV2' DEVICE2_ID = {'device_uuid': {'uuid': DEVICE2_UUID}} DEVICE2 = { 'device_id': deepcopy(DEVICE2_ID), 'device_type': 'packet-router', 'device_config': {'config_rules': [ config_rule(ConfigActionEnum.CONFIGACTION_SET, 'dev/rsrc1/value', 'value4'), config_rule(ConfigActionEnum.CONFIGACTION_SET, 'dev/rsrc2/value', 'value5'), config_rule(ConfigActionEnum.CONFIGACTION_SET, 'dev/rsrc3/value', 'value6'), ]}, 'device_operational_status': DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_ENABLED, 'device_drivers': [DeviceDriverEnum.DEVICEDRIVER_OPENCONFIG, DeviceDriverEnum.DEVICEDRIVER_P4], 'device_endpoints': [ endpoint(TOPOLOGY_ID, DEVICE2_ID, 'EP1', 'port-packet-100G'), endpoint(TOPOLOGY_ID, DEVICE2_ID, 'EP3', 'port-packet-100G'), endpoint(TOPOLOGY_ID, DEVICE2_ID, 'EP100', 'port-packet-10G'), ], } DEVICE3_UUID = 'DEV3' DEVICE3_ID = {'device_uuid': {'uuid': DEVICE3_UUID}} DEVICE3 = { 'device_id': deepcopy(DEVICE3_ID), 'device_type': 'packet-router', 'device_config': {'config_rules': [ config_rule(ConfigActionEnum.CONFIGACTION_SET, 'dev/rsrc1/value', 'value4'), config_rule(ConfigActionEnum.CONFIGACTION_SET, 'dev/rsrc2/value', 'value5'), config_rule(ConfigActionEnum.CONFIGACTION_SET, 'dev/rsrc3/value', 'value6'), ]}, 'device_operational_status': DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_ENABLED, 'device_drivers': [DeviceDriverEnum.DEVICEDRIVER_OPENCONFIG, DeviceDriverEnum.DEVICEDRIVER_P4], 'device_endpoints': [ endpoint(TOPOLOGY_ID, DEVICE3_ID, 'EP1', 'port-packet-100G'), endpoint(TOPOLOGY_ID, DEVICE3_ID, 'EP2', 'port-packet-100G'), endpoint(TOPOLOGY_ID, DEVICE3_ID, 'EP100', 'port-packet-10G'), ], } LINK_DEV1_DEV2_UUID = 'DEV1/EP2 ==> DEV2/EP1' LINK_DEV1_DEV2_ID = {'link_uuid': {'uuid': LINK_DEV1_DEV2_UUID}} LINK_DEV1_DEV2 = { 'link_id': deepcopy(LINK_DEV1_DEV2_ID), 'link_endpoint_ids' : [ endpoint_id(TOPOLOGY_ID, DEVICE1_ID, 'EP2'), endpoint_id(TOPOLOGY_ID, DEVICE2_ID, 'EP1'), ] } LINK_DEV2_DEV3_UUID = 'DEV2/EP3 ==> DEV3/EP2' LINK_DEV2_DEV3_ID = {'link_uuid': {'uuid': LINK_DEV2_DEV3_UUID}} LINK_DEV2_DEV3 = { 'link_id': deepcopy(LINK_DEV2_DEV3_ID), 'link_endpoint_ids' : [ endpoint_id(TOPOLOGY_ID, DEVICE2_ID, 'EP3'), endpoint_id(TOPOLOGY_ID, DEVICE3_ID, 'EP2'), ] } LINK_DEV1_DEV3_UUID = 'DEV1/EP3 ==> DEV3/EP1' LINK_DEV1_DEV3_ID = {'link_uuid': {'uuid': LINK_DEV1_DEV3_UUID}} LINK_DEV1_DEV3 = { 'link_id': deepcopy(LINK_DEV1_DEV3_ID), 'link_endpoint_ids' : [ endpoint_id(TOPOLOGY_ID, DEVICE1_ID, 'EP3'), endpoint_id(TOPOLOGY_ID, DEVICE3_ID, 'EP1'), ] } SERVICE_DEV1_DEV2_UUID = 'SVC:DEV1/EP100-DEV2/EP100' SERVICE_DEV1_DEV2_ID = { 'context_id': deepcopy(CONTEXT_ID), 'service_uuid': {'uuid': SERVICE_DEV1_DEV2_UUID}, } SERVICE_DEV1_DEV2 = { 'service_id': deepcopy(SERVICE_DEV1_DEV2_ID), 'service_type': ServiceTypeEnum.SERVICETYPE_L3NM, 'service_endpoint_ids' : [ endpoint_id(TOPOLOGY_ID, DEVICE1_ID, 'EP100'), endpoint_id(TOPOLOGY_ID, DEVICE2_ID, 'EP100'), ], 'service_constraints': [ {'constraint_type': 'latency_ms', 'constraint_value': '15.2'}, {'constraint_type': 'jitter_us', 'constraint_value': '1.2'}, ], 'service_status': {'service_status': ServiceStatusEnum.SERVICESTATUS_ACTIVE}, 'service_config': {'config_rules': [ config_rule(ConfigActionEnum.CONFIGACTION_SET, 'svc/rsrc1/value', 'value7'), config_rule(ConfigActionEnum.CONFIGACTION_SET, 'svc/rsrc2/value', 'value8'), config_rule(ConfigActionEnum.CONFIGACTION_SET, 'svc/rsrc3/value', 'value9'), ]}, } SERVICE_DEV1_DEV3_UUID = 'SVC:DEV1/EP100-DEV3/EP100' SERVICE_DEV1_DEV3_ID = { 'context_id': deepcopy(CONTEXT_ID), 'service_uuid': {'uuid': SERVICE_DEV1_DEV3_UUID}, } SERVICE_DEV1_DEV3 = { 'service_id': deepcopy(SERVICE_DEV1_DEV3_ID), 'service_type': ServiceTypeEnum.SERVICETYPE_L3NM, 'service_endpoint_ids' : [ endpoint_id(TOPOLOGY_ID, DEVICE1_ID, 'EP100'), endpoint_id(TOPOLOGY_ID, DEVICE3_ID, 'EP100'), ], 'service_constraints': [ {'constraint_type': 'latency_ms', 'constraint_value': '5.8'}, {'constraint_type': 'jitter_us', 'constraint_value': '0.1'}, ], 'service_status': {'service_status': ServiceStatusEnum.SERVICESTATUS_ACTIVE}, 'service_config': {'config_rules': [ config_rule(ConfigActionEnum.CONFIGACTION_SET, 'svc/rsrc1/value', 'value7'), config_rule(ConfigActionEnum.CONFIGACTION_SET, 'svc/rsrc2/value', 'value8'), config_rule(ConfigActionEnum.CONFIGACTION_SET, 'svc/rsrc3/value', 'value9'), ]}, } SERVICE_DEV2_DEV3_UUID = 'SVC:DEV2/EP100-DEV3/EP100' SERVICE_DEV2_DEV3_ID = { 'context_id': deepcopy(CONTEXT_ID), 'service_uuid': {'uuid': SERVICE_DEV2_DEV3_UUID}, } SERVICE_DEV2_DEV3 = { 'service_id': deepcopy(SERVICE_DEV2_DEV3_ID), 'service_type': ServiceTypeEnum.SERVICETYPE_L3NM, 'service_endpoint_ids' : [ endpoint_id(TOPOLOGY_ID, DEVICE2_ID, 'EP100'), endpoint_id(TOPOLOGY_ID, DEVICE3_ID, 'EP100'), ], 'service_constraints': [ {'constraint_type': 'latency_ms', 'constraint_value': '23.1'}, {'constraint_type': 'jitter_us', 'constraint_value': '3.4'}, ], 'service_status': {'service_status': ServiceStatusEnum.SERVICESTATUS_ACTIVE}, 'service_config': {'config_rules': [ config_rule(ConfigActionEnum.CONFIGACTION_SET, 'svc/rsrc1/value', 'value7'), config_rule(ConfigActionEnum.CONFIGACTION_SET, 'svc/rsrc2/value', 'value8'), config_rule(ConfigActionEnum.CONFIGACTION_SET, 'svc/rsrc3/value', 'value9'), ]}, }
src/opticalcentralizedattackdetector/tests/test_unitary.py +139 −4 Original line number Diff line number Diff line import logging, pytest from unittest.mock import patch from opticalcentralizedattackdetector.Config import GRPC_SERVICE_PORT, GRPC_MAX_WORKERS, GRPC_GRACE_PERIOD from opticalcentralizedattackdetector.client.OpticalCentralizedAttackDetectorClient import OpticalCentralizedAttackDetectorClient from opticalcentralizedattackdetector.proto.context_pb2 import Empty, Service from opticalcentralizedattackdetector.proto.context_pb2 import ContextIdList, ContextId, Empty, Service, ContextId, ServiceList from opticalcentralizedattackdetector.proto.monitoring_pb2 import Kpi, KpiList from opticalcentralizedattackdetector.service.OpticalCentralizedAttackDetectorService import OpticalCentralizedAttackDetectorService from .example_objects import CONTEXT_ID, CONTEXT_ID_2, SERVICE_DEV1_DEV2 port = 10000 + GRPC_SERVICE_PORT # avoid privileged ports Loading @@ -14,9 +16,17 @@ LOGGER.setLevel(logging.DEBUG) def optical_centralized_attack_detector_service(): _service = OpticalCentralizedAttackDetectorService( port=port, max_workers=GRPC_MAX_WORKERS, grace_period=GRPC_GRACE_PERIOD) # mocker_context_client = mock.patch('opticalcentralizedattackdetector.service.OpticalCentralizedAttackDetectorServiceServicerImpl.context_client') # mocker_context_client.start() # mocker_influx_db = mock.patch('opticalcentralizedattackdetector.service.OpticalCentralizedAttackDetectorServiceServicerImpl.influxdb_client') # mocker_influx_db.start() _service.start() yield _service _service.stop() # mocker_context_client.stop() # mocker_influx_db.stop() @pytest.fixture(scope='session') def optical_centralized_attack_detector_client(optical_centralized_attack_detector_service): Loading @@ -28,10 +38,135 @@ def test_notify_service_update(optical_centralized_attack_detector_client: Optic service = Service() optical_centralized_attack_detector_client.NotifyServiceUpdate(service) def test_detect_attack(optical_centralized_attack_detector_client: OpticalCentralizedAttackDetectorClient): def test_detect_attack_no_contexts(optical_centralized_attack_detector_client: OpticalCentralizedAttackDetectorClient): with patch('opticalcentralizedattackdetector.service.OpticalCentralizedAttackDetectorServiceServicerImpl.context_client') as context, \ patch('opticalcentralizedattackdetector.service.OpticalCentralizedAttackDetectorServiceServicerImpl.influxdb_client') as influxdb: request = Empty() optical_centralized_attack_detector_client.DetectAttack(request) context.ListContextIds.assert_called_once() influxdb.query.assert_called_once() context.ListServices.assert_not_called() def test_detect_attack_with_context(optical_centralized_attack_detector_client: OpticalCentralizedAttackDetectorClient,): with patch('opticalcentralizedattackdetector.service.OpticalCentralizedAttackDetectorServiceServicerImpl.context_client') as context, \ patch('opticalcentralizedattackdetector.service.OpticalCentralizedAttackDetectorServiceServicerImpl.influxdb_client') as influxdb: # setting up the mock cid_list = ContextIdList() cid_list.context_ids.append(ContextId(**CONTEXT_ID)) context.ListContextIds.return_value = cid_list # making the test request = Empty() optical_centralized_attack_detector_client.DetectAttack(request) # checking behavior context.ListContextIds.assert_called_once() context.ListServices.assert_called_with(cid_list.context_ids[0]) influxdb.query.assert_called_once() def test_detect_attack_with_contexts(optical_centralized_attack_detector_client: OpticalCentralizedAttackDetectorClient,): with patch('opticalcentralizedattackdetector.service.OpticalCentralizedAttackDetectorServiceServicerImpl.context_client') as context, \ patch('opticalcentralizedattackdetector.service.OpticalCentralizedAttackDetectorServiceServicerImpl.influxdb_client') as influxdb: # setting up the mock cid_list = ContextIdList() cid_list.context_ids.append(ContextId(**CONTEXT_ID)) cid_list.context_ids.append(ContextId(**CONTEXT_ID_2)) context.ListContextIds.return_value = cid_list # making the test request = Empty() optical_centralized_attack_detector_client.DetectAttack(request) # checking behavior context.ListContextIds.assert_called_once() context.ListServices.assert_any_call(cid_list.context_ids[0]) context.ListServices.assert_any_call(cid_list.context_ids[1]) influxdb.query.assert_called_once() def test_detect_attack_with_service(optical_centralized_attack_detector_client: OpticalCentralizedAttackDetectorClient,): with patch('opticalcentralizedattackdetector.service.OpticalCentralizedAttackDetectorServiceServicerImpl.context_client') as context, \ patch('opticalcentralizedattackdetector.service.OpticalCentralizedAttackDetectorServiceServicerImpl.influxdb_client') as influxdb, \ patch('opticalcentralizedattackdetector.service.OpticalCentralizedAttackDetectorServiceServicerImpl.dbscanserving_client') as dbscan: # setting up the mock cid_list = ContextIdList() cid_list.context_ids.append(ContextId(**CONTEXT_ID)) context.ListContextIds.return_value = cid_list service_list = ServiceList() service_list.services.append(Service(**SERVICE_DEV1_DEV2)) context.ListServices.return_value = service_list influxdb.query.return_value.get_points.return_value = [(1, 2), (3, 4)] # making the test request = Empty() optical_centralized_attack_detector_client.DetectAttack(request) # checking behavior context.ListContextIds.assert_called_once() context.ListServices.assert_called_with(cid_list.context_ids[0]) influxdb.query.assert_called_once() dbscan.Detect.assert_called() def test_detect_attack_no_attack(optical_centralized_attack_detector_client: OpticalCentralizedAttackDetectorClient,): with patch('opticalcentralizedattackdetector.service.OpticalCentralizedAttackDetectorServiceServicerImpl.context_client') as context, \ patch('opticalcentralizedattackdetector.service.OpticalCentralizedAttackDetectorServiceServicerImpl.influxdb_client') as influxdb, \ patch('opticalcentralizedattackdetector.service.OpticalCentralizedAttackDetectorServiceServicerImpl.dbscanserving_client') as dbscan, \ patch('opticalcentralizedattackdetector.service.OpticalCentralizedAttackDetectorServiceServicerImpl.attack_mitigator_client') as mitigator: # setting up the mock cid_list = ContextIdList() cid_list.context_ids.append(ContextId(**CONTEXT_ID)) context.ListContextIds.return_value = cid_list service_list = ServiceList() service_list.services.append(Service(**SERVICE_DEV1_DEV2)) context.ListServices.return_value = service_list # dbscan.Detect.return_value = object() dbscan.Detect.return_value.cluster_indices = [0, 1, 2, 3, 4, 5] # making the test request = Empty() optical_centralized_attack_detector_client.DetectAttack(request) # checking behavior context.ListContextIds.assert_called_once() context.ListServices.assert_called_with(cid_list.context_ids[0]) influxdb.query.assert_called_once() dbscan.Detect.assert_called() mitigator.NotifyAttack.assert_not_called() def test_detect_attack_with_attack(optical_centralized_attack_detector_client: OpticalCentralizedAttackDetectorClient,): with patch('opticalcentralizedattackdetector.service.OpticalCentralizedAttackDetectorServiceServicerImpl.context_client') as context, \ patch('opticalcentralizedattackdetector.service.OpticalCentralizedAttackDetectorServiceServicerImpl.influxdb_client') as influxdb, \ patch('opticalcentralizedattackdetector.service.OpticalCentralizedAttackDetectorServiceServicerImpl.dbscanserving_client') as dbscan, \ patch('opticalcentralizedattackdetector.service.OpticalCentralizedAttackDetectorServiceServicerImpl.attack_mitigator_client') as mitigator: # setting up the mock cid_list = ContextIdList() cid_list.context_ids.append(ContextId(**CONTEXT_ID)) context.ListContextIds.return_value = cid_list service_list = ServiceList() service_list.services.append(Service(**SERVICE_DEV1_DEV2)) context.ListServices.return_value = service_list # dbscan.Detect.return_value = object() dbscan.Detect.return_value.cluster_indices = [0, 1, 2, 3, 4, -1] # making the test request = Empty() optical_centralized_attack_detector_client.DetectAttack(request) # checking behavior context.ListContextIds.assert_called_once() context.ListServices.assert_called_with(cid_list.context_ids[0]) influxdb.query.assert_called_once() dbscan.Detect.assert_called() mitigator.NotifyAttack.assert_called() def test_report_summarized_kpi(optical_centralized_attack_detector_client: OpticalCentralizedAttackDetectorClient): kpi_list = KpiList() optical_centralized_attack_detector_client.ReportSummarizedKpi(kpi_list) Loading