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/accounting/collector.go b/accounting/collector.go
index a0c167bc..b6cbcd78 100644
--- a/accounting/collector.go
+++ b/accounting/collector.go
@@ -96,9 +96,16 @@ func (c *accountingCollector) Collect(client *rpc.Client, ch chan<- prometheus.M
func (c *accountingCollector) accountingFlows(client *rpc.Client) (*AccountingFlow, error) {
var x = AccountingFlowRpc{}
- err := client.RunCommandAndParse("show services accounting flow inline-jflow", &x)
- if err != nil {
- return nil, err
+ if client.Netconf {
+ err := client.RunCommandAndParse("", &x)
+ if err != nil {
+ return nil, err
+ }
+ } else {
+ err := client.RunCommandAndParse("show services accounting flow inline-jflow", &x)
+ if err != nil {
+ return nil, err
+ }
}
if x.Error.Message != "" {
@@ -119,9 +126,16 @@ func (c *accountingCollector) accountingFlows(client *rpc.Client) (*AccountingFl
func (c *accountingCollector) accountingFailures(client *rpc.Client) (*AccountingError, error) {
var x = AccountingFlowErrorRpc{}
- err := client.RunCommandAndParse("show services accounting errors inline-jflow fpc-slot 0", &x)
- if err != nil {
- return nil, err
+ if client.Netconf {
+ err := client.RunCommandAndParse("0", &x)
+ if err != nil {
+ return nil, err
+ }
+ } else {
+ err := client.RunCommandAndParse("show services accounting errors inline-jflow fpc-slot 0", &x)
+ if err != nil {
+ return nil, err
+ }
}
return &AccountingError{
diff --git a/alarm/collector.go b/alarm/collector.go
index 55754d29..4df4b693 100644
--- a/alarm/collector.go
+++ b/alarm/collector.go
@@ -78,6 +78,13 @@ func (c *alarmCollector) alarmCounter(client *rpc.Client) (*AlarmCounter, *[]Ala
"show chassis alarms",
}
+ if client.Netconf {
+ cmds = []string{
+ "",
+ "",
+ }
+ }
+
var alarms []AlarmDetails
messages := make(map[string]interface{})
diff --git a/bfd/collector.go b/bfd/collector.go
index 4dc0db06..f9746155 100644
--- a/bfd/collector.go
+++ b/bfd/collector.go
@@ -41,10 +41,17 @@ func (*bfdCollector) Describe(ch chan<- *prometheus.Desc) {
// Collect collects metrics from JunOS
func (c *bfdCollector) Collect(client *rpc.Client, ch chan<- prometheus.Metric, labelValues []string) error {
- var x = bfdRpc{}
- err := client.RunCommandAndParse("show bfd session extensive", &x)
- if err != nil {
- return err
+ var x = bfdRpc{}
+ if client.Netconf {
+ err := client.RunCommandAndParse("", &x)
+ if err != nil {
+ return err
+ }
+ } else {
+ err := client.RunCommandAndParse("show bfd session extensive", &x)
+ if err != nil {
+ return err
+ }
}
for _, bfds := range x.Information.BfdSessions {
diff --git a/bgp/collector.go b/bgp/collector.go
index 9c9b2680..9a14940e 100644
--- a/bgp/collector.go
+++ b/bgp/collector.go
@@ -77,9 +77,13 @@ func (c *bgpCollector) Collect(client *rpc.Client, ch chan<- prometheus.Metric,
func (c *bgpCollector) collect(client *rpc.Client, ch chan<- prometheus.Metric, labelValues []string) error {
var x = BGPRPC{}
var cmd strings.Builder
- cmd.WriteString("show bgp neighbor")
- if c.LogicalSystem != "" {
- cmd.WriteString(" logical-system " + c.LogicalSystem)
+ if client.Netconf {
+ cmd.WriteString("")
+ } else {
+ cmd.WriteString("show bgp neighbor")
+ if c.LogicalSystem != "" {
+ cmd.WriteString(" logical-system " + c.LogicalSystem)
+ }
}
err := client.RunCommandAndParse(cmd.String(), &x)
@@ -87,6 +91,7 @@ func (c *bgpCollector) collect(client *rpc.Client, ch chan<- prometheus.Metric,
return err
}
+
for _, peer := range x.Information.Peers {
c.collectForPeer(peer, ch, labelValues)
}
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..acff763d 100644
--- a/config/config.go
+++ b/config/config.go
@@ -57,10 +57,12 @@ type FeatureConfig struct {
RPKI bool `yaml:"rpki,omitempty"`
RPM bool `yaml:"rpm,omitempty"`
Satellite bool `yaml:"satellite,omitempty"`
+ Netconf bool `yaml:"netconf,omitempty"`
System bool `yaml:"system,omitempty"`
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"`
}
@@ -127,9 +129,11 @@ func setDefaultValues(c *Config) {
f.RPKI = false
f.RPM = false
f.Satellite = false
+ f.Netconf = false
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/connector/connection.go b/connector/connection.go
index e9d1250f..89155d50 100644
--- a/connector/connection.go
+++ b/connector/connection.go
@@ -4,10 +4,12 @@ import (
"bytes"
"net"
"sync"
-
+ "fmt"
+ "io"
"github.com/pkg/errors"
"golang.org/x/crypto/ssh"
+ "github.com/Juniper/go-netconf/netconf"
)
// SSHConnection encapsulates the connection to the device
@@ -17,10 +19,27 @@ type SSHConnection struct {
conn net.Conn
mu sync.Mutex
done chan struct{}
+ netconf bool
+ netconfsession *netconf.Session
+}
+
+type TransportSSH struct {
+ transportBasicIO
+ sshClient *ssh.Client
+ sshSession *ssh.Session
}
+
// RunCommand runs a command against the device
func (c *SSHConnection) RunCommand(cmd string) ([]byte, error) {
+ if c.netconf {
+ return c.RunCommandNETCONF(cmd)
+ } else {
+ return c.RunCommandSSH(cmd)
+ }
+}
+
+func (c *SSHConnection) RunCommandSSH(cmd string) ([]byte, error) {
c.mu.Lock()
defer c.mu.Unlock()
@@ -45,6 +64,53 @@ func (c *SSHConnection) RunCommand(cmd string) ([]byte, error) {
return b.Bytes(), nil
}
+
+func (c *SSHConnection) RunCommandNETCONF(cmd string) ([]byte, error) {
+ c.mu.Lock()
+ defer c.mu.Unlock()
+ var err error
+
+ if c.client == nil {
+ return nil, errors.New("not connected")
+ }
+
+ t := &TransportSSH{}
+ if c.netconfsession == nil {
+ t.sshSession, err = c.client.NewSession()
+ if err != nil {
+ return nil, errors.Wrap(err, "could not open session")
+ }
+
+ writer, err := t.sshSession.StdinPipe()
+ if err != nil {
+ return nil, errors.Wrap(err, "could not open session stdin")
+ }
+
+ reader, err := t.sshSession.StdoutPipe()
+ if err != nil {
+ return nil, errors.Wrap(err, "could not open session stdout")
+ }
+
+ t.ReadWriteCloser = netconf.NewReadWriteCloser(reader, writer)
+ t.sshSession.RequestSubsystem("netconf")
+ c.netconfsession = netconf.NewSession(t)
+ }
+
+ reply, err := c.netconfsession.Exec(netconf.RawMethod(cmd))
+
+ if err != nil {
+ if err == io.EOF {
+ //probably lost the session, closing to force a reopen
+ fmt.Println("Error - Closing")
+ c.netconfsession.Close()
+ c.netconfsession = nil
+ }
+ return nil, errors.Wrap(err, "could not run command")
+ }
+
+ return []byte(reply.RawReply), nil
+}
+
func (c *SSHConnection) isConnected() bool {
return c.conn != nil
}
diff --git a/connector/connection_manager.go b/connector/connection_manager.go
index 8a44ca56..e39451f0 100644
--- a/connector/connection_manager.go
+++ b/connector/connection_manager.go
@@ -32,6 +32,7 @@ func WithKeepAliveInterval(d time.Duration) Option {
}
}
+
// WithKeepAliveTimeout sets the timeout after an ssh connection to be determined dead (default 15 seconds)
func WithKeepAliveTimeout(d time.Duration) Option {
return func(m *SSHConnectionManager) {
@@ -39,6 +40,7 @@ func WithKeepAliveTimeout(d time.Duration) Option {
}
}
+
// SSHConnectionManager manages SSH connections to different devices
type SSHConnectionManager struct {
connections map[string]*SSHConnection
@@ -65,7 +67,7 @@ func NewConnectionManager(opts ...Option) *SSHConnectionManager {
}
// Connect connects to a device or returns an long living connection
-func (m *SSHConnectionManager) Connect(device *Device) (*SSHConnection, error) {
+func (m *SSHConnectionManager) Connect(device *Device, netconf bool) (*SSHConnection, error) {
m.mu.Lock()
defer m.mu.Unlock()
@@ -77,10 +79,10 @@ func (m *SSHConnectionManager) Connect(device *Device) (*SSHConnection, error) {
return connection, nil
}
- return m.connect(device)
+ return m.connect(device, netconf)
}
-func (m *SSHConnectionManager) connect(device *Device) (*SSHConnection, error) {
+func (m *SSHConnectionManager) connect(device *Device, netconf bool) (*SSHConnection, error) {
client, conn, err := m.connectToDevice(device)
if err != nil {
return nil, err
@@ -91,6 +93,7 @@ func (m *SSHConnectionManager) connect(device *Device) (*SSHConnection, error) {
client: client,
device: device,
done: make(chan struct{}),
+ netconf: netconf,
}
go m.keepAlive(c)
diff --git a/connector/transport.go b/connector/transport.go
new file mode 100644
index 00000000..bfaec9ee
--- /dev/null
+++ b/connector/transport.go
@@ -0,0 +1,183 @@
+package connector
+
+import (
+ "bytes"
+ "encoding/xml"
+ "fmt"
+ "io"
+ "regexp"
+ "github.com/Juniper/go-netconf/netconf"
+
+)
+
+const (
+ // msgSeperator is used to separate sent messages via NETCONF
+ msgSeperator = "]]>]]>"
+ msgSeperator_v11 = "\n##\n"
+)
+
+
+// Transport interface defines what characterisitics make up a NETCONF transport
+// layer object.
+type Transport interface {
+ Send([]byte) error
+ Receive() ([]byte, error)
+ Close() error
+ ReceiveHello() (*netconf.HelloMessage, error)
+ SendHello(*netconf.HelloMessage) error
+ SetVersion(version string)
+}
+
+type transportBasicIO struct {
+ io.ReadWriteCloser
+ //new add
+ version string
+}
+
+func (t *transportBasicIO) SetVersion(version string) {
+ t.version = version
+}
+
+// Sends a well formated NETCONF rpc message as a slice of bytes adding on the
+// nessisary framining messages.
+func (t *transportBasicIO) Send(data []byte) error {
+ var seperator []byte
+ var dataInfo []byte
+ //headlen := 0
+ if t.version == "v1.1" {
+ seperator = append(seperator, []byte(msgSeperator_v11)...)
+ } else {
+ seperator = append(seperator, []byte(msgSeperator)...)
+ }
+
+ if t.version == "v1.1" {
+ header := fmt.Sprintf("\n#%d\n", len(string(data)))
+ dataInfo = append(dataInfo, header...)
+ //t.Write([]byte(header))
+ //headlen = len([]byte(header))
+ }
+ dataInfo = append(dataInfo, data...)
+ dataInfo = append(dataInfo, seperator...)
+ _, err := t.Write(dataInfo)
+
+ return err
+}
+
+func (t *transportBasicIO) Receive() ([]byte, error) {
+ var seperator []byte
+ if t.version == "v1.1" {
+ seperator = append(seperator, []byte(msgSeperator_v11)...)
+ } else {
+ seperator = append(seperator, []byte(msgSeperator)...)
+ }
+ return t.WaitForBytes([]byte(seperator))
+}
+
+func (t *transportBasicIO) SendHello(hello *netconf.HelloMessage) error {
+ val, err := xml.Marshal(hello)
+ if err != nil {
+ return err
+ }
+
+ header := []byte(xml.Header)
+ val = append(header, val...)
+ err = t.Send(val)
+ return err
+}
+
+func (t *transportBasicIO) ReceiveHello() (*netconf.HelloMessage, error) {
+ hello := new(netconf.HelloMessage)
+
+ val, err := t.Receive()
+ if err != nil {
+ return hello, err
+ }
+
+ err = xml.Unmarshal(val, hello)
+ return hello, err
+}
+
+func (t *transportBasicIO) Writeln(b []byte) (int, error) {
+ t.Write(b)
+ t.Write([]byte("\n"))
+ return 0, nil
+}
+
+func (t *transportBasicIO) WaitForFunc(f func([]byte) (int, error)) ([]byte, error) {
+ var out bytes.Buffer
+ buf := make([]byte, 8192)
+
+ pos := 0
+ for {
+ n, err := t.Read(buf[pos : pos+(len(buf)/2)])
+ if err != nil {
+ if err != io.EOF {
+ return nil, err
+ }
+ break
+ }
+
+ if n > 0 {
+ end, err := f(buf[0 : pos+n])
+ if err != nil {
+ return nil, err
+ }
+
+ if end > -1 {
+ out.Write(buf[0:end])
+ return out.Bytes(), nil
+ }
+
+ if pos > 0 {
+ out.Write(buf[0:pos])
+ copy(buf, buf[pos:pos+n])
+ }
+
+ pos = n
+ }
+ }
+
+ return nil, fmt.Errorf("WaitForFunc failed")
+}
+
+func (t *transportBasicIO) WaitForBytes(b []byte) ([]byte, error) {
+ return t.WaitForFunc(func(buf []byte) (int, error) {
+ return bytes.Index(buf, b), nil
+ })
+}
+
+func (t *transportBasicIO) WaitForString(s string) (string, error) {
+ out, err := t.WaitForBytes([]byte(s))
+ if out != nil {
+ return string(out), err
+ }
+ return "", err
+}
+
+func (t *transportBasicIO) WaitForRegexp(re *regexp.Regexp) ([]byte, [][]byte, error) {
+ var matches [][]byte
+ out, err := t.WaitForFunc(func(buf []byte) (int, error) {
+ loc := re.FindSubmatchIndex(buf)
+ if loc != nil {
+ for i := 2; i < len(loc); i += 2 {
+ matches = append(matches, buf[loc[i]:loc[i+1]])
+ }
+ return loc[1], nil
+ }
+ return -1, nil
+ })
+ return out, matches, err
+}
+
+// ReadWriteCloser represents a combined IO Reader and WriteCloser
+type ReadWriteCloser struct {
+ io.Reader
+ io.WriteCloser
+}
+
+// NewReadWriteCloser creates a new combined IO Reader and Write Closer from the
+// provided objects
+func NewReadWriteCloser(r io.Reader, w io.WriteCloser) *ReadWriteCloser {
+ return &ReadWriteCloser{r, w}
+}
+
diff --git a/environment/collector.go b/environment/collector.go
index 68a62e69..ecab65ca 100644
--- a/environment/collector.go
+++ b/environment/collector.go
@@ -78,30 +78,61 @@ func (c *environmentCollector) environmentItems(client *rpc.Client, ch chan<- pr
"Present": 5,
}
- err := client.RunCommandAndParseWithParser("show chassis environment", func(b []byte) error {
- return parseXML(b, &x)
- })
- if err != nil {
- return nil
- }
+ if client.Netconf {
+ err := client.RunCommandAndParseWithParser("", func(b []byte) error {
+ return parseXML(b, &x)
+ })
+ if err != nil {
+ return nil
+ }
- // gather satellite data
- if client.Satellite {
- var y = RpcReply{}
- err = client.RunCommandAndParseWithParser("show chassis environment satellite", func(b []byte) error {
- if string(b[:]) == "\nerror: syntax error, expecting : satellite\n" {
- log.Printf("system doesn't seem to have satellite enabled")
- return nil
- }
+ // gather satellite data
+ if client.Satellite {
+ var y = RpcReply{}
+ err = client.RunCommandAndParseWithParser("", func(b []byte) error {
+ if string(b[:]) == "\nerror: syntax error, expecting : satellite\n" {
+ log.Printf("system doesn't seem to have satellite enabled")
+ return nil
+ }
- return parseXML(b, &y)
+ return parseXML(b, &y)
+ })
+ if err != nil {
+ // probably no satellite, but let's continue the task
+ //return nil
+ } else {
+ // add satellite details (only if y.MultiRoutingEngineResults.RoutingEngine has elements)
+ if len(y.MultiRoutingEngineResults.RoutingEngine) > 0 {
+ x.MultiRoutingEngineResults.RoutingEngine[0].EnvironmentInformation.Items = append(x.MultiRoutingEngineResults.RoutingEngine[0].EnvironmentInformation.Items, y.MultiRoutingEngineResults.RoutingEngine[0].EnvironmentInformation.Items...)
+ }
+ }
+ }
+ } else {
+ err := client.RunCommandAndParseWithParser("show chassis environment", func(b []byte) error {
+ return parseXML(b, &x)
})
if err != nil {
return nil
- } else {
- // add satellite details (only if y.MultiRoutingEngineResults.RoutingEngine has elements)
- if len(y.MultiRoutingEngineResults.RoutingEngine) > 0 {
- x.MultiRoutingEngineResults.RoutingEngine[0].EnvironmentInformation.Items = append(x.MultiRoutingEngineResults.RoutingEngine[0].EnvironmentInformation.Items, y.MultiRoutingEngineResults.RoutingEngine[0].EnvironmentInformation.Items...)
+ }
+
+ // gather satellite data
+ if client.Satellite {
+ var y = RpcReply{}
+ err = client.RunCommandAndParseWithParser("show chassis environment satellite", func(b []byte) error {
+ if string(b[:]) == "\nerror: syntax error, expecting : satellite\n" {
+ log.Printf("system doesn't seem to have satellite enabled")
+ return nil
+ }
+
+ return parseXML(b, &y)
+ })
+ if err != nil {
+ return nil
+ } else {
+ // add satellite details (only if y.MultiRoutingEngineResults.RoutingEngine has elements)
+ if len(y.MultiRoutingEngineResults.RoutingEngine) > 0 {
+ x.MultiRoutingEngineResults.RoutingEngine[0].EnvironmentInformation.Items = append(x.MultiRoutingEngineResults.RoutingEngine[0].EnvironmentInformation.Items, y.MultiRoutingEngineResults.RoutingEngine[0].EnvironmentInformation.Items...)
+ }
}
}
}
@@ -132,11 +163,20 @@ func (c *environmentCollector) environmentPEMItems(client *rpc.Client, ch chan<-
"Empty": 3,
}
- err := client.RunCommandAndParseWithParser("show chassis environment pem", func(b []byte) error {
- return parseXML(b, &x)
- })
- if err != nil {
- return err
+ if client.Netconf {
+ err := client.RunCommandAndParseWithParser("", func(b []byte) error {
+ return parseXML(b, &x)
+ })
+ if err != nil {
+ return err
+ }
+ } else {
+ err := client.RunCommandAndParseWithParser("show chassis environment pem", func(b []byte) error {
+ return parseXML(b, &x)
+ })
+ if err != nil {
+ return err
+ }
}
for _, re := range x.MultiRoutingEngineResults.RoutingEngine {
diff --git a/firewall/collector.go b/firewall/collector.go
index 16bd7980..4654e181 100644
--- a/firewall/collector.go
+++ b/firewall/collector.go
@@ -48,9 +48,17 @@ func (*firewallCollector) Describe(ch chan<- *prometheus.Desc) {
// Collect collects metrics from JunOS
func (c *firewallCollector) Collect(client *rpc.Client, ch chan<- prometheus.Metric, labelValues []string) error {
var x = FirewallRpc{}
- err := client.RunCommandAndParse("show firewall filter regex .*", &x)
- if err != nil {
- return err
+
+ if client.Netconf {
+ err := client.RunCommandAndParse(".*", &x)
+ if err != nil {
+ return err
+ }
+ } else {
+ err := client.RunCommandAndParse("show firewall filter regex .*", &x)
+ if err != nil {
+ return err
+ }
}
for _, t := range x.Information.Filters {
diff --git a/fpc/collector.go b/fpc/collector.go
index 2d5ce542..a272d427 100644
--- a/fpc/collector.go
+++ b/fpc/collector.go
@@ -100,12 +100,20 @@ func (c *fpcCollector) Collect(client *rpc.Client, ch chan<- prometheus.Metric,
// CollectFPC collects metrics from JunOS
func (c *fpcCollector) CollectFPCDetail(client *rpc.Client, ch chan<- prometheus.Metric, labelValues []string) error {
r := RpcReply{}
- err := client.RunCommandAndParseWithParser("show chassis fpc detail", func(b []byte) error {
- return parseXML(b, &r)
- })
-
- if err != nil {
- return err
+ if client.Netconf {
+ err := client.RunCommandAndParseWithParser("", func(b []byte) error {
+ return parseXML(b, &r)
+ })
+ if err != nil {
+ return err
+ }
+ } else {
+ err := client.RunCommandAndParseWithParser("show chassis fpc detail", func(b []byte) error {
+ return parseXML(b, &r)
+ })
+ if err != nil {
+ return err
+ }
}
for _, r := range r.MultiRoutingEngineResults.RoutingEngine {
@@ -121,11 +129,20 @@ func (c *fpcCollector) CollectFPCDetail(client *rpc.Client, ch chan<- prometheus
// Collect collects metrics from JunOS
func (c *fpcCollector) CollectFPC(client *rpc.Client, ch chan<- prometheus.Metric, labelValues []string) error {
r := RpcReply{}
- err := client.RunCommandAndParseWithParser("show chassis fpc", func(b []byte) error {
- return parseXML(b, &r)
- })
- if err != nil {
- return err
+ if client.Netconf {
+ err := client.RunCommandAndParseWithParser("", func(b []byte) error {
+ return parseXML(b, &r)
+ })
+ if err != nil {
+ return err
+ }
+ } else {
+ err := client.RunCommandAndParseWithParser("show chassis fpc", func(b []byte) error {
+ return parseXML(b, &r)
+ })
+ if err != nil {
+ return err
+ }
}
for _, r := range r.MultiRoutingEngineResults.RoutingEngine {
@@ -139,11 +156,20 @@ func (c *fpcCollector) CollectFPC(client *rpc.Client, ch chan<- prometheus.Metri
func (c *fpcCollector) CollectPIC(client *rpc.Client, ch chan<- prometheus.Metric, labelValues []string) error {
r := RpcReply{}
- err := client.RunCommandAndParseWithParser("show chassis fpc pic-status", func(b []byte) error {
- return parseXML(b, &r)
- })
- if err != nil {
- return err
+ if client.Netconf {
+ err := client.RunCommandAndParseWithParser("", func(b []byte) error {
+ return parseXML(b, &r)
+ })
+ if err != nil {
+ return err
+ }
+ } else {
+ err := client.RunCommandAndParseWithParser("show chassis fpc pic-status", func(b []byte) error {
+ return parseXML(b, &r)
+ })
+ if err != nil {
+ return err
+ }
}
for _, r := range r.MultiRoutingEngineResults.RoutingEngine {
labels := append(labelValues, r.Name)
diff --git a/go.mod b/go.mod
index 46d8df57..0208dd40 100644
--- a/go.mod
+++ b/go.mod
@@ -3,6 +3,7 @@ module github.com/czerwonk/junos_exporter
go 1.18
require (
+ github.com/Juniper/go-netconf v0.1.1
github.com/pkg/errors v0.9.1
github.com/prometheus/client_golang v1.12.2
github.com/prometheus/client_model v0.2.0
@@ -21,6 +22,7 @@ require (
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/common v0.34.0 // indirect
github.com/prometheus/procfs v0.7.3 // indirect
+ github.com/ziutek/telnet v0.0.0-20180329124119-c3b780dc415b // indirect
golang.org/x/sys v0.0.0-20220513210249-45d2b4557a2a // indirect
google.golang.org/protobuf v1.28.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20220512140231-539c8e751b99 // indirect
diff --git a/go.sum b/go.sum
index 785fb2ac..70e9bbd9 100644
--- a/go.sum
+++ b/go.sum
@@ -33,6 +33,8 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
+github.com/Juniper/go-netconf v0.1.1 h1:5fx/T7L2Fwq51UnESPOP1CXgGCs7IYxR/pnyC5quu/k=
+github.com/Juniper/go-netconf v0.1.1/go.mod h1:2Fy6tQTWnL//D/Ll1hb0RYXN4jndcTyneRn6xj5E1VE=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
@@ -109,7 +111,6 @@ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
@@ -140,10 +141,8 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
-github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
-github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
@@ -200,6 +199,8 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/ziutek/telnet v0.0.0-20180329124119-c3b780dc415b h1:VfPXB/wCGGt590QhD1bOpv2J/AmC/RJNTg/Q59HKSB0=
+github.com/ziutek/telnet v0.0.0-20180329124119-c3b780dc415b/go.mod h1:IZpXDfkJ6tWD3PhBK5YzgQT+xJWh7OsdwiG8hA2MkO4=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
@@ -332,7 +333,6 @@ golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220513210249-45d2b4557a2a h1:N2T1jUrTQE9Re6TFF5PhvEHXHCguynGhKjWVsIUt5cY=
golang.org/x/sys v0.0.0-20220513210249-45d2b4557a2a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
-golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -387,7 +387,6 @@ golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
@@ -469,7 +468,6 @@ google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
diff --git a/interfacediagnostics/collector.go b/interfacediagnostics/collector.go
index c5695c54..1ad8b1e5 100644
--- a/interfacediagnostics/collector.go
+++ b/interfacediagnostics/collector.go
@@ -255,9 +255,16 @@ func (c *interfaceDiagnosticsCollector) Collect(client *rpc.Client, ch chan<- pr
func (c *interfaceDiagnosticsCollector) interfaceDiagnostics(client *rpc.Client) ([]*InterfaceDiagnostics, error) {
var x = InterfaceDiagnosticsRPC{}
- err := client.RunCommandAndParse("show interfaces diagnostics optics", &x)
- if err != nil {
- return nil, err
+ if client.Netconf {
+ err := client.RunCommandAndParse("", &x)
+ if err != nil {
+ return nil, err
+ }
+ } else {
+ err := client.RunCommandAndParse("show interfaces diagnostics optics", &x)
+ if err != nil {
+ return nil, err
+ }
}
return interfaceDiagnosticsFromRPCResult(x), nil
@@ -279,42 +286,77 @@ func (c *interfaceDiagnosticsCollector) interfaceDiagnosticsSatellite(client *rp
//
// workaround: go through all lines of the XML and remove identical, consecutive lines
- err := client.RunCommandAndParseWithParser("show interfaces diagnostics optics satellite", func(b []byte) error {
- var (
- lines []string = strings.Split(string(b[:]), "\n")
- lineIndex int
- tmpByte []byte
- )
-
- // check if satellite is enabled
- if string(b[:]) == "\nerror: syntax error, expecting : satellite\n" {
+ if client.Netconf {
+ err := client.RunCommandAndParseWithParser("", func(b []byte) error {
+ var (
+ lines []string = strings.Split(string(b[:]), "\n")
+ lineIndex int
+ tmpByte []byte
+ )
+
+ for lineIndex = range lines {
+ if lineIndex == 0 {
+ // add good lines to new byte buffer
+ tmpByte = append(tmpByte, lines[lineIndex]...)
+ continue
+ }
+
+ // check if two consecutive lines are identical (except whitespaces)
+ if strings.TrimSpace(lines[lineIndex]) == strings.TrimSpace(lines[lineIndex-1]) {
+ // skip the duplicate line
+ continue
+
+ } else {
+ // add good lines to new byte buffer
+ tmpByte = append(tmpByte, lines[lineIndex]...)
+ }
+ }
+
+ return xml.Unmarshal(tmpByte, &x)
+ })
+
+ if err != nil {
log.Printf("system doesn't seem to have satellite enabled")
- return nil
+ return nil,nil
}
-
- for lineIndex = range lines {
- if lineIndex == 0 {
- // add good lines to new byte buffer
- tmpByte = append(tmpByte, lines[lineIndex]...)
- continue
+ } else {
+ err := client.RunCommandAndParseWithParser("show interfaces diagnostics optics satellite", func(b []byte) error {
+ var (
+ lines []string = strings.Split(string(b[:]), "\n")
+ lineIndex int
+ tmpByte []byte
+ )
+
+ // check if satellite is enabled
+ if string(b[:]) == "\nerror: syntax error, expecting : satellite\n" {
+ log.Printf("system doesn't seem to have satellite enabled")
+ return nil
}
- // check if two consecutive lines are identical (except whitespaces)
- if strings.TrimSpace(lines[lineIndex]) == strings.TrimSpace(lines[lineIndex-1]) {
- // skip the duplicate line
- continue
+ for lineIndex = range lines {
+ if lineIndex == 0 {
+ // add good lines to new byte buffer
+ tmpByte = append(tmpByte, lines[lineIndex]...)
+ continue
+ }
+
+ // check if two consecutive lines are identical (except whitespaces)
+ if strings.TrimSpace(lines[lineIndex]) == strings.TrimSpace(lines[lineIndex-1]) {
+ // skip the duplicate line
+ continue
- } else {
- // add good lines to new byte buffer
- tmpByte = append(tmpByte, lines[lineIndex]...)
+ } else {
+ // add good lines to new byte buffer
+ tmpByte = append(tmpByte, lines[lineIndex]...)
+ }
}
- }
- return xml.Unmarshal(tmpByte, &x)
- })
+ return xml.Unmarshal(tmpByte, &x)
+ })
- if err != nil {
- return nil, err
+ if err != nil {
+ return nil, err
+ }
}
return interfaceDiagnosticsFromRPCResult(x), nil
diff --git a/interfacelabels/dynamic_labels.go b/interfacelabels/dynamic_labels.go
index 24339da6..d169e78a 100644
--- a/interfacelabels/dynamic_labels.go
+++ b/interfacelabels/dynamic_labels.go
@@ -47,9 +47,16 @@ type interfaceLabel struct {
// CollectDescriptions collects labels from descriptions
func (l *DynamicLabels) CollectDescriptions(device *connector.Device, client *rpc.Client, ifDescReg *regexp.Regexp) error {
r := &InterfaceRPC{}
- err := client.RunCommandAndParse("show interfaces descriptions", r)
- if err != nil {
- return errors.Wrap(err, "could not retrieve interface descriptions for "+device.Host)
+ if client.Netconf {
+ err := client.RunCommandAndParse("", r)
+ if err != nil {
+ return errors.Wrap(err, "could not retrieve interface descriptions for "+device.Host)
+ }
+ } else {
+ err := client.RunCommandAndParse("show interfaces descriptions", r)
+ if err != nil {
+ return errors.Wrap(err, "could not retrieve interface descriptions for "+device.Host)
+ }
}
l.parseDescriptions(device, r.Information.Interfaces, ifDescReg)
diff --git a/interfacequeue/collector.go b/interfacequeue/collector.go
index 4435a586..3ff9775b 100644
--- a/interfacequeue/collector.go
+++ b/interfacequeue/collector.go
@@ -101,9 +101,16 @@ func (c *interfaceQueueCollector) Describe(ch chan<- *prometheus.Desc) {
func (c *interfaceQueueCollector) Collect(client *rpc.Client, ch chan<- prometheus.Metric, labelValues []string) error {
q := InterfaceQueueRPC{}
- err := client.RunCommandAndParse("show interfaces queue", &q)
- if err != nil {
- return err
+ if client.Netconf {
+ err := client.RunCommandAndParse("", &q)
+ if err != nil {
+ return err
+ }
+ } else {
+ err := client.RunCommandAndParse("show interfaces queue", &q)
+ if err != nil {
+ return err
+ }
}
for _, iface := range q.InterfaceInformation.Interfaces {
diff --git a/interfaces/collector.go b/interfaces/collector.go
index 110049c3..98d7bf7c 100644
--- a/interfaces/collector.go
+++ b/interfaces/collector.go
@@ -146,9 +146,16 @@ func (c *interfaceCollector) Collect(client *rpc.Client, ch chan<- prometheus.Me
func (c *interfaceCollector) interfaceStats(client *rpc.Client) ([]*InterfaceStats, error) {
var x = InterfaceRpc{}
- err := client.RunCommandAndParse("show interfaces extensive", &x)
- if err != nil {
- return nil, err
+ if client.Netconf {
+ err := client.RunCommandAndParse("", &x)
+ if err != nil {
+ return nil, err
+ }
+ } else {
+ err := client.RunCommandAndParse("show interfaces extensive", &x)
+ if err != nil {
+ return nil, err
+ }
}
stats := make([]*InterfaceStats, 0)
diff --git a/ipsec/collector.go b/ipsec/collector.go
index aae8b882..95600870 100644
--- a/ipsec/collector.go
+++ b/ipsec/collector.go
@@ -49,9 +49,16 @@ func (*ipsecCollector) Describe(ch chan<- *prometheus.Desc) {
// Collect collects metrics from JunOS
func (c *ipsecCollector) Collect(client *rpc.Client, ch chan<- prometheus.Metric, labelValues []string) error {
var x = RpcReply{}
- err := client.RunCommandAndParse("show security ipsec security-associations", &x)
- if err != nil {
- return err
+ if client.Netconf {
+ err := client.RunCommandAndParse("", &x)
+ if err != nil {
+ return err
+ }
+ } else {
+ err := client.RunCommandAndParse("show security ipsec security-associations", &x)
+ if err != nil {
+ return err
+ }
}
for _, re := range x.MultiRoutingEngineResults.RoutingEngine {
@@ -63,14 +70,24 @@ func (c *ipsecCollector) Collect(client *rpc.Client, ch chan<- prometheus.Metric
}
}
- var conf = ConfigurationSecurityIpsec{}
- err = client.RunCommandAndParse("show configuration security ipsec", &conf)
- if err != nil {
- return err
+ if client.Netconf {
+ var conf = ConfigurationSecurityIpsecnetconf{}
+ err := client.RunCommandAndParse("", &conf)
+ if err != nil {
+ return err
+ }
+ cls := append(labelValues, "N/A", "configured tunnels", "")
+ ch <- prometheus.MustNewConstMetric(configuredTunnels, prometheus.GaugeValue, float64(len(conf.Configuration.Security.Ipsec.Vpn)), cls...)
+ } else {
+ var conf = ConfigurationSecurityIpsec{}
+ err := client.RunCommandAndParse("show configuration security ipsec", &conf)
+ if err != nil {
+ return err
+ }
+ cls := append(labelValues, "N/A", "configured tunnels", "")
+ ch <- prometheus.MustNewConstMetric(configuredTunnels, prometheus.GaugeValue, float64(len(conf.Configuration.Security.Ipsec.Vpn)), cls...)
}
- cls := append(labelValues, "N/A", "configured tunnels", "")
- ch <- prometheus.MustNewConstMetric(configuredTunnels, prometheus.GaugeValue, float64(len(conf.Configuration.Security.Ipsec.Vpn)), cls...)
return nil
}
diff --git a/ipsec/rpc.go b/ipsec/rpc.go
index cdbc8b23..0f26cc97 100644
--- a/ipsec/rpc.go
+++ b/ipsec/rpc.go
@@ -55,7 +55,7 @@ type ConfigurationSecurityIpsec struct {
Configuration struct {
Security struct {
Ipsec struct {
- Proposal struct {
+ Proposal []struct {
Text string `xml:",chardata"`
Name string `xml:"name"`
Protocol string `xml:"protocol"`
@@ -63,7 +63,7 @@ type ConfigurationSecurityIpsec struct {
EncryptionAlgorithm string `xml:"encryption-algorithm"`
LifetimeSeconds string `xml:"lifetime-seconds"`
} `xml:"proposal"`
- Policy struct {
+ Policy []struct {
Name string `xml:"name"`
Proposals string `xml:"proposals"`
} `xml:"policy"`
@@ -80,3 +80,33 @@ type ConfigurationSecurityIpsec struct {
} `xml:"security"`
} `xml:"configuration"`
}
+
+type ConfigurationSecurityIpsecnetconf struct {
+ Configuration struct {
+ Security struct {
+ Ipsec struct {
+ Proposal []struct {
+ Text string `xml:",chardata"`
+ Name string `xml:"name"`
+ Protocol string `xml:"protocol"`
+ AuthenticationAlgorithm string `xml:"authentication-algorithm"`
+ EncryptionAlgorithm string `xml:"encryption-algorithm"`
+ LifetimeSeconds string `xml:"lifetime-seconds"`
+ } `xml:"proposal"`
+ Policy []struct {
+ Name string `xml:"name"`
+ Proposals string `xml:"proposals"`
+ } `xml:"policy"`
+ Vpn []struct {
+ Name string `xml:"name"`
+ BindInterface string `xml:"bind-interface"`
+ Ike struct {
+ Gateway string `xml:"gateway"`
+ IpsecPolicy string `xml:"ipsec-policy"`
+ } `xml:"ike"`
+ EstablishTunnels string `xml:"establish-tunnels"`
+ } `xml:"vpn"`
+ } `xml:"ipsec"`
+ } `xml:"security"`
+ } `xml:"data>configuration"`
+}
diff --git a/isis/collector.go b/isis/collector.go
index 6714efbf..d3207452 100644
--- a/isis/collector.go
+++ b/isis/collector.go
@@ -56,9 +56,17 @@ func (c *isisCollector) isisAdjancies(client *rpc.Client) (*IsisAdjacencies, err
total := 0
var x = IsisRpc{}
- err := client.RunCommandAndParse("show isis adjacency", &x)
- if err != nil {
- return nil, err
+
+ if client.Netconf {
+ err := client.RunCommandAndParse("", &x)
+ if err != nil {
+ return nil, err
+ }
+ } else {
+ err := client.RunCommandAndParse("show isis adjacency", &x)
+ if err != nil {
+ return nil, err
+ }
}
for _, adjacency := range x.Information.Adjacencies {
diff --git a/junos_collector.go b/junos_collector.go
index 36774adc..b8c6f390 100644
--- a/junos_collector.go
+++ b/junos_collector.go
@@ -81,7 +81,7 @@ func newJunosCollector(devices []*connector.Device, connectionManager *connector
}
func clientForDevice(device *connector.Device, connManager *connector.SSHConnectionManager) (*rpc.Client, error) {
- conn, err := connManager.Connect(device)
+ conn, err := connManager.Connect(device, cfg.Features.Netconf)
if err != nil {
return nil, err
}
@@ -96,6 +96,10 @@ func clientForDevice(device *connector.Device, connManager *connector.SSHConnect
c.EnableSatellite()
}
+ if cfg.Features.Netconf {
+ c.EnableNetconf()
+ }
+
return c, nil
}
diff --git a/l2circuit/collector.go b/l2circuit/collector.go
index 1e0dd678..2331922b 100644
--- a/l2circuit/collector.go
+++ b/l2circuit/collector.go
@@ -78,9 +78,16 @@ func (c *l2circuitCollector) Collect(client *rpc.Client, ch chan<- prometheus.Me
func (c *l2circuitCollector) collectL2circuitMetrics(client *rpc.Client, ch chan<- prometheus.Metric, labelValues []string) error {
var x = L2circuitRpc{}
- err := client.RunCommandAndParse("show l2circuit connections brief", &x)
- if err != nil {
- return err
+ if client.Netconf {
+ err := client.RunCommandAndParse("", &x)
+ if err != nil {
+ return err
+ }
+ } else {
+ err := client.RunCommandAndParse("show l2circuit connections brief", &x)
+ if err != nil {
+ return err
+ }
}
neighbors := x.Information.Neighbors
diff --git a/lacp/collector.go b/lacp/collector.go
index 97a9ae32..431e8c68 100644
--- a/lacp/collector.go
+++ b/lacp/collector.go
@@ -45,10 +45,17 @@ func (*lacpCollector) Describe(ch chan<- *prometheus.Desc) {
// Collect collects metrics from JunOS
func (c *lacpCollector) Collect(client *rpc.Client, ch chan<- prometheus.Metric, labelValues []string) error {
- var x = lacpRpc{}
- err := client.RunCommandAndParse("show lacp interfaces", &x)
- if err != nil {
- return err
+ var x = lacpRpc{}
+ if client.Netconf {
+ err := client.RunCommandAndParse("", &x)
+ if err != nil {
+ return err
+ }
+ } else {
+ err := client.RunCommandAndParse("show lacp interfaces", &x)
+ if err != nil {
+ return err
+ }
}
for _, iface := range x.Information.LacpInterfaces {
diff --git a/ldp/collector.go b/ldp/collector.go
index bb8a1e51..79901011 100644
--- a/ldp/collector.go
+++ b/ldp/collector.go
@@ -62,9 +62,16 @@ func (c *ldpCollector) Collect(client *rpc.Client, ch chan<- prometheus.Metric,
func (c *ldpCollector) collectLDPMetrics(client *rpc.Client, ch chan<- prometheus.Metric, labelValues []string) error {
var x = LDPRpc{}
- err := client.RunCommandAndParse("show ldp neighbor", &x)
- if err != nil {
- return err
+ if client.Netconf {
+ err := client.RunCommandAndParse("", &x)
+ if err != nil {
+ return err
+ }
+ } else {
+ err := client.RunCommandAndParse("show ldp neighbor", &x)
+ if err != nil {
+ return err
+ }
}
neighbors := x.Information.Neighbors
@@ -75,9 +82,16 @@ func (c *ldpCollector) collectLDPMetrics(client *rpc.Client, ch chan<- prometheu
func (c *ldpCollector) collectLDPSessions(client *rpc.Client, ch chan<- prometheus.Metric, labelValues []string) error {
var x = LDPSessionRpc{}
+ if client.Netconf {
+ err := client.RunCommandAndParse("", &x)
+ if err != nil {
+ return err
+ }
+ } else {
err := client.RunCommandAndParse("show ldp session", &x)
- if err != nil {
- return err
+ if err != nil {
+ return err
+ }
}
sessions := x.Information.Sessions
diff --git a/mac/collector.go b/mac/collector.go
index 1e40af76..956617a4 100644
--- a/mac/collector.go
+++ b/mac/collector.go
@@ -47,9 +47,16 @@ func (*macCollector) Describe(ch chan<- *prometheus.Desc) {
// Collect collects metrics from JunOS
func (c *macCollector) Collect(client *rpc.Client, ch chan<- prometheus.Metric, labelValues []string) error {
var x = MacRpc{}
- err := client.RunCommandAndParse("show ethernet-switching table summary", &x)
- if err != nil {
- return err
+ if client.Netconf {
+ err := client.RunCommandAndParse("", &x)
+ if err != nil {
+ return err
+ }
+ } else {
+ err := client.RunCommandAndParse("show ethernet-switching table summary", &x)
+ if err != nil {
+ return err
+ }
}
entry := x.Information.Table.Entry
diff --git a/main.go b/main.go
index 6d5f780e..40342b00 100644
--- a/main.go
+++ b/main.go
@@ -58,6 +58,7 @@ var (
interfaceQueuesEnabled = flag.Bool("queues.enabled", false, "Scrape interface queue metrics")
rpkiEnabled = flag.Bool("rpki.enabled", false, "Scrape rpki metrics")
satelliteEnabled = flag.Bool("satellite.enabled", false, "Scrape metrics from satellite devices")
+ netconfEnabled = flag.Bool("netconf.enabled", false, "enable netconf rpc query style")
systemEnabled = flag.Bool("system.enabled", false, "Scrape system metrics")
macEnabled = flag.Bool("mac.enabled", false, "Scrape MAC address table metrics")
alarmFilter = flag.String("alarms.filter", "", "Regex to filter for alerts to ignore")
@@ -215,6 +216,7 @@ func loadConfigFromFlags() *config.Config {
f.RPKI = *rpkiEnabled
f.Storage = *storageEnabled
f.Satellite = *satelliteEnabled
+ f.Netconf = *netconfEnabled
f.System = *systemEnabled
f.Power = *powerEnabled
f.MAC = *macEnabled
diff --git a/mpls_lsp/collector.go b/mpls_lsp/collector.go
index 26abb34a..c3b92628 100644
--- a/mpls_lsp/collector.go
+++ b/mpls_lsp/collector.go
@@ -48,10 +48,17 @@ func (*mpls_lspCollector) Describe(ch chan<- *prometheus.Desc) {
// Collect collects metrics from JunOS
func (c *mpls_lspCollector) Collect(client *rpc.Client, ch chan<- prometheus.Metric, labelValues []string) error {
- var x = mpls_lspRpc{}
- err := client.RunCommandAndParse("show mpls lsp ingress extensive", &x) //ingress:Display LSPs originating at this router
- if err != nil {
- return err
+ var x = mpls_lspRpc{}
+ if client.Netconf {
+ err := client.RunCommandAndParse("", &x) //ingress:Display LSPs originating at this router
+ if err != nil {
+ return err
+ }
+ } else {
+ err := client.RunCommandAndParse("show mpls lsp ingress extensive", &x) //ingress:Display LSPs originating at this router
+ if err != nil {
+ return err
+ }
}
for _, lsp := range x.Information.Sessions {
diff --git a/nat/collector.go b/nat/collector.go
index 650695a8..073357a6 100644
--- a/nat/collector.go
+++ b/nat/collector.go
@@ -1,6 +1,7 @@
package nat
import (
+ "fmt"
"github.com/czerwonk/junos_exporter/collector"
"github.com/czerwonk/junos_exporter/rpc"
"github.com/prometheus/client_golang/prometheus"
@@ -506,9 +507,16 @@ func (c *natCollector) Collect(client *rpc.Client, ch chan<- prometheus.Metric,
func (c *natCollector) NatInterfaces(client *rpc.Client) ([]*NatInterface, error) {
var x = NatRpc{}
- err := client.RunCommandAndParse("show services nat statistics", &x)
- if err != nil {
- return nil, err
+ if client.Netconf {
+ err := client.RunCommandAndParse("", &x)
+ if err != nil {
+ return nil, err
+ }
+ } else {
+ err := client.RunCommandAndParse("show services nat statistics", &x)
+ if err != nil {
+ return nil, err
+ }
}
interfaces := make([]*NatInterface, 0)
@@ -916,9 +924,14 @@ func (*natCollector) collectForInterface(s *NatInterface, ch chan<- prometheus.M
func (c *natCollector) NatPoolInterfaces(client *rpc.Client, ch chan<- prometheus.Metric, labelValues []string) ([]*NatPoolInterface, error) {
var x = NatPoolRpc{}
- err := client.RunCommandAndParse("show services nat pool", &x)
- if err != nil {
- return nil, err
+ if client.Netconf {
+ //TODO
+ return nil, fmt.Errorf("not implemented")
+ } else {
+ err := client.RunCommandAndParse("show services nat pool", &x)
+ if err != nil {
+ return nil, err
+ }
}
interfaces := make([]*NatPoolInterface, 0)
@@ -950,9 +963,14 @@ func (c *natCollector) collectForPoolInterface(s *NatPoolInterface, ch chan<- pr
func (c *natCollector) NatPoolDetailInterfaces(client *rpc.Client, ch chan<- prometheus.Metric, labelValues []string) ([]*NatPoolDetailInterface, error) {
var x = NatPoolDetailRpc{}
- err := client.RunCommandAndParse("show services nat pool detail", &x)
- if err != nil {
- return nil, err
+ if client.Netconf {
+ //TODO
+ return nil, fmt.Errorf("not implemented")
+ } else {
+ err := client.RunCommandAndParse("show services nat pool detail", &x)
+ if err != nil {
+ return nil, err
+ }
}
interfacesdetail := make([]*NatPoolDetailInterface, 0)
@@ -992,9 +1010,16 @@ func (c *natCollector) collectForPoolDetailInterface(s *NatPoolDetailInterface,
func (c *natCollector) ServiceSetsCpuInterfaces(client *rpc.Client, ch chan<- prometheus.Metric, labelValues []string) ([]*ServiceSetsCpuInterface, error) {
var x = ServiceSetsCpuRpc{}
- err := client.RunCommandAndParse("show services service-sets cpu-usage", &x)
- if err != nil {
- return nil, err
+ if client.Netconf {
+ err := client.RunCommandAndParse("", &x)
+ if err != nil {
+ return nil, err
+ }
+ } else {
+ err := client.RunCommandAndParse("show services service-sets cpu-usage", &x)
+ if err != nil {
+ return nil, err
+ }
}
interfacesdetail := make([]*ServiceSetsCpuInterface, 0)
diff --git a/nat2/collector.go b/nat2/collector.go
index b223eb45..29fb4432 100644
--- a/nat2/collector.go
+++ b/nat2/collector.go
@@ -225,9 +225,16 @@ func (c *natCollector) Collect(client *rpc.Client, ch chan<- prometheus.Metric,
func (c *natCollector) NatInterfaces(client *rpc.Client) ([]*NatInterface, error) {
var x = NatRpc{}
- err := client.RunCommandAndParse("show services nat statistics", &x)
- if err != nil {
- return nil, err
+ if client.Netconf {
+ err := client.RunCommandAndParse("", &x)
+ if err != nil {
+ return nil, err
+ }
+ } else {
+ err := client.RunCommandAndParse("show services nat statistics", &x)
+ if err != nil {
+ return nil, err
+ }
}
interfaces := make([]*NatInterface, 0)
@@ -320,9 +327,16 @@ func (*natCollector) collectForInterface(s *NatInterface, ch chan<- prometheus.M
func (c *natCollector) SrcNatPools(client *rpc.Client, ch chan<- prometheus.Metric, labelValues []string) ([]SrcNatPool, error) {
var x = SrcNatPoolRpc{}
- err := client.RunCommandAndParse("show services nat source pool all", &x)
- if err != nil {
- return nil, err
+ if client.Netconf {
+ err := client.RunCommandAndParse("", &x)
+ if err != nil {
+ return nil, err
+ }
+ } else {
+ err := client.RunCommandAndParse("show services nat source pool all", &x)
+ if err != nil {
+ return nil, err
+ }
}
return x.Information.Pools[:], nil
@@ -392,9 +406,16 @@ func (c *natCollector) collectForSrcNatPool(s []SrcNatPool, ch chan<- prometheus
func (c *natCollector) ServiceSetsCpuInterfaces(client *rpc.Client, ch chan<- prometheus.Metric, labelValues []string) ([]*ServiceSetsCpuInterface, error) {
var x = ServiceSetsCpuRpc{}
- err := client.RunCommandAndParse("show services service-sets cpu-usage", &x)
- if err != nil {
- return nil, err
+ if client.Netconf {
+ err := client.RunCommandAndParse("", &x)
+ if err != nil {
+ return nil, err
+ }
+ } else {
+ err := client.RunCommandAndParse("show services service-sets cpu-usage", &x)
+ if err != nil {
+ return nil, err
+ }
}
interfacesdetail := make([]*ServiceSetsCpuInterface, 0)
diff --git a/ospf/collector.go b/ospf/collector.go
index 86ac8ffe..29e5d3d4 100644
--- a/ospf/collector.go
+++ b/ospf/collector.go
@@ -64,9 +64,14 @@ func (c *ospfCollector) Collect(client *rpc.Client, ch chan<- prometheus.Metric,
func (c *ospfCollector) collectOSPFMetrics(client *rpc.Client, ch chan<- prometheus.Metric, labelValues []string) error {
var x = OspfRpc{}
var cmd strings.Builder
- cmd.WriteString("show ospf overview")
- if c.LogicalSystem != "" {
- cmd.WriteString(" logical-system " + c.LogicalSystem)
+
+ if client.Netconf {
+ cmd.WriteString("")
+ } else {
+ cmd.WriteString("show ospf overview")
+ if c.LogicalSystem != "" {
+ cmd.WriteString(" logical-system " + c.LogicalSystem)
+ }
}
err := client.RunCommandAndParse(cmd.String(), &x)
@@ -94,9 +99,14 @@ func (c *ospfCollector) collectOSPFMetrics(client *rpc.Client, ch chan<- prometh
func (c *ospfCollector) collectOSPFv3Metrics(client *rpc.Client, ch chan<- prometheus.Metric, labelValues []string) error {
var x = Ospf3Rpc{}
var cmd strings.Builder
- cmd.WriteString("show ospf3 overview")
- if c.LogicalSystem != "" {
- cmd.WriteString(" logical-system " + c.LogicalSystem)
+
+ if client.Netconf {
+ cmd.WriteString("")
+ } else {
+ cmd.WriteString("show ospf3 overview")
+ if c.LogicalSystem != "" {
+ cmd.WriteString(" logical-system " + c.LogicalSystem)
+ }
}
err := client.RunCommandAndParse(cmd.String(), &x)
diff --git a/power/collector.go b/power/collector.go
index 2ade7145..44af0fc6 100644
--- a/power/collector.go
+++ b/power/collector.go
@@ -88,11 +88,20 @@ func (c *powerCollector) Collect(client *rpc.Client, ch chan<- prometheus.Metric
}
var x = RpcReply{}
- err := client.RunCommandAndParseWithParser("show chassis power", func(b []byte) error {
- return parseXML(b, &x)
- })
- if err != nil {
- return err
+ if client.Netconf {
+ err := client.RunCommandAndParseWithParser("", func(b []byte) error {
+ return parseXML(b, &x)
+ })
+ if err != nil {
+ return err
+ }
+ } else {
+ err := client.RunCommandAndParseWithParser("show chassis power", func(b []byte) error {
+ return parseXML(b, &x)
+ })
+ if err != nil {
+ return err
+ }
}
for _, re := range x.MultiRoutingEngineResults.RoutingEngine {
diff --git a/route/collector.go b/route/collector.go
index fa81705a..d3a3742e 100644
--- a/route/collector.go
+++ b/route/collector.go
@@ -52,9 +52,16 @@ func (*routeCollector) Describe(ch chan<- *prometheus.Desc) {
// Collect collects metrics from JunOS
func (c *routeCollector) Collect(client *rpc.Client, ch chan<- prometheus.Metric, labelValues []string) error {
var x = RouteRpc{}
- err := client.RunCommandAndParse("show route summary", &x)
- if err != nil {
- return err
+ if client.Netconf {
+ err := client.RunCommandAndParse("", &x)
+ if err != nil {
+ return err
+ }
+ } else {
+ err := client.RunCommandAndParse("show route summary", &x)
+ if err != nil {
+ return err
+ }
}
for _, t := range x.Information.Tables {
diff --git a/routingengine/collector.go b/routingengine/collector.go
index c7c7df6c..5c392efc 100644
--- a/routingengine/collector.go
+++ b/routingengine/collector.go
@@ -168,11 +168,20 @@ func (*routingEngineCollector) Describe(ch chan<- *prometheus.Desc) {
// Collect collects metrics from JunOS
func (c *routingEngineCollector) Collect(client *rpc.Client, ch chan<- prometheus.Metric, labelValues []string) error {
var x = RpcReply{}
- err := client.RunCommandAndParseWithParser("show chassis routing-engine", func(b []byte) error {
- return parseXML(b, &x)
- })
- if err != nil {
- return err
+ if client.Netconf {
+ err := client.RunCommandAndParseWithParser("", func(b []byte) error {
+ return parseXML(b, &x)
+ })
+ if err != nil {
+ return err
+ }
+ } else {
+ err := client.RunCommandAndParseWithParser("show chassis routing-engine", func(b []byte) error {
+ return parseXML(b, &x)
+ })
+ if err != nil {
+ return err
+ }
}
for _, re := range x.MultiRoutingEngineResults.RoutingEngine {
diff --git a/rpc/rpc_client.go b/rpc/rpc_client.go
index c5e55edf..0c07dc4f 100644
--- a/rpc/rpc_client.go
+++ b/rpc/rpc_client.go
@@ -3,7 +3,7 @@ package rpc
import (
"encoding/xml"
"fmt"
-
+ "bytes"
"log"
"github.com/czerwonk/junos_exporter/connector"
@@ -19,6 +19,7 @@ type Client struct {
conn *connector.SSHConnection
debug bool
Satellite bool
+ Netconf bool
}
// NewClient creates a new client to connect to
@@ -30,9 +31,16 @@ func NewClient(ssh *connector.SSHConnection) *Client {
// RunCommandAndParse runs a command on JunOS and unmarshals the XML result
func (c *Client) RunCommandAndParse(cmd string, obj interface{}) error {
- return c.RunCommandAndParseWithParser(cmd, func(b []byte) error {
- return xml.Unmarshal(b, obj)
- })
+ if c.Netconf {
+ return c.RunCommandAndParseWithParser(cmd, func(b []byte) error {
+ //in junos the xml interfaces contains line returns in the values
+ return xml.Unmarshal(bytes.ReplaceAll(b, []byte("\n"), []byte("")), obj)
+ })
+ } else {
+ return c.RunCommandAndParseWithParser(cmd, func(b []byte) error {
+ return xml.Unmarshal(b, obj)
+ })
+ }
}
// RunCommandAndParseWithParser runs a command on JunOS and uses the given parser to handle the result
@@ -41,7 +49,15 @@ func (c *Client) RunCommandAndParseWithParser(cmd string, parser Parser) error {
log.Printf("Running command on %s: %s\n", c.conn.Host(), cmd)
}
- b, err := c.conn.RunCommand(fmt.Sprintf("%s | display xml", cmd))
+ var err error
+ var b []byte
+
+ if c.Netconf {
+ b, err = c.conn.RunCommand(cmd)
+ } else {
+ b, err = c.conn.RunCommand(fmt.Sprintf("%s | display xml", cmd))
+ }
+
if err != nil {
return err
}
@@ -73,3 +89,8 @@ func (c *Client) DisableDebug() {
func (c *Client) EnableSatellite() {
c.Satellite = true
}
+
+// EnableNetconf enables netconf RPCs instead of SSH-CLI
+func (c *Client) EnableNetconf() {
+ c.Netconf = true
+}
diff --git a/rpki/collector.go b/rpki/collector.go
index bbf5cad8..35d48976 100644
--- a/rpki/collector.go
+++ b/rpki/collector.go
@@ -79,9 +79,16 @@ func (c *rpkiCollector) Collect(client *rpc.Client, ch chan<- prometheus.Metric,
func (c *rpkiCollector) collectSessions(client *rpc.Client, ch chan<- prometheus.Metric, labelValues []string) error {
var x = RpkiSessionRpc{}
- err := client.RunCommandAndParse("show validation session", &x)
- if err != nil {
- return err
+ if client.Netconf {
+ err := client.RunCommandAndParse("", &x)
+ if err != nil {
+ return err
+ }
+ } else {
+ err := client.RunCommandAndParse("show validation session", &x)
+ if err != nil {
+ return err
+ }
}
for _, session := range x.Information.RpkiSessions {
@@ -129,9 +136,16 @@ func (c *rpkiCollector) collectForSession(s RpkiSession, ch chan<- prometheus.Me
func (c *rpkiCollector) collectStatistics(client *rpc.Client, ch chan<- prometheus.Metric, labelValues []string) error {
var x = RpkiStatisticsRpc{}
- err := client.RunCommandAndParse("show validation statistics", &x)
- if err != nil {
- return err
+ if client.Netconf {
+ err := client.RunCommandAndParse("", &x)
+ if err != nil {
+ return err
+ }
+ } else {
+ err := client.RunCommandAndParse("show validation statistics", &x)
+ if err != nil {
+ return err
+ }
}
ch <- prometheus.MustNewConstMetric(memoryUtilizationDesc, prometheus.GaugeValue, float64(x.Information.Statistics.MemoryUtilization), labelValues...)
diff --git a/rpm/collector.go b/rpm/collector.go
index cfe9f863..67208724 100644
--- a/rpm/collector.go
+++ b/rpm/collector.go
@@ -68,9 +68,16 @@ func (c *rpmCollector) Collect(client *rpc.Client, ch chan<- prometheus.Metric,
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
+ if client.Netconf {
+ err := client.RunCommandAndParse("", &x)
+ if err != nil {
+ return err
+ }
+ } else {
+ err := client.RunCommandAndParse("show services rpm probe-results", &x)
+ if err != nil {
+ return err
+ }
}
for _, probe := range x.Results.Probes {
diff --git a/security/collector.go b/security/collector.go
index 4c6eb3b5..4775fdc5 100644
--- a/security/collector.go
+++ b/security/collector.go
@@ -63,9 +63,16 @@ func (*securityCollector) Describe(ch chan<- *prometheus.Desc) {
// Collect collects metrics from JunOS
func (c *securityCollector) Collect(client *rpc.Client, ch chan<- prometheus.Metric, labelValues []string) error {
var x = RpcReply{}
- err := client.RunCommandAndParse("show security monitoring", &x)
- if err != nil {
- return err
+ if client.Netconf {
+ err := client.RunCommandAndParse("", &x)
+ if err != nil {
+ return err
+ }
+ } else {
+ err := client.RunCommandAndParse("show security monitoring", &x)
+ if err != nil {
+ return err
+ }
}
for _, re := range x.MultiRoutingEngineResults.RoutingEngine {
diff --git a/storage/collector.go b/storage/collector.go
index 26869296..8c803d92 100644
--- a/storage/collector.go
+++ b/storage/collector.go
@@ -4,6 +4,7 @@ import (
"encoding/xml"
"strconv"
"strings"
+ "bytes"
"github.com/czerwonk/junos_exporter/collector"
"github.com/czerwonk/junos_exporter/rpc"
@@ -51,11 +52,20 @@ func (*storageCollector) Describe(ch chan<- *prometheus.Desc) {
// Collect collects metrics from JunOS
func (c *storageCollector) Collect(client *rpc.Client, ch chan<- prometheus.Metric, labelValues []string) error {
var x = RpcReply{}
- err := client.RunCommandAndParseWithParser("show system storage", func(b []byte) error {
- return parseXML(b, &x)
- })
- if err != nil {
- return err
+ if client.Netconf {
+ err := client.RunCommandAndParseWithParser("", func(b []byte) error {
+ return parseXMLnetconf(b, &x)
+ })
+ if err != nil {
+ return err
+ }
+ } else {
+ err := client.RunCommandAndParseWithParser("show system storage", func(b []byte) error {
+ return parseXML(b, &x)
+ })
+ if err != nil {
+ return err
+ }
}
for _, re := range x.MultiRoutingEngineResults.RoutingEngine {
@@ -97,3 +107,24 @@ func parseXML(b []byte, res *RpcReply) error {
}
return nil
}
+
+func parseXMLnetconf(b []byte, res *RpcReply) error {
+ if strings.Contains(string(b), "multi-routing-engine-results") {
+ return xml.Unmarshal(b, res)
+ }
+
+ fi := RpcReplyNoRE{}
+
+ err := xml.Unmarshal(bytes.ReplaceAll(b, []byte("\n"), []byte("")), &fi)
+ if err != nil {
+ return err
+ }
+
+ res.MultiRoutingEngineResults.RoutingEngine = []RoutingEngine{
+ {
+ Name: "N/A",
+ StorageInformation: fi.StorageInformation,
+ },
+ }
+ return nil
+}
diff --git a/system/collector.go b/system/collector.go
index 6332492b..fe8c0afd 100644
--- a/system/collector.go
+++ b/system/collector.go
@@ -162,9 +162,16 @@ func (c *systemCollector) CollectSystem(client *rpc.Client, ch chan<- prometheus
r = new(BuffersRPC)
- err = client.RunCommandAndParse("show system buffers", r)
- if err != nil {
- return err
+ if client.Netconf {
+ err = client.RunCommandAndParse("", r)
+ if err != nil {
+ return err
+ }
+ } else {
+ err = client.RunCommandAndParse("show system buffers", r)
+ if err != nil {
+ return err
+ }
}
if r.Output != "" {
@@ -277,9 +284,16 @@ func (c *systemCollector) CollectSystem(client *rpc.Client, ch chan<- prometheus
// system information
r2 = new(SystemInformationRPC)
- err = client.RunCommandAndParse("show system information", r2)
- if err != nil {
- return err
+ if client.Netconf {
+ err = client.RunCommandAndParse("", r2)
+ if err != nil {
+ return err
+ }
+ } else {
+ err = client.RunCommandAndParse("show system information", r2)
+ if err != nil {
+ return err
+ }
}
// create LabelSet (target, "model", "os", "os_version", "serial", "hostname", "alias", "slot_id", "state")
@@ -298,7 +312,11 @@ func (c *systemCollector) CollectSystem(client *rpc.Client, ch chan<- prometheus
// system information of satellites
r3 = new(SatelliteChassisRPC)
- err = client.RunCommandAndParse("show chassis satellite detail", r3)
+ if client.Netconf {
+ err = client.RunCommandAndParse("", r3)
+ } else {
+ err = client.RunCommandAndParse("show chassis satellite detail", r3)
+ }
// there are various error messages when satellite is not enabled; thus here we just ignore the error and continue
if err == nil {
for i = range r3.SatelliteInfo.Satellite {
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..9f458e51 100644
--- a/vpws/collector.go
+++ b/vpws/collector.go
@@ -52,10 +52,17 @@ func (*vpwsCollector) Describe(ch chan<- *prometheus.Desc) {
// Collect collects metrics from JunOS
func (c *vpwsCollector) Collect(client *rpc.Client, ch chan<- prometheus.Metric, labelValues []string) error {
- var x = vpwsRpc{}
- err := client.RunCommandAndParse("show evpn vpws-instance", &x)
- if err != nil {
- return err
+ var x = vpwsRpc{}
+ if client.Netconf {
+ err := client.RunCommandAndParse("", &x)
+ if err != nil {
+ return err
+ }
+ } else {
+ err := client.RunCommandAndParse("show evpn vpws-instance", &x)
+ if err != nil {
+ return err
+ }
}
for _, vInst := range x.Information.VpwsInstances {
@@ -68,6 +75,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"`
}
diff --git a/vrrp/collector.go b/vrrp/collector.go
index 903ebf5e..5290449f 100644
--- a/vrrp/collector.go
+++ b/vrrp/collector.go
@@ -43,10 +43,17 @@ func (c *vrrpCollector) Collect(client *rpc.Client, ch chan<- prometheus.Metric,
"master": 3,
}
- var x = VrrpRpc{}
- err := client.RunCommandAndParse("show vrrp summary", &x)
- if err != nil {
- return err
+ var x = VrrpRpc{}
+ if client.Netconf {
+ err := client.RunCommandAndParse("", &x)
+ if err != nil {
+ return err
+ }
+ } else {
+ err := client.RunCommandAndParse("show vrrp summary", &x)
+ if err != nil {
+ return err
+ }
}
for _, iface := range x.Information.Interfaces {