summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md113
-rwxr-xr-xbin/oxidized21
-rw-r--r--lib/oxidized/cli.rb48
-rw-r--r--lib/oxidized/config.rb44
-rw-r--r--lib/oxidized/config/bootstrap.rb33
-rw-r--r--lib/oxidized/config/core.rb33
-rw-r--r--lib/oxidized/config/defaults.rb14
-rw-r--r--lib/oxidized/core.rb2
-rw-r--r--lib/oxidized/input/ssh.rb14
-rw-r--r--lib/oxidized/input/telnet.rb2
-rw-r--r--lib/oxidized/node.rb4
-rw-r--r--lib/oxidized/nodes.rb2
-rw-r--r--lib/oxidized/output/file.rb15
-rw-r--r--lib/oxidized/output/git.rb23
-rw-r--r--lib/oxidized/output/output.rb1
-rw-r--r--lib/oxidized/source/csv.rb27
-rw-r--r--lib/oxidized/source/source.rb1
-rw-r--r--lib/oxidized/source/sql.rb29
-rw-r--r--oxidized.gemspec1
19 files changed, 221 insertions, 206 deletions
diff --git a/README.md b/README.md
index c22631f..55c84d3 100644
--- a/README.md
+++ b/README.md
@@ -12,10 +12,10 @@
* early days, but try:
1. apt-get install libsqlite3-dev libssl-dev
2. gem install oxidized
- 3. oxidized
+ 3. oxidized -d
4. vi ~/.config/oxidized/config
5. (maybe point to your rancid/router.db or copy it there)
- 6. oxidized
+ 6. oxidized -d
# API
## Input
@@ -50,63 +50,78 @@
### Configuration I use in one environment
```
-[rancid@lan-login1 /var/rancid/.config/oxidized]% cat config
---
-:username: LANA
-:password: LANAAAAAAA
-:output:
- :default: git
- :git:
- :user: Oxidized
- :email: o@example.com
- :repo: "/usr/local/lan/oxidized.git"
-:source:
- :default: sql
- :sql:
- :adapter: sqlite
- :file: "/usr/local/lan/corona.db"
- :table: device
- :map:
- :name: ptr
- :model: model
-[rancid@lan-login1 /var/rancid/.config/oxidized]%
+username: LANA
+password: LANAAAAAAA
+output:
+ default: git
+ git:
+ user: Oxidized
+ email: o@example.com
+ repo: "/usr/local/lan/oxidized.git"
+source:
+ default: sql
+ sql:
+ adapter: sqlite
+ file: "/usr/local/lan/corona.db"
+ table: device
+ map:
+ name: ptr
+ model: model
```
-### Configuration you end up after first run (and it'll crash on missing router.d file)
+### Configuration you end up after first run
+If you don't configure output and source, it'll further fill them with example
+configs for your chosen output/source in subsequent runs
```
---
-:username: username
-:password: password
-:model: junos
-:interval: 3600
-:log: "/var/rancid/.config/oxidized/log"
-:debug: false
-:threads: 30
-:timeout: 5
-:prompt: !ruby/regexp /^([\w.@-]+[#>]\s?)$/
-:rest: 0.0.0.0:8888
-:vars:
- :enable: enablePW
-:input:
- :default: ssh, telnet
- :ssh:
- :secure: false
-:output:
- :default: git
-:source:
- :default: csv
- :csv:
- :file: "/var/rancid/.config/oxidized/router.db"
- :delimiter: !ruby/regexp /:/
- :map:
- :name: 0
- :model: 1
-:model_map:
+username: username
+password: password
+model: junos
+interval: 3600
+log: "/home/fisakytt/.config/oxidized/log"
+debug: false
+threads: 30
+timeout: 30
+prompt: !ruby/regexp /^([\w.@-]+[#>]\s?)$/
+rest: 0.0.0.0:8888
+vars: {}
+input:
+ default: ssh, telnet
+ ssh:
+ secure: false
+output:
+ default: git
+source:
+ default: csv
+model_map:
cisco: ios
juniper: junos
```
+
+Output and Source could be:
+```
+output:
+ default: git
+ git:
+ user: Oxidized
+ email: o@example.com
+ repo: "/home/fisakytt/.config/oxidized/oxidized.git"
+source:
+ default: csv
+ csv:
+ file: "/home/fisakytt/.config/oxidized/router.db"
+ delimiter: !ruby/regexp /:/
+ map:
+ name: 0
+ model: 1
+```
which reads nodes from rancid compatible router.db maps their model names to
model names oxidized expects, stores config in git, will try ssh first then
telnet, wont crash on changed ssh keys
Hopefully most of them are obvious, log is ignored if Syslog::Logger exists
(>=2.0) and syslog is used instead.
+System wide configurations can be stored in /etc/oxidized/config, this might be
+useful for storing for example source information, if many users are using
+oxs/Oxidized::Script, which would allow user specific config only to include
+username+password
diff --git a/bin/oxidized b/bin/oxidized
index 36ab250..f2fb9ff 100755
--- a/bin/oxidized
+++ b/bin/oxidized
@@ -1,19 +1,12 @@
#!/usr/bin/env ruby
-trap("INT") { exit } # sinatra will otherwise steak this from us
+# FIX ME, killing oxidized needs -9
+trap("INT") { exit } # sinatra will otherwise steal this from us
begin
- require 'oxidized'
- Process.daemon unless $DEBUG
- Oxidized.new
-rescue => e
- open Oxidized::Config::Crash, 'w' do |file|
- file.puts '-' * 50
- file.puts Time.now.utc
- file.puts e.message + ' [' + e.class.to_s + ']'
- file.puts '-' * 50
- file.puts e.backtrace
- file.puts '-' * 50
- end
- warn "ERROR: #{e}"
+ require 'oxidized/cli'
+ Oxidized::CLI.new.run
+rescue => error
+ warn "#{error}"
+ raise if Oxidized::CFG.debug
end
diff --git a/lib/oxidized/cli.rb b/lib/oxidized/cli.rb
new file mode 100644
index 0000000..720f405
--- /dev/null
+++ b/lib/oxidized/cli.rb
@@ -0,0 +1,48 @@
+module Oxidized
+ class CLI
+ require 'oxidized'
+ require 'slop'
+ class CLIError < OxidizedError; end
+ class NoConfig < CLIError; end
+
+ def run
+ Process.daemon unless CFG.debug
+ begin
+ Oxidized.new
+ rescue => error
+ crash error
+ raise
+ end
+ end
+
+ private
+
+ def initialize
+ if CFGS.system.empty? and CFGS.user.empty?
+ CFGS.user = CFGS.default
+ CFGS.save :user
+ raise NoConfig, 'edit ~/.config/oxidized/config'
+ end
+ _args, opts = parse_opts
+ CFG.debug = true if opts[:debug]
+ end
+
+ def crash error
+ open Config::Crash, 'w' do |file|
+ file.puts '-' * 50
+ file.puts Time.now.utc
+ file.puts error.message + ' [' + error.class.to_s + ']'
+ file.puts '-' * 50
+ file.puts error.backtrace
+ file.puts '-' * 50
+ end
+ end
+
+ def parse_opts
+ opts = Slop.new(:help=>true) do
+ on 'd', 'debug', 'turn on debugging'
+ end
+ [opts.parse!, opts]
+ end
+ end
+end
diff --git a/lib/oxidized/config.rb b/lib/oxidized/config.rb
new file mode 100644
index 0000000..475ae14
--- /dev/null
+++ b/lib/oxidized/config.rb
@@ -0,0 +1,44 @@
+module Oxidized
+ require 'asetus'
+ class Config
+ Root = File.join ENV['HOME'], '.config', 'oxidized'
+ Crash = File.join Root, 'crash'
+ InputDir = File.join Directory, %w(lib oxidized input)
+ OutputDir = File.join Directory, %w(lib oxidized output)
+ ModelDir = File.join Directory, %w(lib oxidized model)
+ SourceDir = File.join Directory, %w(lib oxidized source)
+ Sleep = 1
+ end
+ class << self
+ attr_accessor :mgr
+ end
+ CFGS = Asetus.new :name=>'oxidized', :load=>false, :key_to_s=>true
+ CFGS.default.username = 'username'
+ CFGS.default.password = 'password'
+ CFGS.default.model = 'junos'
+ CFGS.default.interval = 3600
+ CFGS.default.log = File.join Config::Root, 'log'
+ CFGS.default.debug = false
+ CFGS.default.threads = 30
+ CFGS.default.timeout = 30
+ CFGS.default.prompt = /^([\w.@-]+[#>]\s?)$/
+ CFGS.default.rest = '0.0.0.0:8888' # or false to disable
+ CFGS.default.vars = {} # could be 'enable'=>'enablePW'
+
+ CFGS.default.input.default = 'ssh, telnet'
+ CFGS.default.input.ssh.secure = false
+
+ CFGS.default.output.default = 'git'
+ CFGS.default.source.default = 'csv'
+
+ CFGS.default.model_map = {
+ 'cisco' => 'ios',
+ 'juniper' => 'junos',
+ }
+
+ CFGS.load # load system+user configs, merge to Config.cfg
+ CFG = CFGS.cfg # convenienence, instead of Config.cfg.password, CFG.password
+
+ Log.level = Logger::INFO unless CFG.debug
+ Log.file = CFG.log if CFG.log
+end
diff --git a/lib/oxidized/config/bootstrap.rb b/lib/oxidized/config/bootstrap.rb
deleted file mode 100644
index 008d88a..0000000
--- a/lib/oxidized/config/bootstrap.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-module Oxidized
- require 'fileutils'
- FileUtils.mkdir_p Config::Root
- CFG.username = 'username'
- CFG.password = 'password'
- CFG.model = 'junos'
- CFG.interval = 3600
- CFG.log = File.join Config::Root, 'log'
- CFG.debug = false
- CFG.threads = 30
- CFG.timeout = 30
- CFG.prompt = /^([\w.@-]+[#>]\s?)$/
- CFG.rest = '0.0.0.0:8888'
- CFG.vars = {
- #:enable => 'enablePW',
- }
- CFG.input = {
- :default => 'ssh, telnet',
- :ssh => {
- :secure => false,
- }
- }
- CFG.output = {
- :default => 'git',
- }
- CFG.source = {
- :default => 'csv',
- }
- CFG.model_map = {
- 'cisco' => 'ios',
- 'juniper' => 'junos',
- }
-end
diff --git a/lib/oxidized/config/core.rb b/lib/oxidized/config/core.rb
deleted file mode 100644
index 59ada3a..0000000
--- a/lib/oxidized/config/core.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-module Oxidized
- require 'ostruct'
- require 'yaml'
- class Config < OpenStruct
- require 'oxidized/config/defaults'
- # @param file [string] configuration file location
- def initialize file=File.join(Config::Root, 'config')
- super()
- @file = file.to_s
- end
- # load config from file or bootstrap with built-ins
- def load
- if File.exists? @file
- cfg = YAML.load_file @file
- marshal_load marshal_dump.merge(cfg)
- else
- save
- end
- end
- def defaults
- require 'oxidized/config/bootstrap'
- end
- # save config to file
- def save
- File.write @file, YAML.dump(marshal_dump)
- end
- end
- CFG = Config.new
- CFG.defaults
- CFG.load
- Log.level = Logger::INFO unless CFG.debug
- Log.file = CFG.log if CFG.log
-end
diff --git a/lib/oxidized/config/defaults.rb b/lib/oxidized/config/defaults.rb
deleted file mode 100644
index c30143f..0000000
--- a/lib/oxidized/config/defaults.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-module Oxidized
- class Config
- Root = File.join ENV['HOME'], '.config', 'oxidized'
- Crash = File.join Root, 'crash'
- InputDir = File.join Directory, %w(lib oxidized input)
- OutputDir = File.join Directory, %w(lib oxidized output)
- ModelDir = File.join Directory, %w(lib oxidized model)
- SourceDir = File.join Directory, %w(lib oxidized source)
- Sleep = 1
- end
- class << self
- attr_accessor :mgr
- end
-end
diff --git a/lib/oxidized/core.rb b/lib/oxidized/core.rb
index 14de9ab..3c728b6 100644
--- a/lib/oxidized/core.rb
+++ b/lib/oxidized/core.rb
@@ -1,6 +1,6 @@
module Oxidized
require 'oxidized/log'
- require 'oxidized/config/core'
+ require 'oxidized/config'
require 'oxidized/worker'
require 'oxidized/nodes'
require 'oxidized/manager'
diff --git a/lib/oxidized/input/ssh.rb b/lib/oxidized/input/ssh.rb
index dae1d74..570f8a8 100644
--- a/lib/oxidized/input/ssh.rb
+++ b/lib/oxidized/input/ssh.rb
@@ -12,14 +12,14 @@ module Oxidized
Net::SSH::AuthenticationFailed,
],
}
- include CLI
+ include Input::CLI
class NoShell < OxidizedError; end
def connect node
@node = node
@output = ''
@node.model.cfg['ssh'].each { |cb| instance_exec(&cb) }
- secure = CFG.input[:ssh][:secure]
+ secure = CFG.input.ssh.secure
@ssh = Net::SSH.start @node.ip, @node.auth[:username],
:password => @node.auth[:password], :timeout => CFG.timeout,
:paranoid => secure
@@ -64,14 +64,14 @@ module Oxidized
def shell_open ssh
@ses = ssh.open_channel do |ch|
- ch.on_data do |ch, data|
+ ch.on_data do |_ch, data|
@output << data
@output = @node.model.expects @output
end
- ch.request_pty do |ch, success|
- raise NoShell, "Can't get PTY" unless success
- ch.send_channel_request 'shell' do |ch, success|
- raise NoShell, "Can't get shell" unless success
+ ch.request_pty 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
end
end
end
diff --git a/lib/oxidized/input/telnet.rb b/lib/oxidized/input/telnet.rb
index 4e80ceb..218b13c 100644
--- a/lib/oxidized/input/telnet.rb
+++ b/lib/oxidized/input/telnet.rb
@@ -3,7 +3,7 @@ module Oxidized
require 'oxidized/input/cli'
class Telnet < Input
RescueFail = {}
- include CLI
+ include Input::CLI
attr_reader :telnet
def connect node
diff --git a/lib/oxidized/node.rb b/lib/oxidized/node.rb
index 0cb5cb3..3ac1c90 100644
--- a/lib/oxidized/node.rb
+++ b/lib/oxidized/node.rb
@@ -106,7 +106,7 @@ module Oxidized
end
def resolve_input opt
- inputs = (opt[:input] or CFG.input[:default])
+ inputs = (opt[:input] or CFG.input.default)
inputs.split(/\s*,\s*/).map do |input|
if not Oxidized.mgr.input[input]
Oxidized.mgr.add_input input or raise MethodNotFound, "#{input} not found for node #{ip}"
@@ -116,7 +116,7 @@ module Oxidized
end
def resolve_output opt
- output = (opt[:output] or CFG.output[:default])
+ output = (opt[:output] or CFG.output.default)
if not Oxidized.mgr.output[output]
Oxidized.mgr.add_output output or raise MethodNotFound, "#{output} not found for node #{ip}"
end
diff --git a/lib/oxidized/nodes.rb b/lib/oxidized/nodes.rb
index 8dadaef..213f534 100644
--- a/lib/oxidized/nodes.rb
+++ b/lib/oxidized/nodes.rb
@@ -10,7 +10,7 @@ module Oxidized
with_lock do
new = []
node_want_ip = (IPAddr.new(node_want) rescue nil) if node_want
- @source = CFG.source[:default]
+ @source = CFG.source.default
Oxidized.mgr.add_source @source
Oxidized.mgr.source[@source].new.load.each do |node|
diff --git a/lib/oxidized/output/file.rb b/lib/oxidized/output/file.rb
index ee8a9a6..f3443b4 100644
--- a/lib/oxidized/output/file.rb
+++ b/lib/oxidized/output/file.rb
@@ -3,20 +3,19 @@ class OxFile < Output
require 'fileutils'
def initialize
- @cfg = CFG.output[:file]
+ @cfg = CFG.output.file
end
def setup
- if not @cfg
- CFG.output[:file] = {
- :directory => File.join(Config::Root, 'configs')
- }
- CFG.save
+ if @cfg.empty?
+ CFGS.user.output.file.directory = File.join(Config::Root, 'configs')
+ CFGS.save :user
+ raise NoConfig, 'no output file config, edit ~/.config/oxidized/config'
end
end
def store node, data, opt={}
- file = @cfg[:directory]
+ file = @cfg.directory
if opt[:group]
file = File.join File.dirname(file), opt[:group]
end
@@ -26,7 +25,7 @@ class OxFile < Output
end
def fetch node, group
- cfg_dir = @cfg[:directory]
+ cfg_dir = @cfg.directory
if group # group is explicitly defined by user
IO.readlines File.join(cfg_dir, group, node)
else
diff --git a/lib/oxidized/output/git.rb b/lib/oxidized/output/git.rb
index b4fa4a8..ff9237b 100644
--- a/lib/oxidized/output/git.rb
+++ b/lib/oxidized/output/git.rb
@@ -5,25 +5,24 @@ class Git < Output
include Grit
def initialize
- @cfg = CFG.output[:git]
+ @cfg = CFG.output.git
end
def setup
- if not @cfg
- CFG.output[:git] = {
- :user => 'Oxidized',
- :email => 'o@example.com',
- :repo => File.join(Config::Root, 'oxidized.git')
- }
- CFG.save
+ if @cfg.empty?
+ CFGS.user.output.git.user = 'Oxidized'
+ CFGS.user.output.git.email = 'o@example.com'
+ CFGS.user.output.git.repo = File.join(Config::Root, 'oxidized.git')
+ CFGS.save :user
+ raise NoConfig, 'no output git config, edit ~/.config/oxidized/config'
end
end
def store file, data, opt={}
msg = opt[:msg]
- user = (opt[:user] or @cfg[:user])
- email = (opt[:email] or @cfg[:email])
- repo = @cfg[:repo]
+ user = (opt[:user] or @cfg.user)
+ email = (opt[:email] or @cfg.email)
+ repo = @cfg.repo
if opt[:group]
repo = File.join File.dirname(repo), opt[:group] + '.git'
end
@@ -41,7 +40,7 @@ class Git < Output
def fetch node, group
begin
- repo = Repo.new(@cfg[:repo])
+ repo = Repo.new(@cfg.repo)
(repo.tree / node).data
rescue
'node not found'
diff --git a/lib/oxidized/output/output.rb b/lib/oxidized/output/output.rb
index 61cb2b5..54d616c 100644
--- a/lib/oxidized/output/output.rb
+++ b/lib/oxidized/output/output.rb
@@ -1,5 +1,6 @@
module Oxidized
class Output
+ class NoConfig < OxidizedError; end
class << self
def inherited klass
Oxidized.mgr.loader = { :class => klass }
diff --git a/lib/oxidized/source/csv.rb b/lib/oxidized/source/csv.rb
index cf73fc8..9d291c7 100644
--- a/lib/oxidized/source/csv.rb
+++ b/lib/oxidized/source/csv.rb
@@ -1,31 +1,28 @@
module Oxidized
class CSV < Source
def initialize
- @cfg = CFG.source[:csv]
+ @cfg = CFG.source.csv
super
end
def setup
- if not @cfg
- CFG.source[:csv] = {
- :file => File.join(Config::Root, 'router.db'),
- :delimiter => /:/,
- :map => {
- :name => 0,
- :model => 1,
- }
- }
- CFG.save
+ if @cfg.empty?
+ CFGS.user.source.csv.file = File.join(Config::Root, 'router.db')
+ CFGS.user.source.csv.delimiter = /:/
+ CFGS.user.source.csv.map.name = 0
+ CFGS.user.source.csv.map.model = 1
+ CFGS.save :user
+ raise NoConfig, 'no source csv config, edit ~/.config/oxidized/config'
end
end
def load
nodes = []
- open(@cfg[:file]).each_line do |line|
- data = line.chomp.split @cfg[:delimiter]
+ open(@cfg.file).each_line do |line|
+ data = line.chomp.split @cfg.delimiter
keys = {}
- @cfg[:map].each do |key, position|
- keys[key] = data[position]
+ @cfg.map.each do |key, position|
+ keys[key.to_sym] = data[position]
end
keys[:model] = map_model keys[:model] if keys.key? :model
nodes << keys
diff --git a/lib/oxidized/source/source.rb b/lib/oxidized/source/source.rb
index f5976a0..93c9b6f 100644
--- a/lib/oxidized/source/source.rb
+++ b/lib/oxidized/source/source.rb
@@ -1,5 +1,6 @@
module Oxidized
class Source
+ class NoConfig < OxidizedError; end
class << self
def inherited klass
Oxidized.mgr.loader = { :class => klass }
diff --git a/lib/oxidized/source/sql.rb b/lib/oxidized/source/sql.rb
index 385f632..f84a7a8 100644
--- a/lib/oxidized/source/sql.rb
+++ b/lib/oxidized/source/sql.rb
@@ -4,34 +4,31 @@ class SQL < Source
def initialize
super
- @cfg = CFG.source[:sql]
+ @cfg = CFG.source.sql
end
def setup
- if not @cfg
- CFG.source[:sql] = {
- :adapter => 'sqlite',
- :file => File.join(Config::Root, 'sqlite.db'),
- :table => 'devices',
- :map => {
- :name => 'name',
- :model => 'rancid',
- }
- }
- CFG.save
+ if @cfg.empty?
+ CFGS.user.source.sql.adapter = 'sqlite'
+ CFGS.user.source.sql.file = File.join(Config::Root, 'sqlite.db')
+ CFGS.user.source.sql.table = 'devices'
+ CFGS.user.source.sql.map.name = 'name'
+ CFGS.user.source.sql.map.model = 'rancid'
+ CFGS.save :user
+ raise NoConfig, 'no source sql config, edit ~/.config/oxidized/config'
end
end
def load
nodes = []
- db = case @cfg[:adapter]
+ db = case @cfg.adapter
when 'sqlite'
require 'sqlite3'
- Sequel.sqlite @cfg[:file]
+ Sequel.sqlite @cfg.file
end
- db[@cfg[:table].to_sym].each do |node|
+ db[@cfg.table.to_sym].each do |node|
keys = {}
- @cfg[:map].each { |key, sql_column| keys[key] = node[sql_column.to_sym] }
+ @cfg.map.each { |key, sql_column| keys[key.to_sym] = node[sql_column.to_sym] }
keys[:model] = map_model keys[:model] if keys.key? :model
nodes << keys
end
diff --git a/oxidized.gemspec b/oxidized.gemspec
index 93d2674..2921d4b 100644
--- a/oxidized.gemspec
+++ b/oxidized.gemspec
@@ -21,5 +21,6 @@ Gem::Specification.new do |s|
s.add_dependency 'puma'
s.add_dependency 'haml'
s.add_dependency 'sass'
+ s.add_dependency 'slop'
end