From c90aa5f7e896cac48b3a729cd5c000880f5c9e15 Mon Sep 17 00:00:00 2001 From: Natalie Gaston Date: Tue, 18 Jan 2022 10:46:10 -0800 Subject: [PATCH] Add bounds and default for node-agent configuration key/value pairs (#14) --- docs/Configuration Parameters.md | 12 ++++----- inbm-lib/inbm_common_lib/validater.py | 27 +++++++++++++++++-- .../unit/inbm_common_lib/test_validater.py | 17 ++++++++++++ inbm-vision/Changelog.md | 1 + inbm-vision/node-agent/node/constant.py | 12 +++++---- inbm-vision/node-agent/node/data_handler.py | 25 +++++++---------- 6 files changed, 66 insertions(+), 28 deletions(-) create mode 100644 inbm-lib/tests/unit/inbm_common_lib/test_validater.py diff --git a/docs/Configuration Parameters.md b/docs/Configuration Parameters.md index 2e3dca3c2..335f3410e 100644 --- a/docs/Configuration Parameters.md +++ b/docs/Configuration Parameters.md @@ -86,9 +86,9 @@ Node Agent configuration file is located at: ````/etc/intel-manageability/public The best way to update the file is either by using the cloud or INBC. -| Key | Default Value | Description | -|:---------------------------|:-------------:|:----------------------------------------------------------------------------------------------------------------------| -| registrationRetryTimerSecs | 20 | Timer interval for the Node agent to send a registration request if a response is not received from the Vision Agent. | -| registrationRetryLimit | 8 | Number of attempted retries for the Node Agent to send a registration request. | -| XLinkPCIeDevID | 0 | Number used to connect the XLink PCIe devices to the Node Agent | -| heartbeatResponseTimerSecs | 300 | | +| Key | Default Value | Lower Limit | Upper Limit | Description | +|:---------------------------|:-------------:|:------------|:------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------| +| registrationRetryTimerSecs | 20 | 1 | 60 | Timer interval for the Node agent to send a registration request if a response is not received from the Vision Agent. | +| registrationRetryLimit | 8 | 3 | 15 | Number of attempted retries for the Node Agent to send a registration request. | +| XLinkPCIeDevID | 0 | N/A | N/A | Number used to connect the XLink PCIe devices to the Node Agent. | +| heartbeatResponseTimerSecs | 300 | 90 | 1800 | Timer interval to wait for heartbeat response from vision-agent after sending heartbeat message. If not received node will re-register with the Vision agent. | diff --git a/inbm-lib/inbm_common_lib/validater.py b/inbm-lib/inbm_common_lib/validater.py index c46358d0a..7e5725aca 100644 --- a/inbm-lib/inbm_common_lib/validater.py +++ b/inbm-lib/inbm_common_lib/validater.py @@ -1,14 +1,18 @@ """ User import validation - Copyright (C) 2017-2021 Intel Corporation + Copyright (C) 2017-2022 Intel Corporation SPDX-License-Identifier: Apache-2.0 """ +import logging import datetime import argparse +from dataclasses import dataclass + +logger = logging.getLogger(__name__) def validate_string_less_than_n_characters(value: str, param_type: str, max_size: int) -> str: - """Validates that the user inputted string does not exeed the maximum allowed + """Validates that the user inputted string does not exceed the maximum allowed @param value: string entered by user @param param_type: parameter type @param max_size: maximum size allowed for the string @@ -31,3 +35,22 @@ def validate_date(date: str) -> str: return str(datetime.datetime.strptime(date, "%Y-%m-%d").date()) except ValueError: raise argparse.ArgumentTypeError(f"Not a valid date - format YYYY-MM-DD: '{date}") + + +@dataclass +class ConfigurationItem: + """Class for keeping track of an item in inventory.""" + key: str + lower_limit: int + upper_limit: int + default_value: int + + +def configuration_bounds_check(item: ConfigurationItem, value: int) -> int: + if item.lower_limit < int(value) < item.upper_limit: + return value + else: + logger.error(f'{item.key} is outside of the allowed limits: ' + f'{item.lower_limit}-{item.upper_limit}. ' + f'Using the default value: {item.default_value}.') + return item.default_value diff --git a/inbm-lib/tests/unit/inbm_common_lib/test_validater.py b/inbm-lib/tests/unit/inbm_common_lib/test_validater.py new file mode 100644 index 000000000..8b65a7392 --- /dev/null +++ b/inbm-lib/tests/unit/inbm_common_lib/test_validater.py @@ -0,0 +1,17 @@ +from unittest import TestCase +from inbm_common_lib.validater import ConfigurationItem, configuration_bounds_check + + +class TestValidater(TestCase): + + def setUp(self): + self.item = ConfigurationItem('RegistrationRetry Timer Secs', 1, 60, 20) + + def test_return_value_when_within_limits(self) -> None: + self.assertEquals(30, configuration_bounds_check(self.item, 30)) + + def test_return_default_when_below_lower_limit(self) -> None: + self.assertEquals(20, configuration_bounds_check(self.item, 0)) + + def test_return_default_when_above_upper_limit(self) -> None: + self.assertEquals(20, configuration_bounds_check(self.item, 61)) diff --git a/inbm-vision/Changelog.md b/inbm-vision/Changelog.md index 29dcb1d0e..1a41171fe 100644 --- a/inbm-vision/Changelog.md +++ b/inbm-vision/Changelog.md @@ -10,6 +10,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/). - 506035, HSD 15010309026 - Update node apparmor policy by adding /sys/kernel/xlink_secure/debug - HSD 15010516458 - Fix storage checks failed during mender file transferring in SOTA/POTA - 506874 - Fix node config schema error when upgrading from v2.16.0 to v2.17.2 +- 507151 - Add lower bound, upper bound, and default values to node-agent configuration values. ## 3.0.7 - 2022-01-04 diff --git a/inbm-vision/node-agent/node/constant.py b/inbm-vision/node-agent/node/constant.py index 272a1763f..ede6a677b 100644 --- a/inbm-vision/node-agent/node/constant.py +++ b/inbm-vision/node-agent/node/constant.py @@ -2,10 +2,12 @@ """ Constants and other config variables used throughout the node-agent - Copyright (C) 2019-2021 Intel Corporation + Copyright (C) 2019-2022 Intel Corporation SPDX-License-Identifier: Apache-2.0 """ +from inbm_common_lib.validater import ConfigurationItem + AGENT = 'node' STATE_CHANNEL = '+/state' @@ -95,10 +97,10 @@ # Node version file path NODE_VERSION_PATH = '/usr/share/node-agent/version.txt' -# Configuration value limits -CONFIG_HEARTBEAT_RESPONSE_SECS_UPPER_LIMIT = 1800 -CONFIG_HEARTBEAT_RESPONSE_SECS_LOWER_LIMIT = 90 -CONFIG_HEARTBEAT_RESPONSE_SECS_DEFAULT = 300 +# Configuration items (key, lower bound, upper bound, default value) +CONFIG_REGISTRATION_RETRY_TIMER_SECS = ConfigurationItem('RegistrationRetry Timer Secs', 1, 60, 20) +CONFIG_HEARTBEAT_RESPONSE_TIMER_SECS = ConfigurationItem('Heartbeat Response Timer Secs', 90, 1800, 300) +CONFIG_REGISTRATION_RETRY_LIMIT = ConfigurationItem('Registration Retry Limit', 3, 15, 8) # Var directory VAR_DIR = '/var' diff --git a/inbm-vision/node-agent/node/data_handler.py b/inbm-vision/node-agent/node/data_handler.py index 136542bd6..af1fbc280 100644 --- a/inbm-vision/node-agent/node/data_handler.py +++ b/inbm-vision/node-agent/node/data_handler.py @@ -13,6 +13,7 @@ from typing import Optional, Any from pathlib import Path +from inbm_common_lib.validater import configuration_bounds_check from inbm_vision_lib.invoker import Invoker from inbm_vision_lib import checksum_validator from inbm_vision_lib.configuration_manager import ConfigurationManager @@ -27,8 +28,8 @@ from .command.configuration_command import ConfigValuesCommand, LoadConfigCommand, SendConfigResponseCommand from .constant import INVOKER_QUEUE_SIZE, GET_ELEMENT, SET_ELEMENT, \ REGISTRATION_RETRY_TIMER_SECS, REGISTRATION_RETRY_LIMIT, LOAD, APPEND, REMOVE, \ - XLINK_SCHEMA_LOCATION, KEY_DICTIONARY, HEARTBEAT_RESPONSE_TIMER_SECS, CONFIG_HEARTBEAT_RESPONSE_SECS_DEFAULT, \ - CONFIG_HEARTBEAT_RESPONSE_SECS_LOWER_LIMIT, CONFIG_HEARTBEAT_RESPONSE_SECS_UPPER_LIMIT + XLINK_SCHEMA_LOCATION, KEY_DICTIONARY, HEARTBEAT_RESPONSE_TIMER_SECS, CONFIG_REGISTRATION_RETRY_TIMER_SECS, \ + CONFIG_REGISTRATION_RETRY_LIMIT, CONFIG_HEARTBEAT_RESPONSE_TIMER_SECS from .heartbeat_timer import HeartbeatTimer from .node_exception import NodeException from .xlink_parser import XLinkParser @@ -53,10 +54,10 @@ def __init__(self, node_callback: inode.INode, config_callback: ConfigurationMan self._heartbeat_interval: Optional[int] = None self._nid: Optional[str] = None self._timer: Optional[HeartbeatTimer] = None - self._retry_limit = 0 + self._retry_limit: int = 0 self._retry_interval: int = 0 self._retry_timer: int = 0 - self._heartbeat_response: int = CONFIG_HEARTBEAT_RESPONSE_SECS_DEFAULT + self._heartbeat_response: int = CONFIG_HEARTBEAT_RESPONSE_TIMER_SECS.default_value self._heartbeat_response_timer: Optional[HeartbeatTimer] = None self.load_config_file() self.file_name = None @@ -292,7 +293,7 @@ def send_heartbeat(self) -> None: self.start_heartbeat_response_timer() def start_heartbeat_response_timer(self) -> None: - """Start a timer to wait for heartbeat response. If timer expires, it create a Register Command + """Start a timer to wait for heartbeat response. If timer expires, it creates a Register Command and start the Register sequence again""" if self._heartbeat_response_timer: self._heartbeat_response_timer.stop() @@ -331,18 +332,12 @@ def publish_config_value(self, children: Optional[dict]) -> None: for child in children: value = children[child] if child == REGISTRATION_RETRY_TIMER_SECS: - self._retry_timer = int(value) + self._retry_timer = configuration_bounds_check(CONFIG_REGISTRATION_RETRY_TIMER_SECS, int(value)) if child == REGISTRATION_RETRY_LIMIT: - self._retry_interval = int(value) + self._retry_interval = configuration_bounds_check(CONFIG_REGISTRATION_RETRY_LIMIT, int(value)) if child == HEARTBEAT_RESPONSE_TIMER_SECS: - if CONFIG_HEARTBEAT_RESPONSE_SECS_LOWER_LIMIT < int(value) < CONFIG_HEARTBEAT_RESPONSE_SECS_UPPER_LIMIT: - self._heartbeat_response = int(value) - else: - logger.error(f'Heartbeat Response is outside of the allowed limits: ' - f'{CONFIG_HEARTBEAT_RESPONSE_SECS_LOWER_LIMIT}-' - f'{CONFIG_HEARTBEAT_RESPONSE_SECS_UPPER_LIMIT}. ' - f'Using the default value: {CONFIG_HEARTBEAT_RESPONSE_SECS_DEFAULT}.') - self._heartbeat_response = CONFIG_HEARTBEAT_RESPONSE_SECS_DEFAULT + self._heartbeat_response = \ + configuration_bounds_check(CONFIG_HEARTBEAT_RESPONSE_TIMER_SECS, int(value)) else: logger.error('Children value is empty')