def test_poller(self): """Test the update method to see if it pushes port stats""" prom_client = gauge_prom.GaugePrometheusClient() datapath = create_mock_datapath(2) conf = mock.Mock(dp=datapath, type='', interval=1, prometheus_port=9303, prometheus_addr='localhost') prom_poller = gauge_prom.GaugePortStatsPrometheusPoller( conf, '__name__', prom_client) msg = port_stats_msg(datapath) prom_poller.update(time.time(), datapath.dp_id, msg) prom_lines = self.get_prometheus_stats(conf.prometheus_addr, conf.prometheus_port) prom_lines = self.parse_prom_output(prom_lines) for port_num, port in datapath.ports.items(): port_stats = msg.body[int(port_num) - 1] stats = prom_lines[(datapath.dp_id, port.name)] stats_found = set() for stat_name, stat_val in stats: self.assertAlmostEqual(stat_val, getattr(port_stats, stat_name)) stats_found.add(stat_name) self.assertEqual(stats_found, set(gauge_prom.PROM_PORT_VARS))
def test_poller(self): """Test the update method to see if it pushes port stats""" prom_client = gauge_prom.GaugePrometheusClient() datapath = create_mock_datapath(2) conf = mock.Mock(dp=datapath, type='', interval=1, prometheus_port=9303, prometheus_addr='localhost') prom_poller = gauge_prom.GaugePortStatsPrometheusPoller( conf, '__name__', prom_client) port1 = parser.OFPPortStats(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 100, 50) port2 = parser.OFPPortStats(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 100, 50) message = parser.OFPPortStatsReply(datapath, body=[port1, port2]) dp_id = 1 prom_poller.update(time.time(), dp_id, message) prom_lines = self.get_prometheus_stats(conf.prometheus_addr, conf.prometheus_port) prom_lines = self.parse_prom_output(prom_lines) for port_num, port in datapath.ports.items(): stats = prom_lines[(dp_id, port.name)] stats_found = set() for stat_name, stat_val in stats: self.assertAlmostEqual(stat_val, port_num) stats_found.add(stat_name) self.assertEqual(stats_found, set(gauge_prom.PROM_PORT_VARS))
class GaugePrometheusTests(unittest.TestCase): # pytype: disable=module-attr """Tests the GaugePortStatsPrometheusPoller update method""" prom_client = gauge_prom.GaugePrometheusClient(reg=CollectorRegistry()) @staticmethod def parse_prom_output(output): """Parses the port stats from prometheus into a dictionary""" parsed_output = {} for line in output.split('\n'): # discard comments and stats not related to port stats if line.startswith('#') or not line.startswith( gauge_prom.PROM_PORT_PREFIX): continue index = line.find('{') # get the stat name e.g. of_port_rx_bytes and strip 'of_port_' prefix = gauge_prom.PROM_PORT_PREFIX + gauge_prom.PROM_PREFIX_DELIM stat_name = line[0:index].replace(prefix, '') # get the labels within {} labels = line[index + 1:line.find('}')].split(',') for label in labels: lab_name, lab_val = label.split('=', 1) lab_val = lab_val.replace('"', '') if lab_name == 'dp_id': dp_id = int(lab_val, 16) elif lab_name == 'port': port_name = lab_val key = (dp_id, port_name) stat_val = line.split(' ')[-1] if key not in parsed_output: parsed_output[key] = [] parsed_output[key].append((stat_name, float(stat_val))) return parsed_output @staticmethod def get_prometheus_stats(addr, port): """Attempts to contact the prometheus server at the address to grab port stats.""" url = 'http://{}:{}'.format(addr, port) session = requests.Session() adapter = requests.adapters.HTTPAdapter(max_retries=10) session.mount('http://', adapter) return session.get(url).text def test_poller(self): """Test the update method to see if it pushes port stats""" datapath = create_mock_datapath(2) conf = mock.Mock(dp=datapath, type='', interval=1, prometheus_port=9303, prometheus_addr='localhost', use_test_thread=True) prom_poller = gauge_prom.GaugePortStatsPrometheusPoller( conf, '__name__', self.prom_client) prom_poller._running = True msg = port_stats_msg(datapath) prom_poller.update(time.time(), msg) prom_lines = self.get_prometheus_stats(conf.prometheus_addr, conf.prometheus_port) prom_lines = self.parse_prom_output(prom_lines) for port_num, port in datapath.ports.items(): port_stats = msg.body[int(port_num) - 1] stats = prom_lines[(datapath.dp_id, port.name)] stats_found = set() for stat_name, stat_val in stats: self.assertAlmostEqual(stat_val, getattr(port_stats, stat_name)) stats_found.add(stat_name) self.assertEqual(stats_found, set(gauge_prom.PROM_PORT_VARS)) def test_port_state(self): """Test the update method to see if it pushes port state""" datapath = create_mock_datapath(2) conf = mock.Mock(dp=datapath, type='', interval=1, prometheus_port=9303, prometheus_addr='localhost', use_test_thread=True) prom_poller = gauge_prom.GaugePortStatePrometheusPoller( conf, '__name__', self.prom_client) prom_poller._running = True reasons = [ ofproto.OFPPR_ADD, ofproto.OFPPR_DELETE, ofproto.OFPPR_MODIFY ] for i in range(1, len(conf.dp.ports) + 1): msg = port_state_msg(conf.dp, i, reasons[i - 1]) port_name = conf.dp.ports[i].name rcv_time = int(time.time()) prom_poller.update(rcv_time, msg) prom_lines = self.get_prometheus_stats(conf.prometheus_addr, conf.prometheus_port) prom_lines = self.parse_prom_output(prom_lines) stats = prom_lines[(datapath.dp_id, port_name)] stats_found = set() for stat_name, stat_val in stats: msg_data = msg if stat_name == 'reason' else msg.desc self.assertAlmostEqual(stat_val, getattr(msg_data, stat_name)) stats_found.add(stat_name) self.assertEqual(stats_found, set(gauge_prom.PROM_PORT_STATE_VARS)) def test_flow_stats(self): """Check the update method of the GaugeFlowTablePrometheusPoller class""" datapath = create_mock_datapath(2) conf = mock.Mock(dp=datapath, type='', interval=1, prometheus_port=9303, prometheus_addr='localhost', use_test_thread=True) prom_poller = gauge_prom.GaugeFlowTablePrometheusPoller( conf, '__name__', self.prom_client) rcv_time = int(time.time()) instructions = [parser.OFPInstructionGotoTable(1)] msg = flow_stats_msg(conf.dp, instructions) prom_poller.update(rcv_time, msg)