Quickstart: Ruby for Junos Automation

I need help getting started with Ruby ….

I’ve been asked by a few people to do a quick blog on getting started with Ruby.  The focus on this blog will be setting up your computer with the Ruby language and libraries that you can use to write programs to automate Junos based networking devices.

I_love_automating_networks

Step-1: Install Ruby

Chances are you already have Ruby on your computer.  If you have a Mac, you will, but the question is what version is installed (and what version you could use…).   If you want to check if you have Ruby already installed, just do the following from a terminal window:

jeremy@laptop$ ruby -v
ruby 1.9.3p327 (2012-11-10 revision 37606) [i386-cygwin]

If you do not have Ruby installed, you can find installation instructions here from the main Ruby language website here.

If you are using a Windows computer, you have two options: (1) Install Cygwin and all of the Ruby bits, or (2) use the native Ruby distribution for Windows

Step-2: Install Ruby “Gem” Tool

The Ruby “gem” tool is the utility to manage Ruby libraries, aka “gems”.  Ruby gems are hosted on RubyGems.org.  The instructions for downloading the Ruby gems tool and installing it on your system can be found here. Once it’s installed, you can check the version:

jeremy@laptop$ gem -v
1.8.23

Step-3: Install Gems

There are a few gems that I would recommend you install.  You install these using the “gem” tool, and on Unix/like systems you will either need to do this as “root” or using “sudo”.  Here is a list of gems I’d recommend installing first:

  • rdoc – Get the latest copy of the Ruby Documentation tools
  • pry – This allows you to set breaks in your code for debugging
  • highline – This allows you to prompt users for “secret” input, like passwords

To install the “highline” gem, for example, you would do the following command:

jeremy@laptop$ gem install highline

You can get a listing of all the gems you installed, for example:

jeremy@laptop$ gem list

*** LOCAL GEMS ***

highline (1.6.15)
net-scp (1.0.4)
net-ssh (2.6.2)
netconf (0.2.5)
nokogiri (1.5.6)
pry (0.9.10)
psych (1.3.4)
rdoc (3.12)
rubyforge (2.0.4)
serialport (1.1.0)

Step-4: Write Your First Program

Here is a short program to ask you for a secret and then puts it to the screen:

require 'highline/import'

secret = ask("What's your secret? "){|a| a.echo = false}

puts "I'm telling your secret: #{secret}"

You execute this program on the shell and enter “magic” at the prompt:

jeremy@laptop$ ruby secret.rb
What's your secret?
I'm telling your secret: magic

Step-5: Install the Nokogiri Gem

Nokogiri is one of the most popular XML libraries for Ruby.  Junos management is XML “under the hood”, so we need a library to handle XML. If you’re not familiar with XML, don’t worry, I’ll cover the basics in an upcoming blog.

The Ruby gem to automate Junos is called “netconf” (next step), and it uses the nokogiri gem.  So if you just skip to the next step and install netconf, and if you don’t have nokogiri installed then the gem tool will install nokogiri first.  The issue that I’ve commonly seen is that nokogiri requires “native extensions”, which basically means you need to have some system libraries on your computer.  If you don’t have those libraries already installed, then the gem install will fail and you will need to follow the Nokogiri installation instructions on their website here.

jeremy@laptop$ gem install nokogiri
Fetching: nokogiri-1.5.6.gem (100%)
Building native extensions.  This could take a while...
Successfully installed nokogiri-1.5.6
1 gem installed
Installing ri documentation for nokogiri-1.5.6...
Installing RDoc documentation for nokogiri-1.5.6...

Step-6: Install the NETCONF Gem

Once you have Nokogiri installed, install the NETCONF gem.  This should go smoothly.

jeremy@laptop$ gem install netconf
Fetching: netconf-0.2.5.gem (100%)
Successfully installed netconf-0.2.5
1 gem installed
Installing ri documentation for netconf-0.2.5...
Installing RDoc documentation for netconf-0.2.5...

Now you’re ready to write your first Ruby program to automate Junos.

Step-7: Enable NETCONF on Junos

You will need to enable the NETCONF service on the Junos device, it is not enabled by default.  At the Junos CLI do the following:

jeremy@junos> configure
[edit]
user@junos# set system services netconf ssh
user@junos# commit and-quit

NETCONF is over TCP/830, so if you have a firewall along the path you will need to open access for that port.

Step-8: Write Your first Ruby Program for Junos

Here is a short program that will display the system up-time.  I’ll cover the basics of Junos Automation programming in another blog.  Here’s the sample output for this program

jeremy@laptop$ ruby get-sn.rb jeremy@mx960-190.inmylab.net
password:
MX960: JN1096862AFA

 

require 'highline/import'
require 'net/netconf'

target = ARGV[0].split '@'

login = Hash.new
login[:username] = ( target.count > 1 ) ? target.shift : ENV['USER']
login[:target] = target.shift
login[:password] = ask("password: "){ |a| a.echo = false }

