oxidized 0.9.0 → 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +3 -0
- data/CHANGELOG.md +6 -0
- data/Gemfile.lock +41 -0
- data/README.md +64 -35
- data/Rakefile +7 -9
- data/bin/console +9 -0
- data/bin/oxidized +1 -1
- data/extra/nagios_check_failing_nodes.rb +4 -4
- data/extra/oxidized-report-git-commits +80 -0
- data/extra/rvm.oxidized.upstart +18 -0
- data/lib/oxidized.rb +45 -2
- data/lib/oxidized/cli.rb +54 -4
- data/lib/oxidized/config.rb +45 -39
- data/lib/oxidized/config/vars.rb +8 -3
- data/lib/oxidized/core.rb +5 -12
- data/lib/oxidized/hook.rb +4 -4
- data/lib/oxidized/hook/exec.rb +2 -0
- data/lib/oxidized/hook/githubrepo.rb +57 -0
- data/lib/oxidized/input/cli.rb +2 -1
- data/lib/oxidized/input/ftp.rb +3 -3
- data/lib/oxidized/input/ssh.rb +9 -9
- data/lib/oxidized/input/telnet.rb +3 -3
- data/lib/oxidized/job.rb +3 -3
- data/lib/oxidized/model/fortios.rb +1 -1
- data/lib/oxidized/model/junos.rb +8 -10
- data/lib/oxidized/model/model.rb +3 -2
- data/lib/oxidized/model/powerconnect.rb +11 -6
- data/lib/oxidized/model/saos.rb +24 -0
- data/lib/oxidized/node.rb +16 -16
- data/lib/oxidized/nodes.rb +12 -12
- data/lib/oxidized/output/file.rb +15 -3
- data/lib/oxidized/output/git.rb +10 -7
- data/lib/oxidized/source/csv.rb +7 -7
- data/lib/oxidized/source/http.rb +1 -1
- data/lib/oxidized/source/source.rb +1 -1
- data/lib/oxidized/source/sql.rb +7 -7
- data/lib/oxidized/string.rb +1 -1
- data/lib/oxidized/version.rb +3 -0
- data/lib/oxidized/worker.rb +11 -9
- data/oxidized.gemspec +12 -3
- metadata +75 -7
- data/lib/oxidized/log.rb +0 -22
- data/spec/nodes_spec.rb +0 -46
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4f601ebdf3c7562322e2b76313f60e4128863968
|
4
|
+
data.tar.gz: c0151bcf8e6c02d53511321f198bdd7fd55ac1cf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ff1578ea27961bdf57d32433da245795a880f95e6698f1f2b37692617d4779467673c78a1e27318204c8fc5b0ef4bbb05c379bee870f1fe59365727bef7a8222
|
7
|
+
data.tar.gz: fde31a1ef6e58ceebe9b1bcc822efdcc37971c234b474f64daa679bb50c87f308e474c7aad132ac41f837be91e4034aaba8db346fed987cc3f3a6dea7846bc3d
|
data/.travis.yml
ADDED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
# 0.10.0
|
2
|
+
- FEATURE: Various refactoring (by @ElvinEfendi)
|
3
|
+
- FEATURE: Ciena SOAS support (by @jgroom33)
|
4
|
+
- FEATURE: support group variables (by @supertylerc)
|
5
|
+
- BUGFIX: various ((orly)) (by @marnovdm, @danbaugher, @MrRJ45, @asynet, @nickhilliard)
|
6
|
+
|
1
7
|
# 0.9.0
|
2
8
|
- FEATURE: input log now uses devices name as file, instead of string from config (by @skoef)
|
3
9
|
- FEATURE: Dell Networkign OS (dnos) support (by @erefre)
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
oxidized (0.9.0)
|
5
|
+
asetus (~> 0.1)
|
6
|
+
net-ssh (~> 3.0, >= 3.0.2)
|
7
|
+
rugged (~> 0.21, >= 0.21.4)
|
8
|
+
slop (~> 3.5)
|
9
|
+
|
10
|
+
GEM
|
11
|
+
remote: https://rubygems.org/
|
12
|
+
specs:
|
13
|
+
asetus (0.3.0)
|
14
|
+
coderay (1.1.0)
|
15
|
+
metaclass (0.0.4)
|
16
|
+
method_source (0.8.2)
|
17
|
+
minitest (5.8.3)
|
18
|
+
mocha (1.1.0)
|
19
|
+
metaclass (~> 0.0.1)
|
20
|
+
net-ssh (3.0.2)
|
21
|
+
pry (0.10.3)
|
22
|
+
coderay (~> 1.1.0)
|
23
|
+
method_source (~> 0.8.1)
|
24
|
+
slop (~> 3.4)
|
25
|
+
rake (10.4.2)
|
26
|
+
rugged (0.23.3)
|
27
|
+
slop (3.6.0)
|
28
|
+
|
29
|
+
PLATFORMS
|
30
|
+
ruby
|
31
|
+
|
32
|
+
DEPENDENCIES
|
33
|
+
bundler (~> 1.10)
|
34
|
+
minitest (~> 5.8)
|
35
|
+
mocha (~> 1.1)
|
36
|
+
oxidized!
|
37
|
+
pry (~> 0)
|
38
|
+
rake (~> 10.0)
|
39
|
+
|
40
|
+
BUNDLED WITH
|
41
|
+
1.11.2
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Oxidized
|
1
|
+
# Oxidized [![Build Status](https://travis-ci.org/Shopify/oxidized.svg)](https://travis-ci.org/Shopify/oxidized)
|
2
2
|
|
3
3
|
[![Gem Version](https://badge.fury.io/rb/oxidized.svg)](http://badge.fury.io/rb/oxidized)
|
4
4
|
|
@@ -42,39 +42,66 @@ Oxidized is a network device configuration backup tool. It's a RANCID replacemen
|
|
42
42
|
|
43
43
|
# Supported OS types
|
44
44
|
|
45
|
-
* A10 Networks
|
46
|
-
|
47
|
-
* Alcatel-Lucent
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
*
|
54
|
-
|
55
|
-
*
|
56
|
-
|
57
|
-
*
|
58
|
-
|
59
|
-
*
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
*
|
65
|
-
|
66
|
-
*
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
*
|
74
|
-
|
75
|
-
*
|
76
|
-
|
77
|
-
|
45
|
+
* A10 Networks
|
46
|
+
* ACOS
|
47
|
+
* Alcatel-Lucent
|
48
|
+
* ISAM
|
49
|
+
* AOS
|
50
|
+
* AOS7
|
51
|
+
* Wireless
|
52
|
+
* TiMOS
|
53
|
+
* Arista
|
54
|
+
* EOS
|
55
|
+
* Arris
|
56
|
+
* C4CMTS
|
57
|
+
* Aruba
|
58
|
+
* AOSW
|
59
|
+
* Brocade
|
60
|
+
* FabricOS
|
61
|
+
* Ironware
|
62
|
+
* NOS (Network Operating System)
|
63
|
+
* Vyatta
|
64
|
+
* Ciena
|
65
|
+
* SOAS
|
66
|
+
* Cisco
|
67
|
+
* AireOS
|
68
|
+
* ASA
|
69
|
+
* IOS
|
70
|
+
* IOSXR
|
71
|
+
* NXOS
|
72
|
+
* SMB (Nikola series)
|
73
|
+
* Cumulus
|
74
|
+
* Linux
|
75
|
+
* DELL
|
76
|
+
* PowerConnect
|
77
|
+
* AOSW
|
78
|
+
* Extreme Networks
|
79
|
+
* XOS
|
80
|
+
* Force10
|
81
|
+
* FTOS
|
82
|
+
* Force10
|
83
|
+
* DNOS
|
84
|
+
* FortiGate
|
85
|
+
* FortiOS
|
86
|
+
* HP
|
87
|
+
* Comware (HP A-series, H3C, 3Com)
|
88
|
+
* Procurve
|
89
|
+
* Huawei
|
90
|
+
* VRP
|
91
|
+
* Juniper
|
92
|
+
* JunOS
|
93
|
+
* ScreenOS (Netscreen)
|
94
|
+
* Mikrotik
|
95
|
+
* RouterOS
|
96
|
+
* MRV
|
97
|
+
* MasterOS
|
98
|
+
* Ubiquiti
|
99
|
+
* AirOS
|
100
|
+
* Edgeos
|
101
|
+
* Palo Alto
|
102
|
+
* PANOS
|
103
|
+
* Zyxel
|
104
|
+
* ZyNOS
|
78
105
|
|
79
106
|
|
80
107
|
# Installation
|
@@ -113,7 +140,7 @@ Oxidized supports ```CSV```, ```SQLite``` and ```HTTP``` as source backends. The
|
|
113
140
|
|
114
141
|
Possible outputs are either ```file``` or ```git```. The file backend takes a destination directory as argument and will keep a file per device, with most recent running version of a device. The GIT backend (recommended) will initialize an empty GIT repository in the specified path and create a new commit on every configuration change. Take a look at the [Cookbook](#cookbook) for more details.
|
115
142
|
|
116
|
-
Maps define how to map a model's fields to model [model fields](https://github.com/ytti/oxidized/tree/master/lib/oxidized/model). Most of the settings should be self explanatory, log is ignored if
|
143
|
+
Maps define how to map a model's fields to model [model fields](https://github.com/ytti/oxidized/tree/master/lib/oxidized/model). Most of the settings should be self explanatory, log is ignored if `use_syslog`(requires Ruby >= 2.0) is set to `true`.
|
117
144
|
|
118
145
|
First create the directory where the CSV ```output``` is going to store device configs and start Oxidized once.
|
119
146
|
```
|
@@ -444,6 +471,8 @@ OX_NODE_MSG
|
|
444
471
|
OX_NODE_GROUP
|
445
472
|
OX_JOB_STATUS
|
446
473
|
OX_JOB_TIME
|
474
|
+
OX_REPO_COMMITREF
|
475
|
+
OX_REPO_NAME
|
447
476
|
```
|
448
477
|
|
449
478
|
Exec hook recognizes following configuration keys:
|
data/Rakefile
CHANGED
@@ -1,10 +1,5 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require 'bundler'
|
4
|
-
# Bundler.setup
|
5
|
-
rescue LoadError
|
6
|
-
warn 'bundler missing'
|
7
|
-
end
|
1
|
+
require 'bundler/gem_tasks'
|
2
|
+
require 'rake/testtask'
|
8
3
|
|
9
4
|
gemspec = eval(File.read(Dir['*.gemspec'].first))
|
10
5
|
file = [gemspec.name, gemspec.version].join('-') + '.gem'
|
@@ -17,8 +12,9 @@ end
|
|
17
12
|
desc 'Run minitest'
|
18
13
|
task :test do
|
19
14
|
Rake::TestTask.new do |t|
|
20
|
-
t.libs
|
21
|
-
t.test_files = FileList['spec
|
15
|
+
t.libs << 'spec'
|
16
|
+
t.test_files = FileList['spec/**/*_spec.rb']
|
17
|
+
t.warning = true
|
22
18
|
t.verbose = true
|
23
19
|
end
|
24
20
|
end
|
@@ -49,3 +45,5 @@ desc 'Push to rubygems'
|
|
49
45
|
task :push => :tag do
|
50
46
|
system "gem push gems/#{file}"
|
51
47
|
end
|
48
|
+
|
49
|
+
task default: :test
|
data/bin/console
ADDED
data/bin/oxidized
CHANGED
@@ -23,12 +23,12 @@ json.each do |node|
|
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
-
if
|
27
|
-
puts '[WARN] Pending backup: ' + pending_nodes.join(',')
|
28
|
-
exit 1
|
29
|
-
elsif critical
|
26
|
+
if critical
|
30
27
|
puts '[CRIT] Unable to backup: ' + critical_nodes.join(',')
|
31
28
|
exit 2
|
29
|
+
elsif pending
|
30
|
+
puts '[WARN] Pending backup: ' + pending_nodes.join(',')
|
31
|
+
exit 1
|
32
32
|
else
|
33
33
|
puts '[OK] Backup of all nodes completed successfully.'
|
34
34
|
exit 0
|
@@ -0,0 +1,80 @@
|
|
1
|
+
#!/bin/sh
|
2
|
+
#
|
3
|
+
# A script to maintain a local working copy of an oxidized configuration
|
4
|
+
# repository and mail out diffs for configuration changes
|
5
|
+
#
|
6
|
+
# Copyright 2016 Nick Hilliard <nick@foobar.org>, All Rights Reserved
|
7
|
+
#
|
8
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
9
|
+
# you may not use this file except in compliance with the License.
|
10
|
+
# You may obtain a copy of the License at
|
11
|
+
#
|
12
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
13
|
+
#
|
14
|
+
# Unless required by applicable law or agreed to in writing, software
|
15
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
16
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
17
|
+
# See the License for the specific language governing permissions and
|
18
|
+
# limitations under the License.
|
19
|
+
#
|
20
|
+
# usage: add the following hook to the oxidized config file:
|
21
|
+
#
|
22
|
+
# hooks:
|
23
|
+
# email_output:
|
24
|
+
# type: exec
|
25
|
+
# events: [post_store, node_fail]
|
26
|
+
# cmd: 'update-local-repo.sh ~/gitdir/ | mail -s "Oxidized updates for ${OX_NODE_NAME}" update-recipient@example.com'
|
27
|
+
# async: true
|
28
|
+
# timeout: 120
|
29
|
+
#
|
30
|
+
#
|
31
|
+
# The script takes a single argument, namely a git working directory name,
|
32
|
+
# e.g. "~/gitdir/". This is only used as a staging directory and should
|
33
|
+
# not be set to be the same as the git repo directory.
|
34
|
+
#
|
35
|
+
|
36
|
+
PATH=${PATH}:/usr/local/bin:/usr/local/sbin
|
37
|
+
export PATH
|
38
|
+
|
39
|
+
gitdir=$1
|
40
|
+
|
41
|
+
if [ X${OX_REPO_COMMITREF} = "X" ]; then
|
42
|
+
echo \$OX_REPO_COMMITREF not set
|
43
|
+
exit 64
|
44
|
+
fi
|
45
|
+
|
46
|
+
if [ X${OX_REPO_NAME} = "X" ]; then
|
47
|
+
echo \$OX_REPO_NAME not set
|
48
|
+
exit 64
|
49
|
+
fi
|
50
|
+
|
51
|
+
if [ ! -d ${gitdir}/.git ]; then
|
52
|
+
git clone -q ${OX_REPO_NAME} ${gitdir}
|
53
|
+
|
54
|
+
ret=$?
|
55
|
+
if [ X"${ret}" != X0 ] && [ X"${ret}" != X1 ]; then
|
56
|
+
echo git clone failed: aborting.
|
57
|
+
exit 128
|
58
|
+
fi
|
59
|
+
fi
|
60
|
+
|
61
|
+
cd ${gitdir}
|
62
|
+
|
63
|
+
git pull -q > /dev/null 2>&1
|
64
|
+
ret=$?
|
65
|
+
if [ X"${ret}" != X0 ] && [ X"${ret}" != X1 ]; then
|
66
|
+
echo git pull failed: aborting.
|
67
|
+
exit 128
|
68
|
+
fi
|
69
|
+
|
70
|
+
# Git is probably working at this stage, so safe to emit more info
|
71
|
+
|
72
|
+
echo "Node name: ${OX_NODE_NAME}"
|
73
|
+
echo "Group Name: ${OX_NODE_GROUP}"
|
74
|
+
echo "Job Time: ${OX_JOB_TIME}"
|
75
|
+
echo "Git Commit ID: ${OX_REPO_COMMITREF}"
|
76
|
+
echo "Git Repo: ${OX_REPO_NAME}"
|
77
|
+
echo "Local working dir: ${gitdir}"
|
78
|
+
echo ""
|
79
|
+
|
80
|
+
git diff --no-color ${OX_REPO_COMMITREF}~1..${OX_REPO_COMMITREF}
|
@@ -0,0 +1,18 @@
|
|
1
|
+
start on started networking
|
2
|
+
|
3
|
+
respawn
|
4
|
+
|
5
|
+
setuid oxidized
|
6
|
+
setgid oxidized
|
7
|
+
|
8
|
+
chdir /home/oxidized
|
9
|
+
|
10
|
+
env HOME=/home/oxidized
|
11
|
+
|
12
|
+
pre-start script
|
13
|
+
test -x /usr/local/rvm/wrappers/ruby-2.1.2/oxidized || { stop; exit 0; }
|
14
|
+
end script
|
15
|
+
|
16
|
+
script
|
17
|
+
exec /usr/local/rvm/wrappers/ruby-2.1.2/oxidized
|
18
|
+
end script
|
data/lib/oxidized.rb
CHANGED
@@ -1,6 +1,49 @@
|
|
1
1
|
module Oxidized
|
2
2
|
class OxidizedError < StandardError; end
|
3
|
-
|
4
|
-
Directory = File.expand_path
|
3
|
+
|
4
|
+
Directory = File.expand_path(File.join(File.dirname(__FILE__), '../'))
|
5
|
+
|
6
|
+
require 'oxidized/string'
|
7
|
+
require 'oxidized/config'
|
8
|
+
require 'oxidized/config/vars'
|
9
|
+
require 'oxidized/worker'
|
10
|
+
require 'oxidized/nodes'
|
11
|
+
require 'oxidized/manager'
|
12
|
+
require 'oxidized/hook'
|
5
13
|
require 'oxidized/core'
|
14
|
+
|
15
|
+
def self.asetus
|
16
|
+
@@asetus
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.asetus=(val)
|
20
|
+
@@asetus = val
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.config
|
24
|
+
asetus.cfg
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.logger
|
28
|
+
@@logger
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.logger=(val)
|
32
|
+
@@logger = val
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.setup_logger
|
36
|
+
self.logger = if config.has_key?('use_syslog') && config.use_syslog
|
37
|
+
require 'syslog/logger'
|
38
|
+
Syslog::Logger.new('oxidized')
|
39
|
+
else
|
40
|
+
require 'logger'
|
41
|
+
if config.has_key?('log')
|
42
|
+
Logger.new(config.log)
|
43
|
+
else
|
44
|
+
Logger.new(STDERR)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
logger.level = Logger::INFO unless config.debug
|
48
|
+
end
|
6
49
|
end
|
data/lib/oxidized/cli.rb
CHANGED
@@ -1,11 +1,14 @@
|
|
1
1
|
module Oxidized
|
2
2
|
class CLI
|
3
|
-
require 'oxidized'
|
4
3
|
require 'slop'
|
4
|
+
require 'oxidized'
|
5
5
|
|
6
6
|
def run
|
7
|
+
check_pid
|
7
8
|
Process.daemon if @opts[:daemonize]
|
9
|
+
write_pid
|
8
10
|
begin
|
11
|
+
Oxidized.logger.info "Oxidized starting, running as pid #{$$}"
|
9
12
|
Oxidized.new
|
10
13
|
rescue => error
|
11
14
|
crash error
|
@@ -16,13 +19,16 @@ module Oxidized
|
|
16
19
|
private
|
17
20
|
|
18
21
|
def initialize
|
19
|
-
Log.info "Oxidized starting, running as pid #{$$}"
|
20
22
|
_args, @opts = parse_opts
|
21
|
-
|
23
|
+
|
24
|
+
Config.load(@opts)
|
25
|
+
Oxidized.setup_logger
|
26
|
+
|
27
|
+
@pidfile = File.expand_path("pid")
|
22
28
|
end
|
23
29
|
|
24
30
|
def crash error
|
25
|
-
|
31
|
+
Oxidized.logger.fatal "Oxidized crashed, crashfile written in #{Config::Crash}"
|
26
32
|
open Config::Crash, 'w' do |file|
|
27
33
|
file.puts '-' * 50
|
28
34
|
file.puts Time.now.utc
|
@@ -40,5 +46,49 @@ module Oxidized
|
|
40
46
|
end
|
41
47
|
[opts.parse!, opts]
|
42
48
|
end
|
49
|
+
|
50
|
+
def pidfile
|
51
|
+
@pidfile
|
52
|
+
end
|
53
|
+
|
54
|
+
def pidfile?
|
55
|
+
!!pidfile
|
56
|
+
end
|
57
|
+
|
58
|
+
def write_pid
|
59
|
+
if pidfile?
|
60
|
+
begin
|
61
|
+
File.open(pidfile, ::File::CREAT | ::File::EXCL | ::File::WRONLY){|f| f.write("#{Process.pid}") }
|
62
|
+
at_exit { File.delete(pidfile) if File.exists?(pidfile) }
|
63
|
+
rescue Errno::EEXIST
|
64
|
+
check_pid
|
65
|
+
retry
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def check_pid
|
71
|
+
if pidfile?
|
72
|
+
case pid_status(pidfile)
|
73
|
+
when :running, :not_owned
|
74
|
+
puts "A server is already running. Check #{pidfile}"
|
75
|
+
exit(1)
|
76
|
+
when :dead
|
77
|
+
File.delete(pidfile)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def pid_status(pidfile)
|
83
|
+
return :exited unless File.exists?(pidfile)
|
84
|
+
pid = ::File.read(pidfile).to_i
|
85
|
+
return :dead if pid == 0
|
86
|
+
Process.kill(0, pid)
|
87
|
+
:running
|
88
|
+
rescue Errno::ESRCH
|
89
|
+
:dead
|
90
|
+
rescue Errno::EPERM
|
91
|
+
:not_owned
|
92
|
+
end
|
43
93
|
end
|
44
94
|
end
|