/net-netconf

A Ruby gem for NETCONF

Primary LanguageRubyOtherNOASSERTION

Netconf

Gem Version Dependency Status Build Status Code Climate Test Coverage

Description

Device management using the NETCONF protocol as specified in RFC4741 and RFC6241.

Features

  • Extensible protocol transport framework for SSH and non-SSH

    • SSH transport using Net::SSH
    • Telnet transport using Net::Telnet (Ruby Library)
    • Serial transport using Ruby/SerialPort
  • NETCONF Standard RPCs

    • get-config, edit-config
    • lock, unlock
    • validate, discard-changes
  • Flexible RPC mechanism

    • Netconf::RPC::Builder to metaprogram RPCs
    • Vendor extension framework for custom RPCs
  • XML processing using Nokogiri

Synopsis

require 'net/netconf'

# create the options hash for the new NETCONF session. If you are
# using ssh-agent, then omit the :password

login = { target: 'vsrx', username: 'root', password: 'Amnesiac' }

# provide a block and the session will open, execute, and close

Netconf::SSH.new( login ){ |dev|

  # perform the RPC command:
  # <rpc>
  #    <get-chassis-inventory/>
  # </rpc>

  inv = dev.rpc.get_chassis_inventory

  # The response is in Nokogiri XML format for easy processing ...

  puts 'Chassis: ' + inv.xpath('chassis/description').text
  puts 'Chassis Serial-Number: ' + inv.xpath('chassis/serial-number').text
}

Alternative explicity open, execute RPCs, and close

require 'net/netconf'

login = { target: 'vsrx', username: 'root', password: 'Amnesiac' }

dev = Netconf::SSH.new(login)
dev.open

inv = dev.rpc.get_chassis_inventory

puts 'Chassis: ' + inv.xpath('chassis/description').text
puts 'Chassis Serial-Number: ' + inv.xpath('chassis/serial-number').text

dev.close

Using Netconf

Remote Procedure Calls (RPCs)

Each Netconf session provides a readable instance variable - rpc. This is used to execute Remote Procedure Calls (RPCs). The @rpc will include the NETCONF standard RPCs, any vendor specific extension, as well as the ability to metaprogram new onces via method_missing.

Here are some examples to illustrate the metaprogamming:

Without any parameters, the RPC is created by swapping underscores (_) to hyphens (-):

require 'net/netconf'

dev.rpc.get_chassis_inventory

# <rpc>
#    <get-chassis-inventory/>
# </rpc>

You can optionally provide RPC parameters as a hash:

dev.rpc.get_interface_information(interface_name: 'ge-0/0/0', terse: true )

# <rpc>
#    <get-interface-information>
#       <interface-name>ge-0/0/0</interface-name>
#       <terse/>
#   </get-interface-information>
# </rpc>

You can additionally supply attributes that get assigned to the toplevel element. In this case You must enclose the parameters hash to disambiquate it from the attributes hash, or declare a variable for the parameters hash.

dev.rpc.get_interface_information({interface_name: 'ge-0/0/0', terse: true }, { format: 'text'})

# <rpc>
#    <get-interface-information format='text'>
#       <interface-name>ge-0/0/0</interface-name>
#       <terse/>
#   </get-interface-information>
# </rpc>

If you want to provide attributes, but no parameters, then:

dev.rpc.get_chassis_inventory(nil, format: 'text')

# <rpc>
#    <get-chassis-inventory format='text'/>
# </rpc>

Retrieving Configuration

To retrieve configuration from a device, use the get-config RPC. Here is an example, but you can find others in the examples directory:

require 'net/netconf'

login = { target: 'vsrx', username: 'root', password: 'Amnesia' }

puts "Connecting to device: #{login[:target]}"

Netconf::SSH.new(login) do |dev|
  puts 'Connected.'

  # ----------------------------------------------------------------------
  # retrieve the full config.  Default source is 'running'
  # Alternatively you can pass the source name as a string parameter
  # to #get_config

  puts 'Retrieving full config, please wait ... '
  cfgall = dev.rpc.get_config
  puts "Showing 'system' hierarchy ..."
  puts cfgall.xpath('configuration/system')     # JUNOS toplevel config element is <configuration>

  # ----------------------------------------------------------------------
  # specifying a filter as a block to get_config

  cfgsvc1 = dev.rpc.get_config do |x|
   x.configuration { x.system { x.services } }
  end

  puts 'Retrieved services as BLOCK:'
  cfgsvc1.xpath('//services/*').each { |s| puts s.name }

  # ----------------------------------------------------------------------
  # specifying a filter as a parameter to get_config

  filter = Nokogiri::XML::Builder.new do |x|
   x.configuration { x.system { x.services } }
  end

  cfgsvc2 = dev.rpc.get_config(filter)
  puts 'Retrieved services as PARAM:'
  cfgsvc2.xpath('//services/*').each { |s| puts s.name }

  cfgsvc3 = dev.rpc.get_config(filter)
  puts 'Retrieved services as PARAM, re-used filter'
  cfgsvc3.xpath('//services/*').each { |s| puts s.name }
end

NOTE: There is a JUNOS RPC, get-configuration, that provides Juniper specific extensions as well.

Changing Configuration

To retrieve configuration from a device, use the edit-config RPC. Here is an example, but you can find others in the examples directory:

require 'net/netconf'

login = { target: 'vsrx', username: 'root', password: 'Amnesia' }

new_host_name = 'vsrx-abc'

puts "Connecting to device: #{login[:target]}"

Netconf::SSH.new(login) do |dev|
  puts 'Connected!'

  target = 'candidate'

  # JUNOS toplevel element is 'configuration'

  location = Nokogiri::XML::Builder.new do |x|
    x.configuration {
      x.system {
        x.location {
          x.building 'Main Campus, A'
          x.floor 5
          x.rack 27
        }
      }
    }
  end

  begin
    rsp = dev.rpc.lock target

    # --------------------------------------------------------------------
    # configuration as BLOCK

    rsp = dev.rpc.edit_config do |x|
      x.configuration {
        x.system {
          x.send(:'host-name', new_host_name )
        }
      }
    end

    # --------------------------------------------------------------------
    # configuration as PARAM

    rsp = dev.rpc.edit_config(location)

    rsp = dev.rpc.validate target
    rpc = dev.rpc.commit
    rpc = dev.rpc.unlock target

  rescue Netconf::LockError => e
    puts 'Lock error'
  rescue Netconf::EditError => e
    puts 'Edit error'
  rescue Netconf::ValidateError => e
    puts 'Validate error'
  rescue Netconf::CommitError => e
    puts 'Commit error'
  rescue Netconf::RpcError => e
    puts 'General RPC error'
  else
    puts 'Configuration Committed.'
  end
end

NOTE: There is a JUNOS RPC, load-configuration, that provides Juniper specific extensions as well.

Authors and Contributors