Streaming Junos Telemetry To MQTT Via Telegraf

In response to my previous blog post on how to get Junos streaming telemetry data pushed to a Kafka bus by using Telegraf as an intermediate collector, I received a request to write a similar blog post, but this time pushing the telemetry data to a Mosquitto MQTT broker instead of Kafka.

MQTT (Message Queuing Telemetry Transport) is a lightweight publish/subscribe-based messaging protocol that works on top of TCP/IP.  The protocol is ideally suited for resource-constrained network clients (eg. IoT devices) to distribute telemetry information.  Similar to Kafka, MQTT is based on the idea of publishing messages and subscribing to “Topics“.  Multiple clients connect to a central communication point, called an “MQTT Broker“, and subscribe to topics that they are interested in.  These same clients can also publish messages to various topics via this connection to the central broker.

Mosquitto (part of the Eclipse Foundation as an “iot.eclipse.org” project) is an open-source message broker that implements the MQTT protocol (versions 3.1 and 3.1.1).  This blog post is meant to serve as a Quick Start Guide on how to get Junos streaming telemetry data pushed to a Mosquitto MQTT Broker by using Telegraf as an intermediate collector, as depicted in Figure 1 below.

Note: In this blog post, we will install both Telegraf and Mosquitto on an Ubuntu 16.04 server.

graffle1
Figure 1:  Streaming Junos Telemetry To Mosquitto MQTT Broker Via Telegraf

Configuring gRPC Telemetry Streaming On The Juniper Router

The process to setup and configure the Juniper router for gRPC telemetry streaming is covered in depth in the “Prerequisites: OpenConfig & Network Agent Packages” and “Junos Configuration” sections of the following blog post.  Rather than repeat and duplicate the content here, the Reader is encouraged to peruse the post for further details.

Installing Mosquitto MQTT Broker

Installing Mosquitto MQTT Broker is a very straightforward process.  First, we add the Mosquitto PPA repository so that we can get the latest version of Mosquitto:

root@ubuntu:~# sudo apt-add-repository ppa:mosquitto-dev/mosquitto-ppa
 
 More info: https://launchpad.net/~mosquitto-dev/+archive/ubuntu/mosquitto-ppa
Press [ENTER] to continue or ctrl-c to cancel adding it

gpg: keyring `/tmp/tmp23eqmju4/secring.gpg' created
gpg: keyring `/tmp/tmp23eqmju4/pubring.gpg' created
gpg: requesting key 262C4500 from hkp server keyserver.ubuntu.com
gpg: /tmp/tmp23eqmju4/trustdb.gpg: trustdb created
gpg: key 262C4500: public key "Launchpad mosquitto" imported
gpg: Total number processed: 1
gpg:               imported: 1  (RSA: 1)
OK

Next, we need to update Ubuntu’s package list to ensure that we install the newest versions of the required packages and their dependencies, as follows:

root@ubuntu:~# sudo apt-get update
Hit:1 http://us.archive.ubuntu.com/ubuntu xenial InRelease
Hit:2 http://us.archive.ubuntu.com/ubuntu xenial-updates InRelease                                                       
Hit:3 http://security.ubuntu.com/ubuntu xenial-security InRelease                             
Hit:4 http://us.archive.ubuntu.com/ubuntu xenial-backports InRelease    
Get:5 http://ppa.launchpad.net/mosquitto-dev/mosquitto-ppa/ubuntu xenial InRelease [23.8 kB]
Get:6 http://ppa.launchpad.net/mosquitto-dev/mosquitto-ppa/ubuntu xenial/main amd64 Packages [2,048 B]
Get:7 http://ppa.launchpad.net/mosquitto-dev/mosquitto-ppa/ubuntu xenial/main i386 Packages [2,052 B]
Get:8 http://ppa.launchpad.net/mosquitto-dev/mosquitto-ppa/ubuntu xenial/main Translation-en [1,296 B]
Fetched 29.2 kB in 1s (17.7 kB/s)                   
Reading package lists... Done
root@ubuntu:~#

