Skip to main content

junos-exporter

PyPI - Python Version PyPI GitHub

Overview

This exporter turns Junos device information into Prometheus metrics. It collects NETCONF RPC replies and parses them with pygxml, a streaming XML parser with gjson-style path queries. Everything about a metric -- which RPC to send, how to read records out of the reply, and how to expose them -- is declared in config.yml, so adding a metric never requires writing code.

To allow junos-exporter connectivity via NETCONF over SSH, ensure the following configuration is applied to your Junos devices.

set system service netconf ssh

Note: 0.1.0 introduces the following breaking changes from 0.0.12.

  • Change the parser from PyEZ Tables and Views to pygxml.
  • Change the config.yml format.
  • Change the scrape endpoint from /metrics to /probe.

Installation

pip install junos-exporter

Usage

  1. Write your config.yml

    The exporter always loads the bundled config.yml first, which already defines 20 probes and the default module. Your own config.yml is layered on top of it, so it only needs to carry what you want to change -- usually just the credentials.

    mkdir -p ~/.junos-exporter && cat > ~/.junos-exporter/config.yml <<'EOF'
    credentials:
      default:
        username: admin      # Junos device login username
        password: admin@123  # Junos device login password
    EOF
    

    The exporter looks for ./config.yml first, then ~/.junos-exporter/config.yml, and layers the first one it finds.

  2. Configure the config.yml

    Anything under general is overridden key by key, while credentials, modules and probes are overridden by the names directly under them -- a name that already exists in the bundled config is replaced whole.

    general:
      prefix: junos          # Prefix prepended to all exported metric names
      timeout: 60            # Total timeout for Junos RPC execution and data collection
      timeout_socket: 15     # Timeout for establishing the initial NETCONF SSH connection
      # ssh_config: ~/.ssh/config  # SSH config for the NETCONF connection, e.g. to reach devices via a jump host
    
    credentials:
      default:
        username: admin      # Junos device login username
        password: admin@123  # Junos device login password
    

    To customize a probe, copy just that probe from the bundled config.yml into yours and edit it. Probes you do not copy keep following the bundled definitions as they are updated.

  3. Configure the Prometheus

    scrape_configs:
      - job_name: "junos-exporter"
        metrics_path: /probe
        static_configs:
          - targets:
              - "192.168.1.1"  # Target device
              - "192.168.1.2,192.168.1.3"  # Multiple Target device such as dual RE
        relabel_configs:
          - source_labels: [__address__]
            target_label: __param_target
          - source_labels: [__param_target]
            regex: '^([^,]+).*'
            replacement: '$1'
            target_label: instance
          - target_label: __address__
            replacement: 127.0.0.1:9326
    

    When multiple targets are provided in a comma-separated list, if the first target is unreachable, it proceeds to the next one in the sequence.

  4. Run the exporter

    junos-exporter
    

    For Docker users, use the following command

    docker run -d \
      -p 9326:9326 \
      -v /path/to/config.yml:/app/config.yml \
      ghcr.io/minefuto/junos-exporter
    

CLI Options

The junos-exporter is powered by the uvicorn ASGI server. You can customize the server's behavior using the following command-line options.

usage: junos-exporter [-h] [--host HOST] [--log-level {critical,error,warning,info,debug,trace}]
                      [--no-access-log] [--port PORT] [--reload] [--root-path ROOT_PATH] [--version]
                      [--workers WORKERS]

options:
  -h, --help            Show this help message and exit
  --host HOST           Listen address [default: 0.0.0.0]
  --log-level           Log level [default: info]
  --no-access-log       Disable access log
  --port PORT           Listen port [default: 9326]
  --reload              Enable auto reload
  --root-path ROOT_PATH 
                        Root path [default: ""]
  --version             Show version number and exit
  --workers WORKERS     Number of worker processes [default: 1]

Credentials

This exporter allows you to configure specific authentication methods for each Junos device. To select a profile defined in the credentials section of your config.yml, add the credential query parameter to the scrape URL.
e.g. http://localhost:9326/probe?credential=vjunos&target=192.168.10.12

credentials:
  default: # password authentication
    username: admin
    password: admin@123

  vjunos: # public key authentication
    username: admin
    private_key: ~/.ssh/id_rsa
    private_key_passphrase: admin@123 # option

In your Prometheus configuration, setting __params_credential to vjunos ensures the corresponding credentials are used. If the credential parameter is omitted, the default profile will be used.

scrape_configs:
  - job_name: "junos-exporter"
    metrics_path: /probe
    static_configs:
      - targets:
          - "192.168.1.1"  # Target device using "default" credential
      - targets:
          - "192.168.1.2"  # Target device using "vjunos" credential
        labels:
          __params_credential: "vjunos"
    relabel_configs:
      - source_labels: [__address__]
        target_label: __param_target
      - source_labels: [__param_target]
        target_label: instance
      - target_label: __address__
        replacement: 127.0.0.1:9326

