mirror of
				https://github.com/KevinMidboe/mktxp-no-cli.git
				synced 2025-10-29 17:50:23 +00:00 
			
		
		
		
	remote dhcp info resolution (wireless/capsman), more wifiwave2 support
This commit is contained in:
		| @@ -331,7 +331,7 @@ mktxp is running as pid 36704 | |||||||
|  |  | ||||||
| ```` | ```` | ||||||
| ❯ mktxp -h | ❯ mktxp -h | ||||||
| usage: MKTXP [-h] [--dir DIR] {info, edit, export, print, show, } ... | usage: MKTXP [-h] [--cfg-dir CFG_DIR] {info, edit, export, print, show, } ... | ||||||
| ```` | ```` | ||||||
| To learn more about individual commands, just run it with ```-h```: | To learn more about individual commands, just run it with ```-h```: | ||||||
| For example, to learn everything about ````mktxp show````: | For example, to learn everything about ````mktxp show````: | ||||||
|   | |||||||
| @@ -62,6 +62,7 @@ class MKTXPConfigKeys: | |||||||
|  |  | ||||||
|     FE_USER_KEY = 'user' |     FE_USER_KEY = 'user' | ||||||
|     FE_QUEUE_KEY = 'queue' |     FE_QUEUE_KEY = 'queue' | ||||||
|  |     FE_REMOTE_DHCP_ENTRY = 'remote_dhcp_entry' | ||||||
|  |  | ||||||
|     MKTXP_SOCKET_TIMEOUT = 'socket_timeout' |     MKTXP_SOCKET_TIMEOUT = 'socket_timeout' | ||||||
|     MKTXP_INITIAL_DELAY = 'initial_delay_on_failure' |     MKTXP_INITIAL_DELAY = 'initial_delay_on_failure' | ||||||
| @@ -88,6 +89,7 @@ class MKTXPConfigKeys: | |||||||
|     # Default values |     # Default values | ||||||
|     DEFAULT_API_PORT = 8728 |     DEFAULT_API_PORT = 8728 | ||||||
|     DEFAULT_API_SSL_PORT = 8729 |     DEFAULT_API_SSL_PORT = 8729 | ||||||
|  |     DEFAULT_FE_REMOTE_DHCP_ENTRY = 'None' | ||||||
|     DEFAULT_MKTXP_PORT = 49090 |     DEFAULT_MKTXP_PORT = 49090 | ||||||
|     DEFAULT_MKTXP_SOCKET_TIMEOUT = 2 |     DEFAULT_MKTXP_SOCKET_TIMEOUT = 2 | ||||||
|     DEFAULT_MKTXP_INITIAL_DELAY = 120 |     DEFAULT_MKTXP_INITIAL_DELAY = 120 | ||||||
| @@ -113,7 +115,7 @@ class MKTXPConfigKeys: | |||||||
|     SYSTEM_BOOLEAN_KEYS_YES = {MKTXP_BANDWIDTH_KEY} |     SYSTEM_BOOLEAN_KEYS_YES = {MKTXP_BANDWIDTH_KEY} | ||||||
|     SYSTEM_BOOLEAN_KEYS_NO = {MKTXP_VERBOSE_MODE, MKTXP_FETCH_IN_PARALLEL} |     SYSTEM_BOOLEAN_KEYS_NO = {MKTXP_VERBOSE_MODE, MKTXP_FETCH_IN_PARALLEL} | ||||||
|  |  | ||||||
|     STR_KEYS = (HOST_KEY, USER_KEY, PASSWD_KEY) |     STR_KEYS = (HOST_KEY, USER_KEY, PASSWD_KEY, FE_REMOTE_DHCP_ENTRY) | ||||||
|     MKTXP_INT_KEYS = (PORT_KEY, MKTXP_SOCKET_TIMEOUT, MKTXP_INITIAL_DELAY, MKTXP_MAX_DELAY, |     MKTXP_INT_KEYS = (PORT_KEY, MKTXP_SOCKET_TIMEOUT, MKTXP_INITIAL_DELAY, MKTXP_MAX_DELAY, | ||||||
|                       MKTXP_INC_DIV, MKTXP_BANDWIDTH_TEST_INTERVAL, MKTXP_MIN_COLLECT_INTERVAL, |                       MKTXP_INC_DIV, MKTXP_BANDWIDTH_TEST_INTERVAL, MKTXP_MIN_COLLECT_INTERVAL, | ||||||
|                       MKTXP_MAX_WORKER_THREADS, MKTXP_MAX_SCRAPE_DURATION, MKTXP_TOTAL_MAX_SCRAPE_DURATION) |                       MKTXP_MAX_WORKER_THREADS, MKTXP_MAX_SCRAPE_DURATION, MKTXP_TOTAL_MAX_SCRAPE_DURATION) | ||||||
| @@ -130,7 +132,7 @@ class ConfigEntry: | |||||||
|                                                        MKTXPConfigKeys.FE_FIREWALL_KEY, MKTXPConfigKeys.FE_MONITOR_KEY, MKTXPConfigKeys.FE_ROUTE_KEY, MKTXPConfigKeys.FE_WIRELESS_KEY, MKTXPConfigKeys.FE_WIRELESS_CLIENTS_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_CAPSMAN_KEY, MKTXPConfigKeys.FE_CAPSMAN_CLIENTS_KEY, MKTXPConfigKeys.FE_POE_KEY, MKTXPConfigKeys.FE_NETWATCH_KEY, |                                                        MKTXPConfigKeys.FE_IP_CONNECTIONS_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.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_USER_KEY, MKTXPConfigKeys.FE_QUEUE_KEY, MKTXPConfigKeys.FE_REMOTE_DHCP_ENTRY | ||||||
|                                                        ]) |                                                        ]) | ||||||
|     MKTXPSystemEntry = namedtuple('MKTXPSystemEntry', [MKTXPConfigKeys.PORT_KEY, MKTXPConfigKeys.MKTXP_SOCKET_TIMEOUT, |     MKTXPSystemEntry = namedtuple('MKTXPSystemEntry', [MKTXPConfigKeys.PORT_KEY, MKTXPConfigKeys.MKTXP_SOCKET_TIMEOUT, | ||||||
|                                                        MKTXPConfigKeys.MKTXP_INITIAL_DELAY, MKTXPConfigKeys.MKTXP_MAX_DELAY, |                                                        MKTXPConfigKeys.MKTXP_INITIAL_DELAY, MKTXPConfigKeys.MKTXP_MAX_DELAY, | ||||||
| @@ -277,7 +279,12 @@ class MKTXPConfigHandler: | |||||||
|                 new_keys.append(key) # read from disk next time |                 new_keys.append(key) # read from disk next time | ||||||
|  |  | ||||||
|         for key in MKTXPConfigKeys.STR_KEYS: |         for key in MKTXPConfigKeys.STR_KEYS: | ||||||
|             config_entry_reader[key] = self.config[entry_name][key] |             if self.config[entry_name].get(key): | ||||||
|  |                 config_entry_reader[key] = self.config[entry_name].get(key) | ||||||
|  |             else: | ||||||
|  |                 config_entry_reader[key] = self._default_value_for_key(key) | ||||||
|  |                 new_keys.append(key) # read from disk next time | ||||||
|  |  | ||||||
|             if key is MKTXPConfigKeys.PASSWD_KEY and type(config_entry_reader[key]) is list: |             if key is MKTXPConfigKeys.PASSWD_KEY and type(config_entry_reader[key]) is list: | ||||||
|                 config_entry_reader[key] = ','.join(config_entry_reader[key]) |                 config_entry_reader[key] = ','.join(config_entry_reader[key]) | ||||||
|  |  | ||||||
| @@ -338,6 +345,7 @@ class MKTXPConfigHandler: | |||||||
|         return { |         return { | ||||||
|             MKTXPConfigKeys.SSL_KEY: lambda value: MKTXPConfigKeys.DEFAULT_API_SSL_PORT if value else MKTXPConfigKeys.DEFAULT_API_PORT, |             MKTXPConfigKeys.SSL_KEY: lambda value: MKTXPConfigKeys.DEFAULT_API_SSL_PORT if value else MKTXPConfigKeys.DEFAULT_API_PORT, | ||||||
|             MKTXPConfigKeys.PORT_KEY: lambda value: MKTXPConfigKeys.DEFAULT_MKTXP_PORT, |             MKTXPConfigKeys.PORT_KEY: lambda value: MKTXPConfigKeys.DEFAULT_MKTXP_PORT, | ||||||
|  |             MKTXPConfigKeys.FE_REMOTE_DHCP_ENTRY:  lambda value: MKTXPConfigKeys.DEFAULT_FE_REMOTE_DHCP_ENTRY, | ||||||
|             MKTXPConfigKeys.MKTXP_SOCKET_TIMEOUT: lambda value: MKTXPConfigKeys.DEFAULT_MKTXP_SOCKET_TIMEOUT, |             MKTXPConfigKeys.MKTXP_SOCKET_TIMEOUT: lambda value: MKTXPConfigKeys.DEFAULT_MKTXP_SOCKET_TIMEOUT, | ||||||
|             MKTXPConfigKeys.MKTXP_INITIAL_DELAY: lambda value: MKTXPConfigKeys.DEFAULT_MKTXP_INITIAL_DELAY, |             MKTXPConfigKeys.MKTXP_INITIAL_DELAY: lambda value: MKTXPConfigKeys.DEFAULT_MKTXP_INITIAL_DELAY, | ||||||
|             MKTXPConfigKeys.MKTXP_MAX_DELAY: lambda value: MKTXPConfigKeys.DEFAULT_MKTXP_MAX_DELAY, |             MKTXPConfigKeys.MKTXP_MAX_DELAY: lambda value: MKTXPConfigKeys.DEFAULT_MKTXP_MAX_DELAY, | ||||||
|   | |||||||
| @@ -47,5 +47,6 @@ | |||||||
|  |  | ||||||
|     user = True                     # Active Users metrics |     user = True                     # Active Users metrics | ||||||
|     queue = True                    # Queues metrics |     queue = True                    # Queues metrics | ||||||
|  |     remote_dhcp_entry = None        # Alternative mktxp entry for DHCP info resolution (capsman/wireless) | ||||||
|  |  | ||||||
|     use_comments_over_names = True  # when available, forces using comments over the interfaces names  |     use_comments_over_names = True  # when available, forces using comments over the interfaces names  | ||||||
| @@ -66,8 +66,8 @@ Selected metrics info can be printed on the command line. For more information, | |||||||
|         global_options_parser = ArgumentParser(add_help=False) |         global_options_parser = ArgumentParser(add_help=False) | ||||||
|         self.parse_global_options(global_options_parser) |         self.parse_global_options(global_options_parser) | ||||||
|         namespace, _ = global_options_parser.parse_known_args()     |         namespace, _ = global_options_parser.parse_known_args()     | ||||||
|         if namespace.dir: |         if namespace.cfg_dir: | ||||||
|             config_handler(CustomConfig(namespace.dir)) |             config_handler(CustomConfig(namespace.cfg_dir)) | ||||||
|         else: |         else: | ||||||
|             config_handler() |             config_handler() | ||||||
|  |  | ||||||
| @@ -84,7 +84,7 @@ Selected metrics info can be printed on the command line. For more information, | |||||||
|     def parse_global_options(self, parser): |     def parse_global_options(self, parser): | ||||||
|         ''' Parses global options |         ''' Parses global options | ||||||
|         ''' |         ''' | ||||||
|         parser.add_argument('--dir', dest = 'dir',  |         parser.add_argument('--cfg-dir', dest = 'cfg_dir',  | ||||||
|                     type = lambda d: self._is_valid_dir_path(parser, d), |                     type = lambda d: self._is_valid_dir_path(parser, d), | ||||||
|                     help = 'MKTXP config files directory (optional)') |                     help = 'MKTXP config files directory (optional)') | ||||||
|  |  | ||||||
|   | |||||||
| @@ -14,9 +14,9 @@ | |||||||
|  |  | ||||||
| from mktxp.flow.processor.output import BaseOutputProcessor | from mktxp.flow.processor.output import BaseOutputProcessor | ||||||
| from mktxp.datasource.dhcp_ds import DHCPMetricsDataSource | from mktxp.datasource.dhcp_ds import DHCPMetricsDataSource | ||||||
|  | from mktxp.datasource.wireless_ds import WirelessMetricsDataSource | ||||||
| from mktxp.datasource.capsman_ds import CapsmanRegistrationsMetricsDataSource | from mktxp.datasource.capsman_ds import CapsmanRegistrationsMetricsDataSource | ||||||
|  |  | ||||||
|  |  | ||||||
| class CapsmanOutput: | class CapsmanOutput: | ||||||
|     ''' CAPsMAN CLI Output |     ''' CAPsMAN CLI Output | ||||||
|     '''     |     '''     | ||||||
| @@ -30,7 +30,8 @@ class CapsmanOutput: | |||||||
|  |  | ||||||
|         # translate / trim / augment registration records |         # translate / trim / augment registration records | ||||||
|         dhcp_lease_labels = ['host_name', 'comment', 'address', 'mac_address'] |         dhcp_lease_labels = ['host_name', 'comment', 'address', 'mac_address'] | ||||||
|         dhcp_lease_records = DHCPMetricsDataSource.metric_records(router_entry, metric_labels = dhcp_lease_labels, add_router_id = False)    |         dhcp_entry = WirelessMetricsDataSource.dhcp_entry(router_entry) | ||||||
|  |         dhcp_lease_records = DHCPMetricsDataSource.metric_records(dhcp_entry, metric_labels = dhcp_lease_labels, add_router_id = False)    | ||||||
|  |  | ||||||
|         dhcp_rt_by_interface = {} |         dhcp_rt_by_interface = {} | ||||||
|         for registration_record in sorted(registration_records, key = lambda rt_record: rt_record['rx_signal'], reverse=True): |         for registration_record in sorted(registration_records, key = lambda rt_record: rt_record['rx_signal'], reverse=True): | ||||||
| @@ -60,4 +61,3 @@ class CapsmanOutput: | |||||||
|             print(f'{server} clients: {len(dhcp_rt_by_interface[server])}') |             print(f'{server} clients: {len(dhcp_rt_by_interface[server])}') | ||||||
|         print(f'Total connected CAPsMAN clients: {output_records}', '\n') |         print(f'Total connected CAPsMAN clients: {output_records}', '\n') | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -15,6 +15,7 @@ | |||||||
| from mktxp.flow.processor.output import BaseOutputProcessor | from mktxp.flow.processor.output import BaseOutputProcessor | ||||||
| from mktxp.datasource.dhcp_ds import DHCPMetricsDataSource | from mktxp.datasource.dhcp_ds import DHCPMetricsDataSource | ||||||
| from mktxp.datasource.wireless_ds import WirelessMetricsDataSource | from mktxp.datasource.wireless_ds import WirelessMetricsDataSource | ||||||
|  | from mktxp.flow.router_entries_handler import RouterEntriesHandler | ||||||
|  |  | ||||||
|  |  | ||||||
| class WirelessOutput: | class WirelessOutput: | ||||||
| @@ -30,7 +31,8 @@ class WirelessOutput: | |||||||
|  |  | ||||||
|         # translate / trim / augment registration records |         # translate / trim / augment registration records | ||||||
|         dhcp_lease_labels = ['host_name', 'comment', 'address', 'mac_address'] |         dhcp_lease_labels = ['host_name', 'comment', 'address', 'mac_address'] | ||||||
|         dhcp_lease_records = DHCPMetricsDataSource.metric_records(router_entry, metric_labels = dhcp_lease_labels, add_router_id = False)    |         dhcp_entry = WirelessMetricsDataSource.dhcp_entry(router_entry) | ||||||
|  |         dhcp_lease_records = DHCPMetricsDataSource.metric_records(dhcp_entry, metric_labels = dhcp_lease_labels, add_router_id = False)    | ||||||
|  |  | ||||||
|         dhcp_rt_by_interface = {} |         dhcp_rt_by_interface = {} | ||||||
|  |  | ||||||
| @@ -46,7 +48,8 @@ class WirelessOutput: | |||||||
|  |  | ||||||
|         output_records = 0 |         output_records = 0 | ||||||
|         registration_records = len(registration_records)                 |         registration_records = len(registration_records)                 | ||||||
|         output_entry = BaseOutputProcessor.OutputWiFiEntry |         output_entry = BaseOutputProcessor.OutputWiFiWave2Entry \ | ||||||
|  |                         if WirelessMetricsDataSource.wifiwave2_installed(router_entry) else BaseOutputProcessor.OutputWiFiEntry | ||||||
|         output_table = BaseOutputProcessor.output_table(output_entry) |         output_table = BaseOutputProcessor.output_table(output_entry) | ||||||
|          |          | ||||||
|         for key in dhcp_rt_by_interface.keys(): |         for key in dhcp_rt_by_interface.keys(): | ||||||
|   | |||||||
| @@ -17,6 +17,7 @@ from mktxp.flow.processor.output import BaseOutputProcessor | |||||||
| from mktxp.collector.base_collector import BaseCollector | from mktxp.collector.base_collector import BaseCollector | ||||||
| from mktxp.datasource.dhcp_ds import DHCPMetricsDataSource | from mktxp.datasource.dhcp_ds import DHCPMetricsDataSource | ||||||
| from mktxp.datasource.capsman_ds import CapsmanCapsMetricsDataSource, CapsmanRegistrationsMetricsDataSource, CapsmanInterfacesDatasource | from mktxp.datasource.capsman_ds import CapsmanCapsMetricsDataSource, CapsmanRegistrationsMetricsDataSource, CapsmanInterfacesDatasource | ||||||
|  | from mktxp.datasource.wireless_ds import WirelessMetricsDataSource | ||||||
|  |  | ||||||
|  |  | ||||||
| class CapsmanCollector(BaseCollector): | class CapsmanCollector(BaseCollector): | ||||||
| @@ -51,9 +52,11 @@ class CapsmanCollector(BaseCollector): | |||||||
|  |  | ||||||
|             # the client info metrics |             # the client info metrics | ||||||
|             if router_entry.config_entry.capsman_clients: |             if router_entry.config_entry.capsman_clients: | ||||||
|  |  | ||||||
|                 # translate / trim / augment registration records |                 # translate / trim / augment registration records | ||||||
|                 dhcp_lease_labels = ['mac_address', 'address', 'host_name', 'comment'] |                 dhcp_lease_labels = ['mac_address', 'address', 'host_name', 'comment'] | ||||||
|                 dhcp_lease_records = DHCPMetricsDataSource.metric_records(router_entry, metric_labels = dhcp_lease_labels) |                 dhcp_entry = WirelessMetricsDataSource.dhcp_entry(router_entry) | ||||||
|  |                 dhcp_lease_records = DHCPMetricsDataSource.metric_records(dhcp_entry, metric_labels = dhcp_lease_labels) | ||||||
|                 for registration_record in registration_records: |                 for registration_record in registration_records: | ||||||
|                     BaseOutputProcessor.augment_record(router_entry, registration_record, dhcp_lease_records) |                     BaseOutputProcessor.augment_record(router_entry, registration_record, dhcp_lease_records) | ||||||
|                      |                      | ||||||
|   | |||||||
| @@ -54,7 +54,8 @@ class WLANCollector(BaseCollector): | |||||||
|             registration_records = WirelessMetricsDataSource.metric_records(router_entry, metric_labels = registration_labels) |             registration_records = WirelessMetricsDataSource.metric_records(router_entry, metric_labels = registration_labels) | ||||||
|             if registration_records: |             if registration_records: | ||||||
|                 dhcp_lease_labels = ['mac_address', 'address', 'host_name', 'comment'] |                 dhcp_lease_labels = ['mac_address', 'address', 'host_name', 'comment'] | ||||||
|                 dhcp_lease_records = DHCPMetricsDataSource.metric_records(router_entry, metric_labels = dhcp_lease_labels) |                 dhcp_entry = WirelessMetricsDataSource.dhcp_entry(router_entry)             | ||||||
|  |                 dhcp_lease_records = DHCPMetricsDataSource.metric_records(dhcp_entry, metric_labels = dhcp_lease_labels) | ||||||
|        |        | ||||||
|                 for registration_record in registration_records: |                 for registration_record in registration_records: | ||||||
|                     BaseOutputProcessor.augment_record(router_entry, registration_record, dhcp_lease_records)                 |                     BaseOutputProcessor.augment_record(router_entry, registration_record, dhcp_lease_records)                 | ||||||
|   | |||||||
| @@ -19,14 +19,14 @@ from mktxp.datasource.wireless_ds import WirelessMetricsDataSource | |||||||
| class CapsmanInfo: | class CapsmanInfo: | ||||||
|     @staticmethod |     @staticmethod | ||||||
|     def capsman_path(router_entry): |     def capsman_path(router_entry): | ||||||
|         if WirelessMetricsDataSource.wireless_package(router_entry) == WirelessMetricsDataSource.WIFIWAVE2: |         if WirelessMetricsDataSource.wifiwave2_installed(router_entry): | ||||||
|             return '/interface/wifiwave2/capsman' |             return '/interface/wifiwave2/capsman' | ||||||
|         else: |         else: | ||||||
|             return '/caps-man' |             return '/caps-man' | ||||||
|  |  | ||||||
|     @staticmethod |     @staticmethod | ||||||
|     def registration_table_path(router_entry): |     def registration_table_path(router_entry): | ||||||
|         if WirelessMetricsDataSource.wireless_package(router_entry) == WirelessMetricsDataSource.WIFIWAVE2: |         if WirelessMetricsDataSource.wifiwave2_installed(router_entry): | ||||||
|             return '/interface/wifiwave2/registration-table' |             return '/interface/wifiwave2/registration-table' | ||||||
|         else: |         else: | ||||||
|             return '/caps-man/registration-table' |             return '/caps-man/registration-table' | ||||||
| @@ -57,6 +57,12 @@ class CapsmanRegistrationsMetricsDataSource: | |||||||
|         try: |         try: | ||||||
|             registration_table_path = CapsmanInfo.registration_table_path(router_entry) |             registration_table_path = CapsmanInfo.registration_table_path(router_entry) | ||||||
|             registration_table_records = router_entry.api_connection.router_api().get_resource(f'{registration_table_path}').get() |             registration_table_records = router_entry.api_connection.router_api().get_resource(f'{registration_table_path}').get() | ||||||
|  |              | ||||||
|  |             # With wifiwave2, Mikrotik renamed the field 'rx_signal' to 'signal'  | ||||||
|  |             for record in registration_table_records: | ||||||
|  |                 if 'signal' in record: | ||||||
|  |                     record['rx_signal'] = record['signal'] | ||||||
|  |  | ||||||
|             return BaseDSProcessor.trimmed_records(router_entry, router_records = registration_table_records, metric_labels = metric_labels, add_router_id = add_router_id) |             return BaseDSProcessor.trimmed_records(router_entry, router_records = registration_table_records, metric_labels = metric_labels, add_router_id = add_router_id) | ||||||
|         except Exception as exc: |         except Exception as exc: | ||||||
|             print(f'Error getting CAPsMAN registration table info from router{router_entry.router_name}@{router_entry.config_entry.hostname}: {exc}') |             print(f'Error getting CAPsMAN registration table info from router{router_entry.router_name}@{router_entry.config_entry.hostname}: {exc}') | ||||||
|   | |||||||
| @@ -22,7 +22,6 @@ class WirelessMetricsDataSource: | |||||||
|     WIFIWAVE2 = 'wifiwave2' |     WIFIWAVE2 = 'wifiwave2' | ||||||
|     WIRELESS = 'wireless' |     WIRELESS = 'wireless' | ||||||
|  |  | ||||||
|  |  | ||||||
|     @staticmethod |     @staticmethod | ||||||
|     def metric_records(router_entry, *, metric_labels = None, add_router_id = True): |     def metric_records(router_entry, *, metric_labels = None, add_router_id = True): | ||||||
|         if metric_labels is None: |         if metric_labels is None: | ||||||
| @@ -31,8 +30,7 @@ class WirelessMetricsDataSource: | |||||||
|             wireless_package = WirelessMetricsDataSource.wireless_package(router_entry) |             wireless_package = WirelessMetricsDataSource.wireless_package(router_entry) | ||||||
|             registration_table_records = router_entry.api_connection.router_api().get_resource(f'/interface/{wireless_package}/registration-table').get() |             registration_table_records = router_entry.api_connection.router_api().get_resource(f'/interface/{wireless_package}/registration-table').get() | ||||||
|  |  | ||||||
|             # Mikrotik renamed the field 'signal_strength' to 'signal' when using wifiwave2. |             # With wifiwave2, Mikrotik renamed the field 'signal_strength' to 'signal'  | ||||||
|             # Rename this field back to 'signal_strength' to preserve backwards compatibility |  | ||||||
|             for record in registration_table_records: |             for record in registration_table_records: | ||||||
|                 if 'signal' in record: |                 if 'signal' in record: | ||||||
|                     record['signal_strength'] = record['signal'] |                     record['signal_strength'] = record['signal'] | ||||||
| @@ -49,3 +47,15 @@ class WirelessMetricsDataSource: | |||||||
|             ww2_installed = PackageMetricsDataSource.is_package_installed(router_entry, package_name = WirelessMetricsDataSource.WIFIWAVE2) |             ww2_installed = PackageMetricsDataSource.is_package_installed(router_entry, package_name = WirelessMetricsDataSource.WIFIWAVE2) | ||||||
|             router_entry.wifi_package = WirelessMetricsDataSource.WIFIWAVE2 if ww2_installed else WirelessMetricsDataSource.WIRELESS |             router_entry.wifi_package = WirelessMetricsDataSource.WIFIWAVE2 if ww2_installed else WirelessMetricsDataSource.WIRELESS | ||||||
|         return router_entry.wifi_package |         return router_entry.wifi_package | ||||||
|  |  | ||||||
|  |     @staticmethod | ||||||
|  |     def wifiwave2_installed(router_entry): | ||||||
|  |         return WirelessMetricsDataSource.wireless_package(router_entry) == WirelessMetricsDataSource.WIFIWAVE2 | ||||||
|  |  | ||||||
|  |     @staticmethod | ||||||
|  |     def dhcp_entry(router_entry): | ||||||
|  |         if router_entry.dhcp_entry: | ||||||
|  |             return router_entry.dhcp_entry | ||||||
|  |         return router_entry | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -35,9 +35,8 @@ class CollectorHandler: | |||||||
|         Thus, the total runtime of this function scales linearly with the number of registered routers. |         Thus, the total runtime of this function scales linearly with the number of registered routers. | ||||||
|         """ |         """ | ||||||
|         for router_entry in self.entries_handler.router_entries: |         for router_entry in self.entries_handler.router_entries: | ||||||
|             if not router_entry.api_connection.is_connected(): |             if not router_entry.is_connected(): | ||||||
|                 # let's pick up on things in the next run |                 # let's pick up on things in the next run | ||||||
|                 router_entry.api_connection.connect() |  | ||||||
|                 continue |                 continue | ||||||
|  |  | ||||||
|             for collector_ID, collect_func in self.collector_registry.registered_collectors.items(): |             for collector_ID, collect_func in self.collector_registry.registered_collectors.items(): | ||||||
| @@ -88,9 +87,8 @@ class CollectorHandler: | |||||||
|                     print(f'Hit overall timeout while scraping router entry: {router_entry.router_id[MKTXPConfigKeys.ROUTERBOARD_NAME]}') |                     print(f'Hit overall timeout while scraping router entry: {router_entry.router_id[MKTXPConfigKeys.ROUTERBOARD_NAME]}') | ||||||
|                     break |                     break | ||||||
|  |  | ||||||
|                 if not router_entry.api_connection.is_connected(): |                 if not router_entry.is_connected(): | ||||||
|                     # let's pick up on things in the next run |                     # let's pick up on things in the next run | ||||||
|                     router_entry.api_connection.connect() |  | ||||||
|                     continue |                     continue | ||||||
|                  |                  | ||||||
|                 # Duration of individual scrapes |                 # Duration of individual scrapes | ||||||
|   | |||||||
| @@ -18,6 +18,8 @@ from collections import namedtuple | |||||||
| from texttable import Texttable | from texttable import Texttable | ||||||
| from humanize import naturaldelta | from humanize import naturaldelta | ||||||
| from mktxp.cli.config.config import config_handler | from mktxp.cli.config.config import config_handler | ||||||
|  | from mktxp.datasource.wireless_ds import WirelessMetricsDataSource | ||||||
|  | from math import floor, log | ||||||
|  |  | ||||||
|  |  | ||||||
| class BaseOutputProcessor: | class BaseOutputProcessor: | ||||||
| @@ -27,18 +29,23 @@ class BaseOutputProcessor: | |||||||
|     OutputWiFiEntry = namedtuple('OutputWiFiEntry', ['dhcp_name', 'dhcp_address', 'mac_address', 'signal_strength', 'signal_to_noise', 'interface', 'tx_rate', 'rx_rate', 'uptime']) |     OutputWiFiEntry = namedtuple('OutputWiFiEntry', ['dhcp_name', 'dhcp_address', 'mac_address', 'signal_strength', 'signal_to_noise', 'interface', 'tx_rate', 'rx_rate', 'uptime']) | ||||||
|     OutputWiFiEntry.__new__.__defaults__ = ('',) * len(OutputWiFiEntry._fields) |     OutputWiFiEntry.__new__.__defaults__ = ('',) * len(OutputWiFiEntry._fields) | ||||||
|  |  | ||||||
|  |     OutputWiFiWave2Entry = namedtuple('OutputWiFiWave2Entry', ['dhcp_name', 'dhcp_address', 'mac_address', 'signal_strength', 'interface', 'tx_rate', 'rx_rate', 'uptime']) | ||||||
|  |     OutputWiFiWave2Entry.__new__.__defaults__ = ('',) * len(OutputWiFiWave2Entry._fields) | ||||||
|  |  | ||||||
|     OutputDHCPEntry = namedtuple('OutputDHCPEntry', ['host_name', 'server', 'mac_address', 'address', 'active_address', 'expires_after']) |     OutputDHCPEntry = namedtuple('OutputDHCPEntry', ['host_name', 'server', 'mac_address', 'address', 'active_address', 'expires_after']) | ||||||
|     OutputDHCPEntry.__new__.__defaults__ = ('',) * len(OutputDHCPEntry._fields) |     OutputDHCPEntry.__new__.__defaults__ = ('',) * len(OutputDHCPEntry._fields) | ||||||
|  |  | ||||||
|     @staticmethod |     @staticmethod | ||||||
|     def augment_record(router_entry, registration_record, dhcp_lease_records): |     def augment_record(router_entry, registration_record, dhcp_lease_records): | ||||||
|  |         dhcp_name = registration_record.get('mac_address') | ||||||
|  |         dhcp_address = 'No DHCP Record'               | ||||||
|  |         if dhcp_lease_records: | ||||||
|             try: |             try: | ||||||
|                 dhcp_lease_record = next((dhcp_lease_record for dhcp_lease_record in dhcp_lease_records if dhcp_lease_record.get('mac_address')==registration_record.get('mac_address'))) |                 dhcp_lease_record = next((dhcp_lease_record for dhcp_lease_record in dhcp_lease_records if dhcp_lease_record.get('mac_address')==registration_record.get('mac_address'))) | ||||||
|                 dhcp_name = BaseOutputProcessor.dhcp_name(router_entry, dhcp_lease_record) |                 dhcp_name = BaseOutputProcessor.dhcp_name(router_entry, dhcp_lease_record) | ||||||
|                 dhcp_address = dhcp_lease_record.get('address', '') |                 dhcp_address = dhcp_lease_record.get('address', '') | ||||||
|             except StopIteration: |             except StopIteration: | ||||||
|             dhcp_name = registration_record.get('mac_address') |                 pass | ||||||
|             dhcp_address = 'No DHCP Record'           |  | ||||||
|  |  | ||||||
|         registration_record['dhcp_name'] = dhcp_name |         registration_record['dhcp_name'] = dhcp_name | ||||||
|         registration_record['dhcp_address'] = dhcp_address |         registration_record['dhcp_address'] = dhcp_address | ||||||
| @@ -49,10 +56,13 @@ class BaseOutputProcessor: | |||||||
|             registration_record['rx_bytes'] = registration_record['bytes'].split(',')[1] |             registration_record['rx_bytes'] = registration_record['bytes'].split(',')[1] | ||||||
|             del registration_record['bytes'] |             del registration_record['bytes'] | ||||||
|  |  | ||||||
|  |         ww2_installed = WirelessMetricsDataSource.wifiwave2_installed(router_entry) | ||||||
|         if registration_record.get('tx_rate'): |         if registration_record.get('tx_rate'): | ||||||
|             registration_record['tx_rate'] = BaseOutputProcessor.parse_rates(registration_record['tx_rate']) |             registration_record['tx_rate'] = BaseOutputProcessor.parse_bitrates(registration_record['tx_rate']) \ | ||||||
|  |                                                 if ww2_installed else BaseOutputProcessor.parse_rates(registration_record['tx_rate']) | ||||||
|         if registration_record.get('rx_rate'): |         if registration_record.get('rx_rate'): | ||||||
|             registration_record['rx_rate'] = BaseOutputProcessor.parse_rates(registration_record['rx_rate']) |             registration_record['rx_rate'] = BaseOutputProcessor.parse_bitrates(registration_record['rx_rate']) \ | ||||||
|  |                                                 if ww2_installed else BaseOutputProcessor.parse_rates(registration_record['rx_rate']) | ||||||
|         if registration_record.get('uptime'): |         if registration_record.get('uptime'): | ||||||
|             registration_record['uptime'] = naturaldelta(BaseOutputProcessor.parse_timedelta_seconds(registration_record['uptime']), months=True, minimum_unit='seconds') |             registration_record['uptime'] = naturaldelta(BaseOutputProcessor.parse_timedelta_seconds(registration_record['uptime']), months=True, minimum_unit='seconds') | ||||||
|  |  | ||||||
| @@ -87,6 +97,12 @@ class BaseOutputProcessor: | |||||||
|         rc = wifi_rates_rgx.search(rate) |         rc = wifi_rates_rgx.search(rate) | ||||||
|         return f'{int(float(rc[1]))} {rc[2]}' if rc and len(rc.groups()) == 2 else rate |         return f'{int(float(rc[1]))} {rc[2]}' if rc and len(rc.groups()) == 2 else rate | ||||||
|  |  | ||||||
|  |     @staticmethod | ||||||
|  |     def parse_bitrates(rate): | ||||||
|  |         rate = int(rate) | ||||||
|  |         power = floor(log(rate, 1000)) | ||||||
|  |         return f"{int(rate / 1000 ** power)} {['bps', 'Kbps', 'Mbps', 'Gbps'][int(power)]}" | ||||||
|  |  | ||||||
|     @staticmethod |     @staticmethod | ||||||
|     def parse_timedelta(time): |     def parse_timedelta(time): | ||||||
|         duration_interval_rgx = config_handler.re_compiled.get('duration_interval_rgx') |         duration_interval_rgx = config_handler.re_compiled.get('duration_interval_rgx') | ||||||
| @@ -126,6 +142,3 @@ class BaseOutputProcessor: | |||||||
|             table.header(outputEntry._fields) |             table.header(outputEntry._fields) | ||||||
|             table.set_cols_align(['l']+ ['c']*(len(outputEntry._fields)-1)) |             table.set_cols_align(['l']+ ['c']*(len(outputEntry._fields)-1)) | ||||||
|         return table |         return table | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -22,19 +22,22 @@ class RouterEntriesHandler: | |||||||
|     def __init__(self): |     def __init__(self): | ||||||
|         self.router_entries = [] |         self.router_entries = [] | ||||||
|         for router_name in config_handler.registered_entries(): |         for router_name in config_handler.registered_entries(): | ||||||
|             entry = config_handler.config_entry(router_name) |             router_entry = RouterEntriesHandler.router_entry(router_name, enabled_only = True) | ||||||
|             if entry.enabled: |             if router_entry:                 | ||||||
|                 self.router_entries.append(RouterEntry(router_name)) |                 self.router_entries.append(router_entry) | ||||||
|  |  | ||||||
|     @staticmethod |     @staticmethod | ||||||
|     def router_entry(entry_name, enabled_only = False): |     def router_entry(entry_name, enabled_only = False): | ||||||
|         router_entry = None |         router_entry = None | ||||||
|  |          | ||||||
|         for router_name in config_handler.registered_entries(): |         for router_name in config_handler.registered_entries(): | ||||||
|             if router_name == entry_name: |             if router_name == entry_name: | ||||||
|                 if enabled_only: |                 config_entry = config_handler.config_entry(router_name) | ||||||
|                     entry = config_handler.config_entry(router_name) |                 if enabled_only and not config_entry.enabled: | ||||||
|                     if not entry.enabled: |  | ||||||
|                         break |                         break | ||||||
|  |                          | ||||||
|                 router_entry = RouterEntry(router_name) |                 router_entry = RouterEntry(router_name) | ||||||
|  |                 router_entry.dhcp_entry = RouterEntriesHandler.router_entry(config_entry.remote_dhcp_entry) | ||||||
|                 break |                 break | ||||||
|  |          | ||||||
|         return router_entry |         return router_entry | ||||||
|   | |||||||
| @@ -27,7 +27,10 @@ class RouterEntry: | |||||||
|             MKTXPConfigKeys.ROUTERBOARD_NAME: self.router_name, |             MKTXPConfigKeys.ROUTERBOARD_NAME: self.router_name, | ||||||
|             MKTXPConfigKeys.ROUTERBOARD_ADDRESS: self.config_entry.hostname |             MKTXPConfigKeys.ROUTERBOARD_ADDRESS: self.config_entry.hostname | ||||||
|             } |             } | ||||||
|  |          | ||||||
|         self.wifi_package = None |         self.wifi_package = None | ||||||
|  |         self.dhcp_entry = None | ||||||
|  |  | ||||||
|         self.time_spent =  { 'IdentityCollector': 0, |         self.time_spent =  { 'IdentityCollector': 0, | ||||||
|                             'SystemResourceCollector': 0, |                             'SystemResourceCollector': 0, | ||||||
|                             'HealthCollector': 0, |                             'HealthCollector': 0, | ||||||
| @@ -50,3 +53,17 @@ class RouterEntry: | |||||||
|                             'UserCollector': 0,                             |                             'UserCollector': 0,                             | ||||||
|                             'MKTXPCollector': 0 |                             'MKTXPCollector': 0 | ||||||
|                             }                 |                             }                 | ||||||
|  |  | ||||||
|  |     def is_connected(self): | ||||||
|  |         connected = True | ||||||
|  |         if not self.api_connection.is_connected(): | ||||||
|  |             connected = False                         | ||||||
|  |             # let's get connected now | ||||||
|  |             self.api_connection.connect() | ||||||
|  |             if self.dhcp_entry: | ||||||
|  |                 self.dhcp_entry.api_connection.connect() | ||||||
|  |  | ||||||
|  |         return connected | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user