diff options
| author | Saku Ytti <saku@ytti.fi> | 2013-04-20 00:41:23 +0300 | 
|---|---|---|
| committer | Saku Ytti <saku@ytti.fi> | 2013-04-20 00:41:23 +0300 | 
| commit | f1287a7925901bf3518eb69079304bfb97f7434d (patch) | |
| tree | 3dd2779e4d087b73b99d7136f37db88c76091d8d /extra | |
| parent | 5a393d6102655f575549311e6b250534b4dcbb59 (diff) | |
Example of Syslog triggered fetch
'syslog.rb' listed to UDP port (or reads file). When IOS or JunOS style
config change/commit message is seen, it triggers immediate update ot
config
It transports commit message (junos) remote host from which change was
mde (ios) and who made the change (junos+ios). This is carried over to
the 'output' methods, that is, 'git blame' will show IOS/JunOS user-name
who made the change.
Diffstat (limited to 'extra')
| -rw-r--r-- | extra/rest_client.rb | 25 | ||||
| -rwxr-xr-x | extra/syslog.rb | 111 | 
2 files changed, 136 insertions, 0 deletions
| diff --git a/extra/rest_client.rb b/extra/rest_client.rb new file mode 100644 index 0000000..2c58d04 --- /dev/null +++ b/extra/rest_client.rb @@ -0,0 +1,25 @@ +module Oxidized +  class RestClient +    require 'net/http' +    require 'json' +    HOST = 'localhost' +    PORT = 8888 + +    class << self +      def next node, opt={}, host=HOST, port=PORT +        web = new host, port +        web.next node, opt +      end +    end + +    def initialize host=HOST, port=PORT +      @web = Net::HTTP.new host, port +    end + +    def next node, opt={} +      data = JSON.dump :node => node, :user => opt[:user], :msg => opt[:msg],  :from => opt[:from] +      @web.put '/nodes/next/' + node.to_s, data +    end + +  end +end diff --git a/extra/syslog.rb b/extra/syslog.rb new file mode 100755 index 0000000..10757bc --- /dev/null +++ b/extra/syslog.rb @@ -0,0 +1,111 @@ +#!/usr/bin/env ruby + +# IOS: +# logging discriminator CFG mnemonics includes CONFIG_I  +# logging host SERVER discriminator CFG + +# JunOS: +# set system syslog host SERVER interactive-commands notice +# set system syslog host SERVER match "^mgd\[[0-9]+\]: UI_COMMIT: .*" + +# sudo setcap 'cap_net_bind_service=+ep' /usr/bin/ruby + +# exit if fork   ## TODO: proper daemonize + +require 'socket' +require 'resolv' +require './rest_client' + +module Oxidized +  class SyslogMonitor +    NAME_MAP = { +      /(.*)\.ip\.tdc\.net/ => '\1', +      /(.*)\.ip\.fi/       => '\1', +    } +    PORT = 514 +    FILE = 'messages' +    MSG = { +      :ios   => '%SYS-5-CONFIG_I:', +      :junos => 'UI_COMMIT:', +    } + +    class << self +      def udp port=PORT, listen=0 +        io = UDPSocket.new +        io.bind listen, port +        new io, :udp +      end +      def file syslog_file=FILE +        io = open syslog_file, 'r' +        io.seek 0, IO::SEEK_END +        new io, :file +      end +    end + +    private  + +    def initialize io, mode=:udp +      @mode = mode +      run io +    end + +    def rest opt +      Oxidized::RestClient.next opt[:name], :user => opt[:user], :msg => opt[:msg], +                                            :from => opt[:from] +    end + +    def ios ip, log, i +      # TODO: we need to fetch 'ip/name' in mode == :file here +      user = log[i+5] +      from = log[-1][1..-2] +      rest( :user => user, :from => from, :model => 'ios', :ip => ip, +            :name => getname(ip) ) +    end + +    def jnpr ip, log, i +      # TODO: we need to fetch 'ip/name' in mode == :file here +      user = log[i+2][1..-2] +      msg  = log[(i+6)..-1].join(' ')[10..-2] +      msg  = nil if msg == 'none' +      rest( :user => user, :msg => msg, :model => 'jnpr', :ip => ip, +            :name => getname(ip) ) +    end + +    def handle_log log, ip +      log = log.to_s.split ' ' +      if i = log.index(MSG[:ios]) +        ios ip, log,  i +      elsif i = log.index(MSG[:junos]) +        jnpr ip, log, i +      end +    end + +    def run io +      while true +        log = select [io] +        log, ip = log.first.first, nil +        if @mode == :udp +          log, ip = log.recvfrom_nonblock 2000 +          ip = ip.last +        else  +          begin +            log = log.read_nonblock 2000 +          rescue EOFError +            sleep 1 +            retry +          end +        end +        handle_log log, ip +      end +    end + +    def getname ip +      name = (Resolv.getname ip.to_s rescue ip) +      NAME_MAP.each { |re, sub| name.sub! re, sub } +      name +    end +  end +end + +Oxidized::SyslogMonitor.udp +#Oxidized::SyslogMonitor.file '/var/log/poop' | 
