oxidized 0.12.2 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 6abed81dacfe3d68bc4abd336da9ba97b39f47a7
4
+ data.tar.gz: 5110c826165ef2d14c19369e0c6662fde52c7bd6
5
+ SHA512:
6
+ metadata.gz: 96c4383cfa03d6ef2def511de0b23c2b28c4d275caa3f16f1c9e2b926514245ad8bdf945a0726892152fcda4a04454b43ec7cab6d0f10cb474dc6a4974767839
7
+ data.tar.gz: f6292b48c50e0d74d971df1345c7d391ef44b9a003eb429482f90e113f59633b2cf30b3227e8b8a372b1ff8203a169b49963f5bec75bb0f00d6f2f8a73de081a
data/.travis.yml CHANGED
@@ -1,3 +1,5 @@
1
1
  language: ruby
2
+ sudo: false
3
+ cache: bundler
2
4
  rvm:
3
5
  - 2.1.6
data/CHANGELOG.md CHANGED
@@ -1,3 +1,18 @@
1
+ # 0.13.0
2
+ - FEATURE: http post for configs (by @jgroom33)
3
+ - FEATURE: support ericsson redbacks (by @roedie)
4
+ - FEATURE: support motorola wireless controllers (by @roadie)
5
+ - FEATURE: support citrix netscaler (by @roadie)
6
+ - FEATURE: support datacom devices (by @danilopopeye)
7
+ - FEATURE: support netonix devices
8
+ - FEATURE: support specifying ssh cipher and kex (by @roadie)
9
+ - FEATURE: rename proxy to ssh_proxy (by @roadie)
10
+ - FEATURE: support ssh keys on ssh_proxy (by @awix)
11
+ - BUGFIX: various (by @danilopopeye)
12
+ - BUGFIX: Node#repo with groups (by @danilopopeye)
13
+ - BUGFIX: githubrepohoook (by @danilopopeye)
14
+ - BUGFIX: fortios, airos, junos, xos, edgeswitch, nos, tmos, procurve, ipos models
15
+
1
16
  # 0.12.2
2
17
  - BUGFIX: more MRV model fixes (by @natm)
3
18
 
@@ -12,7 +27,7 @@
12
27
  - FEATURE: EdgeSwitch support (by @doogieconsulting)
13
28
  - BUGFIX: rename input debug log files
14
29
  - BUGFIX: powerconnect model fixes (by @Madpilot0)
15
- - BUGFIX: fortigate model fixes (by @ElvinEfendi)
30
+ - BUGFIX: fortigate model fixes (by @ElvinEfendi)
16
31
  - BUGFIX: various (by @mikebryant)
17
32
  - BUGFIX: write SSH debug to file without buffering
18
33
  - BUGFIX: fix IOS XR prompt handling
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- oxidized (0.11.0)
4
+ oxidized (0.12.2)
5
5
  asetus (~> 0.1)
6
6
  net-ssh (~> 3.0, >= 3.0.2)
7
7
  rugged (~> 0.21, >= 0.21.4)