Metrics

Selecting a module

This exporter allows you to configure which metrics are scraped for each Junos device. To use a specific profile defined in the modules section of your config.yml, add the module query parameter to the scrape URL.
e.g. http://localhost:9326/probe?module=router&target=192.168.10.12

In your Prometheus configuration, setting __params_module to router ensures the corresponding modules are used. If the module parameter is omitted, the default profile will be used.

Bundled probes

The bundled config.yml defines 20 probes covering alarms, chassis, interfaces, LLDP/LACP, routing, ARP, OSPF, BGP, VRRP and BFD -- all of them in the default module. They are always loaded, so your own config.yml only needs to list the ones you want to change.

probe rpc command
system_alarm_status get-system-alarm-information show system alarms
chassis_alarm_status get-alarm-information show chassis alarms
fpc_status get-fpc-information show chassis fpc
hardware_status get-chassis-inventory show chassis hardware
environment_status get-environment-information show chassis environment
routing_engine_status get-route-engine-information show chassis routing-engine
storage_status get-system-storage show system storage
physical_interface_status get-interface-information show interfaces extensive
logical_interface_status get-interface-information show interfaces detail
interface_optic_status get-interface-optics-diagnostics-information show interfaces diagnostics optics
lldp_status get-lldp-neighbors-information show lldp neighbors
lacp_status get-lacp-interface-information show lacp interfaces
route_status get-route-summary-information show route summary
arp_status get-arp-table-information show arp expiration-time
ospf_interface_status get-ospf-interface-information show ospf interface detail
ospf_neighbor_status get-ospf-neighbor-information show ospf neighbor extensive
bgp_status get-bgp-summary-information show bgp summary
bgp_route_status get-bgp-summary-information show bgp summary
vrrp_status get-vrrp-information show vrrp detail
bfd_status get-bfd-session-information show bfd session

Defining a probe

A probe is one RPC plus the rules for reading its reply. The reply XML is scanned into records (a flat path -> value mapping), and each record becomes one metric sample.

Records are cut out of the reply like this:

  • Each element matching container is a starting point, and item marks where a record begins. Junos often emits records without a wrapping element, so a record is not necessarily the subtree of the item element.
  • Every path written in metrics and labels is looked up in three places and the first hit wins: (a) inside the item element, (b) among the siblings that follow it, up to the next item, (c) among the ancestor's children that appeared before that item -- which is how a parent's values are inherited by its records.
  • A path that resolves nowhere is simply left out of the record, and the metric or label using it is not exposed for that record.

For example, show vrrp detail returns each VR as a vrrp-vlan element followed by loose siblings, and the second VR reports its mode under active-inherit instead:

<vrrp-information>
  <vrrp-interface>
    <vrrp-vlan>
      <physical-interface>xe-0/0/0</physical-interface>
      <unit>1</unit>
    </vrrp-vlan>
    <interface-state>up</interface-state>
    <group>10</group>
    <vrrp-state>master</vrrp-state>
    <vrrp-mode>active</vrrp-mode>
    <vrrp-vlan>
      <physical-interface>xe-0/0/0</physical-interface>
      <unit>2</unit>
    </vrrp-vlan>
    <interface-state>up</interface-state>
    <group>20</group>
    <vrrp-state>master</vrrp-state>
    <active-inherit>
      <vrrp-mode>inherit</vrrp-mode>
    </active-inherit>
  </vrrp-interface>
</vrrp-information>

The bundled vrrp_status probe reads it as follows. physical-interface and unit are found by rule (a), the rest by rule (b), and the mode label lists two paths so that the second record falls back to the nested one.

probes:
  vrrp_status:
    rpc: get-vrrp-information
    container: vrrp-interface
    item: vrrp-vlan
    metrics:
      - name: vrrp_state
        path: vrrp-state
        type: gauge
        help: "VR State of show vrrp detail(master: 5, backup: 4, transition: 3, bringup: 2, init: 1, idle: 0)"
        value_transform:
          "master": 5
          "backup": 4
          "transition": 3
          "bringup": 2
          "init": 1
          "idle": 0
    labels:
      - name: interface
        path: physical-interface
      - name: unit
        path: unit
      - name: mode
        path:
          - vrrp-mode
          - active-inherit.vrrp-mode
      - name: group
        path: group

Which is exposed as:

