diff --git a/collectors.go b/collectors.go index 88482527..24f169b2 100644 --- a/collectors.go +++ b/collectors.go @@ -23,6 +23,7 @@ import ( "github.com/czerwonk/junos_exporter/route" "github.com/czerwonk/junos_exporter/routingengine" "github.com/czerwonk/junos_exporter/rpki" + "github.com/czerwonk/junos_exporter/rpm" "github.com/czerwonk/junos_exporter/storage" "github.com/czerwonk/junos_exporter/system" ) @@ -86,6 +87,7 @@ func (c *collectors) initCollectorsForDevices(device *connector.Device) { c.addCollectorIfEnabledForDevice(device, "routes", f.Routes, route.NewCollector) c.addCollectorIfEnabledForDevice(device, "routingengine", f.RoutingEngine, routingengine.NewCollector) c.addCollectorIfEnabledForDevice(device, "rpki", f.RPKI, rpki.NewCollector) + c.addCollectorIfEnabledForDevice(device, "rpm", f.RPM, rpm.NewCollector) c.addCollectorIfEnabledForDevice(device, "storage", f.Storage, storage.NewCollector) c.addCollectorIfEnabledForDevice(device, "system", f.System, system.NewCollector) } diff --git a/config/config.go b/config/config.go index ce7f4760..12df125d 100644 --- a/config/config.go +++ b/config/config.go @@ -46,6 +46,7 @@ type FeatureConfig struct { IPSec bool `yaml:"ipsec,omitempty"` FPC bool `yaml:"fpc,omitempty"` RPKI bool `yaml:"rpki,omitempty"` + RPM bool `yaml:"rpm,omitempty"` Satellite bool `yaml:"satellite,omitempty"` System bool `yaml:"system,omitempty"` } @@ -98,6 +99,7 @@ func setDefaultValues(c *Config) { f.FPC = false f.L2Circuit = false f.RPKI = false + f.RPM = false f.Satellite = false } diff --git a/rpm/collector.go b/rpm/collector.go new file mode 100644 index 00000000..cfe9f863 --- /dev/null +++ b/rpm/collector.go @@ -0,0 +1,94 @@ +package rpm + +import ( + "github.com/czerwonk/junos_exporter/collector" + "github.com/czerwonk/junos_exporter/rpc" + "github.com/prometheus/client_golang/prometheus" +) + +const prefix string = "junos_rpm_probe_results_" + +var ( + currRTTMinDesc *prometheus.Desc + currRTTMaxDesc *prometheus.Desc + currRTTAvgDesc *prometheus.Desc + currRTTJitterDesc *prometheus.Desc + currRTTStddevDesc *prometheus.Desc + currRTTSumDesc *prometheus.Desc + totalSentDesc *prometheus.Desc + totalReceivedDesc *prometheus.Desc +) + +func init() { + l := []string{"target", "owner", "name", "address", "type", "interface"} + totalSentDesc = prometheus.NewDesc(prefix+"sent_total", "Number of probes sent within the current test", l, nil) + totalReceivedDesc = prometheus.NewDesc(prefix+"received_total", "Number of probe responses received within the current test", l, nil) + currRTTMinDesc = prometheus.NewDesc(prefix+"rtt_min_current", "Minimum RTT for the most recently completed test, in microseconds", l, nil) + currRTTMaxDesc = prometheus.NewDesc(prefix+"rtt_max_current", "Maximum RTT for the most recently completed test, in microseconds", l, nil) + currRTTAvgDesc = prometheus.NewDesc(prefix+"rtt_avg_current", "Average RTT for the most recently completed test, in microseconds", l, nil) + currRTTJitterDesc = prometheus.NewDesc(prefix+"rtt_jitter_current", "Peak-to-peak difference, in microseconds", l, nil) + currRTTStddevDesc = prometheus.NewDesc(prefix+"rtt_stddev_current", "Standard deviation, in microseconds", l, nil) + currRTTSumDesc = prometheus.NewDesc(prefix+"rtt_sum_current", "Statistical sum", l, nil) +} + +type rpmCollector struct{} + +// NewCollector creates a new collector +func NewCollector() collector.RPCCollector { + return &rpmCollector{} +} + +// Name returns the name of the collector +func (*rpmCollector) Name() string { + return "RPM" +} + +// Describe describes the metrics +func (*rpmCollector) Describe(ch chan<- *prometheus.Desc) { + ch <- totalSentDesc + ch <- totalReceivedDesc + ch <- currRTTMinDesc + ch <- currRTTMaxDesc + ch <- currRTTAvgDesc + ch <- currRTTJitterDesc + ch <- currRTTStddevDesc + ch <- currRTTSumDesc +} + +// Collect collects metrics from JunOS +func (c *rpmCollector) Collect(client *rpc.Client, ch chan<- prometheus.Metric, labelValues []string) error { + err := c.collect(client, ch, labelValues) + if err != nil { + return err + } + + return nil +} + +func (c *rpmCollector) collect(client *rpc.Client, ch chan<- prometheus.Metric, labelValues []string) error { + var x = RPMRPC{} + + err := client.RunCommandAndParse("show services rpm probe-results", &x) + if err != nil { + return err + } + + for _, probe := range x.Results.Probes { + c.collectForProbe(probe, ch, labelValues) + } + + return nil +} + +func (c *rpmCollector) collectForProbe(p RPMProbe, ch chan<- prometheus.Metric, labelValues []string) { + l := append(labelValues, []string{p.Owner, p.Name, p.Address, p.Type, p.Interface}...) + + ch <- prometheus.MustNewConstMetric(totalSentDesc, prometheus.GaugeValue, float64(p.Global.Results.Sent), l...) + ch <- prometheus.MustNewConstMetric(totalReceivedDesc, prometheus.GaugeValue, float64(p.Global.Results.Responses), l...) + ch <- prometheus.MustNewConstMetric(currRTTMinDesc, prometheus.GaugeValue, float64(p.Last.Results.RTT.Summary.Min), l...) + ch <- prometheus.MustNewConstMetric(currRTTMaxDesc, prometheus.GaugeValue, float64(p.Last.Results.RTT.Summary.Max), l...) + ch <- prometheus.MustNewConstMetric(currRTTAvgDesc, prometheus.GaugeValue, float64(p.Last.Results.RTT.Summary.Avg), l...) + ch <- prometheus.MustNewConstMetric(currRTTJitterDesc, prometheus.GaugeValue, float64(p.Last.Results.RTT.Summary.Jitter), l...) + ch <- prometheus.MustNewConstMetric(currRTTStddevDesc, prometheus.GaugeValue, float64(p.Last.Results.RTT.Summary.Stddev), l...) + ch <- prometheus.MustNewConstMetric(currRTTSumDesc, prometheus.GaugeValue, float64(p.Last.Results.RTT.Summary.Sum), l...) +} diff --git a/rpm/rpc.go b/rpm/rpc.go new file mode 100644 index 00000000..1677d63d --- /dev/null +++ b/rpm/rpc.go @@ -0,0 +1,40 @@ +package rpm + +type RPMRPC struct { + Results struct { + Probes []RPMProbe `xml:"probe-test-results"` + } `xml:"probe-results"` +} + +type RPMProbe struct { + Owner string `xml:"owner"` + Name string `xml:"test-name"` + Address string `xml:"target-address"` + Type string `xml:"probe-type"` + Interface string `xml:"destination-interface"` + Size int64 `xml:"test-size"` + Last struct { + Results RPMGenericResults `xml:"probe-test-generic-results"` + } `xml:"probe-last-test-results"` + Global struct { + Results RPMGenericResults `xml:"probe-test-generic-results"` + } `xml:"probe-test-global-results"` +} + +type RPMGenericResults struct { + Scope string `xml:"results-scope"` + Sent int64 `xml:"probes-sent"` + Responses int64 `xml:"probe-responses"` + LossPercent float64 `xml:"loss-percentage"` + RTT struct { + Summary struct { + Samples int64 `xml:"samples"` + Min int64 `xml:"min-delay"` + Max int64 `xml:"max-delay"` + Avg int64 `xml:"avg-delay"` + Jitter int64 `xml:"jitter-delay"` + Stddev int64 `xml:"stddev-delay"` + Sum int64 `xml:"sum-delay"` + } `xml:"probe-summary-results"` + } `xml:"probe-test-rtt"` +}