data/README.md CHANGED
@@ -31,6 +31,7 @@ Oxidized is a network device configuration backup tool. It's a RANCID replacemen
31
31
  * [Source: SQLite](#source-sqlite)
32
32
  * [Source: HTTP](#source-http)
33
33
  * [Output: GIT](#output-git)
34
+ * [Output: HTTP](#output-http)
34
35
  * [Output: File](#output-file)
35
36
  * [Output types](#output-types)
36
37
  * [Advanced Configuration](#advanced-configuration)
@@ -70,13 +71,20 @@ Oxidized is a network device configuration backup tool. It's a RANCID replacemen
70
71
  * IOSXR
71
72
  * NXOS
72
73
  * SMB (Nikola series)
74
+ * Citrix
75
+ * NetScaler (Virtual Applicance)
73
76
  * Cumulus
74
77
  * Linux
78
+ * DataCom
79
+ * DmSwitch 3000
75
80
  * DELL
76
81
  * PowerConnect
77
82
  * AOSW
83
+ * Ericsson/Redback
84
+ * IPOS (former SEOS)
78
85
  * Extreme Networks
79
86
  * XOS
87
+ * WM
80
88
  * F5
81
89
  * TMOS
82
90
  * Force10
@@ -94,8 +102,12 @@ Oxidized is a network device configuration backup tool. It's a RANCID replacemen
94
102
  * ScreenOS (Netscreen)
95
103
  * Mikrotik
96
104
  * RouterOS
105
+ * Motorola
106
+ * RFS
97
107
  * MRV
98
108
  * MasterOS
109
+ * Netonix
110
+ * WISP Switch (As Netonix)
99
111
  * Opengear
100
112
  * Opengear
101
113
  * Palo Alto
@@ -121,7 +133,7 @@ gem install oxidized-script oxidized-web # if you don't install oxidized-web, ma
121
133
  ## CentOS, Oracle Linux, Red Hat Linux version 6
122
134
  Install Ruby 1.9.3 or greater (for Ruby 2.1.2 installation instructions see "Installing Ruby 2.1.2 using RVM"), then install Oxidized dependencies
123
135
  ```shell
124
- yum install cmake sqlite-devel openssl-devel
136
+ yum install cmake sqlite-devel openssl-devel libssh2-devel
125
137
  ```
126
138
 
127
139
  Now lets install oxidized via Rubygems:
@@ -136,6 +148,21 @@ Oxidized configuration is in YAML format. Configuration files are subsequently s
136
148
 
137
149
  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.
138
150
 
151
+ You can set the env variable `OXIDIZED_HOME` to change its home directory.
152
+
153
+ ```
154
+ OXIDIZED_HOME=/etc/oxidized
155
+
156
+ $ tree -L 1 /etc/oxidized
157
+ /etc/oxidized/
158
+ ├── config
159
+ ├── log-router-ssh
160
+ ├── log-router-telnet
161
+ ├── pid
162
+ ├── router.db
163
+ └── repository.git
164
+ ```
165
+
139
166
  ## Source
140
167
 
141
168
  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.
@@ -181,7 +208,7 @@ Install Ruby 2.1.2 build dependencies
181
208
  ```
182
209
  yum install curl gcc-c++ patch readline readline-devel zlib zlib-devel
183
210
  yum install libyaml-devel libffi-devel openssl-devel make cmake
184
- yum install bzip2 autoconf automake libtool bison iconv-devel
211
+ yum install bzip2 autoconf automake libtool bison iconv-devel libssh2-devel
185
212
  ```
186
213
 
187
214
  Install RVM
@@ -283,7 +310,7 @@ source:
283
310
 
284
311
  ### SSH Proxy Command
285
312
 
286
- Oxidized can `ssh` through a proxy as well. To do so we just need to set `proxy` variable.
313
+ Oxidized can `ssh` through a proxy as well. To do so we just need to set `ssh_proxy` variable.
287
314
 
288
315
  ```
289
316
  ...
@@ -292,7 +319,7 @@ map:
292
319
  model: 1
293
320
  vars_map:
294
321
  enable: 2
295
- proxy: 3
322
+ ssh_proxy: 3
296
323
  ...
297
324
  ```
298
325
 
@@ -354,13 +381,53 @@ output:
354
381
 
355
382
  This uses the rugged/libgit2 interface. So you should remember that normal Git hooks will not be executed.
356
383
 
384
+
385
+ For a single repositories for all devices:
386
+
387
+ ``` yaml
388
+ output:
389
+ default: git
390
+ git:
391
+ user: Oxidized
392
+ email: o@example.com
393
+ repo: "/var/lib/oxidized/devices.git"
357
394
  ```
395
+
396
+ And for groups repositories:
397
+
398
+ ``` yaml
358
399
  output:
359
400
  default: git
360
401
  git:
361
402
  user: Oxidized
362
403
  email: o@example.com
404
+ repo:
405
+ first: "/var/lib/oxidized/first.git"
406
+ second: "/var/lib/oxidized/second.git"
407
+ ```
408
+
409
+ If you would like to use groups and a single repository, you can force this with the `single_repo` config.
410
+
411
+ ``` yaml
412
+ output:
413
+ default: git
414
+ git:
415
+ single_repo: true
363
416
  repo: "/var/lib/oxidized/devices.git"
417
+
418
+ ```
419
+
420
+ ### Output: Http
421
+
422
+ POST a config to the specified URL
423
+
424
+ ```
425
+ output:
426
+ default: http
427
+ http:
428
+ user: admin
429
+ password: changeit
430
+ url: "http://192.168.162.50:8080/db/coll"
364
431
  ```
365
432
 
366
433
  ### Output types
@@ -525,6 +592,42 @@ hooks:
525
592
  timeout: 120
526
593
  ```
527
594
 
595
+ ### githubrepo
596
+
597
+ This hook configures the repository `remote` and _push_ the code when the specified event is triggerd. If the `username` and `password` are not provided, the `Rugged::Credentials::SshKeyFromAgent` will be used.
598
+
599
+ `githubrepo` hook recognizes following configuration keys:
600
+
601
+ * `remote_repo`: the remote repository to be pushed to.
602
+ * `username`: username for repository auth.
603
+ * `password`: password for repository auth.
604
+ * `publickey`: publickey for repository auth.
605
+ * `privatekey`: privatekey for repository auth.
606
+
607
+ When using groups repositories, each group must have its own `remote` in the `remote_repo` config.
608
+
609
+ ``` yaml
610
+ hooks:
611
+ push_to_remote:
612
+ remote_repo:
613
+ routers: git@git.intranet:oxidized/routers.git
614
+ switches: git@git.intranet:oxidized/switches.git
615
+ firewalls: git@git.intranet:oxidized/firewalls.git
616
+ ```
617
+
618
+
619
+ ## Hook configuration example
620
+
621
+ ``` yaml
622
+ hooks:
623
+ push_to_remote:
624
+ type: githubrepo
625
+ events: [post_store]
626
+ remote_repo: git@git.intranet:oxidized/test.git
627
+ username: user
628
+ password: pass
629
+ ```
630
+
528
631
  # Ruby API
529
632
 
530
633
  The following objects exist in Oxidized.
@@ -0,0 +1,87 @@
1
+ #!/bin/sh
2
+ # chkconfig: - 99 01
3
+ # description: Oxidized - Network Device Configuration Backup Tool
4
+ # processname: /opt/ruby-2.1/bin/oxidized
5
+
6
+ # Source function library
7
+ . /etc/rc.d/init.d/functions
8
+
9
+ name="oxidized"
10
+ desc="Oxidized"
11
+ cmd=oxidized
12
+ args="--daemonize"
13
+ lockfile=/var/lock/subsys/$name
14
+ pidfile=/etc/oxidized/pid
15
+
16
+ export OXIDIZED_HOME=/etc/oxidized
17
+
18
+ # Source sysconfig configuration
19
+ [ -r /etc/sysconfig/$name ] && . /etc/sysconfig/$name
20
+
21
+ start() {
22
+ echo -n $"Starting $desc: "
23
+ daemon ${cmd} ${args}
24
+ retval=$?
25
+ if [ $retval = 0 ]
26
+ then
27
+ echo_success
28
+ touch $lockfile
29
+ else
30
+ echo_failure
31
+ fi
32
+ echo
33
+ return $retval
34
+ }
35
+
36
+ stop() {
37
+ echo -n $"Stopping $desc: "
38
+ killproc -p $pidfile
39
+ retval=$?
40
+ [ $retval -eq 0 ] && rm -f $lockfile
41
+ rm -f $pidfile
42
+ echo
43
+ return $retval
44
+ }
45
+
46
+ restart() {
47
+ stop
48
+ start
49
+ }
50
+
51
+ reload() {
52
+ echo -n $"Reloading config..."
53
+ curl -s http://localhost:8888/reload?format=json -O /dev/null
54
+ echo
55
+ }
56
+
57
+ rh_status() {
58
+ status -p $pidfile $cmd
59
+ }
60
+
61
+ rh_status_q() {
62
+ rh_status >/dev/null 2>&1
63
+ }
64
+
65
+ case "$1" in
66
+ start)
67
+ rh_status_q && exit 0
68
+ $1
69
+ ;;
70
+ stop)
71
+ rh_status_q || exit 0
72
+ $1
73
+ ;;
74
+ restart)
75
+ $1
76
+ ;;
77
+ reload)
78
+ rh_status_q || exit 0
79
+ $1
80
+ ;;
81
+ status)
82
+ rh_status
83
+ ;;
84
+ *)
85
+ echo $"Usage: $0 {start|stop|restart|reload|status}"
86
+ exit 2
87
+ esac
data/lib/oxidized.rb CHANGED
@@ -3,6 +3,7 @@ module Oxidized
3
3
 
4
4
  Directory = File.expand_path(File.join(File.dirname(__FILE__), '../'))
5
5
 
6
+ require 'oxidized/version'
6
7
  require 'oxidized/string'
7
8
  require 'oxidized/config'
8
9
  require 'oxidized/config/vars'
data/lib/oxidized/cli.rb CHANGED
@@ -43,6 +43,10 @@ module Oxidized
43
43
  opts = Slop.new(:help=>true) do
44
44
  on 'd', 'debug', 'turn on debugging'
45
45
  on 'daemonize', 'Daemonize/fork the process'
46
+ on 'v', 'version', 'show version' do
47
+ puts Oxidized::VERSION
48
+ Kernel.exit
49
+ end
46
50
  end
47
51
  [opts.parse!, opts]
48
52
  end
@@ -3,7 +3,7 @@ module Oxidized
3
3
  class NoConfig < OxidizedError; end
4
4
  class InvalidConfig < OxidizedError; end
5
5
  class Config
6
- Root = File.join ENV['HOME'], '.config', 'oxidized'
6
+ Root = ENV['OXIDIZED_HOME'] || File.join(ENV['HOME'], '.config', 'oxidized')
7
7
  Crash = File.join Root, 'crash'
8
8
  Log = File.join Root, 'log'
9
9
  InputDir = File.join Directory, %w(lib oxidized input)
@@ -27,7 +27,7 @@ module Oxidized
27
27
  asetus.default.timeout = 20
28
28
  asetus.default.retries = 3
29
29
  asetus.default.prompt = /^([\w.@-]+[#>]\s?)$/
30
- asetus.default.rest = '127.0.0.1:8888' # or false to disable
30
+ asetus.default.rest = '127.0.0.1:8888' # or false to disable
31
31
  asetus.default.vars = {} # could be 'enable'=>'enablePW'
32
32
  asetus.default.groups = {} # group level configuration
33
33
 
@@ -1,12 +1,12 @@
1
1
  class GithubRepo < Oxidized::Hook
2
2
  def validate_cfg!
3
- cfg.has_key?('remote_repo') or raise KeyError, 'remote_repo is required'
3
+ raise KeyError, 'hook.remote_repo is required' unless cfg.has_key?('remote_repo')
4
4
  end
5
5
 
6
6
  def run_hook(ctx)
7
- repo = Rugged::Repository.new(Oxidized.config.output.git.repo)
7
+ repo = Rugged::Repository.new(ctx.node.repo)
8
8
  log "Pushing local repository(#{repo.path})..."
9
- remote = repo.remotes['origin'] || repo.remotes.create('origin', cfg.remote_repo)
9
+ remote = repo.remotes['origin'] || repo.remotes.create('origin', remote_repo(ctx.node))
10
10
  log "to remote: #{remote.url}"
11
11
 
12
12
  fetch_and_merge_remote(repo)
@@ -49,9 +49,21 @@ class GithubRepo < Oxidized::Hook
49
49
  log "Using https auth", :debug
50
50
  Rugged::Credentials::UserPassword.new(username: cfg.username, password: cfg.password)
51
51
  else
52
- log "Using ssh auth", :debug
53
- Rugged::Credentials::SshKeyFromAgent.new(username: 'git')
52
+ if cfg.has_key?('publickey') && cfg.has_key?('privatekey')
53
+ log "Using ssh auth with key", :debug
54
+ Rugged::Credentials::SshKey.new(username: 'git', publickey: File.expand_path(cfg.publickey), privatekey: File.expand_path(cfg.privatekey))
55
+ else
56
+ log "Using ssh auth with agentforwarding", :debug
57
+ Rugged::Credentials::SshKeyFromAgent.new(username: 'git')
58
+ end
54
59
  end
55
60
  end
56
61
 
62
+ def remote_repo(node)
63
+ if node.group.nil? || cfg.remote_repo.is_a?(String)
64
+ cfg.remote_repo
65
+ else
66
+ cfg.remote_repo[node.group]
67
+ end
68
+ end
57
69
  end
@@ -23,15 +23,21 @@ module Oxidized
23
23
  secure = Oxidized.config.input.ssh.secure
24
24
  @log = File.open(Oxidized::Config::Log + "-#{@node.ip}-ssh", 'w') if Oxidized.config.input.debug?
25
25
  port = vars(:ssh_port) || 22
26
- if proxy_host = vars(:proxy)
27
- proxy = Net::SSH::Proxy::Command.new("ssh #{proxy_host} nc %h %p")
26
+ if proxy_host = vars(:ssh_proxy)
27
+ proxy = Net::SSH::Proxy::Command.new("ssh #{proxy_host} -W %h:%p")
28
28
  end
29
- @ssh = Net::SSH.start(@node.ip, @node.auth[:username], :port => port.to_i,
30
- :password => @node.auth[:password], :timeout => Oxidized.config.timeout,
31
- :paranoid => secure,
32
- :auth_methods => %w(none publickey password keyboard-interactive),
33
- :number_of_password_prompts => 0,
34
- :proxy => proxy)
29
+ ssh_opts = {
30
+ :port => port.to_i,
31
+ :password => @node.auth[:password], :timeout => Oxidized.config.timeout,
32
+ :paranoid => secure,
33
+ :auth_methods => %w(none publickey password keyboard-interactive),
34
+ :number_of_password_prompts => 0,
35
+ :proxy => proxy
36
+ }
37
+ ssh_opts[:kex] = vars(:ssh_kex).split(/,\s*/) if vars(:ssh_kex)
38
+ ssh_opts[:encryption] = vars(:ssh_encryption).split(/,\s*/) if vars(:ssh_encryption)
39
+
40
+ @ssh = Net::SSH.start(@node.ip, @node.auth[:username], ssh_opts)
35
41
  unless @exec
36
42
  shell_open @ssh
37
43
  begin
@@ -86,7 +92,7 @@ module Oxidized
86
92
  @output << data
87
93
  @output = @node.model.expects @output
88
94
  end
89
- ch.request_pty (opts={:term=>'vt100'}) do |_ch, success_pty|
95
+ ch.request_pty (_opts={:term=>'vt100'}) do |_ch, success_pty|
90
96
  raise NoShell, "Can't get PTY" unless success_pty
91
97
  ch.send_channel_request 'shell' do |_ch, success_shell|
92
98
  raise NoShell, "Can't get shell" unless success_shell
@@ -7,7 +7,7 @@ class Airos < Oxidized::Model
7
7
  cfg.split("\n").map { |line| "# #{line}" }.join("\n") + "\n"
8
8
  end
9
9
 
10
- cmd 'cat /tmp/system.cfg'
10
+ cmd 'sort /tmp/system.cfg'
11
11
 
12
12
  cmd :secret do |cfg|
13
13
  cfg.gsub! /^(users\.\d+\.password|snmp\.community)=.+/, "# \\1=<hidden>"
@@ -0,0 +1,33 @@
1
+ class DataCom < Oxidized::Model
2
+
3
+ comment '! '
4
+
5
+ expect /^--More--\s+$/ do |data, re|
6
+ send ' '
7
+ data.sub re, ''
8
+ end
9
+
10
+ cmd :all do |cfg|
11
+ cfg.each_line.to_a[1..-2].join
12
+ cfg.cut_head.cut_tail
13
+ end
14
+
15
+ cmd 'show firmware' do |cfg|
16
+ comment cfg
17
+ end
18
+
19
+ cmd 'show system' do |cfg|
20
+ comment cfg
21
+ end
22
+
23
+ cmd 'show running-config' do |cfg|
24
+ cfg.cut_head
25
+ end
26
+
27
+ cfg :telnet, :ssh do
28
+ username /login:\s$/
29
+ password /^Password:\s$/
30
+ pre_logout 'exit'
31
+ end
32
+
33
+ end
@@ -4,22 +4,29 @@ class EdgeSwitch < Oxidized::Model
4
4
 
5
5
  comment '!'
6
6
 
7
- prompt /[(]\w*\s\w*[)][\s#>]*[\s#>]/
7
+ prompt /\(.*\)\s[#>]/
8
8
 
9
9
  cmd 'show running-config' do |cfg|
10
- comment cfg.each_line.reject { |line| line.match /System Up Time.*/ or line.match /Current SNTP Synchronized Time.*/ }.join
10
+ cfg.each_line.to_a[2..-2].reject { |line| line.match /System Up Time.*/ or line.match /Current SNTP Synchronized Time.*/ }.join
11
11
  end
12
12
 
13
13
  cfg :telnet do
14
14
  username /Username:\s/
15
- passsword /^Password:\s/
15
+ password /^Password:\s/
16
16
  end
17
17
 
18
18
  cfg :telnet, :ssh do
19
- post_login 'enable'
20
- post_login 'terminal length 0'
21
- pre_logout 'exit'
22
- pre_logout 'exit'
19
+ post_login do
20
+ if vars :enable
21
+ send "enable\n"
22
+ cmd vars(:enable)
23
+ else
24
+ cmd 'enable'
25
+ end
26
+ cmd 'terminal length 0'
27
+ end
28
+ pre_logout 'quit'
29
+ pre_logout 'n'
23
30
  end
24
31
 
25
- end
32
+ end
@@ -2,11 +2,16 @@ class FortiOS < Oxidized::Model
2
2
 
3
3
  comment '# '
4
4
 
5
- prompt /^([-\w\.]+(\s[\(\w\-\.\)]+)?\~?\s?[#>]\s?)$/
5
+ prompt /^([-\w\.]+(\s[\(\w\-\.\)]+)?\~?\s?[#>$]\s?)$/
6
+
7
+ expect /^--More--\s$/ do |data, re|
8
+ send ' '
9
+ data.sub re, ''
10
+ end
6
11
 
7
12
  cmd :all do |cfg, cmdstring|
8
13
  new_cfg = comment "COMMAND: #{cmdstring}\n"
9
- new_cfg << cfg.each_line.to_a[1..-2].join
14
+ new_cfg << cfg.each_line.to_a[1..-2].map { |line| line.gsub(/(conf_file_ver=)(.*)/, '\1<stripped>\3') }.join
10
15
  end
11
16
 
12
17
  cmd 'get system status' do |cfg|
@@ -25,6 +25,10 @@ class IOS < Oxidized::Model
25
25
  cmd :secret do |cfg|
26
26
  cfg.gsub! /^(snmp-server community).*/, '\\1 <configuration removed>'
27
27
  cfg.gsub! /username (\S+) privilege (\d+) (\S+).*/, '<secret hidden>'
28
+ cfg.gsub! /^username \S+ password \d \S+/, '<secret hidden>'
29
+ cfg.gsub! /^enable password \d \S+/, '<secret hidden>'
30
+ cfg.gsub! /wpa-psk ascii \d \S+/, '<secret hidden>'
31
+ cfg.gsub! /^tacacs-server key \d \S+/, '<secret hidden>'
28
32
  cfg
29
33
  end
30
34
 
@@ -0,0 +1,61 @@
1
+ class IPOS < Oxidized::Model
2
+
3
+ # Ericsson SSR (IPOS)
4
+ # Redback SE (SEOS)
5
+
6
+ prompt /^([\[\]\w.@-]+[#>]\s?)$/
7
+ comment '! '
8
+
9
+ cmd 'show chassis' do |cfg|
10
+ comment cfg.each_line.to_a[0..-2].join
11
+ end
12
+
13
+ cmd 'show hardware' do |cfg|
14
+ comment cfg.each_line.to_a[0..-2].join
15
+ end
16
+
17
+ cmd 'show release' do |cfg|
18
+ comment cfg.each_line.to_a[0..-2].join
19
+ end
20
+
21
+ cmd 'show configuration' do |cfg|
22
+ # SEOS regularly adds some odd line breaks in random places
23
+ # when showing the config, triggering changes.
24
+ cfg.gsub! "\r\n", "\n"
25
+
26
+ cfg = cfg.each_line.to_a
27
+
28
+ # Keeps the issued command commented but removes the uncommented "Building configuration..."
29
+ # and "Current configuration:" lines as well as the last prompt at the end.
30
+ cfg = cfg[4..-2].unshift comment cfg[0]
31
+
32
+ # Later IPOS releases add this line in addition to the usual "last changed" line.
33
+ # It's touched regularly (as often as multiple times per minute) by the OS without actual visible config changes.
34
+ cfg = cfg.reject { |line| line.match "Configuration last changed by system user" }
35
+
36
+ # Earlier IPOS releases lack the "changed by system user" line and instead overwrite
37
+ # the single "last changed by user" line. Because the line has a timestamp it will
38
+ # trigger constant changes if not removed. By doing so there will only be a single
39
+ # extra change trigged after an actual config change by a user but still have the
40
+ # real user.
41
+ cfg = cfg.reject { |line| line.match "Configuration last changed by user '%LICM%' at" }
42
+ cfg = cfg.reject { |line| line.match "Configuration last changed by user '<NO USER>' at" }
43
+ cfg = cfg.reject { |line| line.match "Configuration last changed by user '' at" }
44
+
45
+ cfg.join
46
+ end
47
+
48
+ cfg :telnet do
49
+ username /^login:/
50
+ password /^\r*password:/
51
+ end
52
+
53
+ cfg :telnet, :ssh do
54
+ post_login 'terminal length 0'
55
+ pre_logout do
56
+ send "exit\n"
57
+ send "n\n"
58
+ end
59
+ end
60
+
61
+ end
@@ -30,6 +30,8 @@ class JunOS < Oxidized::Model
30
30
  case @model
31
31
  when 'mx960'
32
32
  out << cmd('show chassis fabric reachability') { |cfg| comment cfg }
33
+ when /^(ex22|ex33|ex4|ex8|qfx)/
34
+ out << cmd('show virtual-chassis') { |cfg| comment cfg }
33
35
  end
34
36
  out
35
37
  end
@@ -0,0 +1,37 @@
1
+ class Mtrlrfs < Oxidized::Model
2
+
3
+ # Motorola RFS/Extreme WM
4
+
5
+ comment '# '
6
+
7
+ cmd :all do |cfg|
8
+ # xos inserts leading \r characters and other trailing white space.
9
+ # this deletes extraneous \r and trailing white space.
10
+ cfg.each_line.to_a[1..-2].map{|line|line.delete("\r").rstrip}.join("\n") + "\n"
11
+ end
12
+
13
+ cmd 'show version' do |cfg|
14
+ comment cfg
15
+ end
16
+
17
+ cmd 'show licenses' do |cfg|
18
+ comment cfg
19
+ end
20
+
21
+ cmd 'show running-config'
22
+
23
+ cfg :telnet do
24
+ username /^login:/
25
+ password /^\r*password:/
26
+ end
27
+
28
+ cfg :telnet, :ssh do
29
+ post_login 'terminal length 0'
30
+ pre_logout do
31
+ send "exit\n"
32
+ send "n\n"
33
+ end
34
+ end
35
+
36
+ end
37
+
@@ -0,0 +1,15 @@
1
+ class Netonix < Oxidized::Model
2
+ prompt /^[\w\s.@_\/:-]+#/
3
+
4
+ cmd :all do |cfg|
5
+ cfg.each_line.to_a[1..-2].join
6
+ end
7
+
8
+ cmd 'cat config.json;echo'
9
+
10
+ cfg :ssh do
11
+ post_login 'cmdline'
12
+ pre_logout 'exit'
13
+ pre_logout 'exit'
14
+ end
15
+ end
@@ -0,0 +1,24 @@
1
+ class NetScaler < Oxidized::Model
2
+
3
+ prompt /^\>\s*$/
4
+ comment '# '
5
+
6
+ cmd :all do |cfg|
7
+ cfg.each_line.to_a[1..-3].join
8
+ end
9
+
10
+ cmd 'show version' do |cfg|
11
+ comment cfg
12
+ end
13
+
14
+ cmd 'show hardware' do |cfg|
15
+ comment cfg
16
+ end
17
+
18
+ cmd 'show ns ns.conf'
19
+
20
+ cfg :ssh do
21
+ pre_logout 'exit'
22
+ end
23
+
24
+ end
@@ -33,7 +33,7 @@ class NOS < Oxidized::Model
33
33
 
34
34
  cfg :telnet do
35
35
  username /^.* login: /
36
- username /^Password:/
36
+ password /^Password:/
37
37
  end
38
38
 
39
39
  cfg :telnet, :ssh do
@@ -1,36 +1,49 @@
1
1
  class Procurve < Oxidized::Model
2
2
 
3
- # FIXME: this is way too unsafe
4
- prompt /.*?(\w+# ).*/m
3
+ # some models start lines with \r
4
+ # previous command is repeated followed by "\eE", which sometimes ends up on last line
5
+ prompt /^\r?([\w -]+\eE)?([\w-]+# )$/
5
6
 
6
7
  comment '! '
7
8
 
9
+ # replace all used vt100 control sequences
10
+ expect /\e\[\??\d+(;\d+)*[A-Za-z]/ do |data, re|
11
+ data.gsub re, ''
12
+ end
13
+
8
14
  expect /Press any key to continue/ do
9
- send ' '
10
- ""
15
+ send ' '
16
+ ""
11
17
  end
12
18
 
13
19
  cmd :all do |cfg|
14
20
  cfg = cfg.each_line.to_a[1..-3].join
15
- cfg = cfg.gsub /\r/, ''
16
- new_cfg = ''
17
- cfg.each_line do |line|
18
- line.sub! /^\e.*(\e.*)/, '\1' #leave last escape
19
- line.sub! /\e\[24;1H/, '' #remove last escape, is it always this?
20
- new_cfg << line
21
- end
22
- new_cfg
21
+ cfg = cfg.gsub /^\r/, ''
22
+ end
23
+
24
+ cmd :secret do |cfg|
25
+ cfg.gsub! /^(snmp-server community).*/, '\\1 <configuration removed>'
26
+ cfg.gsub! /^(snmp-server host).*/, '\\1 <configuration removed>'
27
+ cfg.gsub! /^(radius-server host).*/, '\\1 <configuration removed>'
28
+ cfg
23
29
  end
24
30
 
25
31
  cmd 'show version' do |cfg|
26
32
  comment cfg
27
33
  end
28
34
 
35
+ # not supported on all models
29
36
  cmd 'show system-information' do |cfg|
30
37
  cfg = cfg.split("\n")[0..-8].join("\n")
31
38
  comment cfg
32
39
  end
33
40
 
41
+ # not supported on all models
42
+ cmd 'show system information' do |cfg|
43
+ cfg = cfg.split("\n")[0..-8].join("\n")
44
+ comment cfg
45
+ end
46
+
34
47
  cmd 'show running-config'
35
48
 
36
49
  cfg :telnet do
@@ -22,25 +22,27 @@ class TMOS < Oxidized::Model
22
22
 
23
23
  cmd('cat /config/bigip.license') { |cfg| comment cfg }
24
24
 
25
- cmd 'tmsh list' do |cfg|
26
- cfg.gsub!(/state (up|down)/, '')
25
+ cmd 'tmsh -q list' do |cfg|
26
+ cfg.gsub!(/state (up|down|checking|irule-down)/, '')
27
27
  cfg.gsub!(/errors (\d+)/, '')
28
28
  cfg
29
29
  end
30
30
 
31
- cmd('tmsh list net route all') { |cfg| comment cfg }
31
+ cmd('tmsh -q list net route all') { |cfg| comment cfg }
32
32
 
33
33
  cmd('/bin/ls --full-time --color=never /config/ssl/ssl.crt') { |cfg| comment cfg }
34
34
 
35
35
  cmd('/bin/ls --full-time --color=never /config/ssl/ssl.key') { |cfg| comment cfg }
36
36
 
37
- cmd 'tmsh show running-config sys db all-properties' do |cfg|
37
+ cmd 'tmsh -q show running-config sys db all-properties' do |cfg|
38
38
  cfg.gsub!(/sys db configsync.localconfigtime {[^}]+}/m, '')
39
39
  cfg.gsub!(/sys db gtm.configtime {[^}]+}/m, '')
40
40
  cfg.gsub!(/sys db ltm.configtime {[^}]+}/m, '')
41
41
  comment cfg
42
42
  end
43
43
 
44
+ cmd('cat /config/partitions/*/bigip.conf') { |cfg| comment cfg }
45
+
44
46
  cfg :ssh do
45
47
  exec true # don't run shell, run each command in exec channel
46
48
  end
@@ -36,8 +36,10 @@ class XOS < Oxidized::Model
36
36
 
37
37
  cfg :telnet, :ssh do
38
38
  post_login 'disable clipaging'
39
- pre_logout 'exit'
40
- pre_logout 'n'
39
+ pre_logout do
40
+ send "exit\n"
41
+ send "n\n"
42
+ end
41
43
  end
42
44
 
43
45
  end
data/lib/oxidized/node.rb CHANGED
@@ -24,7 +24,7 @@ module Oxidized
24
24
  @vars = opt[:vars]
25
25
  @stats = Stats.new
26
26
  @retry = 0
27
- @repo = Oxidized.config.output.git.repo
27
+ @repo = resolve_repo
28
28
 
29
29
  # model instance needs to access node instance
30
30
  @model.node = self
@@ -170,5 +170,15 @@ module Oxidized
170
170
  Oxidized.mgr.model[model].new
171
171
  end
172
172
 
173
+ def resolve_repo
174
+ remote_repo = Oxidized.config.output.git.repo
175
+
176
+ if Oxidized.config.output.git.single_repo? || @group.nil? || remote_repo.is_a?(String)
177
+ remote_repo
178
+ else
179
+ remote_repo[@group]
180
+ end
181
+ end
182
+
173
183
  end
174
184
  end
@@ -0,0 +1,58 @@
1
+ module Oxidized
2
+ class Http < Output
3
+ attr_reader :commitref
4
+ def initialize
5
+ @cfg = Oxidized.config.output.http
6
+ end
7
+
8
+ def setup
9
+ if @cfg.empty?
10
+ CFGS.user.output.http.user = 'Oxidized'
11
+ CFGS.user.output.http.pasword = 'secret'
12
+ CFGS.user.output.http.url = 'http://localhost/web-api/oxidized'
13
+ CFGS.save :user
14
+ raise NoConfig, 'no output http config, edit ~/.config/oxidized/config'
15
+ end
16
+ end
17
+ require "net/http"
18
+ require "uri"
19
+ require "json"
20
+ def store node, outputs, opt={}
21
+ @commitref = nil
22
+ json = JSON.pretty_generate(
23
+ {
24
+ 'msg' => opt[:msg],
25
+ 'user' => opt[:user],
26
+ 'email' => opt[:email],
27
+ 'group' => opt[:group],
28
+ 'node' => node,
29
+ 'config' => outputs.to_cfg,
30
+ # actually we need to also iterate outputs, for other types like in gitlab. But most people don't use 'type' functionality.
31
+ }
32
+ )
33
+ uri = URI.parse @cfg.url
34
+ http = Net::HTTP.new uri.host, uri.port
35
+ #http.use_ssl = true if uri.scheme = 'https'
36
+ req = Net::HTTP::Post.new(uri.request_uri, initheader = { 'Content-Type' => 'application/json'})
37
+ req.basic_auth @cfg.user, @cfg.password
38
+ req.body = json
39
+ response = http.request req
40
+
41
+ case response.code.to_i
42
+ when 200 || 201
43
+ Oxidized.logger.info "Configuration http backup complete for #{node}"
44
+ p [:success]
45
+ when (400..499)
46
+ Oxidized.logger.info "Configuration http backup for #{node} failed status: #{response.body}"
47
+ p [:bad_request]
48
+ when (500..599)
49
+ p [:server_problems]
50
+ Oxidized.logger.info "Configuration http backup for #{node} failed status: #{response.body}"
51
+ end
52
+
53
+ end
54
+
55
+ end
56
+ end
57
+
58
+
@@ -1,3 +1,3 @@
1
1
  module Oxidized
2
- VERSION = '0.12.2'
2
+ VERSION = '0.13.0'
3
3
  end
metadata CHANGED
@@ -1,8 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: oxidized
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.12.2
5
- prerelease:
4
+ version: 0.13.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Saku Ytti
@@ -11,162 +10,144 @@ authors:
11
10
  autorequire:
12
11
  bindir: bin
13
12
  cert_chain: []
14
- date: 2016-02-06 00:00:00.000000000 Z
13
+ date: 2016-03-30 00:00:00.000000000 Z
15
14
  dependencies:
16
15
  - !ruby/object:Gem::Dependency
17
16
  name: asetus
18
17
  requirement: !ruby/object:Gem::Requirement
19
- none: false
20
18
  requirements:
21
- - - ~>
19
+ - - "~>"
22
20
  - !ruby/object:Gem::Version
23
21
  version: '0.1'
24
22
  type: :runtime
25
23
  prerelease: false
26
24
  version_requirements: !ruby/object:Gem::Requirement
27
- none: false
28
25
  requirements:
29
- - - ~>
26
+ - - "~>"
30
27
  - !ruby/object:Gem::Version
31
28
  version: '0.1'
32
29
  - !ruby/object:Gem::Dependency
33
30
  name: slop
34
31
  requirement: !ruby/object:Gem::Requirement
35
- none: false
36
32
  requirements:
37
- - - ~>
33
+ - - "~>"
38
34
  - !ruby/object:Gem::Version
39
35
  version: '3.5'
40
36
  type: :runtime
41
37
  prerelease: false
42
38
  version_requirements: !ruby/object:Gem::Requirement
43
- none: false
44
39
  requirements:
45
- - - ~>
40
+ - - "~>"
46
41
  - !ruby/object:Gem::Version
47
42
  version: '3.5'
48
43
  - !ruby/object:Gem::Dependency
49
44
  name: net-ssh
50
45
  requirement: !ruby/object:Gem::Requirement
51
- none: false
52
46
  requirements:
53
- - - ~>
47
+ - - "~>"
54
48
  - !ruby/object:Gem::Version
55
49
  version: '3.0'
56
- - - ! '>='
50
+ - - ">="
57
51
  - !ruby/object:Gem::Version
58
52
  version: 3.0.2
59
53
  type: :runtime
60
54
  prerelease: false
61
55
  version_requirements: !ruby/object:Gem::Requirement
62
- none: false
63
56
  requirements:
64
- - - ~>
57
+ - - "~>"
65
58
  - !ruby/object:Gem::Version
66
59
  version: '3.0'
67
- - - ! '>='
60
+ - - ">="
68
61
  - !ruby/object:Gem::Version
69
62
  version: 3.0.2
70
63
  - !ruby/object:Gem::Dependency
71
64
  name: rugged
72
65
  requirement: !ruby/object:Gem::Requirement
73
- none: false
74
66
  requirements:
75
- - - ~>
67
+ - - "~>"
76
68
  - !ruby/object:Gem::Version
77
69
  version: '0.21'
78
- - - ! '>='
70
+ - - ">="
79
71
  - !ruby/object:Gem::Version
80
72
  version: 0.21.4
81
73
  type: :runtime
82
74
  prerelease: false
83
75
  version_requirements: !ruby/object:Gem::Requirement
84
- none: false
85
76
  requirements:
86
- - - ~>
77
+ - - "~>"
87
78
  - !ruby/object:Gem::Version
88
79
  version: '0.21'
89
- - - ! '>='
80
+ - - ">="
90
81
  - !ruby/object:Gem::Version
91
82
  version: 0.21.4
92
83
  - !ruby/object:Gem::Dependency
93
84
  name: pry
94
85
  requirement: !ruby/object:Gem::Requirement
95
- none: false
96
86
  requirements:
97
- - - ~>
87
+ - - "~>"
98
88
  - !ruby/object:Gem::Version
99
89
  version: '0'
100
90
  type: :development
101
91
  prerelease: false
102
92
  version_requirements: !ruby/object:Gem::Requirement
103
- none: false
104
93
  requirements:
105
- - - ~>
94
+ - - "~>"
106
95
  - !ruby/object:Gem::Version
107
96
  version: '0'
108
97
  - !ruby/object:Gem::Dependency
109
98
  name: bundler
110
99
  requirement: !ruby/object:Gem::Requirement
111
- none: false
112
100
  requirements:
113
- - - ~>
101
+ - - "~>"
114
102
  - !ruby/object:Gem::Version
115
103
  version: '1.10'
116
104
  type: :development
117
105
  prerelease: false
118
106
  version_requirements: !ruby/object:Gem::Requirement
119
- none: false
120
107
  requirements:
121
- - - ~>
108
+ - - "~>"
122
109
  - !ruby/object:Gem::Version
123
110
  version: '1.10'
124
111
  - !ruby/object:Gem::Dependency
125
112
  name: rake
126
113
  requirement: !ruby/object:Gem::Requirement
127
- none: false
128
114
  requirements:
129
- - - ~>
115
+ - - "~>"
130
116
  - !ruby/object:Gem::Version
131
117
  version: '10.0'
132
118
  type: :development
133
119
  prerelease: false
134
120
  version_requirements: !ruby/object:Gem::Requirement
135
- none: false
136
121
  requirements:
137
- - - ~>
122
+ - - "~>"
138
123
  - !ruby/object:Gem::Version
139
124
  version: '10.0'
140
125
  - !ruby/object:Gem::Dependency
141
126
  name: minitest
142
127
  requirement: !ruby/object:Gem::Requirement
143
- none: false
144
128
  requirements:
145
- - - ~>
129
+ - - "~>"
146
130
  - !ruby/object:Gem::Version
147
131
  version: '5.8'
148
132
  type: :development
149
133
  prerelease: false
150
134
  version_requirements: !ruby/object:Gem::Requirement
151
- none: false
152
135
  requirements:
153
- - - ~>
136
+ - - "~>"
154
137
  - !ruby/object:Gem::Version
155
138
  version: '5.8'
156
139
  - !ruby/object:Gem::Dependency
157
140
  name: mocha
158
141
  requirement: !ruby/object:Gem::Requirement
159
- none: false
160
142
  requirements:
161
- - - ~>
143
+ - - "~>"
162
144
  - !ruby/object:Gem::Version
163
145
  version: '1.1'
164
146
  type: :development
165
147
  prerelease: false
166
148
  version_requirements: !ruby/object:Gem::Requirement
167
- none: false
168
149
  requirements:
169
- - - ~>
150
+ - - "~>"
170
151
  - !ruby/object:Gem::Version
171
152
  version: '1.1'
172
153
  description: software to fetch configuration from network devices and store them
@@ -179,7 +160,7 @@ executables:
179
160
  extensions: []
180
161
  extra_rdoc_files: []
181
162
  files:
182
- - .travis.yml
163
+ - ".travis.yml"
183
164
  - CHANGELOG.md
184
165
  - Dockerfile
185
166
  - Gemfile
@@ -193,6 +174,7 @@ files:
193
174
  - extra/nagios_check_failing_nodes.rb
194
175
  - extra/oxidized-report-git-commits
195
176
  - extra/oxidized.init
177
+ - extra/oxidized.init.d
196
178
  - extra/oxidized.runit
197
179
  - extra/oxidized.service
198
180
  - extra/oxidized.supervisord
@@ -228,6 +210,7 @@ files:
228
210
  - lib/oxidized/model/ciscosmb.rb
229
211
  - lib/oxidized/model/comware.rb
230
212
  - lib/oxidized/model/cumulus.rb
213
+ - lib/oxidized/model/datacom.rb
231
214
  - lib/oxidized/model/dnos.rb
232
215
  - lib/oxidized/model/edgeos.rb
233
216
  - lib/oxidized/model/edgeswitch.rb
@@ -237,11 +220,15 @@ files:
237
220
  - lib/oxidized/model/ftos.rb
238
221
  - lib/oxidized/model/ios.rb
239
222
  - lib/oxidized/model/iosxr.rb
223
+ - lib/oxidized/model/ipos.rb
240
224
  - lib/oxidized/model/ironware.rb
241
225
  - lib/oxidized/model/isam.rb
242
226
  - lib/oxidized/model/junos.rb
243
227
  - lib/oxidized/model/masteros.rb
244
228
  - lib/oxidized/model/model.rb
229
+ - lib/oxidized/model/mtrlrfs.rb
230
+ - lib/oxidized/model/netonix.rb
231
+ - lib/oxidized/model/netscaler.rb
245
232
  - lib/oxidized/model/nos.rb
246
233
  - lib/oxidized/model/nxos.rb
247
234
  - lib/oxidized/model/opengear.rb
@@ -263,6 +250,7 @@ files:
263
250
  - lib/oxidized/nodes.rb
264
251
  - lib/oxidized/output/file.rb
265
252
  - lib/oxidized/output/git.rb
253
+ - lib/oxidized/output/http.rb
266
254
  - lib/oxidized/output/output.rb
267
255
  - lib/oxidized/source/csv.rb
268
256
  - lib/oxidized/source/http.rb
@@ -275,26 +263,25 @@ files:
275
263
  homepage: http://github.com/ytti/oxidized
276
264
  licenses:
277
265
  - Apache-2.0
266
+ metadata: {}
278
267
  post_install_message:
279
268
  rdoc_options: []
280
269
  require_paths:
281
270
  - lib
282
271
  required_ruby_version: !ruby/object:Gem::Requirement
283
- none: false
284
272
  requirements:
285
- - - ! '>='
273
+ - - ">="
286
274
  - !ruby/object:Gem::Version
287
275
  version: 2.0.0
288
276
  required_rubygems_version: !ruby/object:Gem::Requirement
289
- none: false
290
277
  requirements:
291
- - - ! '>='
278
+ - - ">="
292
279
  - !ruby/object:Gem::Version
293
280
  version: '0'
294
281
  requirements: []
295
282
  rubyforge_project: oxidized
296
- rubygems_version: 1.8.23
283
+ rubygems_version: 2.5.1
297
284
  signing_key:
298
- specification_version: 3
285
+ specification_version: 4
299
286
  summary: feeble attempt at rancid
300
287
  test_files: []