Once this is done, we install the Mosquitto Broker using the command below:

root@ubuntu:~# sudo apt-get install mosquitto
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following additional packages will be installed:
  libev4 libuv1 libwebsockets7
The following NEW packages will be installed:
  libev4 libuv1 libwebsockets7 mosquitto
0 upgraded, 4 newly installed, 0 to remove and 149 not upgraded.
Need to get 280 kB of archives.
After this operation, 724 kB of additional disk space will be used.
Do you want to continue? [Y/n] y
[... CONTENT OMITTED FOR BREVITY ...]
Setting up mosquitto (1.4.15-0mosquitto1~xenial1) ...
Processing triggers for libc-bin (2.23-0ubuntu10) ...
Processing triggers for systemd (229-4ubuntu21.1) ...
Processing triggers for ureadahead (0.100.0-19) ...
root@ubuntu:~#

Default TCP Port for MQTT:   1883

Default TCP Port for MQTT over SSL:   8883

Note that the Mosquitto service will automatically start after installation.  To verify that it is indeed running, we can check on its status with the following:

root@ubuntu:~# sudo /etc/init.d/mosquitto status
 mosquitto.service - LSB: mosquitto MQTT v3.1 message broker
   Loaded: loaded (/etc/init.d/mosquitto; bad; vendor preset: enabled)
   Active: active (running) since Wed 2018-03-28 06:42:00 PDT; 1min 56s ago
     Docs: man:systemd-sysv-generator(8)
   CGroup: /system.slice/mosquitto.service
           └─6177 /usr/sbin/mosquitto -c /etc/mosquitto/mosquitto.conf

Mar 28 06:42:00 ubuntu systemd[1]: Starting LSB: mosquitto MQTT v3.1 message broker...
Mar 28 06:42:00 ubuntu mosquitto[6168]:  * Starting network daemon: mosquitto
Mar 28 06:42:00 ubuntu mosquitto[6168]:    ...done.
Mar 28 06:42:00 ubuntu systemd[1]: Started LSB: mosquitto MQTT v3.1 message broker.
root@ubuntu:~#

Highlighted in red above, note the configuration file for the Mosquitto broker, where you can find additional runtime details for the service, such as the log file and pid file locations:

root@ubuntu:~# more /etc/mosquitto/mosquitto.conf
# Place your local configuration in /etc/mosquitto/conf.d/
#
# A full description of the configuration file is at
# /usr/share/doc/mosquitto/examples/mosquitto.conf.example

pid_file /var/run/mosquitto.pid

persistence true
persistence_location /var/lib/mosquitto/

log_dest file /var/log/mosquitto/mosquitto.log

include_dir /etc/mosquitto/conf.d
root@ubuntu:~#

To stop the Mosquitto Broker service:   sudo /etc/init.d/mosquitto stop

To start the Mosquitto Broker service:   sudo /etc/init.d/mosquitto start

Finally, we install the “mosquitto-clients” package, which allow us to easily test MQTT through a couple of command line utilities:

    1. mosquitto_pub“: a CLI client which can be used to publish messages to the Mosquitto MQTT Broker to a specific Topic.
    2. mosquitto_sub“: a CLI client which can be used to subscribe to a Topic to receive messages from the Mosquitto MQTT Broker.

Installation of the mosquitto-clients package is just as straightforward as the installation of the Mosquitto Broker itself:

root@ubuntu:~# sudo apt-get install mosquitto-clients
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following additional packages will be installed:
  libmosquitto1
The following NEW packages will be installed:
  libmosquitto1 mosquitto-clients