Netconf::SSH.new( login ) { |dev|
  
  inv = dev.rpc.get_chassis_inventory

  description = inv.xpath('chassis/description').text
  serial_number = inv.xpath('chassis/serial-number').text

  puts "#{description}: #{serial_number}"
}

Summary

I hope you’ve found this brief tutorial helpful and you now have an environment to start writing automation programs!

8 thoughts on “Quickstart: Ruby for Junos Automation

  1. David

    I accidently posted a question in the SLAX section and meant to do it here. I’m having a bit of a issue getting just the lo0 IP to display. I’m unsure of why since it worked fine for version. Below hostname and version work fine, but loopback just display’s blank. Doesn’t matter what I try it will not display any information and I don’t know what i’m missing. I would think the name field would isolate the lo0.0 name and begin the process of displaying ifa-local. I would show the XML, but it’s very long and doesn’t show properly. I must be using tags wrong.

    Code:
    version_rpc = router.rpc.get_software_information
    interface_rpc = router.rpc.get_interface_information
    ver = version_rpc.xpath(‘//package-information[name = "junos"]/comment’).text
    loopback = interface_rpc.xpath(‘//logical-interface[name = "lo0.0"]/address-family/interface-address/ifa-local’).text
    hostname = version_rpc.xpath(‘//software-information/host-name’).text
    puts “Hostname: #{hostname}”
    puts “Loopback: #{loopback}”
    puts “Installed OS is #{ver}”

    Reply
  2. Jeremy Schulman Post author

    @ Dave,

    I would recommend stepping through the code using “binding.pry” after the router.rpc.get_interface_information. Then dump the results by “puts interface_rpc.to_xml” to see what the actual XML looks like. You could also do the same from the Junos CLI using the “show interfaces” command with the “| display xml”.

    HTH

    Reply
  3. David

    I realize this may not be the best place to ask questions, but it seems the most amount of information is from this blog. I do apologize. I’ve exhausted my searching and can’t seem to figure out why my output is spaced. I tried to follow the puts vs. print rules, but doesn’t seem to matter. It seems like I’m following the same process as your get-config-matching.rb which does display the interface and units on same line. Trying to get the output to look like this:

    Hostname: re0.LAB-MX480-01
    xe-0/0/0: -4.88
    xe-0/1/0: -2.42

    Code:
    phyint = diag_rpc.xpath(‘physical-interface’)
    puts “Hostname: #{hostname}”
    phyint.each{ |ifd|
    print ifd.xpath(‘name’)[0].text
    print ifd.xpath(‘optics-diagnostics/laser-rx-optical-power-dbm |
    optics-diagnostics/optic-diagnostics-not-available |
    optics-diagnostics/rx-signal-avg-optical-power-dbm’).text

    Output:
    Hostname: re0.LAB-MX480-01

    xe-0/0/0

    -4.88

    xe-0/1/0

    -2.42

    xe-0/2/0

    -4.10

    xe-0/3/0

    -3.45

    ge-5/0/0

    N/A

    ge-5/0/1

    N/A

    ge-5/0/2

    -23.87

    Thanks for your time,

    David

    Reply
    1. Jeremy Schulman Post author

      Often times the XML text has CRLF (“\n”) encoded, so you will need to remove those. I use the ‘strip’ method for this purpose, as shown:

      print ifd.xpath(‘name’)[0].text.strip

      Give that a shot; hope it helps!

      Reply
      1. David

        Thanks so much. Worked like a charm:

        Hostname: re0.LAB-MX480-01
        xe-0/0/0:-4.88
        xe-0/1/0:-2.42
        xe-0/2/0:-4.12
        xe-0/3/0:-3.45
        ge-5/0/0:N/A
        ge-5/0/1:N/A
        ge-5/0/2:-23.87
        ge-5/1/6:-4.92
        ge-5/1/7:-5.67
        ge-5/1/8:- Inf
        ge-5/1/9:-4.65
        ge-5/2/0:-5.88
        ge-5/2/1:N/A
        ge-5/2/2:N/A
        ge-5/3/6:-4.54
        ge-5/3/7:N/A
        ge-5/3/8:-6.91
        ge-5/3/9:-6.76

        Reply
  4. David

    Have a couple questions I hope you can answer. I’m learning so much and wanted to say thanks.

    1. How do I make rpc calls that have a extra style? Not sure what to call that. For example I would like to add no-resolve to my rpc call. It works right now using(router.rpc.get_arp_table_information). I would like to speed it up by adding no-resolve. Can’t figure out syntax for this.

    {master}

    2. I would love to understand the matching on rpc call more clearly. I can get it to work using your example, but when I try my own it doesn’t. I can’t seem to find documentation on :matching => syntax either.

    arp_rpc = router.rpc.get_arp_table_information{ |x|
    x.arp-table-entry( :matching => ‘[interface-name="*.99"]‘ )
    }

    thanks again for your time and patients,

    David

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>