diff options
| -rw-r--r-- | README.md | 34 | ||||
| -rwxr-xr-x | extra/oxidized.init.d | 87 | ||||
| -rw-r--r-- | lib/oxidized/config.rb | 4 | ||||
| -rw-r--r-- | lib/oxidized/input/ssh.rb | 18 | ||||
| -rw-r--r-- | lib/oxidized/model/edgeswitch.rb | 6 | ||||
| -rw-r--r-- | lib/oxidized/model/fortios.rb | 5 | ||||
| -rw-r--r-- | lib/oxidized/model/ipos.rb | 37 | ||||
| -rw-r--r-- | lib/oxidized/model/mtrlrfs.rb | 37 | ||||
| -rw-r--r-- | lib/oxidized/model/nos.rb | 2 | ||||
| -rw-r--r-- | lib/oxidized/model/xos.rb | 6 | ||||
| -rw-r--r-- | lib/oxidized/output/http.rb | 58 | 
11 files changed, 280 insertions, 14 deletions
| @@ -31,6 +31,7 @@ Oxidized is a network device configuration backup tool. It's a RANCID replacemen      * [Source: SQLite](#source-sqlite)      * [Source: HTTP](#source-http)      * [Output: GIT](#output-git) +    * [Output: HTTP](#output-http)      * [Output: File](#output-file)      * [Output types](#output-types)      * [Advanced Configuration](#advanced-configuration) @@ -75,8 +76,11 @@ Oxidized is a network device configuration backup tool. It's a RANCID replacemen   * DELL     * PowerConnect     * AOSW + * Ericsson/Redback +   * IPOS (former SEOS)   * Extreme Networks     * XOS +   * WM   * F5     * TMOS   * Force10 @@ -94,6 +98,8 @@ Oxidized is a network device configuration backup tool. It's a RANCID replacemen     * ScreenOS (Netscreen)   * Mikrotik     * RouterOS + * Motorola +   * RFS   * MRV     * MasterOS   * Opengear @@ -136,6 +142,21 @@ Oxidized configuration is in YAML format. Configuration files are subsequently s  To initialize a default configuration in your home directory ```~/.config/oxidized/config```, simply run ```oxidized``` once. If you don't further configure anything from the output and source sections, it'll extend the examples on a subsequent ```oxidized``` execution. This is useful to see what options for a specific source or output backend are available. +You can set the env variable `OXIDIZED_HOME` to change its home directory. + +``` +OXIDIZED_HOME=/etc/oxidized + +$ tree -L 1 /etc/oxidized +/etc/oxidized/ +├── config +├── log-router-ssh +├── log-router-telnet +├── pid +├── router.db +└── repository.git +``` +  ## Source  Oxidized supports ```CSV```, ```SQLite``` and ```HTTP``` as source backends. The CSV backend reads nodes from a rancid compatible router.db file. The SQLite backend will fire queries against a database and map certain fields to model items. The HTTP backend will fire queries against a http/https url. Take a look at the [Cookbook](#cookbook) for more details. @@ -390,6 +411,19 @@ output:  ``` +### Output: Http + +POST a config to the specified URL + +``` +output: +  default: http +  http: +    user: admin +    password: changeit +    url: "http://192.168.162.50:8080/db/coll" +``` +  ### Output types  If you prefer to have different outputs in different files and/or directories, you can easily do this by modifying the corresponding model. To change the behaviour for IOS, you would edit `lib/oxidized/model/ios.rb`. diff --git a/extra/oxidized.init.d b/extra/oxidized.init.d new file mode 100755 index 0000000..d2fdf00 --- /dev/null +++ b/extra/oxidized.init.d @@ -0,0 +1,87 @@ +#!/bin/sh +# chkconfig: - 99 01 +# description: Oxidized - Network Device Configuration Backup Tool +# processname: /opt/ruby-2.1/bin/oxidized + +# Source function library +. /etc/rc.d/init.d/functions + +name="oxidized" +desc="Oxidized" +cmd=oxidized +args="--daemonize" +lockfile=/var/lock/subsys/$name +pidfile=/etc/oxidized/pid + +export OXIDIZED_HOME=/etc/oxidized + +# Source sysconfig configuration +[ -r /etc/sysconfig/$name ] && . /etc/sysconfig/$name + +start() { +    echo -n $"Starting $desc: " +    daemon ${cmd} ${args} +    retval=$? +    if [ $retval = 0 ] +    then +        echo_success +        touch $lockfile +    else +        echo_failure +    fi +    echo +    return $retval +} + +stop() { +    echo -n $"Stopping $desc: " +    killproc -p $pidfile +    retval=$? +    [ $retval -eq 0 ] && rm -f $lockfile +    rm -f $pidfile +    echo +    return $retval +} + +restart() { +    stop +    start +} + +reload() { +  echo -n $"Reloading config..." +  curl -s http://localhost:8888/reload?format=json -O /dev/null +  echo +} + +rh_status() { +    status -p $pidfile $cmd +} + +rh_status_q() { +    rh_status >/dev/null 2>&1 +} + +case "$1" in +    start) +        rh_status_q && exit 0 +        $1 +        ;; +    stop) +        rh_status_q || exit 0 +        $1 +        ;; +    restart) +        $1 +        ;; +    reload) +        rh_status_q || exit 0 +        $1 +        ;; +    status) +        rh_status +        ;; +    *) +        echo $"Usage: $0 {start|stop|restart|reload|status}" +        exit 2 +esac diff --git a/lib/oxidized/config.rb b/lib/oxidized/config.rb index d2d12d8..7884625 100644 --- a/lib/oxidized/config.rb +++ b/lib/oxidized/config.rb @@ -3,7 +3,7 @@ module Oxidized    class NoConfig < OxidizedError; end    class InvalidConfig < OxidizedError; end    class Config -    Root      = File.join ENV['HOME'], '.config', 'oxidized' +    Root      = ENV['OXIDIZED_HOME'] || File.join(ENV['HOME'], '.config', 'oxidized')      Crash     = File.join Root, 'crash'      Log       = File.join Root, 'log'      InputDir  = File.join Directory, %w(lib oxidized input) @@ -27,7 +27,7 @@ module Oxidized        asetus.default.timeout       = 20        asetus.default.retries       = 3        asetus.default.prompt        = /^([\w.@-]+[#>]\s?)$/ -        asetus.default.rest          = '127.0.0.1:8888' # or false to disable +      asetus.default.rest          = '127.0.0.1:8888' # or false to disable        asetus.default.vars          = {}             # could be 'enable'=>'enablePW'        asetus.default.groups        = {}             # group level configuration diff --git a/lib/oxidized/input/ssh.rb b/lib/oxidized/input/ssh.rb index e7296b5..7ffdd36 100644 --- a/lib/oxidized/input/ssh.rb +++ b/lib/oxidized/input/ssh.rb @@ -26,12 +26,18 @@ module Oxidized        if proxy_host = vars(:proxy)          proxy =  Net::SSH::Proxy::Command.new("ssh #{proxy_host} nc %h %p")        end -      @ssh = Net::SSH.start(@node.ip, @node.auth[:username], :port => port.to_i, -                            :password => @node.auth[:password], :timeout => Oxidized.config.timeout, -                            :paranoid => secure, -                            :auth_methods => %w(none publickey password keyboard-interactive), -                            :number_of_password_prompts => 0, -                            :proxy => proxy) +      ssh_opts = { +        :port => port.to_i, +        :password => @node.auth[:password], :timeout => Oxidized.config.timeout, +        :paranoid => secure, +        :auth_methods => %w(none publickey password keyboard-interactive), +        :number_of_password_prompts => 0, +        :proxy => proxy +      } +      ssh_opts[:kex] = vars(:ssh_kex).split(/,\s*/) if vars(:ssh_kex) +      ssh_opts[:encryption] = vars(:ssh_encryption).split(/,\s*/) if vars(:ssh_encryption) + +      @ssh = Net::SSH.start(@node.ip, @node.auth[:username], ssh_opts)        unless @exec          shell_open @ssh          begin diff --git a/lib/oxidized/model/edgeswitch.rb b/lib/oxidized/model/edgeswitch.rb index 89a5690..31014da 100644 --- a/lib/oxidized/model/edgeswitch.rb +++ b/lib/oxidized/model/edgeswitch.rb @@ -7,12 +7,12 @@ class EdgeSwitch < Oxidized::Model    prompt /[(]\w*\s\w*[)][\s#>]*[\s#>]/    cmd 'show running-config' do |cfg| -    comment cfg.each_line.reject { |line| line.match /System Up Time.*/ or line.match /Current SNTP Synchronized Time.*/ }.join +    cfg.each_line.reject { |line| line.match /System Up Time.*/ or line.match /Current SNTP Synchronized Time.*/ }.join    end    cfg :telnet do      username /Username:\s/ -    passsword /^Password:\s/ +    password /^Password:\s/    end    cfg :telnet, :ssh do @@ -22,4 +22,4 @@ class EdgeSwitch < Oxidized::Model      pre_logout 'exit'    end -end
\ No newline at end of file +end diff --git a/lib/oxidized/model/fortios.rb b/lib/oxidized/model/fortios.rb index 3515b46..92add0e 100644 --- a/lib/oxidized/model/fortios.rb +++ b/lib/oxidized/model/fortios.rb @@ -4,6 +4,11 @@ class FortiOS < Oxidized::Model    prompt /^([-\w\.]+(\s[\(\w\-\.\)]+)?\~?\s?[#>]\s?)$/ +  expect /^--More--\s$/ do |data, re| +    send ' ' +    data.sub re, '' +  end +    cmd :all do |cfg, cmdstring|      new_cfg = comment "COMMAND: #{cmdstring}\n"      new_cfg << cfg.each_line.to_a[1..-2].map { |line| line.gsub(/(conf_file_ver=)(.*)/, '\1<stripped>\3') }.join diff --git a/lib/oxidized/model/ipos.rb b/lib/oxidized/model/ipos.rb new file mode 100644 index 0000000..1a77807 --- /dev/null +++ b/lib/oxidized/model/ipos.rb @@ -0,0 +1,37 @@ +class IPOS < Oxidized::Model + +  # Ericsson SSR (IPOS) +  # Redback SE (SEOS) + +  prompt /^([\[\]\w.@-]+[#>]\s?)$/ +  comment '! ' + +  cmd 'show chassis' do |cfg| +    comment cfg +  end + +  cmd 'show hardware detail' do |cfg| +    comment cfg +  end + +  cmd 'show release' do |cfg| +    comment cfg +  end + +  cmd 'show config' + +  cfg :telnet do +    username /^login:/ +    password /^\r*password:/ +  end + +  cfg :telnet, :ssh do +    post_login 'terminal length 0' +    pre_logout do +      send "exit\n" +      send "n\n" +    end +  end + +end + diff --git a/lib/oxidized/model/mtrlrfs.rb b/lib/oxidized/model/mtrlrfs.rb new file mode 100644 index 0000000..84bcfe1 --- /dev/null +++ b/lib/oxidized/model/mtrlrfs.rb @@ -0,0 +1,37 @@ +class mtrlrfs < Oxidized::Model + +  # Motorola RFS/Extreme WM + +  comment  '# ' + +  cmd :all do |cfg| +    # xos inserts leading \r characters and other trailing white space. +    # this deletes extraneous \r and trailing white space. +    cfg.each_line.to_a[1..-2].map{|line|line.delete("\r").rstrip}.join("\n") + "\n" +  end + +  cmd 'show version' do |cfg| +    comment cfg +  end + +  cmd 'show licenses' do |cfg| +    comment cfg +  end + +  cmd 'show running-config' + +  cfg :telnet do +    username /^login:/ +    password /^\r*password:/ +  end + +  cfg :telnet, :ssh do +    post_login 'terminal length 0' +    pre_logout do +      send "exit\n" +      send "n\n" +    end +  end + +end + diff --git a/lib/oxidized/model/nos.rb b/lib/oxidized/model/nos.rb index 18ca6a2..bd2cb0f 100644 --- a/lib/oxidized/model/nos.rb +++ b/lib/oxidized/model/nos.rb @@ -33,7 +33,7 @@ class NOS < Oxidized::Model    cfg :telnet do      username /^.* login: / -    username /^Password:/ +    password /^Password:/    end    cfg :telnet, :ssh do diff --git a/lib/oxidized/model/xos.rb b/lib/oxidized/model/xos.rb index de8ec39..6f1323f 100644 --- a/lib/oxidized/model/xos.rb +++ b/lib/oxidized/model/xos.rb @@ -36,8 +36,10 @@ class XOS < Oxidized::Model    cfg :telnet, :ssh do      post_login 'disable clipaging' -    pre_logout 'exit' -    pre_logout 'n' +    pre_logout do +      send "exit\n" +      send "n\n" +    end    end  end diff --git a/lib/oxidized/output/http.rb b/lib/oxidized/output/http.rb new file mode 100644 index 0000000..13ba300 --- /dev/null +++ b/lib/oxidized/output/http.rb @@ -0,0 +1,58 @@ +module Oxidized +  class Http < Output +    attr_reader :commitref +    def initialize +      @cfg = Oxidized.config.output.http +    end + +    def setup +      if @cfg.empty? +        CFGS.user.output.http.user  = 'Oxidized' +        CFGS.user.output.http.pasword = 'secret' +        CFGS.user.output.http.url  =  'http://localhost/web-api/oxidized' +        CFGS.save :user +        raise NoConfig, 'no output http config, edit ~/.config/oxidized/config' +      end +    end +    require "net/http" +    require "uri" +    require "json" +    def store node, outputs, opt={} +      @commitref = nil +      json = JSON.pretty_generate( +          { +              'msg' => opt[:msg], +              'user' => opt[:user], +              'email' => opt[:email], +              'group' => opt[:group], +              'node' => node, +              'config' => outputs.to_cfg, +              # actually we need to also iterate outputs, for other types like in gitlab. But most people don't use 'type' functionality. +          } +      ) +      uri = URI.parse @cfg.url +      http = Net::HTTP.new uri.host, uri.port +      #http.use_ssl = true if uri.scheme = 'https' +      req = Net::HTTP::Post.new(uri.request_uri, initheader = { 'Content-Type' => 'application/json'}) +      req.basic_auth @cfg.user, @cfg.password +      req.body = json +      response = http.request req + +      case response.code.to_i +        when 200 || 201 +          Oxidized.logger.info "Configuration http backup complete for #{node}" +          p [:success] +        when (400..499) +          Oxidized.logger.info "Configuration http backup for #{node} failed status: #{response.body}" +          p [:bad_request] +        when (500..599) +          p [:server_problems] +          Oxidized.logger.info "Configuration http backup for #{node} failed status: #{response.body}" +      end + +    end + +  end +end + + | 
