summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md38
-rw-r--r--README.md155
-rwxr-xr-x[-rw-r--r--]extra/nagios_check_failing_nodes.rb0
-rwxr-xr-x[-rw-r--r--]extra/oxidized.init0
-rwxr-xr-xextra/oxidized.init.d87
-rwxr-xr-x[-rw-r--r--]extra/syslog.rb0
-rw-r--r--lib/oxidized/cli.rb2
-rw-r--r--lib/oxidized/config.rb5
-rw-r--r--lib/oxidized/hook/githubrepo.rb22
-rw-r--r--lib/oxidized/input/ssh.rb6
-rw-r--r--lib/oxidized/model/acos.rb22
-rw-r--r--lib/oxidized/model/asa.rb18
-rw-r--r--lib/oxidized/model/catos.rb36
-rw-r--r--lib/oxidized/model/comware.rb2
-rw-r--r--lib/oxidized/model/datacom.rb33
-rw-r--r--lib/oxidized/model/edgeswitch.rb23
-rw-r--r--lib/oxidized/model/fortios.rb2
-rw-r--r--lib/oxidized/model/iosxr.rb2
-rw-r--r--lib/oxidized/model/ipos.rb61
-rw-r--r--lib/oxidized/model/ironware.rb1
-rw-r--r--lib/oxidized/model/mtrlrfs.rb37
-rw-r--r--lib/oxidized/model/netonix.rb15
-rw-r--r--lib/oxidized/model/netscaler.rb24
-rw-r--r--lib/oxidized/model/nos.rb2
-rw-r--r--lib/oxidized/model/procurve.rb37
-rw-r--r--lib/oxidized/model/supermicro.rb45
-rw-r--r--lib/oxidized/model/tmos.rb26
-rw-r--r--lib/oxidized/model/xos.rb6
-rw-r--r--lib/oxidized/node.rb12
-rw-r--r--lib/oxidized/output/git.rb30
-rw-r--r--lib/oxidized/output/http.rb58
-rw-r--r--lib/oxidized/version.rb2
-rw-r--r--oxidized.gemspec12
-rw-r--r--spec/cli_spec.rb3
-rw-r--r--spec/githubrepo_spec.rb109
-rw-r--r--spec/input/ssh_spec.rb4
-rw-r--r--spec/node_spec.rb46
37 files changed, 884 insertions, 99 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b59e03d..cea6fb4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,39 @@
+# 0.14.3
+- BUGFIX: fix git when using multiple groups without single_repo
+
+# 0.14.2
+- BUGFIX: git expand path for all groups
+- BUGFIX: git get_version, teletubbies do it again
+- BUGFIX: comware, acos, procurve models
+
+# 0.14.1
+- BUGFIX: git get_version when groups and single_repo are used
+
+# 0.14.0
+- FEATURE: support supermicro swithes (by @funzoneq)
+- FEATURE: support catos switches
+- BUGFIX: git+groups+singlerepo (by @PANZERBARON)
+- BUGFIX: asa, tmos, ironware, ios-xr
+- BUGFIX: mandate net-ssh 3.0.x, don't accept 3.1 (numerous issues)
+
+# 0.13.1
+- BUGFIX: file permissions (Sigh...)
+
+# 0.13.0
+- FEATURE: http post for configs (by @jgroom33)
+- FEATURE: support ericsson redbacks (by @roedie)
+- FEATURE: support motorola wireless controllers (by @roadie)
+- FEATURE: support citrix netscaler (by @roadie)
+- FEATURE: support datacom devices (by @danilopopeye)
+- FEATURE: support netonix devices
+- FEATURE: support specifying ssh cipher and kex (by @roadie)
+- FEATURE: rename proxy to ssh_proxy (by @roadie)
+- FEATURE: support ssh keys on ssh_proxy (by @awix)
+- BUGFIX: various (by @danilopopeye)
+- BUGFIX: Node#repo with groups (by @danilopopeye)
+- BUGFIX: githubrepohoook (by @danilopopeye)
+- BUGFIX: fortios, airos, junos, xos, edgeswitch, nos, tmos, procurve, ipos models
+
# 0.12.2
- BUGFIX: more MRV model fixes (by @natm)
@@ -12,7 +48,7 @@
- FEATURE: EdgeSwitch support (by @doogieconsulting)
- BUGFIX: rename input debug log files
- BUGFIX: powerconnect model fixes (by @Madpilot0)
-- BUGFIX: fortigate model fixes (by @ElvinEfendi)
+- BUGFIX: fortigate model fixes (by @ElvinEfendi)
- BUGFIX: various (by @mikebryant)
- BUGFIX: write SSH debug to file without buffering
- BUGFIX: fix IOS XR prompt handling
diff --git a/README.md b/README.md
index 0f58e50..0c92632 100644
--- a/README.md
+++ b/README.md
@@ -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)
@@ -66,17 +67,25 @@ Oxidized is a network device configuration backup tool. It's a RANCID replacemen
* Cisco
* AireOS
* ASA
+ * CatOS
* IOS
* IOSXR
* NXOS
* SMB (Nikola series)
+ * Citrix
+ * NetScaler (Virtual Applicance)
* Cumulus
* Linux
+ * DataCom
+ * DmSwitch 3000
* DELL
* PowerConnect
* AOSW
+ * Ericsson/Redback
+ * IPOS (former SEOS)
* Extreme Networks
* XOS
+ * WM
* F5
* TMOS
* Force10
@@ -96,12 +105,18 @@ Oxidized is a network device configuration backup tool. It's a RANCID replacemen
* MLNX-OS
* Mikrotik
* RouterOS
+ * Motorola
+ * RFS
* MRV
* MasterOS
+ * Netonix
+ * WISP Switch (As Netonix)
* Opengear
* Opengear
* Palo Alto
* PANOS
+ * Supermicro
+ * Supermicro
* Ubiquiti
* AirOS
* Edgeos
@@ -115,7 +130,7 @@ Oxidized is a network device configuration backup tool. It's a RANCID replacemen
Install all required packages and gems.
```shell
-apt-get install ruby ruby-dev libsqlite3-dev libssl-dev pkg-config cmake
+apt-get install ruby ruby-dev libsqlite3-dev libssl-dev pkg-config cmake libssh2-1-dev
gem install oxidized
gem install oxidized-script oxidized-web # if you don't install oxidized-web, make sure you remove "rest" from your config
```
@@ -123,7 +138,7 @@ gem install oxidized-script oxidized-web # if you don't install oxidized-web, ma
## CentOS, Oracle Linux, Red Hat Linux version 6
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
```shell
-yum install cmake sqlite-devel openssl-devel
+yum install cmake sqlite-devel openssl-devel libssh2-devel
```
Now lets install oxidized via Rubygems:
@@ -138,6 +153,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.
@@ -183,7 +213,7 @@ Install Ruby 2.1.2 build dependencies
```
yum install curl gcc-c++ patch readline readline-devel zlib zlib-devel
yum install libyaml-devel libffi-devel openssl-devel make cmake
-yum install bzip2 autoconf automake libtool bison iconv-devel
+yum install bzip2 autoconf automake libtool bison iconv-devel libssh2-devel
```
Install RVM
@@ -264,6 +294,30 @@ vars:
enable: S3cre7
```
+### Removing secrets
+
+To strip out secrets from configurations before storing them, Oxidized needs the the remove_secrets flag. You can globally enable this by adding the following snippet to the global sections of the configuration file.
+
+```
+vars:
+ remove_secret: true
+```
+
+Device models can contain substitution filters to remove potentially sensitive data from configs.
+
+As a partial example from ios.rb:
+
+```
+ cmd :secret do |cfg|
+ cfg.gsub! /^(snmp-server community).*/, '\\1 <configuration removed>'
+ (...)
+ cfg
+ end
+```
+The above strips out snmp community strings from your saved configs.
+
+**NOTE:** Removing secrets reduces the usefulness as a full configuration backup, but it may make sharing configs easier.
+
### Source: CSV
One line per device, colon seperated.
@@ -285,7 +339,7 @@ source:
### SSH Proxy Command
-Oxidized can `ssh` through a proxy as well. To do so we just need to set `proxy` variable.
+Oxidized can `ssh` through a proxy as well. To do so we just need to set `ssh_proxy` variable.
```
...
@@ -294,7 +348,7 @@ map:
model: 1
vars_map:
enable: 2
- proxy: 3
+ ssh_proxy: 3
...
```
@@ -356,13 +410,67 @@ output:
This uses the rugged/libgit2 interface. So you should remember that normal Git hooks will not be executed.
+
+For a single repositories for all devices:
+
+``` yaml
+output:
+ default: git
+ git:
+ user: Oxidized
+ email: o@example.com
+ repo: "/var/lib/oxidized/devices.git"
```
+
+And for groups repositories:
+
+``` yaml
output:
default: git
git:
user: Oxidized
email: o@example.com
+ repo: "/var/lib/oxidized/git-repos/default.git"
+```
+
+Oxidized will create a repository for each group in the same directory as the `default.git`. For
+example:
+
+``` csv
+host1:ios:first
+host2:nxos:second
+```
+
+This will generate the following repositories:
+
+``` bash
+$ ls /var/lib/oxidized/git-repos
+
+default.git first.git second.git
+```
+
+If you would like to use groups and a single repository, you can force this with the `single_repo` config.
+
+``` yaml
+output:
+ default: git
+ git:
+ single_repo: true
repo: "/var/lib/oxidized/devices.git"
+
+```
+
+### 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
@@ -445,6 +553,7 @@ vars:
enable: S3cr3tx
groups: {}
rest: 127.0.0.1:8888
+pid: ~/.config/oxidized/oxidized.pid
input:
default: ssh, telnet
debug: false
@@ -527,6 +636,42 @@ hooks:
timeout: 120
```
+### githubrepo
+
+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.
+
+`githubrepo` hook recognizes following configuration keys:
+
+ * `remote_repo`: the remote repository to be pushed to.
+ * `username`: username for repository auth.
+ * `password`: password for repository auth.
+ * `publickey`: publickey for repository auth.
+ * `privatekey`: privatekey for repository auth.
+
+When using groups repositories, each group must have its own `remote` in the `remote_repo` config.
+
+``` yaml
+hooks:
+ push_to_remote:
+ remote_repo:
+ routers: git@git.intranet:oxidized/routers.git
+ switches: git@git.intranet:oxidized/switches.git
+ firewalls: git@git.intranet:oxidized/firewalls.git
+```
+
+
+## Hook configuration example
+
+``` yaml
+hooks:
+ push_to_remote:
+ type: githubrepo
+ events: [post_store]
+ remote_repo: git@git.intranet:oxidized/test.git
+ username: user
+ password: pass
+```
+
# Ruby API
The following objects exist in Oxidized.
diff --git a/extra/nagios_check_failing_nodes.rb b/extra/nagios_check_failing_nodes.rb
index abb34ba..abb34ba 100644..100755
--- a/extra/nagios_check_failing_nodes.rb
+++ b/extra/nagios_check_failing_nodes.rb
diff --git a/extra/oxidized.init b/extra/oxidized.init
index 197c5b1..197c5b1 100644..100755
--- a/extra/oxidized.init
+++ b/extra/oxidized.init
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/extra/syslog.rb b/extra/syslog.rb
index e364cf9..e364cf9 100644..100755
--- a/extra/syslog.rb
+++ b/extra/syslog.rb
diff --git a/lib/oxidized/cli.rb b/lib/oxidized/cli.rb
index 0594dcb..9a09d41 100644
--- a/lib/oxidized/cli.rb
+++ b/lib/oxidized/cli.rb
@@ -24,7 +24,7 @@ module Oxidized
Config.load(@opts)
Oxidized.setup_logger
- @pidfile = File.join(Oxidized::Config::Root, 'pid')
+ @pidfile = File.expand_path(Oxidized.config.pid)
end
def crash error
diff --git a/lib/oxidized/config.rb b/lib/oxidized/config.rb
index d2d12d8..1797be6 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,9 +27,10 @@ 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
+ asetus.default.pid = File.join(Oxidized::Config::Root, 'pid')
asetus.default.input.default = 'ssh, telnet'
asetus.default.input.debug = false # or String for session log file
diff --git a/lib/oxidized/hook/githubrepo.rb b/lib/oxidized/hook/githubrepo.rb
index d10b51e..d33e54e 100644
--- a/lib/oxidized/hook/githubrepo.rb
+++ b/lib/oxidized/hook/githubrepo.rb
@@ -1,12 +1,12 @@
class GithubRepo < Oxidized::Hook
def validate_cfg!
- cfg.has_key?('remote_repo') or raise KeyError, 'remote_repo is required'
+ raise KeyError, 'hook.remote_repo is required' unless cfg.has_key?('remote_repo')
end
def run_hook(ctx)
- repo = Rugged::Repository.new(Oxidized.config.output.git.repo)
+ repo = Rugged::Repository.new(ctx.node.repo)
log "Pushing local repository(#{repo.path})..."
- remote = repo.remotes['origin'] || repo.remotes.create('origin', cfg.remote_repo)
+ remote = repo.remotes['origin'] || repo.remotes.create('origin', remote_repo(ctx.node))
log "to remote: #{remote.url}"
fetch_and_merge_remote(repo)
@@ -49,9 +49,21 @@ class GithubRepo < Oxidized::Hook
log "Using https auth", :debug
Rugged::Credentials::UserPassword.new(username: cfg.username, password: cfg.password)
else
- log "Using ssh auth", :debug
- Rugged::Credentials::SshKeyFromAgent.new(username: 'git')
+ if cfg.has_key?('publickey') && cfg.has_key?('privatekey')
+ log "Using ssh auth with key", :debug
+ Rugged::Credentials::SshKey.new(username: 'git', publickey: File.expand_path(cfg.publickey), privatekey: File.expand_path(cfg.privatekey))
+ else
+ log "Using ssh auth with agentforwarding", :debug
+ Rugged::Credentials::SshKeyFromAgent.new(username: 'git')
+ end
end
end
+ def remote_repo(node)
+ if node.group.nil? || cfg.remote_repo.is_a?(String)
+ cfg.remote_repo
+ else
+ cfg.remote_repo[node.group]
+ end
+ end
end
diff --git a/lib/oxidized/input/ssh.rb b/lib/oxidized/input/ssh.rb
index 7ffdd36..fef20d6 100644
--- a/lib/oxidized/input/ssh.rb
+++ b/lib/oxidized/input/ssh.rb
@@ -23,8 +23,8 @@ module Oxidized
secure = Oxidized.config.input.ssh.secure
@log = File.open(Oxidized::Config::Log + "-#{@node.ip}-ssh", 'w') if Oxidized.config.input.debug?
port = vars(:ssh_port) || 22
- if proxy_host = vars(:proxy)
- proxy = Net::SSH::Proxy::Command.new("ssh #{proxy_host} nc %h %p")
+ if proxy_host = vars(:ssh_proxy)
+ proxy = Net::SSH::Proxy::Command.new("ssh #{proxy_host} -W %h:%p")
end
ssh_opts = {
:port => port.to_i,
@@ -92,7 +92,7 @@ module Oxidized
@output << data
@output = @node.model.expects @output
end
- ch.request_pty (opts={:term=>'vt100'}) do |_ch, success_pty|
+ ch.request_pty (_opts={:term=>'vt100'}) do |_ch, success_pty|
raise NoShell, "Can't get PTY" unless success_pty
ch.send_channel_request 'shell' do |_ch, success_shell|
raise NoShell, "Can't get shell" unless success_shell
diff --git a/lib/oxidized/model/acos.rb b/lib/oxidized/model/acos.rb
index 75fbacf..7db8b00 100644
--- a/lib/oxidized/model/acos.rb
+++ b/lib/oxidized/model/acos.rb
@@ -1,5 +1,5 @@
class ACOS < Oxidized::Model
- # A10 ACOS model for AX and Thunder series
+ # A10 ACOS model for AX and Thunder series
comment '! '
@@ -17,10 +17,14 @@ class ACOS < Oxidized::Model
cmd 'show running-config all-partitions'
cmd 'show aflex all-partitions' do |cfg|
+ comment cfg
+ end
+
+ cmd 'show aflex all-partitions' do |cfg|
@partitions_aflex = cfg.lines.each_with_object({}) do |l,h|
h[$1] = [] if l.match /partition: (.+)/
# only consider scripts that have passed syntax check
- h[h.keys.last] << $1 if l.match /^([\w-]+) +Check/
+ h[h.keys.last] << $1 if l.match /^([\w-]+) +Check/
end
''
end
@@ -52,18 +56,18 @@ class ACOS < Oxidized::Model
username /login:/
password /^Password:/
end
-
+
cfg :telnet, :ssh do
# preferred way to handle additional passwords
- if vars :enable
- post_login do
- send "enable\n"
- send vars(:enable) + "\n"
- end
+ post_login do
+ pw = vars(:enable)
+ pw ||= ""
+ send "enable\r\n"
+ cmd pw
end
post_login 'terminal length 0'
post_login 'terminal width 0'
- pre_logout "exit\nexit\ny"
+ pre_logout "exit\nexit\nY\r\n"
end
end
diff --git a/lib/oxidized/model/asa.rb b/lib/oxidized/model/asa.rb
index 547afd7..48e6bf4 100644
--- a/lib/oxidized/model/asa.rb
+++ b/lib/oxidized/model/asa.rb
@@ -18,7 +18,7 @@ class ASA < Oxidized::Model
cmd 'show version' do |cfg|
# avoid commits due to uptime / ixo-router01 up 2 mins 28 secs / ixo-router01 up 1 days 2 hours
- cfg = cfg.each_line.select { |line| not line.match /\s+up\s+\d+\s+/ }
+ cfg = cfg.each_line.select { |line| not line.match /(\s+up\s+\d+\s+)|(.*days.*)/ }
cfg = cfg.join
comment cfg
end
@@ -30,6 +30,22 @@ class ASA < Oxidized::Model
cmd 'more system:running-config' do |cfg|
cfg = cfg.each_line.to_a[3..-1].join
cfg.gsub! /^: [^\n]*\n/, ''
+ # backup any xml referenced in the configuration.
+ anyconnect_profiles = cfg.scan(Regexp.new('(\sdisk0:/.+\.xml)')).flatten
+ anyconnect_profiles.each do |profile|
+ cfg << (comment profile + "\n" )
+ cmd ("more" + profile) do |xml|
+ cfg << (comment xml)
+ end
+ end
+ # if DAP is enabled, also backup dap.xml
+ if cfg.rindex(/dynamic-access-policy-record\s(?!DfltAccessPolicy)/)
+ cfg << (comment "disk0:/dap.xml\n")
+ cmd "more disk0:/dap.xml" do |xml|
+ cfg << (comment xml)
+ puts xml
+ end
+ end
cfg
end
diff --git a/lib/oxidized/model/catos.rb b/lib/oxidized/model/catos.rb
new file mode 100644
index 0000000..874ebbc
--- /dev/null
+++ b/lib/oxidized/model/catos.rb
@@ -0,0 +1,36 @@
+class Catos < Oxidized::Model
+
+ prompt /^[\w.@-]+> \(enable\) $/
+ comment '# '
+
+ cmd :all do |cfg|
+ cfg.each_line.to_a[1..-2].join
+ end
+
+ cmd 'show system' do |cfg|
+ cfg = cfg.gsub /(\s+)\d+,\d+:\d+:\d+(\s+)/, '\1X\2'
+ comment cfg
+ end
+
+ cmd 'show version' do |cfg|
+ cfg = cfg.gsub /\d+(K)/, 'X\1'
+ cfg = cfg.gsub /^(Uptime is ).*/, '\1X'
+ comment cfg
+ end
+
+ cmd 'show conf all' do |cfg|
+ cfg = cfg.sub /^(#time: ).*/, '\1X'
+ cfg.each_line.drop_while { |line| not line.match /^begin/ }.join
+ end
+
+ cfg :telnet do
+ username /^Username: /
+ password /^Password:/
+ end
+
+ cfg :ssh, :telnet do
+ post_login 'set length 0'
+ pre_logout 'exit'
+ end
+
+end
diff --git a/lib/oxidized/model/comware.rb b/lib/oxidized/model/comware.rb
index 9b36e8b..27b70ae 100644
--- a/lib/oxidized/model/comware.rb
+++ b/lib/oxidized/model/comware.rb
@@ -13,6 +13,8 @@ class Comware < Oxidized::Model
cmd :all do |cfg|
#cfg.gsub! /^.*\e\[42D/, '' # example how to handle pager
+ #skip rogue ^M
+ cfg = cfg.gsub /\r/, ''
cfg.each_line.to_a[1..-2].join
end
diff --git a/lib/oxidized/model/datacom.rb b/lib/oxidized/model/datacom.rb
new file mode 100644
index 0000000..54091ed
--- /dev/null
+++ b/lib/oxidized/model/datacom.rb
@@ -0,0 +1,33 @@
+class DataCom < Oxidized::Model
+
+ comment '! '
+
+ expect /^--More--\s+$/ do |data, re|
+ send ' '
+ data.sub re, ''
+ end
+
+ cmd :all do |cfg|
+ cfg.each_line.to_a[1..-2].join
+ cfg.cut_head.cut_tail
+ end
+
+ cmd 'show firmware' do |cfg|
+ comment cfg
+ end
+
+ cmd 'show system' do |cfg|
+ comment cfg
+ end
+
+ cmd 'show running-config' do |cfg|
+ cfg.cut_head
+ end
+
+ cfg :telnet, :ssh do
+ username /login:\s$/
+ password /^Password:\s$/
+ pre_logout 'exit'
+ end
+
+end
diff --git a/lib/oxidized/model/edgeswitch.rb b/lib/oxidized/model/edgeswitch.rb
index 89a5690..7c82639 100644
--- a/lib/oxidized/model/edgeswitch.rb
+++ b/lib/oxidized/model/edgeswitch.rb
@@ -4,22 +4,29 @@ class EdgeSwitch < Oxidized::Model
comment '!'
- prompt /[(]\w*\s\w*[)][\s#>]*[\s#>]/
+ prompt /\(.*\)\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.to_a[2..-2].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
- post_login 'enable'
- post_login 'terminal length 0'
- pre_logout 'exit'
- pre_logout 'exit'
+ post_login do
+ if vars :enable
+ send "enable\n"
+ cmd vars(:enable)
+ else
+ cmd 'enable'
+ end
+ cmd 'terminal length 0'
+ end
+ pre_logout 'quit'
+ pre_logout 'n'
end
-end \ No newline at end of file
+end
diff --git a/lib/oxidized/model/fortios.rb b/lib/oxidized/model/fortios.rb
index 92add0e..aad3a6e 100644
--- a/lib/oxidized/model/fortios.rb
+++ b/lib/oxidized/model/fortios.rb
@@ -2,7 +2,7 @@ class FortiOS < Oxidized::Model
comment '# '
- prompt /^([-\w\.]+(\s[\(\w\-\.\)]+)?\~?\s?[#>]\s?)$/
+ prompt /^([-\w\.]+(\s[\(\w\-\.\)]+)?\~?\s?[#>$]\s?)$/
expect /^--More--\s$/ do |data, re|
send ' '
diff --git a/lib/oxidized/model/iosxr.rb b/lib/oxidized/model/iosxr.rb
index a622b66..bf01140 100644
--- a/lib/oxidized/model/iosxr.rb
+++ b/lib/oxidized/model/iosxr.rb
@@ -30,7 +30,7 @@ class IOSXR < Oxidized::Model
cfg :telnet do
username /^Username:/
- password /^Password:/
+ password /^\r?Password:/
end
cfg :telnet, :ssh do
diff --git a/lib/oxidized/model/ipos.rb b/lib/oxidized/model/ipos.rb
new file mode 100644
index 0000000..5efd831
--- /dev/null
+++ b/lib/oxidized/model/ipos.rb
@@ -0,0 +1,61 @@
+class IPOS < Oxidized::Model
+
+ # Ericsson SSR (IPOS)
+ # Redback SE (SEOS)
+
+ prompt /^([\[\]\w.@-]+[#>]\s?)$/
+ comment '! '
+
+ cmd 'show chassis' do |cfg|
+ comment cfg.each_line.to_a[0..-2].join
+ end
+
+ cmd 'show hardware' do |cfg|
+ comment cfg.each_line.to_a[0..-2].join
+ end
+
+ cmd 'show release' do |cfg|
+ comment cfg.each_line.to_a[0..-2].join
+ end
+
+ cmd 'show configuration' do |cfg|
+ # SEOS regularly adds some odd line breaks in random places
+ # when showing the config, triggering changes.
+ cfg.gsub! "\r\n", "\n"
+
+ cfg = cfg.each_line.to_a
+
+ # Keeps the issued command commented but removes the uncommented "Building configuration..."
+ # and "Current configuration:" lines as well as the last prompt at the end.
+ cfg = cfg[4..-2].unshift comment cfg[0]
+
+ # Later IPOS releases add this line in addition to the usual "last changed" line.
+ # It's touched regularly (as often as multiple times per minute) by the OS without actual visible config changes.
+ cfg = cfg.reject { |line| line.match "Configuration last changed by system user" }
+
+ # Earlier IPOS releases lack the "changed by system user" line and instead overwrite
+ # the single "last changed by user" line. Because the line has a timestamp it will
+ # trigger constant changes if not removed. By doing so there will only be a single
+ # extra change trigged after an actual config change by a user but still have the
+ # real user.
+ cfg = cfg.reject { |line| line.match "Configuration last changed by user '%LICM%' at" }
+ cfg = cfg.reject { |line| line.match "Configuration last changed by user '<NO USER>' at" }
+ cfg = cfg.reject { |line| line.match "Configuration last changed by user '' at" }
+
+ cfg.join
+ end
+
+ 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/ironware.rb b/lib/oxidized/model/ironware.rb
index 55b6e57..1e8c30e 100644
--- a/lib/oxidized/model/ironware.rb
+++ b/lib/oxidized/model/ironware.rb
@@ -23,6 +23,7 @@ class IronWare < Oxidized::Model
cmd 'show version' do |cfg|
cfg.gsub! /(^((.*)[Ss]ystem uptime(.*))$)/, '' #remove unwanted line system uptime
+ cfg.gsub! /(^((.*)[Tt]he system started at(.*))$)/, ''
cfg.gsub! /[Uu]p\s?[Tt]ime is .*/,''
comment cfg
diff --git a/lib/oxidized/model/mtrlrfs.rb b/lib/oxidized/model/mtrlrfs.rb
new file mode 100644
index 0000000..8baa4e9
--- /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/netonix.rb b/lib/oxidized/model/netonix.rb
new file mode 100644
index 0000000..4624f83
--- /dev/null
+++ b/lib/oxidized/model/netonix.rb
@@ -0,0 +1,15 @@
+class Netonix < Oxidized::Model
+ prompt /^[\w\s.@_\/:-]+#/
+
+ cmd :all do |cfg|
+ cfg.each_line.to_a[1..-2].join
+ end
+
+ cmd 'cat config.json;echo'
+
+ cfg :ssh do
+ post_login 'cmdline'
+ pre_logout 'exit'
+ pre_logout 'exit'
+ end
+end
diff --git a/lib/oxidized/model/netscaler.rb b/lib/oxidized/model/netscaler.rb
new file mode 100644
index 0000000..9ca66b6
--- /dev/null
+++ b/lib/oxidized/model/netscaler.rb
@@ -0,0 +1,24 @@
+class NetScaler < Oxidized::Model
+
+ prompt /^\>\s*$/
+ comment '# '
+
+ cmd :all do |cfg|
+ cfg.each_line.to_a[1..-3].join
+ end
+
+ cmd 'show version' do |cfg|
+ comment cfg
+ end
+
+ cmd 'show hardware' do |cfg|
+ comment cfg
+ end
+
+ cmd 'show ns ns.conf'
+
+ cfg :ssh do
+ pre_logout 'exit'
+ 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/procurve.rb b/lib/oxidized/model/procurve.rb
index 684a4b6..392f510 100644
--- a/lib/oxidized/model/procurve.rb
+++ b/lib/oxidized/model/procurve.rb
@@ -1,36 +1,49 @@
class Procurve < Oxidized::Model
- # FIXME: this is way too unsafe
- prompt /.*?(\w+# ).*/m
+ # some models start lines with \r
+ # previous command is repeated followed by "\eE", which sometimes ends up on last line
+ prompt /^\r?([\w -]+\eE)?([\w.-]+# )$/
comment '! '
+ # replace all used vt100 control sequences
+ expect /\e\[\??\d+(;\d+)*[A-Za-z]/ do |data, re|
+ data.gsub re, ''
+ end
+
expect /Press any key to continue/ do
- send ' '
- ""
+ send ' '
+ ""
end
cmd :all do |cfg|
cfg = cfg.each_line.to_a[1..-3].join
- cfg = cfg.gsub /\r/, ''
- new_cfg = ''
- cfg.each_line do |line|
- line.sub! /^\e.*(\e.*)/, '\1' #leave last escape
- line.sub! /\e\[24;1H/, '' #remove last escape, is it always this?
- new_cfg << line
- end
- new_cfg
+ cfg = cfg.gsub /^\r/, ''
+ end
+
+ cmd :secret do |cfg|
+ cfg.gsub! /^(snmp-server community).*/, '\\1 <configuration removed>'
+ cfg.gsub! /^(snmp-server host).*/, '\\1 <configuration removed>'
+ cfg.gsub! /^(radius-server host).*/, '\\1 <configuration removed>'
+ cfg
end
cmd 'show version' do |cfg|
comment cfg
end
+ # not supported on all models
cmd 'show system-information' do |cfg|
cfg = cfg.split("\n")[0..-8].join("\n")
comment cfg
end
+ # not supported on all models
+ cmd 'show system information' do |cfg|
+ cfg = cfg.split("\n")[0..-8].join("\n")
+ comment cfg
+ end
+
cmd 'show running-config'
cfg :telnet do
diff --git a/lib/oxidized/model/supermicro.rb b/lib/oxidized/model/supermicro.rb
new file mode 100644
index 0000000..361244c
--- /dev/null
+++ b/lib/oxidized/model/supermicro.rb
@@ -0,0 +1,45 @@
+class Supermicro < Oxidized::Model
+ comment '! '
+
+ cmd :secret do |cfg|
+ cfg.gsub!(/password \d+ (\S+).*/, '<secret removed>')
+ cfg.gsub!(/community (\S+)/, 'community <hidden>')
+ cfg
+ end
+
+ cmd :all do |cfg|
+ cfg.each_line.to_a[2..-2].join
+ end
+
+ cmd 'show running-config'
+
+ cmd 'show access-list tcam-utilization' do |cfg|
+ comment cfg
+ end
+
+ cmd 'show memory' do |cfg|
+ comment cfg
+ end
+
+ cmd 'show system' do |cfg|
+ comment cfg
+ end
+
+ cmd 'show version' do |cfg|
+ comment cfg
+ end
+
+ cmd 'show watchdog' do |cfg|
+ comment cfg
+ end
+
+ cfg :telnet do
+ username /^Username:/
+ password /^Password:/
+ end
+
+ cfg :telnet, :ssh do
+ post_login 'terminal length 0'
+ pre_logout 'exit'
+ end
+end \ No newline at end of file
diff --git a/lib/oxidized/model/tmos.rb b/lib/oxidized/model/tmos.rb
index 4841b98..390046d 100644
--- a/lib/oxidized/model/tmos.rb
+++ b/lib/oxidized/model/tmos.rb
@@ -3,18 +3,20 @@ class TMOS < Oxidized::Model
comment '# '
cmd :secret do |cfg|
- cfg.gsub!(/password (\S+)/, 'password <secret removed>')
- cfg.gsub!(/passphrase (\S+)/, 'passphrase <secret removed>')
- cfg.gsub!(/community (\S+)/, 'community <secret removed>')
- cfg.gsub!(/community-name (\S+)/, 'community-name <secret removed>')
+ cfg.gsub!(/^([\s\t]*)secret \S+/, '\1secret <secret removed>')
+ cfg.gsub!(/^([\s\t]*\S*)password \S+/, '\1password <secret removed>')
+ cfg.gsub!(/^([\s\t]*\S*)passphrase \S+/, '\1passphrase <secret removed>')
+ cfg.gsub!(/community \S+/, 'community <secret removed>')
+ cfg.gsub!(/community-name \S+/, 'community-name <secret removed>')
+ cfg.gsub!(/^([\s\t]*\S*)encrypted \S+$/, '\1encrypted <secret removed>')
cfg
end
- cmd('tmsh show sys version') { |cfg| comment cfg }
+ cmd('tmsh -q show sys version') { |cfg| comment cfg }
- cmd('tmsh show sys software') { |cfg| comment cfg }
+ cmd('tmsh -q show sys software') { |cfg| comment cfg }
- cmd 'tmsh show sys hardware field-fmt' do |cfg|
+ cmd 'tmsh -q show sys hardware field-fmt' do |cfg|
cfg.gsub!(/fan-speed (\S+)/, '')
cfg.gsub!(/temperature (\S+)/, '')
comment cfg
@@ -22,25 +24,27 @@ class TMOS < Oxidized::Model
cmd('cat /config/bigip.license') { |cfg| comment cfg }
- cmd 'tmsh list' do |cfg|
- cfg.gsub!(/state (up|down)/, '')
+ cmd 'tmsh -q list' do |cfg|
+ cfg.gsub!(/state (up|down|checking|irule-down)/, '')
cfg.gsub!(/errors (\d+)/, '')
cfg
end
- cmd('tmsh list net route all') { |cfg| comment cfg }
+ cmd('tmsh -q list net route all') { |cfg| comment cfg }
cmd('/bin/ls --full-time --color=never /config/ssl/ssl.crt') { |cfg| comment cfg }
cmd('/bin/ls --full-time --color=never /config/ssl/ssl.key') { |cfg| comment cfg }
- cmd 'tmsh show running-config sys db all-properties' do |cfg|
+ cmd 'tmsh -q show running-config sys db all-properties' do |cfg|
cfg.gsub!(/sys db configsync.localconfigtime {[^}]+}/m, '')
cfg.gsub!(/sys db gtm.configtime {[^}]+}/m, '')
cfg.gsub!(/sys db ltm.configtime {[^}]+}/m, '')
comment cfg
end
+ cmd('cat /config/partitions/*/bigip.conf') { |cfg| comment cfg }
+
cfg :ssh do
exec true # don't run shell, run each command in exec channel
end
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/node.rb b/lib/oxidized/node.rb
index 7a278a9..35bcad9 100644
--- a/lib/oxidized/node.rb
+++ b/lib/oxidized/node.rb
@@ -24,7 +24,7 @@ module Oxidized
@vars = opt[:vars]
@stats = Stats.new
@retry = 0
- @repo = Oxidized.config.output.git.repo
+ @repo = resolve_repo
# model instance needs to access node instance
@model.node = self
@@ -170,5 +170,15 @@ module Oxidized
Oxidized.mgr.model[model].new
end
+ def resolve_repo
+ remote_repo = Oxidized.config.output.git.repo
+
+ if Oxidized.config.output.git.single_repo? || @group.nil? || remote_repo.is_a?(String)
+ remote_repo
+ else
+ remote_repo[@group]
+ end
+ end
+
end
end
diff --git a/lib/oxidized/output/git.rb b/lib/oxidized/output/git.rb
index 8b605f6..8d9dae1 100644
--- a/lib/oxidized/output/git.rb
+++ b/lib/oxidized/output/git.rb
@@ -21,7 +21,14 @@ class Git < Output
Oxidized.asetus.save :user
raise NoConfig, 'no output git config, edit ~/.config/oxidized/config'
end
- @cfg.repo = File.expand_path @cfg.repo
+
+ if @cfg.repo.respond_to?(:each)
+ @cfg.repo.each do |group, repo|
+ @cfg.repo["#{group}="] = File.expand_path repo
+ end
+ else
+ @cfg.repo = File.expand_path @cfg.repo
+ end
end
def store file, outputs, opt={}
@@ -70,7 +77,10 @@ class Git < Output
def version node, group
begin
repo = @cfg.repo
- if group
+ path = node
+ if group and @cfg.single_repo?
+ path = "#{group}/#{node}"
+ elsif group
repo = File.join File.dirname(repo), group + '.git'
end
repo = Rugged::Repository.new repo
@@ -80,7 +90,7 @@ class Git < Output
i = -1
tab = []
walker.each do |commit|
- if commit.diff(paths: [node]).size > 0
+ if commit.diff(paths: [path]).size > 0
hash = {}
hash[:date] = commit.time.to_s
hash[:oid] = commit.oid
@@ -100,8 +110,10 @@ class Git < Output
def get_version node, group, oid
begin
repo = @cfg.repo
- if group && group != ''
+ if group && group != '' && !@cfg.single_repo?
repo = File.join File.dirname(repo), group + '.git'
+ elsif group && group != ''
+ node = File.join group, node
end
repo = Rugged::Repository.new repo
repo.blob_at(oid,node).content
@@ -115,7 +127,7 @@ class Git < Output
begin
repo = @cfg.repo
diff_commits = nil
- if group && group != ''
+ if group && group != '' && !@cfg.single_repo?
repo = File.join File.dirname(repo), group + '.git'
end
repo = Rugged::Repository.new repo
@@ -147,13 +159,19 @@ class Git < Output
def update repo, file, data
return if data.empty?
+
if @opt[:group]
if @cfg.single_repo?
file = File.join @opt[:group], file
else
- repo = File.join File.dirname(repo), @opt[:group] + '.git'
+ repo = if repo.is_a?(::String)
+ File.join File.dirname(repo), @opt[:group] + '.git'
+ else
+ repo[@opt[:group]]
+ end
end
end
+
begin
repo = Rugged::Repository.new repo
update_repo repo, file, data, @msg, @user, @email
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
+
+
diff --git a/lib/oxidized/version.rb b/lib/oxidized/version.rb
index c06a14a..428cd19 100644
--- a/lib/oxidized/version.rb
+++ b/lib/oxidized/version.rb
@@ -1,3 +1,3 @@
module Oxidized
- VERSION = '0.12.2'
+ VERSION = '0.14.3'
end
diff --git a/oxidized.gemspec b/oxidized.gemspec
index efa21db..9ff795c 100644
--- a/oxidized.gemspec
+++ b/oxidized.gemspec
@@ -21,11 +21,11 @@ Gem::Specification.new do |s|
s.required_ruby_version = '>= 2.0.0'
s.add_runtime_dependency 'asetus', '~> 0.1'
s.add_runtime_dependency 'slop', '~> 3.5'
- s.add_runtime_dependency 'net-ssh', '~> 3.0', '>= 3.0.2'
- s.add_runtime_dependency 'rugged', '~> 0.21', '>= 0.21.4'
- s.add_development_dependency 'pry', '~> 0'
- s.add_development_dependency 'bundler', '~> 1.10'
- s.add_development_dependency 'rake', '~> 10.0'
+ s.add_runtime_dependency 'net-ssh', '>= 3.0.0', '<3.1'
+ s.add_runtime_dependency 'rugged', '~> 0.21', '>= 0.21.4'
+ s.add_development_dependency 'pry', '~> 0'
+ s.add_development_dependency 'bundler', '~> 1.10'
+ s.add_development_dependency 'rake', '~> 10.0'
s.add_development_dependency 'minitest', '~> 5.8'
- s.add_development_dependency 'mocha', '~> 1.1'
+ s.add_development_dependency 'mocha', '~> 1.1'
end
diff --git a/spec/cli_spec.rb b/spec/cli_spec.rb
index 783d9c8..0a6c91b 100644
--- a/spec/cli_spec.rb
+++ b/spec/cli_spec.rb
@@ -12,7 +12,8 @@ describe Oxidized::CLI do
before { ARGV.replace [option] }
it 'prints the version and exits' do
- Oxidized::Config.expects(:load).returns(asetus)
+ Oxidized::Config.expects(:load)
+ Oxidized.expects(:setup_logger)
Kernel.expects(:exit)
proc {
diff --git a/spec/githubrepo_spec.rb b/spec/githubrepo_spec.rb
index 9ad43e9..ab5e251 100644
--- a/spec/githubrepo_spec.rb
+++ b/spec/githubrepo_spec.rb
@@ -2,19 +2,32 @@ require 'spec_helper'
require 'rugged'
require 'oxidized/hook/githubrepo'
-describe Oxidized::Node do
+describe GithubRepo do
let(:credentials) { mock() }
let(:remote) { mock() }
+ let(:remotes) { mock() }
let(:repo_head) { mock() }
let(:repo) { mock() }
let(:gr) { GithubRepo.new }
before(:each) do
Oxidized.asetus = Asetus.new
- Oxidized.config.output.git.repo = 'foo.git'
+ Oxidized.config.log = '/dev/null'
Oxidized.setup_logger
end
+ describe '#validate_cfg!' do
+ before do
+ gr.expects(:respond_to?).with(:validate_cfg!).returns(false) # `cfg=` call
+ end
+
+ it 'raise a error when `remote_repo` is not configured' do
+ Oxidized.config.hooks.github_repo_hook = { type: 'githubrepo' }
+ gr.cfg = Oxidized.config.hooks.github_repo_hook
+ proc { gr.validate_cfg! }.must_raise(KeyError)
+ end
+ end
+
describe "#fetch_and_merge_remote" do
before(:each) do
Oxidized.config.hooks.github_repo_hook.remote_repo = 'git@github.com:username/foo.git'
@@ -68,31 +81,89 @@ describe Oxidized::Node do
end
describe "#run_hook" do
- before(:each) do
- remote.expects(:url).returns('https://github.com/username/foo.git')
- remote.expects(:push).with(['refs/heads/master'], credentials: credentials).returns(true)
+ let(:group) { nil }
+ let(:ctx) { OpenStruct.new(node: node) }
+ let(:node) do
+ Oxidized::Node.new(ip: '127.0.0.1', group: group, model: 'junos', output: 'output')
+ end
+
+ before do
repo_head.expects(:name).twice.returns('refs/heads/master')
repo.expects(:head).twice.returns(repo_head)
repo.expects(:path).returns('foo.git')
- repo.expects(:remotes).returns({'origin' => remote})
repo.expects(:fetch).with('origin', ['refs/heads/master'], credentials: credentials).returns(Hash.new(0))
- Rugged::Repository.expects(:new).with('foo.git').returns(repo)
end
- it "will push to the remote repository using https" do
- Oxidized.config.hooks.github_repo_hook.remote_repo = 'https://github.com/username/foo.git'
- Oxidized.config.hooks.github_repo_hook.username = 'username'
- Oxidized.config.hooks.github_repo_hook.password = 'password'
- Rugged::Credentials::UserPassword.expects(:new).with(username: 'username', password: 'password').returns(credentials)
- gr.cfg = Oxidized.config.hooks.github_repo_hook
- gr.run_hook(nil).must_equal true
+ describe 'when there is only one repository and no groups' do
+ before do
+ Oxidized.config.output.git.repo = 'foo.git'
+ remote.expects(:url).returns('https://github.com/username/foo.git')
+ remote.expects(:push).with(['refs/heads/master'], credentials: credentials).returns(true)
+ repo.expects(:remotes).returns({'origin' => remote})
+ Rugged::Repository.expects(:new).with('foo.git').returns(repo)
+ end
+
+ it "will push to the remote repository using https" do
+ Oxidized.config.hooks.github_repo_hook.remote_repo = 'https://github.com/username/foo.git'
+ Oxidized.config.hooks.github_repo_hook.username = 'username'
+ Oxidized.config.hooks.github_repo_hook.password = 'password'
+ Rugged::Credentials::UserPassword.expects(:new).with(username: 'username', password: 'password').returns(credentials)
+ gr.cfg = Oxidized.config.hooks.github_repo_hook
+ gr.run_hook(ctx).must_equal true
+ end
+
+ it "will push to the remote repository using ssh" do
+ Oxidized.config.hooks.github_repo_hook.remote_repo = 'git@github.com:username/foo.git'
+ Rugged::Credentials::SshKeyFromAgent.expects(:new).with(username: 'git').returns(credentials)
+ gr.cfg = Oxidized.config.hooks.github_repo_hook
+ gr.run_hook(ctx).must_equal true
+ end
end
- it "will push to the remote repository using ssh" do
- Oxidized.config.hooks.github_repo_hook.remote_repo = 'git@github.com:username/foo.git'
- Rugged::Credentials::SshKeyFromAgent.expects(:new).with(username: 'git').returns(credentials)
- gr.cfg = Oxidized.config.hooks.github_repo_hook
- gr.run_hook(nil).must_equal true
+ describe "when there are groups" do
+ let(:group) { 'ggrroouupp' }
+
+ before do
+ Rugged::Credentials::SshKeyFromAgent.expects(:new).with(username: 'git').returns(credentials)
+ Rugged::Repository.expects(:new).with(repository).returns(repo)
+
+ repo.expects(:remotes).twice.returns(remotes)
+ remotes.expects(:[]).with('origin').returns(nil)
+ remotes.expects(:create).with('origin', create_remote).returns(remote)
+ remote.expects(:url).returns('url')
+ remote.expects(:push).with(['refs/heads/master'], credentials: credentials).returns(true)
+ end
+
+ describe 'and there are several repositories' do
+ let(:create_remote) { 'ggrroouupp#remote_repo' }
+ let(:repository) { './ggrroouupp.git' }
+
+ before do
+ Oxidized.config.output.git.repo.ggrroouupp = repository
+ Oxidized.config.hooks.github_repo_hook.remote_repo.ggrroouupp = 'ggrroouupp#remote_repo'
+ end
+
+ it 'will push to the node group repository' do
+ gr.cfg = Oxidized.config.hooks.github_repo_hook
+ gr.run_hook(ctx).must_equal true
+ end
+ end
+
+ describe 'and has a single repository' do
+ let(:create_remote) { 'github_repo_hook#remote_repo' }
+ let(:repository) { 'foo.git' }
+
+ before do
+ Oxidized.config.output.git.repo = repository
+ Oxidized.config.hooks.github_repo_hook.remote_repo = 'github_repo_hook#remote_repo'
+ Oxidized.config.output.git.single_repo = true
+ end
+
+ it 'will push to the correct repository' do
+ gr.cfg = Oxidized.config.hooks.github_repo_hook
+ gr.run_hook(ctx).must_equal true
+ end
+ end
end
end
end
diff --git a/spec/input/ssh_spec.rb b/spec/input/ssh_spec.rb
index 43c7d66..c4210f2 100644
--- a/spec/input/ssh_spec.rb
+++ b/spec/input/ssh_spec.rb
@@ -12,7 +12,7 @@ describe Oxidized::SSH do
model: 'junos',
username: 'alma',
password: 'armud',
- vars: {proxy: 'test.com'})
+ vars: {ssh_proxy: 'test.com'})
end
@@ -25,7 +25,7 @@ describe Oxidized::SSH do
@node.expects(:model).returns(model)
proxy = mock()
- Net::SSH::Proxy::Command.expects(:new).with("ssh test.com nc %h %p").returns(proxy)
+ Net::SSH::Proxy::Command.expects(:new).with("ssh test.com -W %h:%p").returns(proxy)
Net::SSH.expects(:start).with('93.184.216.34', 'alma', {:port => 22, :password => 'armud', :timeout => Oxidized.config.timeout,
:paranoid => Oxidized.config.input.ssh.secure, :auth_methods => ['none', 'publickey', 'password', 'keyboard-interactive'],
:number_of_password_prompts => 0, :proxy => proxy})
diff --git a/spec/node_spec.rb b/spec/node_spec.rb
index c568463..21c6e34 100644
--- a/spec/node_spec.rb
+++ b/spec/node_spec.rb
@@ -41,4 +41,50 @@ describe Oxidized::Node do
status.must_equal :success
end
end
+
+ describe '#repo' do
+ let(:group) { nil }
+ let(:node) do
+ Oxidized::Node.new({
+ ip: '127.0.0.1', group: group, model: 'junos'
+ })
+ end
+
+ it 'when there are no groups' do
+ Oxidized.config.output.git.repo = '/tmp/repository.git'
+ node.repo.must_equal '/tmp/repository.git'
+ end
+
+ describe 'when there are groups' do
+ let(:group) { 'ggrroouupp' }
+
+ before do
+ Oxidized.config.output.git.single_repo = single_repo
+ end
+
+ describe 'with only one repository' do
+ let(:single_repo) { true }
+
+ before do
+ Oxidized.config.output.git.repo = '/tmp/repository.git'
+ end
+
+ it 'should use the correct remote' do
+ node.repo.must_equal '/tmp/repository.git'
+ end
+ end
+
+ describe 'with more than one repository' do
+ let(:single_repo) { nil }
+
+ before do
+ Oxidized.config.output.git.repo.ggrroouupp = '/tmp/ggrroouupp.git'
+ end
+
+ it 'should use the correct remote' do
+ node.repo.must_equal '/tmp/ggrroouupp.git'
+ end
+ end
+ end
+ end
end