0 upgraded, 2 newly installed, 0 to remove and 149 not upgraded.
Need to get 110 kB of archives.
After this operation, 248 kB of additional disk space will be used.
Do you want to continue? [Y/n] y
Get:1 http://ppa.launchpad.net/mosquitto-dev/mosquitto-ppa/ubuntu xenial/main amd64 libmosquitto1 amd64 1.4.15-0mosquitto1~xenial1 [54.6 kB]
Get:2 http://ppa.launchpad.net/mosquitto-dev/mosquitto-ppa/ubuntu xenial/main amd64 mosquitto-clients amd64 1.4.15-0mosquitto1~xenial1 [55.6 kB]
[... CONTENT OMITTED FOR BREVITY ...]
Setting up libmosquitto1:amd64 (1.4.15-0mosquitto1~xenial1) ...
Setting up mosquitto-clients (1.4.15-0mosquitto1~xenial1) ...
Processing triggers for libc-bin (2.23-0ubuntu10) ...
root@ubuntu:~# 

Testing The Mosquitto MQTT Broker

With the installation of both the Mosquitto Broker and CLI clients, a quick test is in order to ensure that messages can be both published to and consumed from MQTT Topics.  First, in one console window (let’s call this Console # 1), let’s subscribe to a Topic called “juniper”, as follows:

root@ubuntu:~# mosquitto_sub -h localhost -t "juniper"

Next, using another console window (let’s call this Console # 2), let’s publish a message to the “juniper” Topic, as follows:

root@ubuntu:~# mosquitto_pub -d -h localhost -t "juniper" -m "Hello World!"
Client mosqpub|6976-ubuntu sending CONNECT
Client mosqpub|6976-ubuntu received CONNACK
Client mosqpub|6976-ubuntu sending PUBLISH (d0, q0, r0, m1, 'juniper', ... (12 bytes))
Client mosqpub|6976-ubuntu sending DISCONNECT
root@ubuntu:~# 

Now if we return back to Console # 1, we will see that the mosquitto_sub client, listening on the “juniper” Topic, has received the published “Hello World!” message:

root@ubuntu:~# mosquitto_sub -h localhost -t "juniper"
Hello World!

Installing Telegraf

Telegraf is an open-source collector that can readily be used to ingest streaming telemetry data from Juniper devices.  Telegraf can either be installed as a subcomponent within an OpenNTI deployment or as a standalone instance.  To install OpenNTI, please refer to this introductory blog post.  For simplicity, the author assumes that the Reader has elected to install Telegraf as a standalone instance,  the installation instructions for which can be found in the “Installing Telegraf” section of the following blog postAlso for simplicity, in this post we are going to install Telegraf on the same server as Mosquitto MQTT Broker.

Enabling The MQTT Output Plugin Within Telegraf

Now that Telegraf is installed, it is a relatively easy step to get ingested telemetry data pushed out to a MQTT broker.  This is because Telegraf natively supports a MQTT Output Plugin.  We simply have to include this plugin within the “OUTPUT PLUGINS” section of Telegraf configuration file (ie. “telegraf.conf“), and tweak a few of the plugin’s default parameters.

The first step is to generate an openconfig-telemetry-specific Telegraf configuration file that also supports the MQTT output plugin; to do this we issue the following command from the directory where the Telegraf executable is located (ie. “$HOME/go/src/github.com/influxdata/telegraf“):

telegraf --input-filter jti_openconfig_telemetry --output-filter mqtt config > telegraf.conf

Now, we edit the auto-generated “telegraf.conf” file and configure a few parameters for the MQTT output plugin, as shown below:

###############################################################################
#                               OUTPUT PLUGINS                                #
###############################################################################

# Configuration for MQTT server to send metrics to
[[outputs.mqtt]]
  servers = ["localhost:1883"] # required.

  ## MQTT outputs send metrics to this topic format
  ##    "///"
  ##   ex: prefix/web01.example.com/mem
  topic_prefix = "juniper"

  ## username and password to connect MQTT server.
  # username = "telegraf"
  # password = "metricsmetricsmetricsmetrics"

  ## Timeout for write operations. default: 5s
  # timeout = "5s"

  ## client ID, if not set a random ID is generated
  # client_id = ""

  ## Optional SSL Config
  # ssl_ca = "/etc/telegraf/ca.pem"
  # ssl_cert = "/etc/telegraf/cert.pem"
  # ssl_key = "/etc/telegraf/key.pem"
  ## Use SSL but skip chain & host verification
  # insecure_skip_verify = false

  ## Data format to output.
  ## Each data format has its own unique set of configuration options, read
  ## more about them here:
  ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_OUTPUT.md
  data_format = "json"

The three main parameters that need to be changed from their default values are:

    1. servers: Here, we specify the management IP address and port number (typically 1883) of the target MQTT brokers to which we will be streaming our telemetry data to.  Although a single broker is shown in the example, multiple devices can be specified simply by listing them in a comma-separated list (eg. [“1.1.1.1:1883”, “2.2.2.2:1883”]).
    2. topic_prefix: This is the prefix for the MQTT Topic to which Telegraf will publish its collected telemetry data to.  Listeners on this topic are then able to pick this data up off the MQTT bus and further process it or action on it.  By default, Telegraf pushes the telemetry data using the following template: <topic_prefix>/<server_hostname>/<sensor_name>.  So, for example, if we use a topic_prefix of “juniper”, and our server is named “ubuntu”, and if we subscribe to the “/interfaces/interface/” sensor, then the telemetry data will get pushed to the following MQTT Topic: “juniper/ubuntu//interfaces/interface/“.
    3. data_format:  This is where we specify the data format to generate.  By default this parameter is set to “influx“.  Change it to “json” so we can push the data in basic key/value pair format.

The remaining parameters from above can be left at their default values.

Verifying The Telemetry Data Push To Mosquitto MQTT Broker

After following all of the steps above, you should be streaming gRPC telemetry data from the Juniper router to the Telegraf collector, which in turn should be sending the same data in JSON format to the Mosquitto MQTT broker.  To verify that this is in fact working, we can use the “mosquitto_sub” CLI client in verbose mode (using the ‘-v’ flag), as shown below. Using verbose mode prints the Topic name (shown in red below) to which the telemetry data gets pushed to:

root@ubuntu:~# mosquitto_sub -v -t "#"

juniper/ubuntu//interfaces/interface/
{
   "fields": {
      "/interfaces/interface/state/admin-status": "UP",
      "/interfaces/interface/state/description": "",
      "/interfaces/interface/state/enabled": true,
      "/interfaces/interface/state/ifindex": 519,
      "/interfaces/interface/state/last-change": 66700733,
      "/interfaces/interface/state/mtu": 1514,
      "/interfaces/interface/state/name": "ge-0/0/0",
      "/interfaces/interface/state/oper-status": "UP",
      "/interfaces/interface/state/type": "ethernetCsmacd",
      "_component_id": 65535,
      "_sequence": 27,
      "_subcomponent_id": 0,
      "_timestamp": 1522279323640
   },
   "name": "/interfaces/interface/",
   "tags": {
      "/interfaces/interface/@name": "ge-0/0/0",
      "device": "10.49.120.244",
      "host": "ubuntu",
      "path": "sensor_1000_4_1:/interfaces/interface/:/interfaces/interface/:mib2d",
      "system_id": "mx0_re0"
   },
   "timestamp": 1522279323
}

juniper/ubuntu//interfaces/interface
{
   "fields": {
      "/interfaces/interface/state/counters/in-octets": 49911172,
      "/interfaces/interface/state/counters/in-pkts": 932019,
      "/interfaces/interface/state/counters/last-clear": "Never",
      "/interfaces/interface/state/counters/out-octets": 49911172,
      "/interfaces/interface/state/counters/out-pkts": 932019,
      "_component_id": 65535,
      "_sequence": 23,
      "_subcomponent_id": 0,
      "_timestamp": 1522279326980
   },
   "name": "/interfaces/interface/",
   "tags": {
      "/interfaces/interface/@name": "lo0",
      "device": "10.49.120.244",
      "host": "ubuntu",
      "path": "sensor_1000_6_1:/interfaces/interface/:/interfaces/interface/:xmlproxyd",
      "system_id": "mx0_re0"
   },
   "timestamp": 1522279326
}
[... CONTENT OMITTED FOR BREVITY ...]

Leave a Reply