aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--faucet/gauge_prom.py51
-rw-r--r--faucet/watcher.py15
-rw-r--r--tests/integration/mininet_tests.py25
3 files changed, 78 insertions, 13 deletions
diff --git a/faucet/gauge_prom.py b/faucet/gauge_prom.py
index 48b78061..229b5c54 100644
--- a/faucet/gauge_prom.py
+++ b/faucet/gauge_prom.py
@@ -44,7 +44,14 @@ PROM_FLOW_VARS = (
'flow_byte_count',
'flow_packet_count'
)
-
+PROM_METER_PREFIX = 'of_meter'
+PROM_METER_VARS = (
+ 'flow_count',
+ 'byte_in_count',
+ 'packet_in_count',
+ 'byte_band_count',
+ 'packet_band_count'
+)
class GaugePrometheusClient(PromClient):
"""Wrapper for Prometheus client that is shared between all pollers."""
@@ -61,10 +68,17 @@ class GaugePrometheusClient(PromClient):
for prom_var in PROM_PORT_VARS + PROM_PORT_STATE_VARS:
exported_prom_var = PROM_PREFIX_DELIM.join(
(PROM_PORT_PREFIX, prom_var))
- self.metrics[exported_prom_var] = Gauge( # pylint: disable=unexpected-keyword-arg
+ self.metrics[exported_prom_var] = Gauge( # pylint: disable=unexpected-keyword-arg
exported_prom_var, '',
self.REQUIRED_LABELS + ['port', 'port_description'],
registry=self._reg)
+ for prom_var in PROM_METER_VARS:
+ exported_prom_var = PROM_PREFIX_DELIM.join(
+ (PROM_METER_PREFIX, prom_var))
+ self.metrics[exported_prom_var] = Gauge( # pylint: disable=unexpected-keyword-arg
+ exported_prom_var, '',
+ self.REQUIRED_LABELS + ['meter_id'],
+ registry=self._reg)
def reregister_flow_vars(self, table_name, table_tags):
"""Register the flow variables needed for this client"""
@@ -94,7 +108,6 @@ class GaugePortStatsPrometheusPoller(GaugePortStatsPoller):
return self._format_stats(delim, stat_pairs)
def update(self, rcv_time, msg):
- super(GaugePortStatsPrometheusPoller, self).update(rcv_time, msg)
for stat in msg.body:
port_labels = self.dp.port_labels(stat.port_no)
for stat_name, stat_val in self._format_stat_pairs(
@@ -102,11 +115,40 @@ class GaugePortStatsPrometheusPoller(GaugePortStatsPoller):
self.prom_client.metrics[stat_name].labels(**port_labels).set(stat_val)
+class GaugeMeterStatsPrometheusPoller(GaugePortStatsPoller):
+ """Exports meter stats to Prometheus."""
+
+ def __init__(self, conf, logger, prom_client):
+ super(GaugeMeterStatsPrometheusPoller, self).__init__(
+ conf, logger, prom_client)
+ self.prom_client.start(
+ self.conf.prometheus_port, self.conf.prometheus_addr, self.conf.prometheus_test_thread)
+
+ def _format_stat_pairs(self, delim, stat):
+ band_stats = stat.band_stats[0]
+ stat_pairs = (
+ (('flow', 'count'), stat.flow_count),
+ (('byte', 'in', 'count'), stat.byte_in_count),
+ (('packet', 'in', 'count'), stat.packet_in_count),
+ (('byte', 'band', 'count'), band_stats.byte_band_count),
+ (('packet', 'band', 'count'), band_stats.packet_band_count),
+ )
+ return self._format_stats(delim, stat_pairs)
+
+ def update(self, rcv_time, msg):
+ for stat in msg.body:
+ meter_labels = self.dp.base_prom_labels()
+ meter_labels.update({'meter_id': stat.meter_id})
+ for stat_name, stat_val in self._format_stat_pairs(
+ PROM_PREFIX_DELIM, stat):
+ stat_name = PROM_PREFIX_DELIM.join((PROM_METER_PREFIX, stat_name))
+ self.prom_client.metrics[stat_name].labels(**meter_labels).set(stat_val)
+
+
class GaugePortStatePrometheusPoller(GaugePortStatePoller):
"""Export port state changes to Prometheus."""
def update(self, rcv_time, msg):
- super(GaugePortStatePrometheusPoller, self).update(rcv_time, msg)
port_no = msg.desc.port_no
port = self.dp.ports.get(port_no, None)
if port is None:
@@ -122,7 +164,6 @@ class GaugeFlowTablePrometheusPoller(GaugeFlowTablePoller):
"""Export flow table entries to Prometheus."""
def update(self, rcv_time, msg):
- super(GaugeFlowTablePrometheusPoller, self).update(rcv_time, msg)
jsondict = msg.to_jsondict()
for stats_reply in jsondict['OFPFlowStatsReply']['body']:
stats = stats_reply['OFPFlowStats']
diff --git a/faucet/watcher.py b/faucet/watcher.py
index c580bd83..836ed2f3 100644
--- a/faucet/watcher.py
+++ b/faucet/watcher.py
@@ -23,13 +23,15 @@ import gzip
from ryu.ofproto import ofproto_v1_3 as ofp
+from faucet.conf import InvalidConfigError
from faucet.valve_util import dpid_log
from faucet.gauge_influx import (
GaugePortStateInfluxDBLogger, GaugePortStatsInfluxDBLogger, GaugeFlowTableInfluxDBLogger)
from faucet.gauge_pollers import (
GaugePortStatePoller, GaugePortStatsPoller, GaugeFlowTablePoller, GaugeMeterStatsPoller)
from faucet.gauge_prom import (
- GaugePortStatsPrometheusPoller, GaugePortStatePrometheusPoller, GaugeFlowTablePrometheusPoller)
+ GaugePortStatsPrometheusPoller, GaugePortStatePrometheusPoller, GaugeFlowTablePrometheusPoller,
+ GaugeMeterStatsPrometheusPoller)
def watcher_factory(conf):
@@ -57,6 +59,7 @@ def watcher_factory(conf):
},
'meter_stats': {
'text': GaugeMeterStatsLogger,
+ 'prometheus': GaugeMeterStatsPrometheusPoller,
},
}
@@ -65,7 +68,7 @@ def watcher_factory(conf):
try:
return WATCHER_TYPES[w_type][db_type]
except KeyError:
- return None
+ raise InvalidConfigError('invalid water config')
class GaugePortStateLogger(GaugePortStatePoller):
@@ -118,10 +121,10 @@ class GaugeMeterStatsLogger(GaugeMeterStatsPoller):
band_stats = stat.band_stats[0]
stat_pairs = (
(('flow', 'count'), stat.flow_count),
- (('bytes', 'in'), stat.byte_in_count),
- (('packets', 'in'), stat.packet_in_count),
- (('band', 'bytes', 'in'), band_stats.byte_band_count),
- (('band', 'packets', 'in'), band_stats.packet_band_count))
+ (('byte', 'in', 'count'), stat.byte_in_count),
+ (('packet', 'in', 'count'), stat.packet_in_count),
+ (('byte', 'band', 'count'), band_stats.byte_band_count),
+ (('packet', 'band', 'count'), band_stats.packet_band_count))
return self._format_stats(delim, stat_pairs)
def _dp_stat_name(self, stat, stat_name): # pylint: disable=arguments-differ
diff --git a/tests/integration/mininet_tests.py b/tests/integration/mininet_tests.py
index b3161a74..6b0bd14d 100644
--- a/tests/integration/mininet_tests.py
+++ b/tests/integration/mininet_tests.py
@@ -1618,7 +1618,20 @@ vlans:
type: 'meter_stats'
interval: 5
db: 'meter_file'
-""" % (self.DP_NAME, self.DP_NAME, self.DP_NAME)
+ meter_stats_prom:
+ dps: ['%s']
+ type: 'meter_stats'
+ db: 'prometheus'
+ interval: 5
+""" % (self.DP_NAME, self.DP_NAME, self.DP_NAME, self.DP_NAME)
+
+ GAUGE_CONFIG_DBS = """
+ prometheus:
+ type: 'prometheus'
+ prometheus_addr: '::1'
+ prometheus_port: %(gauge_prom_port)d
+"""
+ config_ports = {'gauge_prom_port': None}
def get_gauge_config(self, faucet_config_file,
monitor_stats_file,
@@ -1683,8 +1696,16 @@ class FaucetUntaggedApplyMeterTest(FaucetUntaggedMeterParseTest):
'ping -c 1000 -f %s' % second_host.IP()))
# Require meter band bytes to match.
self.wait_until_matching_lines_from_file(
- r'.+faucet-1-1-band-bytes-in.+[1-9].+',
+ r'.+faucet-1-1-byte-band-count.+[1-9].+',
self.monitor_meter_stats_file)
+ meter_labels = {
+ 'dp_id': self.dpid,
+ 'dp_name': self.DP_NAME,
+ 'meter_id': 1
+ }
+ byte_band_count = self.scrape_prometheus_var(
+ 'of_meter_byte_band_count', labels=meter_labels, controller='gauge')
+ self.assertTrue(byte_band_count)
class FaucetUntaggedHairpinTest(FaucetUntaggedTest):