# HELP junos_vrrp_state VR State of show vrrp detail(master: 5, backup: 4, transition: 3, bringup: 2, init: 1, idle: 0)
# TYPE junos_vrrp_state gauge
junos_vrrp_state{interface="xe-0/0/0",unit="1",mode="active",group="10"} 5.0
junos_vrrp_state{interface="xe-0/0/0",unit="2",mode="inherit",group="20"} 5.0

probes

key type default description
rpc str required RPC name, sent as <rpc-name format="xml-minified">
args dict {} RPC arguments. _ in a key becomes -. A value of true emits an empty element, anything else emits <key>value</key>
container str "" Path to the parent of the records, . separated and relative to the child level of the reply root. Every match is used
item str | list[str] required Element name that begins a record
recursive bool false Also look for item further down the tree, for replies nested to an arbitrary depth such as show chassis hardware
metrics list [] Metric definitions, see below
labels list [] Label definitions applied to every metric of the probe, see below

paths

Both metrics and labels read their value through a path relative to the record, which takes one of these forms:

      - name: peer_state
        path: peer-state                        # child element
      - name: input_bytes
        path: traffic-statistics.input-bytes    # nested element
      - name: config_flags
        path: if-config-flags.@flag             # attribute
      - name: mode
        path:                                   # first path that resolves wins
          - vrrp-mode
          - active-inherit.vrrp-mode
      - name: iff_up
        path: if-config-flags.iff-up            # presence instead of value
        exists: True

A path with exists: True yields the string "true" or "false" rather than the element value, so it always resolves. It cannot be combined with a list of paths.

metrics

key type default description
name str required Exposed as <prefix>_<name>, with _total appended when type is counter
path str | list[str] required unless value Path to the value, see above
value float required unless path Constant to expose instead of reading the reply
exists bool false Expose whether path resolved, as "true" or "false"
type str untyped untyped, counter or gauge
help str "" Text of the HELP line
regex str none Applied to the value. Capture group 1 is used if present, otherwise the whole match. A value that does not match is dropped
value_transform dict none Maps a string value to a number. The _ key sets a default, otherwise an unlisted value becomes NaN
to_unixtime bool false Reads the value as YYYY-MM-DD HH:MM:SS, <w>w<d>d HH:MM:SS, <d>d HH:MM:SS or HH:MM:SS and converts it to unix time in milliseconds. Anything else becomes 0

labels

key type default description
name str required Label name
path str | list[str] required Path to the label value, see above
exists bool false Expose whether path resolved, as "true" or "false"
regex str none Applied to the label value. Capture group 1 is used, and the label is omitted when it does not match

A label whose path is missing from the record is omitted. Splitting xe-0/0/0.1 into a physical interface and a unit:

    labels:
      - name: interface
        path: name
        regex: ([^\.]*).*
      - name: unit
        path: name
        regex: .*\.(\d+)

Checking a probe definition

Get the RPC reply from the device itself to work out what to write.

# The RPC name to put in `rpc:`
show vrrp detail | display xml rpc

# The reply XML, to work out container / item / path
show vrrp detail | display xml

Then /debug shows the records the current definition extracts from that reply.

curl 'localhost:9326/debug?target=192.168.1.1&probe=vrrp_status'

License

MIT

Metadata

Release files for junos-exporter 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for junos-exporter 0.1.0
File Size Uploaded
junos_exporter-0.1.0.tar.gz 77.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for junos-exporter 0.1.0
File Interpreter ABI Platform
junos_exporter-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 100.1 kB

Release files / junos_exporter-0.1.0.tar.gz

Download URL junos_exporter-0.1.0.tar.gz
Size 77.2 kB
Tags Source
SHA-256 checksum
How to use checksums
ac183a5a955cb66a16085de81f3beb89e50dfb1f754cca3de30c6b07f2959bf5
BLAKE2b-256 checksum
How to use checksums
8c9fc4e6f5baef488bd4f0841ecd3fc4e43fdd3b74dd7c90380394987dd4996a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.10 {"installer":{"name":"uv","version":"0.12.10","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / junos_exporter-0.1.0-py3-none-any.whl

Download URL junos_exporter-0.1.0-py3-none-any.whl
Size 22.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
7294d7e1666171d27a00e8fe9e4edf24ce00739594eb245d70dfd0dd191ba527
BLAKE2b-256 checksum
How to use checksums
01bca254ea499fbfb805a567a0fd4704b5b85da4229b6be8e79557d00a695372
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.10 {"installer":{"name":"uv","version":"0.12.10","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

0.0.12

2 release files

0.0.11

2 release files

0.0.10

2 release files

0.0.9

2 release files

0.0.8

2 release files

0.0.7

2 release files

0.0.6

2 release files

0.0.5

2 release files

0.0.4

2 release files

0.0.3

2 release files

0.0.2

2 release files

0.0.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page