Skip to content

Commit e4bcf0c

Browse files
committed
Scalable route protocols counters via direct API call, #117
1 parent 4252c89 commit e4bcf0c

3 files changed

Lines changed: 65 additions & 66 deletions

File tree

mktxp/cli/config/config.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,8 @@ def __call__(self, os_config = None):
348348
def registered_entries(self):
349349
''' All MKTXP registered entries
350350
'''
351-
return (entry_name for entry_name in self.config.keys() if entry_name != MKTXPConfigKeys.DEFAULT_ENTRY_KEY )
351+
return (entry_name for entry_name in self.config.keys() if entry_name not in
352+
(MKTXPConfigKeys.DEFAULT_ENTRY_KEY, MKTXPConfigKeys.MKTXP_LATEST_DEFAULT_ENTRY_KEY))
352353

353354
def registered_entry(self, entry_name):
354355
''' A specific MKTXP registered entry by name

mktxp/collector/route_collector.py

Lines changed: 29 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -15,73 +15,59 @@
1515
from mktxp.cli.config.config import MKTXPConfigKeys
1616
from mktxp.collector.base_collector import BaseCollector
1717
from mktxp.datasource.route_ds import RouteMetricsDataSource
18-
from mktxp.utils.utils import str2bool
1918

2019

2120
class RouteCollector(BaseCollector):
2221
''' IP Route Metrics collector
23-
'''
22+
'''
2423
@staticmethod
2524
def collect(router_entry):
2625
route_labels = ['connect', 'dynamic', 'static', 'bgp', 'ospf']
2726

28-
# ~*~*~*~*~*~ IPv4 ~*~*~*~*~*~
29-
if router_entry.config_entry.route:
30-
route_records = RouteMetricsDataSource.metric_records(router_entry, metric_labels = route_labels)
31-
if route_records:
27+
# ~*~*~*~*~*~ IPv4 ~*~*~*~*~*~
28+
if router_entry.config_entry.route:
29+
route_counts = RouteMetricsDataSource.metric_records(router_entry, metric_labels=route_labels)
30+
if route_counts:
3231
# compile total routes records
33-
total_routes = len(route_records)
34-
total_routes_records = [{ MKTXPConfigKeys.ROUTERBOARD_NAME: router_entry.router_id[MKTXPConfigKeys.ROUTERBOARD_NAME],
35-
MKTXPConfigKeys.ROUTERBOARD_ADDRESS: router_entry.router_id[MKTXPConfigKeys.ROUTERBOARD_ADDRESS],
36-
'count': total_routes
37-
}]
32+
total_routes_records = [{
33+
MKTXPConfigKeys.ROUTERBOARD_NAME: router_entry.router_id[MKTXPConfigKeys.ROUTERBOARD_NAME],
34+
MKTXPConfigKeys.ROUTERBOARD_ADDRESS: router_entry.router_id[MKTXPConfigKeys.ROUTERBOARD_ADDRESS],
35+
'count': route_counts['total_routes']
36+
}]
3837
total_routes_metrics = BaseCollector.gauge_collector('routes_total_routes', 'Overall number of routes in RIB', total_routes_records, 'count')
3938
yield total_routes_metrics
4039

41-
42-
# init routes per protocol (with 0)
43-
routes_per_protocol = {route_label: 0 for route_label in route_labels}
44-
for route_record in route_records:
45-
for route_label in route_labels:
46-
if str2bool(route_record.get(route_label)):
47-
routes_per_protocol[route_label] += 1
48-
4940
# compile route-per-protocol records
50-
route_per_protocol_records = [{ MKTXPConfigKeys.ROUTERBOARD_NAME: router_entry.router_id[MKTXPConfigKeys.ROUTERBOARD_NAME],
51-
MKTXPConfigKeys.ROUTERBOARD_ADDRESS: router_entry.router_id[MKTXPConfigKeys.ROUTERBOARD_ADDRESS],
52-
'protocol': key, 'count': value} for key, value in routes_per_protocol.items()]
53-
41+
route_per_protocol_records = [{
42+
MKTXPConfigKeys.ROUTERBOARD_NAME: router_entry.router_id[MKTXPConfigKeys.ROUTERBOARD_NAME],
43+
MKTXPConfigKeys.ROUTERBOARD_ADDRESS: router_entry.router_id[MKTXPConfigKeys.ROUTERBOARD_ADDRESS],
44+
'protocol': key, 'count': value
45+
} for key, value in route_counts['routes_per_protocol'].items()]
46+
5447
# yield route-per-protocol metrics
5548
route_per_protocol_metrics = BaseCollector.gauge_collector('routes_protocol_count', 'Number of routes per protocol in RIB', route_per_protocol_records, 'count', ['protocol'])
5649
yield route_per_protocol_metrics
5750

5851
# ~*~*~*~*~*~ IPv6 ~*~*~*~*~*~
5952
if router_entry.config_entry.ipv6_route:
60-
# ~*~*~*~*~*~ IPv4 ~*~*~*~*~*~
61-
route_records = RouteMetricsDataSource.metric_records(router_entry, metric_labels = route_labels, ipv6 = True)
62-
if route_records:
53+
route_counts = RouteMetricsDataSource.metric_records(router_entry, metric_labels=route_labels, ipv6=True)
54+
if route_counts:
6355
# compile total routes records
64-
total_routes = len(route_records)
65-
total_routes_records = [{ MKTXPConfigKeys.ROUTERBOARD_NAME: router_entry.router_id[MKTXPConfigKeys.ROUTERBOARD_NAME],
66-
MKTXPConfigKeys.ROUTERBOARD_ADDRESS: router_entry.router_id[MKTXPConfigKeys.ROUTERBOARD_ADDRESS],
67-
'count': total_routes
68-
}]
56+
total_routes_records = [{
57+
MKTXPConfigKeys.ROUTERBOARD_NAME: router_entry.router_id[MKTXPConfigKeys.ROUTERBOARD_NAME],
58+
MKTXPConfigKeys.ROUTERBOARD_ADDRESS: router_entry.router_id[MKTXPConfigKeys.ROUTERBOARD_ADDRESS],
59+
'count': route_counts['total_routes']
60+
}]
6961
total_routes_metrics = BaseCollector.gauge_collector('routes_total_routes_ipv6', 'Overall number of routes in RIB (IPv6)', total_routes_records, 'count')
7062
yield total_routes_metrics
7163

