diff --git a/mktxp/cli/config/config.py b/mktxp/cli/config/config.py index 013f812..98451d7 100755 --- a/mktxp/cli/config/config.py +++ b/mktxp/cli/config/config.py @@ -95,7 +95,8 @@ class MKTXPConfigKeys: FE_CHECK_FOR_UPDATES = 'check_for_updates' - FE_KID_CONTROL_DEVICE = 'kid_control_devices' + FE_KID_CONTROL_DEVICE = 'kid_control_assigned' + FE_KID_CONTROL_DYNAMIC = 'kid_control_dynamic' MKTXP_SOCKET_TIMEOUT = 'socket_timeout' MKTXP_INITIAL_DELAY = 'initial_delay_on_failure' @@ -140,7 +141,7 @@ class MKTXPConfigKeys: DEFAULT_MKTXP_TOTAL_MAX_SCRAPE_DURATION = 30 - BOOLEAN_KEYS_NO = {ENABLED_KEY, SSL_KEY, NO_SSL_CERTIFICATE, FE_CHECK_FOR_UPDATES, FE_KID_CONTROL_DEVICE, + BOOLEAN_KEYS_NO = {ENABLED_KEY, SSL_KEY, NO_SSL_CERTIFICATE, FE_CHECK_FOR_UPDATES, FE_KID_CONTROL_DEVICE, FE_KID_CONTROL_DYNAMIC, SSL_CERTIFICATE_VERIFY, FE_IPV6_FIREWALL_KEY, FE_IPV6_NEIGHBOR_KEY, FE_CONNECTION_STATS_KEY, FE_BGP_KEY} # Feature keys enabled by default @@ -169,9 +170,10 @@ class ConfigEntry: MKTXPConfigKeys.SSL_KEY, MKTXPConfigKeys.NO_SSL_CERTIFICATE, MKTXPConfigKeys.SSL_CERTIFICATE_VERIFY, MKTXPConfigKeys.FE_DHCP_KEY, MKTXPConfigKeys.FE_PACKAGE_KEY, MKTXPConfigKeys.FE_DHCP_LEASE_KEY, MKTXPConfigKeys.FE_DHCP_POOL_KEY, MKTXPConfigKeys.FE_INTERFACE_KEY, MKTXPConfigKeys.FE_FIREWALL_KEY, MKTXPConfigKeys.FE_MONITOR_KEY, MKTXPConfigKeys.FE_ROUTE_KEY, MKTXPConfigKeys.FE_WIRELESS_KEY, MKTXPConfigKeys.FE_WIRELESS_CLIENTS_KEY, - MKTXPConfigKeys.FE_IP_CONNECTIONS_KEY, MKTXPConfigKeys.FE_CONNECTION_STATS_KEY, MKTXPConfigKeys.FE_CAPSMAN_KEY, MKTXPConfigKeys.FE_CAPSMAN_CLIENTS_KEY, MKTXPConfigKeys.FE_POE_KEY, MKTXPConfigKeys.FE_NETWATCH_KEY, - MKTXPConfigKeys.MKTXP_USE_COMMENTS_OVER_NAMES, MKTXPConfigKeys.FE_PUBLIC_IP_KEY, MKTXPConfigKeys.FE_IPV6_FIREWALL_KEY, MKTXPConfigKeys.FE_IPV6_NEIGHBOR_KEY, - MKTXPConfigKeys.FE_USER_KEY, MKTXPConfigKeys.FE_QUEUE_KEY, MKTXPConfigKeys.FE_REMOTE_DHCP_ENTRY, MKTXPConfigKeys.FE_CHECK_FOR_UPDATES, MKTXPConfigKeys.FE_KID_CONTROL_DEVICE, MKTXPConfigKeys.FE_BGP_KEY, + MKTXPConfigKeys.FE_IP_CONNECTIONS_KEY, MKTXPConfigKeys.FE_CONNECTION_STATS_KEY, MKTXPConfigKeys.FE_CAPSMAN_KEY, MKTXPConfigKeys.FE_CAPSMAN_CLIENTS_KEY, MKTXPConfigKeys.FE_POE_KEY, + MKTXPConfigKeys.FE_NETWATCH_KEY, MKTXPConfigKeys.MKTXP_USE_COMMENTS_OVER_NAMES, MKTXPConfigKeys.FE_PUBLIC_IP_KEY, MKTXPConfigKeys.FE_IPV6_FIREWALL_KEY, MKTXPConfigKeys.FE_IPV6_NEIGHBOR_KEY, + MKTXPConfigKeys.FE_USER_KEY, MKTXPConfigKeys.FE_QUEUE_KEY, MKTXPConfigKeys.FE_REMOTE_DHCP_ENTRY, MKTXPConfigKeys.FE_CHECK_FOR_UPDATES, MKTXPConfigKeys.FE_BGP_KEY, + MKTXPConfigKeys.FE_KID_CONTROL_DEVICE, MKTXPConfigKeys.FE_KID_CONTROL_DYNAMIC ]) MKTXPSystemEntry = namedtuple('MKTXPSystemEntry', [MKTXPConfigKeys.PORT_KEY, MKTXPConfigKeys.LISTEN_KEY, MKTXPConfigKeys.MKTXP_SOCKET_TIMEOUT, MKTXPConfigKeys.MKTXP_INITIAL_DELAY, MKTXPConfigKeys.MKTXP_MAX_DELAY, diff --git a/mktxp/cli/config/mktxp.conf b/mktxp/cli/config/mktxp.conf index 80999bf..f27984e 100644 --- a/mktxp/cli/config/mktxp.conf +++ b/mktxp/cli/config/mktxp.conf @@ -53,7 +53,8 @@ capsman = True # CAPsMAN general metrics capsman_clients = True # CAPsMAN clients metrics - kid_control_devices = False # Kid Control metrics + kid_control_assigned = False # Allow Kid Control metrics for connected devices with assigned users + kid_control_dynamic = False # Allow Kid Control metrics for all connected devices, including those without assigned user user = True # Active Users metrics queue = True # Queues metrics diff --git a/mktxp/collector/bgp_collector.py b/mktxp/collector/bgp_collector.py index 78148fc..6f3449d 100644 --- a/mktxp/collector/bgp_collector.py +++ b/mktxp/collector/bgp_collector.py @@ -25,18 +25,13 @@ class BGPCollector(BaseCollector): return bgp_labels = ['name', 'remote_address', 'remote_as', 'local_as', 'remote_afi', 'local_afi', 'remote_messages', 'remote_bytes', 'local_messages', 'local_bytes', 'prefix_count', 'established', 'uptime'] - bgp_records = BGPMetricsDataSource.metric_records(router_entry, metric_labels=bgp_labels) + translation_table = { + 'established': lambda value: '1' if value=='true' else '0', + 'uptime': lambda value: BaseOutputProcessor.parse_timedelta_milliseconds(value) if value else '0' + } + bgp_records = BGPMetricsDataSource.metric_records(router_entry, metric_labels=bgp_labels, translation_table = translation_table) - if bgp_records: - # translate records to appropriate values - translated_fields = ['established', 'uptime'] - for bgp_record in bgp_records: - for translated_field in translated_fields: - value = bgp_record.get(translated_field, None) - if value: - bgp_record[translated_field] = BGPCollector._translated_values(translated_field, value) - session_info_labes = ['name', 'remote_address', 'remote_as', 'local_as', 'remote_afi', 'local_afi'] bgp_sessions_metrics = BaseCollector.info_collector('bgp_sessions_info', 'BGP sessions info', bgp_records, session_info_labes) yield bgp_sessions_metrics @@ -69,12 +64,3 @@ class BGPCollector(BaseCollector): uptime_metrics = BaseCollector.gauge_collector('bgp_uptime', 'BGP uptime in milliseconds', bgp_records, 'uptime', session_id_labes) yield uptime_metrics - - # Helpers - @staticmethod - def _translated_values(translated_field, value): - return { - 'established': lambda value: '1' if value=='true' else '0', - 'uptime': lambda value: BaseOutputProcessor.parse_timedelta_milliseconds(value) - }[translated_field](value) - diff --git a/mktxp/collector/kid_control_device_collector.py b/mktxp/collector/kid_control_device_collector.py index 5834a23..57d151c 100644 --- a/mktxp/collector/kid_control_device_collector.py +++ b/mktxp/collector/kid_control_device_collector.py @@ -23,43 +23,29 @@ class KidDeviceCollector(BaseCollector): @staticmethod def collect(router_entry): - if not router_entry.config_entry.kid_control_devices: + if not (router_entry.config_entry.kid_control_assigned or router_entry.config_entry.kid_control_dynamic): return - labels = ['name', 'user', 'mac_address', 'ip_address', 'bytes_down', 'bytes_up', 'rate_up', 'rate_down', - 'bytes_up', 'idle_time', - 'blocked', 'limited', 'inactive', 'disabled'] - info_labels = ['name', 'user', 'mac_address', 'ip_address', 'disabled'] - records = KidDeviceMetricsDataSource.metric_records(router_entry, metric_labels=labels) + labels = ['name', 'user', 'mac_address', 'ip_address', 'bytes_down', 'bytes_up', 'rate_up', + 'rate_down','bytes_up', 'idle_time','blocked', 'limited', 'inactive', 'disabled'] + translation_table = { + 'rate_up': lambda value: BaseOutputProcessor.parse_rates(value), + 'rate_down': lambda value: BaseOutputProcessor.parse_rates(value), + 'idle_time': lambda value: BaseOutputProcessor.parse_timedelta_seconds(value) if value else 0, + 'blocked': lambda value: '1' if value == 'true' else '0', + 'limited': lambda value: '1' if value == 'true' else '0', + 'inactive': lambda value: '1' if value == 'true' else '0', + 'disabled': lambda value: '1' if value == 'true' else '0'} + + records = KidDeviceMetricsDataSource.metric_records(router_entry, metric_labels=labels, translation_table=translation_table) if records: - # translate records to appropriate values - for record in records: - for label in record: - value = record.get(label, None) - if value: - record[label] = KidDeviceCollector._translated_values(label, value) - + info_labels = ['name', 'user', 'mac_address', 'ip_address', 'disabled'] yield BaseCollector.info_collector('kid_control_device', 'Kid-control device Info', records, info_labels) - yield BaseCollector.gauge_collector('kid_control_device_bytes_down', 'Number of received bytes', records, 'bytes_down', ['name', 'mac_address', 'user']) - yield BaseCollector.gauge_collector('kid_control_device_bytes_up', 'Number of transmitted bytes', records, 'bytes_up', ['name', 'mac_address', 'user']) - yield BaseCollector.gauge_collector('kid_control_device_rate_down', 'Device rate down', records, 'rate_down', ['name', 'mac_address', 'user']) - yield BaseCollector.gauge_collector('kid_control_device_rate_up', 'Device rate up', records, 'rate_up', ['name', 'mac_address', 'user']) - yield BaseCollector.gauge_collector('kid_control_device_idle_time', 'Device idle time', records, 'idle_time', ['name', 'mac_address', 'user']) - # Helpers - @staticmethod - def _translated_values(monitor_label, value): - try: - return { - 'rate_up': lambda value: BaseOutputProcessor.parse_rates(value), - 'rate_down': lambda value: BaseOutputProcessor.parse_rates(value), - 'idle_time': lambda value: BaseOutputProcessor.parse_timedelta_seconds(value), - 'blocked': lambda value: '1' if value == 'true' else '0', - 'limited': lambda value: '1' if value == 'true' else '0', - 'inactive': lambda value: '1' if value == 'true' else '0', - 'disabled': lambda value: '1' if value == 'true' else '0', - }[monitor_label](value) - except KeyError: - # default to just returning the value - return value + id_labels = ['name', 'mac_address', 'user'] + yield BaseCollector.gauge_collector('kid_control_device_bytes_down', 'Number of received bytes', records, 'bytes_down', id_labels) + yield BaseCollector.gauge_collector('kid_control_device_bytes_up', 'Number of transmitted bytes', records, 'bytes_up', id_labels) + yield BaseCollector.gauge_collector('kid_control_device_rate_down', 'Device rate down', records, 'rate_down', id_labels) + yield BaseCollector.gauge_collector('kid_control_device_rate_up', 'Device rate up', records, 'rate_up', id_labels) + yield BaseCollector.gauge_collector('kid_control_device_idle_time', 'Device idle time', records, 'idle_time', id_labels) diff --git a/mktxp/collector/monitor_collector.py b/mktxp/collector/monitor_collector.py index 7b7e5b2..11878ba 100644 --- a/mktxp/collector/monitor_collector.py +++ b/mktxp/collector/monitor_collector.py @@ -26,15 +26,16 @@ class MonitorCollector(BaseCollector): return monitor_labels = ['status', 'rate', 'full_duplex', 'name', 'sfp_temperature'] - monitor_records = InterfaceMonitorMetricsDataSource.metric_records(router_entry, metric_labels = monitor_labels, include_comments = True) + translation_table = { + 'status': lambda value: '1' if value=='link-ok' else '0', + 'rate': lambda value: MonitorCollector._rates(value) if value else '0', + 'full_duplex': lambda value: '1' if value=='true' else '0', + 'name': lambda value: value if value else '', + 'sfp_temperature': lambda value: value if value else '0' + } + monitor_records = InterfaceMonitorMetricsDataSource.metric_records(router_entry, metric_labels = monitor_labels, + translation_table=translation_table, include_comments = True) if monitor_records: - # translate records to appropriate values - for monitor_record in monitor_records: - for monitor_label in monitor_labels: - value = monitor_record.get(monitor_label, None) - if value: - monitor_record[monitor_label] = MonitorCollector._translated_values(monitor_label, value) - monitor_status_metrics = BaseCollector.gauge_collector('interface_status', 'Current interface link status', monitor_records, 'status', ['name']) yield monitor_status_metrics @@ -50,17 +51,6 @@ class MonitorCollector(BaseCollector): sfp_temperature_metrics = BaseCollector.gauge_collector('interface_sfp_temperature', 'Current SFP temperature', monitor_records, 'sfp_temperature', ['name']) yield sfp_temperature_metrics - # Helpers - @staticmethod - def _translated_values(monitor_label, value): - return { - 'status': lambda value: '1' if value=='link-ok' else '0', - 'rate': lambda value: MonitorCollector._rates(value), - 'full_duplex': lambda value: '1' if value=='true' else '0', - 'name': lambda value: value, - 'sfp_temperature': lambda value: value - }[monitor_label](value) - @staticmethod def _rates(rate_option): # according mikrotik docs, an interface rate should be one of these diff --git a/mktxp/collector/resource_collector.py b/mktxp/collector/resource_collector.py index 15b3d2d..429e9bf 100644 --- a/mktxp/collector/resource_collector.py +++ b/mktxp/collector/resource_collector.py @@ -27,17 +27,10 @@ class SystemResourceCollector(BaseCollector): 'cpu', 'cpu_count', 'cpu_frequency', 'cpu_load', 'free_hdd_space', 'total_hdd_space', 'architecture_name', 'board_name'] - - resource_records = SystemResourceMetricsDataSource.metric_records(router_entry, metric_labels = resource_labels) - if resource_records: - # translate records to appropriate values - translated_fields = ['uptime'] - for resource_record in resource_records: - for translated_field in translated_fields: - value = resource_record.get(translated_field, None) - if value: - resource_record[translated_field] = SystemResourceCollector._translated_values(translated_field, value) + translation_table = {'uptime': lambda value: BaseOutputProcessor.parse_timedelta_seconds(value)} + resource_records = SystemResourceMetricsDataSource.metric_records(router_entry, metric_labels = resource_labels, translation_table=translation_table) + if resource_records: uptime_metrics = BaseCollector.gauge_collector('system_uptime', 'Time interval since boot-up', resource_records, 'uptime', ['version', 'board_name', 'cpu', 'architecture_name']) yield uptime_metrics @@ -71,12 +64,3 @@ class SystemResourceCollector(BaseCollector): update_available_metrics = BaseCollector.gauge_collector('system_update_available', 'Is there a newer version available', resource_records, 'update_available', ['newest_version',]) yield update_available_metrics - - - # Helpers - @staticmethod - def _translated_values(translated_field, value): - return { - 'uptime': lambda value: BaseOutputProcessor.parse_timedelta_seconds(value) - }[translated_field](value) - diff --git a/mktxp/datasource/bgp_ds.py b/mktxp/datasource/bgp_ds.py index 78740be..8f18db3 100644 --- a/mktxp/datasource/bgp_ds.py +++ b/mktxp/datasource/bgp_ds.py @@ -19,12 +19,12 @@ class BGPMetricsDataSource: ''' Wireless Metrics data provider ''' @staticmethod - def metric_records(router_entry, *, metric_labels = None, add_router_id = True): + def metric_records(router_entry, *, metric_labels = None, translation_table = None): if metric_labels is None: metric_labels = [] try: bgp_records = router_entry.api_connection.router_api().get_resource('/routing/bgp/session').get() - return BaseDSProcessor.trimmed_records(router_entry, router_records = bgp_records, metric_labels = metric_labels, add_router_id = add_router_id) + return BaseDSProcessor.trimmed_records(router_entry, router_records = bgp_records, metric_labels = metric_labels, translation_table = translation_table) except Exception as exc: print(f'Error getting BGP sessions info from router{router_entry.router_name}@{router_entry.config_entry.hostname}: {exc}') return None diff --git a/mktxp/datasource/interface_ds.py b/mktxp/datasource/interface_ds.py index 8a12cb7..90aa28b 100644 --- a/mktxp/datasource/interface_ds.py +++ b/mktxp/datasource/interface_ds.py @@ -34,7 +34,7 @@ class InterfaceMonitorMetricsDataSource: ''' Interface Monitor Metrics data provider ''' @staticmethod - def metric_records(router_entry, *, metric_labels = None, kind = 'ethernet', include_comments = False, running_only = True): + def metric_records(router_entry, *, metric_labels = None, translation_table = None, kind = 'ethernet', include_comments = False, running_only = True): if metric_labels is None: metric_labels = [] try: @@ -60,7 +60,7 @@ class InterfaceMonitorMetricsDataSource: for interface_monitor_record in interface_monitor_records: if 'registered-peers' in interface_monitor_record: interface_monitor_record['registered-clients'] = interface_monitor_record['registered-peers'] - return BaseDSProcessor.trimmed_records(router_entry, router_records = interface_monitor_records, metric_labels = metric_labels) + return BaseDSProcessor.trimmed_records(router_entry, router_records = interface_monitor_records, metric_labels = metric_labels, translation_table=translation_table) except Exception as exc: print(f'Error getting {kind} interface monitor info from router{router_entry.router_name}@{router_entry.config_entry.hostname}: {exc}') return None diff --git a/mktxp/datasource/kid_control_device_ds.py b/mktxp/datasource/kid_control_device_ds.py index 143eaec..87be35c 100644 --- a/mktxp/datasource/kid_control_device_ds.py +++ b/mktxp/datasource/kid_control_device_ds.py @@ -20,16 +20,16 @@ class KidDeviceMetricsDataSource: """ @staticmethod - def metric_records(router_entry, *, metric_labels=None): + def metric_records(router_entry, *, metric_labels=None, translation_table = None): if metric_labels is None: metric_labels = [] try: device_records = [] records = router_entry.api_connection.router_api().get_resource('/ip/kid-control/device').get() for record in records: - if record.get('user'): + if record.get('user') or router_entry.config_entry.kid_control_dynamic: device_records.append(record) - return BaseDSProcessor.trimmed_records(router_entry, router_records=device_records, metric_labels=metric_labels) + return BaseDSProcessor.trimmed_records(router_entry, router_records=device_records, metric_labels=metric_labels, translation_table=translation_table) except Exception as exc: print( f'Error getting Kid-control device info from router{router_entry.router_name}@{router_entry.config_entry.hostname}: {exc}') diff --git a/mktxp/datasource/system_resource_ds.py b/mktxp/datasource/system_resource_ds.py index 8c7ffb0..99ec02f 100644 --- a/mktxp/datasource/system_resource_ds.py +++ b/mktxp/datasource/system_resource_ds.py @@ -20,12 +20,12 @@ class SystemResourceMetricsDataSource: ''' System Resource Metrics data provider ''' @staticmethod - def metric_records(router_entry, *, metric_labels = None): + def metric_records(router_entry, *, metric_labels = None, translation_table=None): if metric_labels is None: metric_labels = [] try: system_resource_records = router_entry.api_connection.router_api().get_resource('/system/resource').get() - return BaseDSProcessor.trimmed_records(router_entry, router_records = system_resource_records, metric_labels = metric_labels) + return BaseDSProcessor.trimmed_records(router_entry, router_records = system_resource_records, metric_labels = metric_labels, translation_table=translation_table) except Exception as exc: print(f'Error getting system resource info from router{router_entry.router_name}@{router_entry.config_entry.hostname}: {exc}') return None