diff --git a/.github/workflows/pdr_plugin_ci_workflow.yml b/.github/workflows/pdr_plugin_ci_workflow.yml new file mode 100644 index 000000000..1b1356c71 --- /dev/null +++ b/.github/workflows/pdr_plugin_ci_workflow.yml @@ -0,0 +1,51 @@ +name: PDR Plugin CI Workflow + +on: + push: + paths: + - 'plugins/pdr_deterministic_plugin/**' +jobs: + build: + runs-on: ubuntu-latest + + env: + PYTHONPATH: '.:plugins/pdr_deterministic_plugin/ufm_sim_web_service' + PDRPATH: 'plugins/pdr_deterministic_plugin' + + steps: + - name: Checkout code + uses: actions/checkout@main + + - name: Set up Python + uses: actions/setup-python@main + with: + python-version: 3.9 + + - name: Install dependencies + run: | + pip install -r $PDRPATH/requirements.txt + pip install pylint + pip install pytest-cov + + - name: Run PyLint + run: pylint --rcfile=$PDRPATH/.pylintrc $PDRPATH + + - name: Run exclusion list class test + timeout-minutes: 5 + run: pytest -s $PDRPATH/tests/exclude_list_class_tests.py --cov=$PDRPATH + + - name: Test exclusion list REST API + timeout-minutes: 5 + run: | + sudo bash $PDRPATH/.pytest/run_pdr_standalone_pytest.sh + echo "Test exclusion list REST API methods" + pytest -s $PDRPATH/tests/exclude_list_rest_api_tests.py --cov=$PDRPATH + sudo bash $PDRPATH/.pytest/terminate_pdr_standalone_pytest.sh + + - name: Run full simulation test + timeout-minutes: 10 + run: | + sudo bash $PDRPATH/.pytest/run_pdr_standalone_pytest.sh + echo "Starting simulated test" + python $PDRPATH/tests/simulation_telemetry.py + sudo bash $PDRPATH/.pytest/terminate_pdr_standalone_pytest.sh diff --git a/plugins/pdr_deterministic_plugin/.pylintrc b/plugins/pdr_deterministic_plugin/.pylintrc new file mode 100644 index 000000000..4eda3a070 --- /dev/null +++ b/plugins/pdr_deterministic_plugin/.pylintrc @@ -0,0 +1,17 @@ +[MASTER] +init-hook="import os, sys; sys.path.append(os.path.join(os.getcwd(), 'plugins', 'pdr_deterministic_plugin', 'src')); sys.path.append(os.path.join(os.getcwd(), 'utils'))" + +[MAIN] +max-public-methods=100 + +[DESIGN] +max-attributes=10 + +[MESSAGES CONTROL] +disable=missing-module-docstring,missing-function-docstring,fixme + +[FORMAT] +max-line-length=140 + +[BASIC] +min-public-methods=0 diff --git a/plugins/pdr_deterministic_plugin/.pytest/run_pdr_standalone_pytest.sh b/plugins/pdr_deterministic_plugin/.pytest/run_pdr_standalone_pytest.sh new file mode 100644 index 000000000..841b8cf93 --- /dev/null +++ b/plugins/pdr_deterministic_plugin/.pytest/run_pdr_standalone_pytest.sh @@ -0,0 +1,39 @@ +#!/bin/bash -x + +PLUGIN_DIR="plugins/pdr_deterministic_plugin" +pip install -r $PLUGIN_DIR/requirements.txt >/dev/null 2>&1 + +cp -r utils $PLUGIN_DIR/ufm_sim_web_service +cp -r utils $PLUGIN_DIR/tests + +echo "Init PDR configuration file" +CONFIG_FILE="/config/pdr_deterministic.conf" +mkdir -p /config +cp -f $PLUGIN_DIR/build/config/pdr_deterministic.conf "$CONFIG_FILE" +sed -i -e 's/DRY_RUN=False/DRY_RUN=True/g' "$CONFIG_FILE" +sed -i -e 's/INTERVAL=300/INTERVAL=10/g' "$CONFIG_FILE" +sed -i -e 's/CONFIGURED_TEMP_CHECK=False/CONFIGURED_TEMP_CHECK=True/g' "$CONFIG_FILE" +sed -i -e 's/LINK_DOWN_ISOLATION=False/LINK_DOWN_ISOLATION=True/g' "$CONFIG_FILE" +sed -i -e 's/DEISOLATE_CONSIDER_TIME=5/DEISOLATE_CONSIDER_TIME=1/g' "$CONFIG_FILE" + +# Remove any existing TEST_MODE lines from the file +sed -i -e '/TEST_MODE=\(True\|False\)/d' "$CONFIG_FILE" + +# Check if the section [Common] exists +if grep -q '^\[Common\]' "$CONFIG_FILE"; then + # If section exists, insert TEST_MODE=True under it + awk '/^\[Common\]/ {print; print "TEST_MODE=True"; next}1' "$CONFIG_FILE" > temp && mv temp "$CONFIG_FILE" +else + # If section does not exist, add it to the file + echo -e '\n[Common]\nTEST_MODE=True\n' >> "$CONFIG_FILE" +fi + +bash $PLUGIN_DIR/.pytest/terminate_pdr_standalone_pytest.sh +echo "Starting standalone PDR process" +python $PLUGIN_DIR/ufm_sim_web_service/isolation_algo.py >/dev/null 2>&1 & +sleep 10 +if ! ps aux | grep -q [i]solation_algo.py; then + echo "Failed to start standalone PDR process" + exit 1 +fi +# PDR is up and ready for communication \ No newline at end of file diff --git a/plugins/pdr_deterministic_plugin/.pytest/terminate_pdr_standalone_pytest.sh b/plugins/pdr_deterministic_plugin/.pytest/terminate_pdr_standalone_pytest.sh new file mode 100644 index 000000000..f5c6f00b8 --- /dev/null +++ b/plugins/pdr_deterministic_plugin/.pytest/terminate_pdr_standalone_pytest.sh @@ -0,0 +1,9 @@ +#!/bin/bash -x + +echo "Terminating standalone PDR process" +ps -ef | grep isolation_algo.py | grep -v grep | awk '{print $2}' | xargs kill -9 $1 >/dev/null 2>/dev/null +sleep 10 +if ps aux | grep -q [i]solation_algo.py; then + echo "Failed to terminate standalone PDR process" + exit 1 +fi diff --git a/plugins/pdr_deterministic_plugin/__init__.py b/plugins/pdr_deterministic_plugin/__init__.py new file mode 100644 index 000000000..26680606e --- /dev/null +++ b/plugins/pdr_deterministic_plugin/__init__.py @@ -0,0 +1,11 @@ +# +# Copyright © 2013-2024 NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED. +# +# This software product is a proprietary product of Nvidia Corporation and its affiliates +# (the "Company") and all right, title, and interest in and to the software +# product, including all associated intellectual property rights, are and +# shall remain exclusively with the Company. +# +# This software product is governed by the End User License Agreement +# provided with the software product. +# diff --git a/plugins/pdr_deterministic_plugin/requirements.txt b/plugins/pdr_deterministic_plugin/requirements.txt new file mode 100644 index 000000000..cf712dea9 --- /dev/null +++ b/plugins/pdr_deterministic_plugin/requirements.txt @@ -0,0 +1,9 @@ +flask<=3.0.3 +numpy<=1.26.4 +pandas<=2.2.2 +pytest<=8.2.0 +requests<=2.31.0 +twisted<=22.1.0 +flask_restful<=0.3.10 +tzlocal<=4.2 +jsonschema<=4.5.1 diff --git a/plugins/pdr_deterministic_plugin/tests/exclude_list_class_tests.py b/plugins/pdr_deterministic_plugin/tests/exclude_list_class_tests.py new file mode 100644 index 000000000..1c0626c15 --- /dev/null +++ b/plugins/pdr_deterministic_plugin/tests/exclude_list_class_tests.py @@ -0,0 +1,102 @@ +# +# Copyright © 2013-2024 NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED. +# +# This software product is a proprietary product of Nvidia Corporation and its affiliates +# (the "Company") and all right, title, and interest in and to the software +# product, including all associated intellectual property rights, are and +# shall remain exclusively with the Company. +# +# This software product is governed by the End User License Agreement +# provided with the software product. +# + +import os +import tempfile +import time +from constants import PDRConstants as Constants +from exclude_list import ExcludeList, ExcludeListItem +from isolation_algo import create_logger + + +def get_logger(): + """ + Return logger associated with log file in temporary directory + """ + log_name = os.path.basename(Constants.LOG_FILE) + log_path = os.path.join(tempfile.gettempdir(), log_name) + return create_logger(log_path) + + +def test_exclude_list_class_methods(): + """ + Test exclude list class methods by direct calls + """ + print("\n") # Start tests output from new line + + excluded_ports = [ + ExcludeListItem("0123456789aaabbb_1", 0), # Add forever + ExcludeListItem("9876543210cccddd_2", 30), # Add for 30 seconds + ExcludeListItem("3456789012eeefff_3", 0) # Add forever + ] + + # Create exclusion list and ensure it's empty + exclude_list = ExcludeList(get_logger()) + items = exclude_list.items() + assert not items + print(" - test: create exclusion list and ensure it's empty -- PASS") + + # Add ports to excluded list + for port in excluded_ports: + exclude_list.add(port.port_name, port.ttl_seconds) + + # Test exclusion list size + items = exclude_list.items() + assert items and len(items) == len(excluded_ports) + print(" - test: add ports to exclusion list -- PASS") + + # Test 'contains' method + for port in excluded_ports: + assert exclude_list.contains(port.port_name) + print(" - test: exclusion list 'contains' method -- PASS") + + # Test exclusion list content + for (index, item) in enumerate(items): + assert item.port_name == excluded_ports[index].port_name + assert item.ttl_seconds == excluded_ports[index].ttl_seconds + print(" - test: exclusion list content -- PASS") + + # Test auto-remove of second port after TTL is expired + auto_remove_port = excluded_ports[1] + time.sleep(auto_remove_port.ttl_seconds + 1) + assert not exclude_list.contains(auto_remove_port.port_name) + print(" - test: auto-remove of port from exclusion list after TTL is expired -- PASS") + + # Test excluded list size + items = exclude_list.items() + assert items and len(items) == (len(excluded_ports) - 1) + + # Test excluded list content + for port in excluded_ports: + if port.port_name != auto_remove_port.port_name: + assert exclude_list.contains(port.port_name) + print(" - test: exclusion list content -- PASS") + + # Test forced remove of third port + remove_port = excluded_ports[2] + exclude_list.remove(port.port_name) + assert not exclude_list.contains(remove_port.port_name) + print(" - test: forced remove of port from exclusion list -- PASS") + + # Test excluded list size + items = exclude_list.items() + assert items and len(items) == (len(excluded_ports) - 2) + + # Test excluded list content + for port in excluded_ports: + if port.port_name != remove_port.port_name and port.port_name != auto_remove_port.port_name: + assert exclude_list.contains(port.port_name) + print(" - test: exclusion list content -- PASS") + + +if __name__ == '__main__': + test_exclude_list_class_methods() diff --git a/plugins/pdr_deterministic_plugin/tests/exclude_list_rest_api_tests.py b/plugins/pdr_deterministic_plugin/tests/exclude_list_rest_api_tests.py new file mode 100644 index 000000000..cf7920117 --- /dev/null +++ b/plugins/pdr_deterministic_plugin/tests/exclude_list_rest_api_tests.py @@ -0,0 +1,99 @@ +# +# Copyright © 2013-2024 NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED. +# +# This software product is a proprietary product of Nvidia Corporation and its affiliates +# (the "Company") and all right, title, and interest in and to the software +# product, including all associated intellectual property rights, are and +# shall remain exclusively with the Company. +# +# This software product is governed by the End User License Agreement +# provided with the software product. +# + +import http +import json +import random +import time +import requests + + +def generate_port_name(): + """ + Generate port name + """ + port_guid = f'{random.randrange(16**16):016x}' + port_num = random.randint(10, 99) + return f'{port_guid}_{port_num}' + + +def test_exclude_list_rest_api(): + """ + Test exclude list via plugin REST API + """ + print("\n") # Start tests output from new line + + url = "http://127.0.0.1:8977/excluded" + + excluded_ports = [ + (generate_port_name(), 0), # Add forever + (generate_port_name(), 30), # Add for 30 seconds + (generate_port_name(), 0) # Add forever + ] + + # Get (empty) list content + response = requests.get(url, timeout=5) + assert response.status_code == http.client.OK + assert all(char.isspace() for char in response.text) + print(" - test: get exclusion list and ensure it's empty -- PASS") + + # Add ports to excluded list + response = requests.put(url, data=json.dumps(excluded_ports), timeout=5) + assert response.status_code == http.client.OK + for pair in excluded_ports: + port_name = pair[0] + assert port_name in response.text + print(" - test: add ports to exclusion list -- PASS") + + # Test exclusion list content + response = requests.get(url, timeout=5) + assert response.status_code == http.client.OK + for pair in excluded_ports: + port_name = pair[0] + assert port_name in response.text + print(" - test: get added ports from exclusion list -- PASS") + + # Wait until second port TTL is expired + ttl_seconds = excluded_ports[1][1] + time.sleep(ttl_seconds + 1) + + # Test auto-remove of second port after TTL is expired + response = requests.get(url, timeout=5) + assert response.status_code == http.client.OK + for (index, pair) in enumerate(excluded_ports): + port_name = pair[0] + if index == 1: + assert port_name not in response.text + else: + assert port_name in response.text + print(" - test: auto-remove of port from exclusion list after TTL is expired -- PASS") + + # Test forced remove of third port + port_name = excluded_ports[2][0] + response = requests.delete(url, data=json.dumps([port_name]), timeout=5) + assert response.status_code == http.client.OK + assert f'{port_name} removed' in response.text + print(" - test: forced remove of port from exclusion list -- PASS") + + # Test exclusion list content + response = requests.get(url, timeout=5) + for (index, pair) in enumerate(excluded_ports): + port_name = excluded_ports[index][0] + if index == 1 or index == 2: + assert port_name not in response.text + else: + assert port_name in response.text + print(" - test: exclusion list content -- PASS") + + +if __name__ == '__main__': + test_exclude_list_rest_api() diff --git a/plugins/pdr_deterministic_plugin/tests/simulation_telemetry.py b/plugins/pdr_deterministic_plugin/tests/simulation_telemetry.py index 6a68176a1..59023bf39 100755 --- a/plugins/pdr_deterministic_plugin/tests/simulation_telemetry.py +++ b/plugins/pdr_deterministic_plugin/tests/simulation_telemetry.py @@ -17,7 +17,6 @@ import copy import argparse import random -from os import _exit from os.path import exists from collections import OrderedDict import requests @@ -46,11 +45,13 @@ ] class CsvEndpointHandler(BaseHTTPRequestHandler): - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - - def do_GET(self): + """ + CsvEndpointHandler class + """ + def do_GET(self): # pylint: disable=invalid-name + """ + Response on simulated telemetry request + """ self.send_response(200) self.send_header('Content-type', 'text/plain') self.end_headers() @@ -114,7 +115,7 @@ def do_GET(self): NEGATIVE_DATA_TEST = { # example, also negative test (1, 0, PHY_SYMBOL_ERROR): 0, - + # testing exclusion list (0, 5, EXCLUDE_PORT_LONG_TIME): 0, # add to exclusion list forever (1, 5, LINK_DOWN_COUNTER): 1, @@ -129,15 +130,20 @@ def do_GET(self): } def get_max_iteration_index(tests): - return max([test[0] for test in tests]) if tests else 0 + """ + Return largest iteration for given port index + """ + return max([test[0] for test in tests]) if tests else 0 # getting the max tests we test plus 2 MAX_POSITIVE_ITERATION_INDEX = get_max_iteration_index(POSITIVE_DATA_TEST) MAX_NEGATIVE_ITERATION_INDEX = get_max_iteration_index(NEGATIVE_DATA_TEST) MAX_ITERATIONS = max(MAX_POSITIVE_ITERATION_INDEX, MAX_NEGATIVE_ITERATION_INDEX) + 2 -# return randomize value base on the counter name -def randomize_values(counter_name:str,iteration:int): +def randomize_values(counter_name:str, iteration:int): + """ + Randomize value based on the counter name + """ if counter_name == RCV_PACKETS_COUNTER: return 1000000 + iteration * 10 if counter_name == TEMP_COUNTER: @@ -149,8 +155,11 @@ def randomize_values(counter_name:str,iteration:int): if counter_name == FEC_MODE: return 0 -# return value if found on our testing telemetry simulation, else return default value for that telemetry. def find_value(row_index:int, counter_name:str, iteration:int, default=0): + """ + Return value if found on our testing telemetry simulation, + else return default value for that telemetry. + """ if counter_name == RCV_PACKETS_COUNTER: return str(1000000 + iteration * 10) value = POSITIVE_DATA_TEST.get((iteration, row_index, counter_name), None) @@ -161,6 +170,9 @@ def find_value(row_index:int, counter_name:str, iteration:int, default=0): return value def start_server(port:str,changes_intervals:int, run_forever:bool): + """ + Start simulated telemetry server + """ server_address = ('', int(port)) httpd = HTTPServer(server_address, CsvEndpointHandler) handler_instance = httpd.RequestHandlerClass @@ -208,6 +220,9 @@ def start_server(port:str,changes_intervals:int, run_forever:bool): time.sleep(changes_intervals) def excluded_ports_simulation(endpoint): + """ + Perform operations on exclusion port for current iteration + """ added_ports = [] removed_ports = [] rows = endpoint['row'] @@ -245,23 +260,27 @@ def excluded_ports_simulation(endpoint): removed_ports_str = '[' + ','.join(removed_ports) + ']' requests.delete(url=url, data=removed_ports_str, timeout=5) -# create an array of ports in size of ports_num -def create_ports(config:dict,ports_num: int): +def create_ports(config:dict, ports_num: int): + """ + Create an array of ports in size of ports_num + """ ports_list = [] ports_names = [] for _ in range(ports_num): port_guid = f'0x{random.randrange(16**16):016x}' # holds the prefix of each simulated csv rows, # list of counters structures(will be filled further) - port_num = random.randint(1, 99) + port_num = random.randint(10, 99) ports_list.append([f"{port_guid},,{port_guid},{port_guid},{port_num}", []]) ports_names.append(f"{port_guid[2:]}_{port_num}") config["Ports_names"] = ports_names return ports_list -# create simulate counters base of list of string of the counters def simulate_counters(supported_counters: list): + """ + Create simulate counters base of list of string of the counters + """ counters = {} for counter in supported_counters: counters[counter] = { @@ -271,6 +290,9 @@ def simulate_counters(supported_counters: list): return counters def initialize_simulated_counters(endpoint_obj: dict): + """ + Initialize simulated counters + """ counters = endpoint_obj['counters'] rows = endpoint_obj['row'] for row in rows: @@ -280,13 +302,19 @@ def initialize_simulated_counters(endpoint_obj: dict): counter_obj['last_val'] = initial_val row[1].append(counter_obj) -def assert_equal(message, left_expr, right_expr, test_name="positive"): - if left_expr == right_expr: - print(f" - {test_name} test: {message} -- PASS") - else: - print(f" - {test_name} test: {message} -- FAIL (expected: {right_expr}, actual: {left_expr})") +def print_test_result(message, left_expr, right_expr, test_name="positive"): + """ + Print test result + """ + if left_expr == right_expr: + print(f" - {test_name} test: {message} -- PASS") + else: + print(f" - {test_name} test: {message} -- FAIL (expected: {right_expr}, actual: {left_expr})") def validate_simulation_data(): + """ + Validate simulation data for positive and negative tests + """ positive_test_port_indexes = set([x[1] for x in POSITIVE_DATA_TEST]) negative_test_port_indexes = set([x[1] for x in NEGATIVE_DATA_TEST]) if not positive_test_port_indexes.isdisjoint(negative_test_port_indexes): @@ -296,6 +324,9 @@ def validate_simulation_data(): return True def check_logs(config): + """ + Analyze output log and create tests results + """ lines=[] location_logs_can_be = ["/log/pdr_deterministic_plugin.log", "/tmp/pdr_deterministic_plugin.log", @@ -303,7 +334,7 @@ def check_logs(config): "/opt/ufm/log/plugins/pdr_deterministic/pdr_deterministic_plugin.log"] for log_location in location_logs_can_be: if exists(log_location): - with open(log_location,'r') as log_file: + with open(log_location,'r') as log_file: # pylint: disable=unspecified-encoding lines=log_file.readlines() break if len(lines) == 0: @@ -328,7 +359,7 @@ def check_logs(config): break if not found: number_of_failed_positive_tests += 1 - assert_equal(f"port {port_name} (index: {p}) which check {tested_counter} changed and should be in the logs", found, True) + print_test_result(f"port {port_name} (index: {p}) which check {tested_counter} changed and should be in the logs", found, True) for p in ports_should_not_be_isolated_indices: found=False @@ -340,13 +371,15 @@ def check_logs(config): found = True number_of_failed_negative_tests += 1 break - assert_equal(f"port {port_name} (index: {p}) which check {tested_counter} should not be in the logs", found, False, "negative") + print_test_result(f"port {port_name} (index: {p}) which check {tested_counter} should not be in the logs", found, False, "negative") all_pass = number_of_failed_positive_tests == 0 and number_of_failed_negative_tests == 0 return 0 if all_pass else 1 -# start a server which update the counters every time def main(): + """ + Start a server which update the counters every time + """ parser = argparse.ArgumentParser() parser.add_argument('--num_simulated_ports', type=int, default=10, help="number of ports to simulate if set to 0 ports will be taken from the UFM REST server") @@ -392,5 +425,11 @@ def main(): if not args.run_forever: return check_logs(config) +def test_main(): + """ + To be called by pytest + """ + assert main() == 0 + if __name__ == '__main__': - _exit(main()) + test_main() diff --git a/plugins/pdr_deterministic_plugin/ufm_sim_web_service/isolation_algo.py b/plugins/pdr_deterministic_plugin/ufm_sim_web_service/isolation_algo.py index 58350b4f5..b5272c5d5 100644 --- a/plugins/pdr_deterministic_plugin/ufm_sim_web_service/isolation_algo.py +++ b/plugins/pdr_deterministic_plugin/ufm_sim_web_service/isolation_algo.py @@ -26,27 +26,26 @@ from utils.utils import Utils -def create_logger(file): +def create_logger(log_file): """ create a logger to put all the data of the server action :param file: name of the file :return: """ - format_str = "%(asctime)-15s UFM-PDR_deterministic-plugin-{0} Machine: {1} %(levelname)-7s: %(message)s".format(file,'localhost') - log_name = Constants.LOG_FILE - if not os.path.exists(log_name): - os.makedirs('/'.join(log_name.split('/')[:-1]), exist_ok=True) - logger = logging.getLogger(log_name) + format_str = "%(asctime)-15s UFM-PDR_deterministic-plugin-{0} Machine: {1} %(levelname)-7s: %(message)s".format(log_file,'localhost') + if not os.path.exists(log_file): + os.makedirs('/'.join(log_file.split('/')[:-1]), exist_ok=True) + logger = logging.getLogger(log_file) logging_level = logging.getLevelName(Constants.log_level) \ if isinstance(Constants.log_level, str) else Constants.log_level logging.basicConfig(format=format_str,level=logging_level) - rotateHandler = RotatingFileHandler(log_name,maxBytes=Constants.log_file_max_size, + rotate_handler = RotatingFileHandler(log_file,maxBytes=Constants.log_file_max_size, backupCount=Constants.log_file_backup_count) - rotateHandler.setLevel(Constants.log_level) - rotateHandler.setFormatter(logging.Formatter(format_str)) - logger.addHandler(rotateHandler) + rotate_handler.setLevel(Constants.log_level) + rotate_handler.setFormatter(logging.Formatter(format_str)) + logger.addHandler(rotate_handler) return logger diff --git a/plugins/pdr_deterministic_plugin/ufm_sim_web_service/isolation_mgr.py b/plugins/pdr_deterministic_plugin/ufm_sim_web_service/isolation_mgr.py index 69947a422..c5eb8d632 100644 --- a/plugins/pdr_deterministic_plugin/ufm_sim_web_service/isolation_mgr.py +++ b/plugins/pdr_deterministic_plugin/ufm_sim_web_service/isolation_mgr.py @@ -315,7 +315,8 @@ def eval_isolation(self, port_name, cause): log_message = f"Isolated port: {port_name} cause: {cause}. dry_run: {self.dry_run}" self.logger.warning(log_message) - self.ufm_client.send_event(log_message, event_id=Constants.EXTERNAL_EVENT_ALERT, external_event_name="Isolating Port") + if not self.test_mode: + self.ufm_client.send_event(log_message, event_id=Constants.EXTERNAL_EVENT_ALERT, external_event_name="Isolating Port") def eval_deisolate(self, port_name): @@ -373,8 +374,9 @@ def eval_deisolate(self, port_name): self.ports_states.pop(port_name) log_message = f"Deisolated port: {port_name}. dry_run: {self.dry_run}" self.logger.warning(log_message) - self.ufm_client.send_event(log_message, event_id=Constants.EXTERNAL_EVENT_NOTICE, external_event_name="Deisolating Port") - + if not self.test_mode: + self.ufm_client.send_event(log_message, event_id=Constants.EXTERNAL_EVENT_NOTICE, external_event_name="Deisolating Port") + def get_rate(self, port_obj, counter_name, new_val, timestamp): """ Calculate the rate of the counter @@ -907,7 +909,7 @@ def main_flow(self): self.logger.warning(event_msg) if not self.test_mode: self.ufm_client.send_event(event_msg, event_id=Constants.EXTERNAL_EVENT_ALERT, external_event_name="Skipping isolation") - + # deal with reported new issues else: for issue in issues.values():