Created
April 18, 2013 23:58
-
-
Save jof/5417132 to your computer and use it in GitHub Desktop.
NETCONF-speaking script to poll a Juniper SRX NAT pool and stuff the metrics into Graphite
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
require 'rubygems' | |
require 'pry' | |
require 'socket' | |
$:.unshift '/home/jof/src/net-netconf/lib' | |
$:.unshift '/home/jof/src/net-ssh/lib' | |
require 'net/netconf' | |
require 'net/ssh' | |
require 'net/ssh/proxy/command' | |
jump_host = ARGV.shift | |
target = ARGV.shift | |
snat_pool = ARGV.shift | |
unless jump_host and target and snat_pool then | |
STDERR.puts "This needs a jump host, target, and snat pool name as arguments" | |
exit 1 | |
end | |
poll_interval = 5 | |
corp_jump_host = Net::SSH::Proxy::Command.new("ssh #{jump_host} nc %h %p") | |
netconf = Netconf::SSH.new(:target => target, :username => ENV['USER'], :port => 22) | |
netconf.trans_open(:proxy => corp_jump_host) | |
netconf.open | |
graphite_socket = TCPSocket.new('localhost', 2003) | |
at_exit do | |
netconf.close | |
graphite_socket.close | |
end | |
loop do | |
sleep poll_interval | |
cluster_status = netconf.rpc.get_chassis_cluster_status(:redundancy_group => '0') | |
nodes = cluster_status.xpath('//device-stats/device-name').map { |node| node.text } | |
statuses = cluster_status.xpath('//device-stats/redundancy-group-status').map { |status| status.text } | |
states = nodes.zip(statuses) | |
active_node = states.select { |state| state[1] == 'primary' }.flatten.first | |
pools = netconf.rpc.retrieve_source_nat_pool_information(:pool_name => snat_pool) | |
# FIXME: Detect <error> tags in RPC response when the remote node times out. | |
# FIXME: Maybe there is a better way to walk the <multi-routing-engine-item> nodes. xpath'ing a Nokogiri::XML::NodeSet seems to still require the full path from the root. | |
total_addresses = pools.xpath("//multi-routing-engine-item[re-name=\"#{active_node}\"]//total-pool-address").text # "16" | |
total_addresses = total_addresses.to_i | |
translation_range = pools.xpath("//multi-routing-engine-item[re-name=\"#{active_node}\"]//source-pool-port-translation").text # "[1024, 63487]" | |
translation_range = translation_range.gsub(/[\[\]]/,'').split(/,\s*/).map { |i| i.to_i } | |
translation_range = Range.new(*translation_range) | |
single_port_translations = pools.xpath("//multi-routing-engine-item[re-name=\"#{active_node}\"]//single-port").text | |
single_port_translations = single_port_translations.to_i | |
twin_port_translations = pools.xpath("//multi-routing-engine-item[re-name=\"#{active_node}\"]//twin-port").text | |
twin_port_translations = twin_port_translations.to_i | |
available_source_port_translations = translation_range.count * total_addresses | |
in_use_port_translations = single_port_translations + twin_port_translations | |
now = Time.now | |
metrics = { 'available' => available_source_port_translations, | |
'single_port_used' => single_port_translations, | |
'twin_port_used' => twin_port_translations, | |
'ports_used' => (single_port_translations + twin_port_translations) } | |
metrics.each do |metric, value| | |
# Change this metric name for your own Graphite environment | |
graphite_socket.puts "jof.nat_pools.#{target}.#{snat_pool}.#{metric} #{value} #{now.to_i}" | |
end | |
graphite_socket.flush | |
metrics.each do |metric, value| | |
puts "Reporting that jof.nat_pools.#{target}.#{snat_pool}.#{metric} is #{value} at #{now}" | |
end | |
end | |
#netconf.close |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment