diff --git a/README.md b/README.md index 39839201..e609995f 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,11 @@ States map to human readable names like this: 4 = "Ex-Incr" 5 = "Ex-Full" ``` +* VirtualChassis (status of members) +``` +0 = "NotPrsnt" +1 = "NotPrsnt" +``` * VRRP (state per interface) States map to human readable names like this: ``` diff --git a/collectors.go b/collectors.go index 9429bb19..c92ad26d 100644 --- a/collectors.go +++ b/collectors.go @@ -33,6 +33,7 @@ import ( "github.com/czerwonk/junos_exporter/security" "github.com/czerwonk/junos_exporter/storage" "github.com/czerwonk/junos_exporter/system" + "github.com/czerwonk/junos_exporter/virtualchassis" "github.com/czerwonk/junos_exporter/vrrp" "github.com/czerwonk/junos_exporter/vpws" ) @@ -105,6 +106,7 @@ func (c *collectors) initCollectorsForDevices(device *connector.Device) { c.addCollectorIfEnabledForDevice(device, "system", f.System, system.NewCollector) c.addCollectorIfEnabledForDevice(device, "power", f.Power, power.NewCollector) c.addCollectorIfEnabledForDevice(device, "mac", f.MAC, mac.NewCollector) + c.addCollectorIfEnabledForDevice(device, "virtualchassis", f.VirtualChassis, virtualchassis.NewCollector) c.addCollectorIfEnabledForDevice(device, "vrrp", f.VRRP, vrrp.NewCollector) c.addCollectorIfEnabledForDevice(device, "vpws", f.VPWS, vpws.NewCollector) c.addCollectorIfEnabledForDevice(device, "mpls_lsp", f.MPLS_LSP, mpls_lsp.NewCollector) diff --git a/config/config.go b/config/config.go index 61ea8fa6..912bf629 100644 --- a/config/config.go +++ b/config/config.go @@ -61,6 +61,7 @@ type FeatureConfig struct { Power bool `yaml:"power,omitempty"` MAC bool `yaml:"mac,omitempty"` MPLS_LSP bool `yaml:"mpls_lsp,omitempty"` + VirtualChassis bool `yaml:"virtualchassis,omitempty"` VPWS bool `yaml:"vpws,omitempty"` VRRP bool `yaml:"vrrp,omitempty"` } @@ -130,6 +131,7 @@ func setDefaultValues(c *Config) { f.Power = false f.MAC = false f.MPLS_LSP = false + f.VirtualChassis = false f.VPWS = false f.VRRP = false f.BFD = false diff --git a/virtualchassis/collector.go b/virtualchassis/collector.go new file mode 100644 index 00000000..52d4731d --- /dev/null +++ b/virtualchassis/collector.go @@ -0,0 +1,65 @@ +package virtualchassis + +import ( + "github.com/czerwonk/junos_exporter/collector" + "github.com/czerwonk/junos_exporter/rpc" + "github.com/prometheus/client_golang/prometheus" +) + +const prefix = "junos_virtualchassis_" + +var ( + virtualchassismemberstatus *prometheus.Desc +) + +func init() { + l := []string{"target", "status", "serial", "model", "id", "fpcslot", "role"} + virtualchassismemberstatus = prometheus.NewDesc(prefix+"member_status", "virtualchassis member-status (1: Prsnt, 0: NotPrsnt)", l, nil) +} + +type virtualchassisCollector struct { +} + +// Name returns the name of the collector +func (*virtualchassisCollector) Name() string { + return "virtualchassis" +} + +// NewCollector creates a new collector +func NewCollector() collector.RPCCollector { + return &virtualchassisCollector{} +} + +// Describe describes the metrics +func (*virtualchassisCollector) Describe(ch chan<- *prometheus.Desc) { + ch <- virtualchassismemberstatus +} + +// Collect collects metrics from JunOS +func (c *virtualchassisCollector) Collect(client *rpc.Client, ch chan<- prometheus.Metric, labelValues []string) error { + statusValues := map[string]int{ + "NotPrsnt": 0, + "Prsnt": 1, + } + + var x = virtualChassisRpc{} + if client.Netconf { + err := client.RunCommandAndParse("", &x) + if err != nil { + return nil + } + } else { + err := client.RunCommandAndParse("show virtual-chassis", &x) + if err != nil { + return err + } + } + + for _, m := range x.VirtualChassisInformation.MemberList.Member { + l := labelValues + l = append(l, m.Status, m.SerialNumber, m.Model, m.Id, m.FpcSlot, m.Role ) + ch <- prometheus.MustNewConstMetric(virtualchassismemberstatus, prometheus.GaugeValue, float64(statusValues[m.Status]), l...) + } + + return nil +} diff --git a/virtualchassis/rpc.go b/virtualchassis/rpc.go new file mode 100644 index 00000000..f0a5660f --- /dev/null +++ b/virtualchassis/rpc.go @@ -0,0 +1,22 @@ +package virtualchassis + +type virtualChassisRpc struct { + VirtualChassisInformation struct { + VirtualChassisIdInformation struct { + VirtualChassisId string `xml:"virtual-chassis-id"` + VirtualChassisMode string `xml:"virtual-chassis-mode"` + } `xml:"virtual-chassis-id-information"` + MemberList struct { + Member []vcmembers `xml:"member"` + } `xml:"member-list"` + } `xml:"virtual-chassis-information"` +} + +type vcmembers struct { + Status string `xml:"member-status"` + Id string `xml:"member-id"` + FpcSlot string `xml:"fpc-slot"` + SerialNumber string `xml:"member-serial-number"` + Model string `xml:"member-model"` + Role string `xml:"member-role"` +} diff --git a/vpws/collector.go b/vpws/collector.go index b9db370f..f5b34039 100644 --- a/vpws/collector.go +++ b/vpws/collector.go @@ -68,6 +68,12 @@ func (c *vpwsCollector) Collect(client *rpc.Client, ch chan<- prometheus.Metric, ch <- prometheus.MustNewConstMetric(vpwsSid, prometheus.GaugeValue, float64(vpwsSidMap[vSid.Status]), l...) } + + if vIf.RemoteStatus.LocalInterfaceName != "" { + l := append(labelValues, vInst.Name, vInst.RD, vIf.Name, "remote", vIf.RemoteStatus.Sid, vIf.RemoteStatus.LocalInterfaceName, "", "local", "") + ch <- prometheus.MustNewConstMetric(vpwsSid, prometheus.GaugeValue, float64(vpwsStatusMap[vIf.RemoteStatus.LocalInterfaceStatus]), l...) + } + for _, vSid := range vIf.RemoteStatus.SidPeInfo { l := append(labelValues, vInst.Name, vInst.RD, vIf.Name, "remote", vIf.RemoteStatus.Sid, vSid.IP, vSid.Esi, vSid.Mode, vSid.Role) ch <- prometheus.MustNewConstMetric(vpwsSid, prometheus.GaugeValue, float64(vpwsSidMap[vSid.Status]), l...) diff --git a/vpws/rpc.go b/vpws/rpc.go index 959eb619..762daad4 100644 --- a/vpws/rpc.go +++ b/vpws/rpc.go @@ -28,8 +28,10 @@ type vpwsInterface struct { } `xml:"evpn-vpws-service-id-local-status-table>evpn-vpws-sid-local"` RemoteStatus struct { - Sid string `xml:"evpn-vpws-sid-remote-value"` - SidPeInfo []vpwsSidPeInfo `xml:"evpn-vpws-sid-pe-status-table>evpn-vpws-sid-pe-info"` + Sid string `xml:"evpn-vpws-sid-remote-value"` + LocalInterfaceName string `xml:"evpn-vpws-sid-local-interface-name"` + LocalInterfaceStatus string `xml:"evpn-vpws-sid-local-interface-status"` + SidPeInfo []vpwsSidPeInfo `xml:"evpn-vpws-sid-pe-status-table>evpn-vpws-sid-pe-info"` } `xml:"evpn-vpws-service-id-remote-status-table>evpn-vpws-sid-remote"` }