summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.rubocop_todo.yml2
-rw-r--r--CHANGELOG.md4
-rw-r--r--README.md2
-rw-r--r--docs/Supported-OS-Types.md1
-rw-r--r--lib/oxidized/input/telnet.rb20
-rw-r--r--lib/oxidized/model/boss.rb4
-rw-r--r--lib/oxidized/model/opengear.rb2
-rw-r--r--lib/oxidized/model/openwrt.rb77
-rw-r--r--lib/oxidized/source/csv.rb2
-rw-r--r--lib/oxidized/worker.rb7
10 files changed, 108 insertions, 13 deletions
diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml
index 77c1026..6598a37 100644
--- a/.rubocop_todo.yml
+++ b/.rubocop_todo.yml
@@ -140,7 +140,7 @@ Metrics/CyclomaticComplexity:
# Offense count: 53
# Configuration parameters: CountComments.
Metrics/MethodLength:
- Max: 72
+ Max: 75
# Offense count: 2
# Configuration parameters: CountKeywordArgs.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0e03883..4e7f09e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,9 @@
# Changelog
+## Master
+
+* FEATURE: openwrt model (@z00nx)
+
## 0.21.0
* FEATURE: routeros include system history (@InsaneSplash)
diff --git a/README.md b/README.md
index d5bbf81..bb19d64 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# Oxidized [![Build Status](https://travis-ci.org/ytti/oxidized.svg)](https://travis-ci.org/ytti/oxidized) [![codecov.io](https://codecov.io/gh/ytti/oxidized/coverage.svg?branch=master)](https://codecov.io/gh/ytti/oxidized?branch=master) [![Gem Version](https://badge.fury.io/rb/oxidized.svg)](http://badge.fury.io/rb/oxidized) [![Join the chat at https://gitter.im/oxidized/Lobby](https://badges.gitter.im/oxidized/Lobby.svg)](https://gitter.im/oxidized/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
+# Oxidized [![Build Status](https://api.travis-ci.com/ytti/oxidized.svg)](https://travis-ci.com/ytti/oxidized) [![codecov.io](https://codecov.io/gh/ytti/oxidized/coverage.svg?branch=master)](https://codecov.io/gh/ytti/oxidized?branch=master) [![Gem Version](https://badge.fury.io/rb/oxidized.svg)](http://badge.fury.io/rb/oxidized) [![Join the chat at https://gitter.im/oxidized/Lobby](https://badges.gitter.im/oxidized/Lobby.svg)](https://gitter.im/oxidized/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
Oxidized is a network device configuration backup tool. It's a RANCID replacement!
diff --git a/docs/Supported-OS-Types.md b/docs/Supported-OS-Types.md
index 8839cc3..75845b9 100644
--- a/docs/Supported-OS-Types.md
+++ b/docs/Supported-OS-Types.md
@@ -127,6 +127,7 @@
* [OneOS](/lib/oxidized/model/oneos.rb)
* Opengear
* [Opengear](/lib/oxidized/model/opengear.rb)
+* [OpenWRT](/lib/oxidized/model/openwrt.rb)
* [OPNsense](/lib/oxidized/model/opnsense.rb)
* Palo Alto
* [PANOS](/lib/oxidized/model/panos.rb)
diff --git a/lib/oxidized/input/telnet.rb b/lib/oxidized/input/telnet.rb
index b1b3222..e7c2ee3 100644
--- a/lib/oxidized/input/telnet.rb
+++ b/lib/oxidized/input/telnet.rb
@@ -10,15 +10,15 @@ module Oxidized
@node = node
@timeout = Oxidized.config.timeout
@node.model.cfg['telnet'].each { |cb| instance_exec(&cb) }
+ @log = File.open(Oxidized::Config::Log + "/#{@node.ip}-telnet", 'w') if Oxidized.config.input.debug?
port = vars(:telnet_port) || 23
- opt = { 'Host' => @node.ip,
- 'Port' => port.to_i,
- 'Timeout' => @timeout,
- 'Model' => @node.model }
- opt['Output_log'] = Oxidized::Config::Log + "/#{@node.ip}-telnet" if Oxidized.config.input.debug?
+ telnet_opts = { 'Host' => @node.ip,
+ 'Port' => port.to_i,
+ 'Timeout' => @timeout,
+ 'Model' => @node.model }
- @telnet = Net::Telnet.new opt
+ @telnet = Net::Telnet.new telnet_opts
if @node.auth[:username] and @node.auth[:username].length > 0
expect username
@telnet.puts @node.auth[:username]
@@ -62,6 +62,9 @@ module Oxidized
disconnect_cli
@telnet.close
rescue Errno::ECONNRESET
+ ensure
+ @log.close if Oxidized.config.input.debug?
+ (@telnet.close rescue true) unless @telnet.closed?
end
end
end
@@ -137,7 +140,10 @@ class Net::Telnet
buf.gsub!(/#{EOL}/no, "\n")
end
end
- @log.print(buf) if @options.has_key?("Output_log")
+ if Oxidized.config.input.debug?
+ @log.print buf
+ @log.flush
+ end
line += buf
line = model.expects line
line = yield line if block_given?
diff --git a/lib/oxidized/model/boss.rb b/lib/oxidized/model/boss.rb
index cf762ee..0adf4c0 100644
--- a/lib/oxidized/model/boss.rb
+++ b/lib/oxidized/model/boss.rb
@@ -1,5 +1,5 @@
class Boss < Oxidized::Model
- # Avaya Baystack Operating System Software(BOSS)
+ # Extreme Baystack Operating System Software(BOSS)
# Created by danielcoxman@gmail.com
# May 15, 2017
# This was tested on ers3510, ers5530, ers4850, ers5952
@@ -28,6 +28,8 @@ class Boss < Oxidized::Model
expect /ommand Line Interface\.\.\./ do |data, re|
send "c"
data.sub re, ''
+ send "\n"
+ data.sub re, ''
end
# needed for proper formatting
diff --git a/lib/oxidized/model/opengear.rb b/lib/oxidized/model/opengear.rb
index e0d4c0a..1f94edb 100644
--- a/lib/oxidized/model/opengear.rb
+++ b/lib/oxidized/model/opengear.rb
@@ -1,7 +1,7 @@
class OpenGear < Oxidized::Model
comment '# '
- prompt /^(\$\s)?$/
+ prompt /^(\$\s)$/
cmd :secret do |cfg|
cfg.gsub!(/password (\S+)/, 'password <secret removed>')
diff --git a/lib/oxidized/model/openwrt.rb b/lib/oxidized/model/openwrt.rb
new file mode 100644
index 0000000..7ba9e98
--- /dev/null
+++ b/lib/oxidized/model/openwrt.rb
@@ -0,0 +1,77 @@
+class OpenWrt < Oxidized::Model
+ prompt /^[^#]+#/
+ comment '#'
+
+ cmd 'cat /etc/banner' do |cfg|
+ comment "#### Info: /etc/banner #####\n#{cfg}"
+ end
+
+ cmd 'cat /proc/cpuinfo' do |cfg|
+ comment "#### Info: /proc/cpuinfo #####\n#{cfg}"
+ end
+
+ cmd 'cat /etc/openwrt_release' do |cfg|
+ comment "#### Info: /etc/openwrt_release #####\n#{cfg}"
+ end
+
+ cmd 'sysupgrade -l' do |cfg|
+ @sysupgradefiles = cfg
+ comment "#### Info: sysupgrade -l #####\n#{cfg}"
+ end
+
+ cmd 'cat /proc/mtd' do |cfg|
+ @mtdpartitions = cfg
+ comment "#### Info: /proc/mtd #####\n#{cfg}"
+ end
+
+ post do
+ cfg = []
+ binary_files = vars(:openwrt_binary_files) || %w[/etc/dropbear/dropbear_rsa_host_key]
+ non_sensitive_files = vars(:openwrt_non_sensitive_files) || %w[rpcd uhttpd]
+ partitions_to_backup = vars(:openwrt_partitions_to_backup) || %w[art devinfo u_env config caldata]
+ @sysupgradefiles.lines.each do |sysupgradefile|
+ sysupgradefile = sysupgradefile.strip
+ if sysupgradefile.start_with?('/etc/config/')
+ unless sysupgradefile.end_with?('-opkg')
+ filename = sysupgradefile.split('/')[-1]
+ cfg << comment("#### File: #{sysupgradefile} #####")
+ uciexport = cmd("uci export #{filename}")
+ Oxidized.logger.debug "Exporting uci config - #{filename}"
+ if vars(:remove_secret) && !(non_sensitive_files.include? filename)
+ Oxidized.logger.debug "Scrubbing uci config - #{filename}"
+ uciexport.gsub!(/^(\s+option\s+(password|key)\s+')[^']+'/, '\\1<secret hidden>\'')
+ end
+ cfg << uciexport
+ end
+ elsif binary_files.include? sysupgradefile
+ Oxidized.logger.debug "Exporting binary file - #{sysupgradefile}"
+ cfg << comment("#### Binary file: #{sysupgradefile} #####")
+ cfg << comment("Decode using 'echo -en <data> | gzip -dc > #{sysupgradefile}'")
+ cfg << cmd("gzip -c #{sysupgradefile} | hexdump -ve '1/1 \"_x%.2x\"' | tr _ \\")
+ elsif vars(:remove_secret) && sysupgradefile == '/etc/shadow'
+ Oxidized.logger.debug 'Exporting and scrubbing /etc/shadow'
+ cfg << comment("#### File: #{sysupgradefile} #####")
+ shadow = cmd("cat #{sysupgradefile}")
+ shadow.gsub!(/^([^:]+:)[^:]*(:[^:]*:[^:]*:[^:]*:[^:]*:[^:]*:[^:]*:)/, '\\1\\2')
+ cfg << shadow
+ else
+ Oxidized.logger.debug "Exporting file - #{sysupgradefile}"
+ cfg << comment("#### File: #{sysupgradefile} #####")
+ cfg << cmd("cat #{sysupgradefile}")
+ end
+ end
+ @mtdpartitions.scan(/(\w+):\s+\w+\s+\w+\s+"(.*)"/).each do |partition, name|
+ next unless vars(:openwrt_backup_partitions) && partitions_to_backup.include?(name)
+ Oxidized.logger.debug "Exporting partition - #{name}(#{partition})"
+ cfg << comment("#### Partition: #{name} /dev/#{partition} #####")
+ cfg << comment("Decode using 'echo -en <data> | gzip -dc > #{name}'")
+ cfg << cmd("dd if=/dev/#{partition} 2>/dev/null | gzip -c | hexdump -ve '1/1 \"%.2x\"'")
+ end
+ cfg.join "\n"
+ end
+
+ cfg :ssh do
+ exec true
+ pre_logout 'exit'
+ end
+end
diff --git a/lib/oxidized/source/csv.rb b/lib/oxidized/source/csv.rb
index ae1c0a9..7b771f6 100644
--- a/lib/oxidized/source/csv.rb
+++ b/lib/oxidized/source/csv.rb
@@ -18,7 +18,7 @@ module Oxidized
require 'gpgme' if @cfg.gpg?
end
- def load
+ def load _node_want = nil
nodes = []
file = File.expand_path(@cfg.file)
file = if @cfg.gpg?
diff --git a/lib/oxidized/worker.rb b/lib/oxidized/worker.rb
index 692b060..5d5fc01 100644
--- a/lib/oxidized/worker.rb
+++ b/lib/oxidized/worker.rb
@@ -42,9 +42,9 @@ module Oxidized
node.stats.add job
@jobs.duration job.time
node.running = false
- @jobs_done += 1 # needed for worker_done event
if job.status == :success
+ @jobs_done += 1 # needed for :nodes_done hook
Oxidized.Hooks.handle :node_success, :node => node,
:job => job
msg = "update #{node.name}"
@@ -66,6 +66,11 @@ module Oxidized
msg += ", retry attempt #{node.retry}"
@nodes.next node.name
else
+ # Only increment the @jobs_done when we give up retries for a node (or success).
+ # As it would otherwise cause @jobs_done to be incremented with generic retries.
+ # This would cause :nodes_done hook to desync from running at the end of the nodelist and
+ # be fired when the @jobs_done > @nodes.count (could be mid-cycle on the next cycle).
+ @jobs_done += 1
msg += ", retries exhausted, giving up"
node.retry = 0
Oxidized.Hooks.handle :node_fail, :node => node,