diff --git a/pkg/features/isis/collector.go b/pkg/features/isis/collector.go index f18f7761..aba72449 100644 --- a/pkg/features/isis/collector.go +++ b/pkg/features/isis/collector.go @@ -4,25 +4,48 @@ package isis import ( "strconv" + "strings" - "github.com/czerwonk/junos_exporter/pkg/collector" + "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" + + "github.com/czerwonk/junos_exporter/pkg/collector" ) const prefix string = "junos_isis_" var ( - upCount *prometheus.Desc - totalCount *prometheus.Desc - adjState *prometheus.Desc + upCountDesc *prometheus.Desc + totalCountDesc *prometheus.Desc + adjStateDesc *prometheus.Desc + adjCountDesc *prometheus.Desc + adjPriorityDesc *prometheus.Desc + adjMetricDesc *prometheus.Desc + adjHelloTimerDesc *prometheus.Desc + adjHoldTimerDesc *prometheus.Desc + lspIntervalDesc *prometheus.Desc + csnpIntervalDesc *prometheus.Desc + helloPaddingDesc *prometheus.Desc + maxHelloSizeDesc *prometheus.Desc ) func init() { l := []string{"target"} - upCount = prometheus.NewDesc(prefix+"up_count", "Number of ISIS Adjacencies in state up", l, nil) - totalCount = prometheus.NewDesc(prefix+"total_count", "Number of ISIS Adjacencies", l, nil) - l = append(l, "interface_name", "sysem_name", "level") - adjState = prometheus.NewDesc(prefix+"adjacency_state", "The ISIS Adjacency state (0 = DOWN, 1 = UP, 2 = NEW, 3 = ONE-WAY, 4 =INITIALIZING , 5 = REJECTED)", l, nil) + upCountDesc = prometheus.NewDesc(prefix+"up_count", "Number of ISIS Adjacencies in state up", l, nil) + totalCountDesc = prometheus.NewDesc(prefix+"total_count", "Number of ISIS Adjacencies", l, nil) + l = append(l, "interface_name") + lspIntervalDesc = prometheus.NewDesc(prefix+"lsp_interval_ms", "The ISIS LSP interval", l, nil) + csnpIntervalDesc = prometheus.NewDesc(prefix+"csnp_interval_seconds", "The ISIS CSNP interval", l, nil) + helloPaddingDesc = prometheus.NewDesc(prefix+"hello_padding", "The ISIS hello padding (0 = UNKNOWN, 1 = ADAPTIVE, 2 = DISABLE, 3 = LOOSE, 4 = STRICT)", l, nil) + maxHelloSizeDesc = prometheus.NewDesc(prefix+"max_hello_size_bytes", "The ISIS max hello size", l, nil) + l = append(l, "system_name", "level") + adjStateDesc = prometheus.NewDesc(prefix+"adjacency_state", "The ISIS Adjacency state (0 = DOWN, 1 = UP, 2 = NEW, 3 = ONE-WAY, 4 =INITIALIZING , 5 = REJECTED)", l, nil) + interfaceMetricsLabels := []string{"target", "interface_name", "level"} + adjCountDesc = prometheus.NewDesc(prefix+"adjacency_count", "The number of ISIS adjacencies for an interface", interfaceMetricsLabels, nil) + adjPriorityDesc = prometheus.NewDesc(prefix+"adjacency_priority", "The ISIS adjacency priority", interfaceMetricsLabels, nil) + adjMetricDesc = prometheus.NewDesc(prefix+"adjacency_metric", "The ISIS adjacency metric", interfaceMetricsLabels, nil) + adjHelloTimerDesc = prometheus.NewDesc(prefix+"adjacency_hello_timer_seconds", "The ISIS adjacency hello timer", interfaceMetricsLabels, nil) + adjHoldTimerDesc = prometheus.NewDesc(prefix+"adjacency_hold_timer_seconds", "The ISIS adjacency hold timer", interfaceMetricsLabels, nil) } type isisCollector struct { @@ -40,8 +63,17 @@ func (*isisCollector) Name() string { // Describe describes the metrics func (*isisCollector) Describe(ch chan<- *prometheus.Desc) { - ch <- upCount - ch <- totalCount + ch <- upCountDesc + ch <- totalCountDesc + ch <- adjCountDesc + ch <- adjPriorityDesc + ch <- adjMetricDesc + ch <- adjHelloTimerDesc + ch <- adjHoldTimerDesc + ch <- lspIntervalDesc + ch <- csnpIntervalDesc + ch <- helloPaddingDesc + ch <- maxHelloSizeDesc } // Collect collects metrics from JunOS @@ -51,8 +83,8 @@ func (c *isisCollector) Collect(client collector.Client, ch chan<- prometheus.Me return err } - ch <- prometheus.MustNewConstMetric(upCount, prometheus.GaugeValue, adjancies.Up, labelValues...) - ch <- prometheus.MustNewConstMetric(totalCount, prometheus.GaugeValue, adjancies.Total, labelValues...) + ch <- prometheus.MustNewConstMetric(upCountDesc, prometheus.GaugeValue, adjancies.Up, labelValues...) + ch <- prometheus.MustNewConstMetric(totalCountDesc, prometheus.GaugeValue, adjancies.Total, labelValues...) if adjancies.Adjacencies != nil { for _, adj := range adjancies.Adjacencies { @@ -73,10 +105,16 @@ func (c *isisCollector) Collect(client collector.Client, ch chan<- prometheus.Me state = 5.0 } - ch <- prometheus.MustNewConstMetric(adjState, prometheus.GaugeValue, state, localLabelvalues...) + ch <- prometheus.MustNewConstMetric(adjStateDesc, prometheus.GaugeValue, state, localLabelvalues...) } } + var ifas interfaces + err = client.RunCommandAndParse("show isis interface extensive", &ifas) + if err != nil { + return errors.Wrap(err, "failed to run command 'show isis interface extensive'") + } + c.isisInterfaces(ifas, ch, labelValues) return nil } @@ -99,3 +137,40 @@ func (c *isisCollector) isisAdjancies(client collector.Client) (*adjacencies, er return &adjacencies{Up: float64(up), Total: float64(total), Adjacencies: x.Information.Adjacencies}, nil } + +func (c *isisCollector) isisInterfaces(interfaces interfaces, ch chan<- prometheus.Metric, labelValues []string) { + for _, i := range interfaces.IsisInterfaceInformation.IsisInterface { + if strings.ToLower(i.InterfaceLevelData.Passive) == "passive" { + continue + } + labels := append(labelValues, + i.InterfaceName, + i.InterfaceLevelData.Level) + ch <- prometheus.MustNewConstMetric(adjCountDesc, prometheus.CounterValue, i.InterfaceLevelData.AdjacencyCount, labels...) + ch <- prometheus.MustNewConstMetric(adjPriorityDesc, prometheus.GaugeValue, i.InterfaceLevelData.InterfacePriority, labels...) + ch <- prometheus.MustNewConstMetric(adjMetricDesc, prometheus.GaugeValue, i.InterfaceLevelData.Metric, labels...) + ch <- prometheus.MustNewConstMetric(adjHelloTimerDesc, prometheus.GaugeValue, i.InterfaceLevelData.HelloTime, labels...) + ch <- prometheus.MustNewConstMetric(adjHoldTimerDesc, prometheus.GaugeValue, i.InterfaceLevelData.HoldTime, labels...) + additionaLabels := append(labelValues, i.InterfaceName) + helloPadding := getHelloPadding(i.HelloPadding) + ch <- prometheus.MustNewConstMetric(lspIntervalDesc, prometheus.GaugeValue, i.LSPInterval, additionaLabels...) + ch <- prometheus.MustNewConstMetric(csnpIntervalDesc, prometheus.GaugeValue, i.CSNPInterval, additionaLabels...) + ch <- prometheus.MustNewConstMetric(helloPaddingDesc, prometheus.GaugeValue, helloPadding, additionaLabels...) + ch <- prometheus.MustNewConstMetric(maxHelloSizeDesc, prometheus.GaugeValue, i.MaxHelloSize, additionaLabels...) + } +} + +func getHelloPadding(h string) float64 { + switch strings.ToLower(h) { + case "adaptive": + return 1.0 + case "disable": + return 2.0 + case "loose": + return 3.0 + case "strict": + return 4.0 + default: + return 0.0 + } +} diff --git a/pkg/features/isis/rpc.go b/pkg/features/isis/rpc.go index 3b1bd672..b22d1ec1 100644 --- a/pkg/features/isis/rpc.go +++ b/pkg/features/isis/rpc.go @@ -2,6 +2,8 @@ package isis +import "encoding/xml" + type result struct { Information struct { Adjacencies []adjacency `xml:"isis-adjacency"` @@ -16,3 +18,33 @@ type adjacency struct { Holdtime int64 `xml:"holdtime"` SNPA string `xml:"snpa"` } + +type interfaces struct { + XMLName xml.Name `xml:"rpc-reply"` + Text string `xml:",chardata"` + Junos string `xml:"junos,attr"` + IsisInterfaceInformation struct { + Text string `xml:",chardata"` + Xmlns string `xml:"xmlns,attr"` + IsisInterface []struct { + InterfaceName string `xml:"interface-name"` + LSPInterval float64 `xml:"lsp-interval"` + CSNPInterval float64 `xml:"csnp-interval"` + HelloPadding string `xml:"hello-padding"` + MaxHelloSize float64 `xml:"max-hello-size"` + InterfaceLevelData struct { + Level string `xml:"level"` + AdjacencyCount float64 `xml:"adjacency-count"` + InterfacePriority float64 `xml:"interface-priority"` + Metric float64 `xml:"metric"` + HelloTime float64 `xml:"hello-time"` + HoldTime float64 `xml:"holdtime"` + Passive string `xml:"passive"` + } `xml:"interface-level-data"` + } `xml:"isis-interface"` + } `xml:"isis-interface-information"` + Cli struct { + Text string `xml:",chardata"` + Banner string `xml:"banner"` + } `xml:"cli"` +}