72-
73-
# init routes per protocol (with 0)
74-
routes_per_protocol = {route_label: 0 for route_label in route_labels}
75-
for route_record in route_records:
76-
for route_label in route_labels:
77-
if route_record.get(route_label):
78-
routes_per_protocol[route_label] += 1
79-
8064
# compile route-per-protocol records
81-
route_per_protocol_records = [{ MKTXPConfigKeys.ROUTERBOARD_NAME: router_entry.router_id[MKTXPConfigKeys.ROUTERBOARD_NAME],
82-
MKTXPConfigKeys.ROUTERBOARD_ADDRESS: router_entry.router_id[MKTXPConfigKeys.ROUTERBOARD_ADDRESS],
83-
'protocol': key, 'count': value} for key, value in routes_per_protocol.items()]
84-
65+
route_per_protocol_records = [{
66+
MKTXPConfigKeys.ROUTERBOARD_NAME: router_entry.router_id[MKTXPConfigKeys.ROUTERBOARD_NAME],
67+
MKTXPConfigKeys.ROUTERBOARD_ADDRESS: router_entry.router_id[MKTXPConfigKeys.ROUTERBOARD_ADDRESS],
68+
'protocol': key, 'count': value
69+
} for key, value in route_counts['routes_per_protocol'].items()]
70+
8571
# yield route-per-protocol metrics
8672
route_per_protocol_metrics = BaseCollector.gauge_collector('routes_protocol_count_ipv6', 'Number of routes per protocol in RIB (IPv6)', route_per_protocol_records, 'count', ['protocol'])
8773
yield route_per_protocol_metrics

mktxp/datasource/route_ds.py

Lines changed: 34 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -13,36 +13,48 @@
1313

1414

1515
from mktxp.datasource.base_ds import BaseDSProcessor
16-
from mktxp.utils.utils import str2bool
1716

1817
class RouteMetricsDataSource:
1918
''' Routes Metrics data provider
20-
'''
19+
'''
2120
@staticmethod
22-
def metric_records(router_entry, *, metric_labels = None, ipv6 = False):
21+
def _count_records(router_entry, *, protocol_label=None, ipv6=False):
2322
ip_stack = 'ipv6' if ipv6 else 'ip'
23+
try:
24+
resource = router_entry.api_connection.router_api().get_resource(f'/{ip_stack}/route')
25+
if protocol_label:
26+
response = resource.call('print', {'count-only': ''}, {f'{protocol_label}': 'yes'}).done_message
27+
else:
28+
response = resource.call('print', {'count-only': ''}).done_message
29+
return int(response.get('ret', 0))
30+
except Exception as exc:
31+
print(f'Error getting {"IPv6" if ipv6 else "IPv4"} routes count for protocol {protocol_label or "total"} from router {router_entry.router_name}@{router_entry.config_entry.hostname}: {exc}')
32+
return None
33+
34+
@staticmethod
35+
def metric_records(router_entry, *, metric_labels = None, ipv6 = False):
2436
if metric_labels is None:
25-
metric_labels = []
37+
metric_labels = []
2638
try:
27-
#route_records = router_entry.api_connection.router_api().get_resource(f'/{ip_stack}/route').get(active='yes')
28-
route_records = router_entry.api_connection.router_api().get_resource(f'/{ip_stack}/route').call('print', {'proplist':'active,connect,dynamic,static,bgp,ospf'})
29-
30-
#active_records = [record for record in route_records if record.get('active')]
31-
RouteMetricsDataSource._remove_from_list_of_dict(route_records, 'active')
39+
# Get total routes
40+
total_routes = RouteMetricsDataSource._count_records(router_entry, protocol_label=None, ipv6=ipv6)
41+
if total_routes is None:
42+
# Abort if there was an error
43+
return None
44+
45+
# Get counts per protocol
46+
routes_per_protocol = {}
47+
for label in metric_labels:
48+
count = RouteMetricsDataSource._count_records(router_entry, protocol_label=label, ipv6=ipv6)
49+
if count is None:
50+
# Abort if there was an error
51+
return None
52+
routes_per_protocol[label] = count
3253

33-
return BaseDSProcessor.trimmed_records(router_entry, router_records = route_records, metric_labels = metric_labels)
54+
return {
55+
'total_routes': total_routes,
56+
'routes_per_protocol': routes_per_protocol
57+
}
3458
except Exception as exc:
3559
print(f'Error getting {"IPv6" if ipv6 else "IPv4"} routes info from router {router_entry.router_name}@{router_entry.config_entry.hostname}: {exc}')
3660
return None
37-
38-
# helpers
39-
@staticmethod
40-
def _remove_from_list_of_dict(dict_list, key):
41-
indexes = []
42-
for index, dict in enumerate(dict_list):
43-
if not str2bool(dict.get(key)):
44-
indexes.append(index)
45-
offset = 0
46-
for index in indexes:
47-
dict_list.pop(index-offset)
48-
offset += 1

0 commit comments

Comments
 (0)