oxidized 0.3.0 → 0.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c4e125d54180398e4fd35652a8ca384c85d451ec
4
- data.tar.gz: 46cef914c85dcaadfafcbde310d7c9bbc3707f0b
3
+ metadata.gz: c8b4c0fb1595706703f57f1d8235cb0521186931
4
+ data.tar.gz: ec43f93a8c891a3818d36daf7376650da1b4cc59
5
5
  SHA512:
6
- metadata.gz: 0261cf513efbab1d3bc06ff184c72e70d7371256628441501e2b1d2a44796531091f4fba0eee3b93130993030c4c3e1d78d8c33db01727c17af1760337640f32
7
- data.tar.gz: 0662f963ddcbd6da7ab8e6e1cd12ef723c88511cd69ed4673e58e66f00657287cc39c6aec9b0e66bb4c2b441474aa76a67f5bab3a8b5ed7e16ddd1c845236272
6
+ metadata.gz: 31482aac75b5c83ea25f2e8d3c92ab86f09813caca3e68612a2a719bda2c142bacdf95e29094abf87b0c5f3fa49cfb8fc4a61cd6c4a968cc6f2e60e276282197
7
+ data.tar.gz: 7a41f80ef435e574734ec761b32c5f86849d4cea2425cdc40694809e59a7087b3618ab174f92d37ef6ab86567d9cda029649c123829b84f5160600db90b9c0da
data/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ # 0.4.0
2
+ - FEATURE: allow setting IP address in addition to name in source (SQL/CSV)
3
+ - FEATURE: approximate how long it takes to get node from larger view than 1
4
+ - FEATURE: unconditionally start new job if too long has passed since previous start
5
+ - FEATURE: add enable to Arista EOS model
6
+ - FEATURE: add rugged dependency in gemspec
7
+ - FEATURE: log prompt detection failures
8
+ - BUGFIX: xos while using telnet (by @fhibler)
9
+ - BUGFIX: ironware logout on some models (by @fhibler)
10
+ - BUGFIX: allow node to be removed while it is being collected
11
+ - BUGFIX: if model returns non string value, return empty string
12
+ - BUGFIX: better prompt for Arista EOS model (by @rodecker)
13
+ - BUGFIX: improved configuration handling for Arista EOS model (by @rodecker)
14
+
1
15
  # 0.3.0
2
16
  - FEATURE: *FIXME* bunch of stuff I did for richih, docs needed
3
17
  - FEATURE: ComWare model (by erJasp)
data/README.md CHANGED
@@ -71,7 +71,6 @@ Install all required packages and gems.
71
71
 
72
72
  ```shell
73
73
  apt-get install ruby ruby-dev libsqlite3-dev libssl-dev pkg-config cmake
74
- gem install rugged
75
74
  gem install oxidized
76
75
  gem install oxidized-script oxidized-web # if you don't install oxidized-web, make sure you remove "rest" from your config
77
76
  ```
@@ -193,7 +192,7 @@ source:
193
192
  model: 1
194
193
  username: 2
195
194
  password: 3
196
- var_map:
195
+ vars_map:
197
196
  enable: 4
198
197
  ```
199
198
 
@@ -213,7 +212,7 @@ source:
213
212
  model: model
214
213
  username: username
215
214
  password: password
216
- var_map:
215
+ vars_map:
217
216
  enable: enable
218
217
  ```
219
218
 
@@ -279,7 +278,7 @@ source:
279
278
  model: 1
280
279
  username: 2
281
280
  password: 3
282
- var_map:
281
+ vars_map:
283
282
  enable: 4
284
283
  model_map:
285
284
  cisco: ios
data/Rakefile CHANGED
@@ -3,7 +3,7 @@ begin
3
3
  require 'bundler'
4
4
  # Bundler.setup
5
5
  rescue LoadError
6
- warn 'bunler missing'
6
+ warn 'bundler missing'
7
7
  end
8
8
 
9
9
  gemspec = eval(File.read(Dir['*.gemspec'].first))
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ ## contrib via https://github.com/ytti/oxidized/issues/67
4
+
5
+ require 'open-uri'
6
+ require 'json'
7
+
8
+ critical = false
9
+ critical_nodes = []
10
+
11
+ json = JSON.load(open("http://localhost:8888/nodes.json"))
12
+ json.each do |node|
13
+ if node['last']['status'] != 'success'
14
+ critical_nodes << node['name']
15
+ critical = true
16
+ end
17
+ end
18
+
19
+ if critical
20
+ puts 'Unable to backup: ' + critical_nodes.join(' ')
21
+ exit 2
22
+ else
23
+ puts 'Backup of all nodes completed successfully.'
24
+ exit 0
25
+ end
data/lib/oxidized/core.rb CHANGED
@@ -17,6 +17,7 @@ module Oxidized
17
17
  Oxidized.mgr = Manager.new
18
18
  nodes = Nodes.new
19
19
  @worker = Worker.new nodes
20
+ trap('HUP') { nodes.load }
20
21
  if CFG.rest?
21
22
  begin
22
23
  require 'oxidized/web'
@@ -1,4 +1,5 @@
1
1
  module Oxidized
2
+ class PromptUndetect < OxidizedError; end
2
3
  class Input
3
4
  include Oxidized::Config::Vars
4
5
 
@@ -8,6 +9,7 @@ module Oxidized
8
9
  ],
9
10
  :warn => [
10
11
  IOError,
12
+ PromptUndetect,
11
13
  Timeout::Error,
12
14
  Errno::ECONNRESET,
13
15
  Errno::EHOSTUNREACH,
@@ -26,7 +26,11 @@ module Oxidized
26
26
  :paranoid => secure
27
27
  unless @exec
28
28
  shell_open @ssh
29
- @username ? shell_login : expect(@node.prompt)
29
+ begin
30
+ @username ? shell_login : expect(@node.prompt)
31
+ rescue Timeout::Error
32
+ raise PromptUndetect, [ @output, 'not matching configured prompt', @node.prompt ].join(' ')
33
+ end
30
34
  end
31
35
  connected?
32
36
  end
@@ -20,7 +20,11 @@ module Oxidized
20
20
  @telnet.puts @node.auth[:username]
21
21
  expect password
22
22
  @telnet.puts @node.auth[:password]
23
- expect @node.prompt
23
+ begin
24
+ expect @node.prompt
25
+ rescue Timeout::Error
26
+ raise PromptUndetect, [ 'unable to detect prompt:', @node.prompt ].join(' ')
27
+ end
24
28
  end
25
29
 
26
30
  def connected?
data/lib/oxidized/jobs.rb CHANGED
@@ -1,24 +1,46 @@
1
1
  module Oxidized
2
2
  class Jobs < Array
3
- attr_accessor :interval, :duration, :max, :want
3
+ AVERAGE_DURATION = 5 # initially presume nodes take 5s to complete
4
+ MAX_INTER_JOB_GAP = 300 # add job if more than X from last job started
5
+ attr_accessor :interval, :max, :want
6
+
4
7
  def initialize max, interval, nodes
5
8
  @max = max
6
- #@interval = interval * 60
7
9
  @interval = interval
8
10
  @nodes = nodes
9
- @duration = 4
10
- new_count
11
+ @last = Time.now.utc
12
+ @durations = Array.new @nodes.size, AVERAGE_DURATION
13
+ duration AVERAGE_DURATION
11
14
  super()
12
15
  end
16
+
17
+ def push arg
18
+ @last = Time.now.utc
19
+ super
20
+ end
21
+
13
22
  def duration last
14
- @duration = (@duration + last) / 2
23
+ @durations.push(last).shift
24
+ @duration = @durations.inject(:+).to_f / @nodes.size #rolling average
15
25
  new_count
16
26
  end
27
+
17
28
  def new_count
18
29
  @want = ((@nodes.size * @duration) / @interval).to_i
19
30
  @want = 1 if @want < 1
20
31
  @want = @nodes.size if @want > @nodes.size
21
32
  @want = @max if @want > @max
22
33
  end
34
+
35
+ def work
36
+ # if a) we want less or same amount of threads as we now running
37
+ # and b) we want less threads running than the total amount of nodes
38
+ # and c) there is more than MAX_INTER_JOB_GAP since last one was started
39
+ # then we want one more thread (rationale is to fix hanging thread causing HOLB)
40
+ if @want <= size and @want < @nodes.size
41
+ @want +=1 if (Time.now.utc - @last) > MAX_INTER_JOB_GAP
42
+ end
43
+ end
44
+
23
45
  end
24
46
  end
@@ -1,14 +1,13 @@
1
1
  class EOS < Oxidized::Model
2
2
 
3
3
  # Arista EOS model #
4
- # need to add telnet support here .. #
5
4
 
6
- prompt /^[^\(]+\([^\)]+\)#/
5
+ prompt /^.+[#>]\s?$/
7
6
 
8
7
  comment '! '
9
8
 
10
9
  cmd :all do |cfg|
11
- cfg.each_line.to_a[2..-2].join
10
+ cfg.each_line.to_a[1..-2].join
12
11
  end
13
12
 
14
13
  cmd :secret do |cfg|
@@ -26,7 +25,17 @@ class EOS < Oxidized::Model
26
25
  end
27
26
 
28
27
  cfg :telnet, :ssh do
28
+ if vars :enable
29
+ post_login do
30
+ send "enable\n"
31
+ expect /[pP]assword:\s?$/
32
+ send vars(:enable) + "\n"
33
+ expect /^.+[#>]\s?$/
34
+ end
35
+ post_login 'terminal length 0'
36
+ end
29
37
  pre_logout 'exit'
30
38
  end
31
39
 
32
40
  end
41
+
@@ -27,7 +27,7 @@ class IronWare < Oxidized::Model
27
27
 
28
28
  cfg :telnet, :ssh do
29
29
  post_login 'skip-page-display'
30
- pre_logout 'exit'
30
+ pre_logout 'logout'
31
31
  end
32
32
 
33
33
  end
@@ -133,10 +133,10 @@ module Oxidized
133
133
  outputs << out
134
134
  end
135
135
  procs[:pre].each do |pre_proc|
136
- outputs.unshift Oxidized::String.new(instance_eval(&pre_proc))
136
+ outputs.unshift process_cmd_output(instance_eval(&pre_proc), '')
137
137
  end
138
138
  procs[:post].each do |post_proc|
139
- outputs << Oxidized::String.new(instance_eval(&post_proc))
139
+ outputs << process_cmd_output(instance_eval(&post_proc), '')
140
140
  end
141
141
  outputs
142
142
  end
@@ -152,9 +152,8 @@ module Oxidized
152
152
  private
153
153
 
154
154
  def process_cmd_output output, name
155
- if output.class != Oxidized::String
156
- output = Oxidized::String.new output
157
- end
155
+ output = Oxidized::String.new output if ::String === output
156
+ output = Oxidized::String.new '' unless Oxidized::String === output
158
157
  output.set_cmd(name)
159
158
  output
160
159
  end
@@ -29,7 +29,7 @@ class XOS < Oxidized::Model
29
29
 
30
30
  cfg :telnet do
31
31
  username /^login:/
32
- password /^passowrd:/
32
+ password /^\r*password:/
33
33
  end
34
34
 
35
35
  cfg :telnet, :ssh do
data/lib/oxidized/node.rb CHANGED
@@ -10,7 +10,8 @@ module Oxidized
10
10
  alias :running? :running
11
11
  def initialize opt
12
12
  @name = opt[:name]
13
- @ip = Resolv.getaddress @name
13
+ @ip = IPAddr.new(opt[:ip]).to_s rescue nil
14
+ @ip ||= Resolv.new.getaddress @name
14
15
  @group = opt[:group]
15
16
  @input = resolve_input opt
16
17
  @output = resolve_output opt
@@ -1,6 +1,6 @@
1
1
  module Oxidized
2
- require 'oxidized/node'
3
2
  require 'ipaddr'
3
+ require 'oxidized/node'
4
4
  class Oxidized::NotSupported < OxidizedError; end
5
5
  class Oxidized::NodeNotFound < OxidizedError; end
6
6
  class Nodes < Array
@@ -23,8 +23,8 @@ module Oxidized
23
23
  Log.error "node %s is not resolvable, raised %s with message '%s'" % [node, err.class, err.message]
24
24
  end
25
25
  end
26
- Log.info "Loaded #{size} nodes"
27
26
  size == 0 ? replace(new) : update_nodes(new)
27
+ Log.info "Loaded #{size} nodes"
28
28
  end
29
29
  end
30
30
 
@@ -1,5 +1,6 @@
1
1
  module Oxidized
2
2
  class Git < Output
3
+ class GitError < OxidizedError; end
3
4
  begin
4
5
  gem 'rugged', '~> 0.21.0'
5
6
  require 'rugged'
@@ -71,8 +72,12 @@ class Git < Output
71
72
  end
72
73
  repo = Rugged::Repository.new repo
73
74
  update_repo repo, file, data, @msg, @user, @email
74
- rescue Rugged::OSError, Rugged::RepositoryError
75
- Rugged::Repository.init_at repo, :bare
75
+ rescue Rugged::OSError, Rugged::RepositoryError => open_error
76
+ begin
77
+ Rugged::Repository.init_at repo, :bare
78
+ rescue => create_error
79
+ raise GitError, "first '#{open_error.message}' was raised while opening git repo, then '#{create_error.message}' was while trying to create git repo"
80
+ end
76
81
  retry
77
82
  end
78
83
 
@@ -7,10 +7,12 @@ module Oxidized
7
7
  @jobs = Jobs.new CFG.threads, CFG.interval, @nodes
8
8
  Thread.abort_on_exception = true
9
9
  end
10
+
10
11
  def work
11
12
  ended = []
12
13
  @jobs.delete_if { |job| ended << job if not job.alive? }
13
14
  ended.each { |job| process job }
15
+ @jobs.work
14
16
  while @jobs.size < @jobs.want
15
17
  Log.debug "Jobs #{@jobs.size}, Want: #{@jobs.want}"
16
18
  # ask for next node in queue non destructive way
@@ -24,6 +26,7 @@ module Oxidized
24
26
  @jobs.push Job.new node
25
27
  end
26
28
  end
29
+
27
30
  def process job
28
31
  node = job.node
29
32
  node.last = job
@@ -49,6 +52,9 @@ module Oxidized
49
52
  end
50
53
  Log.warn msg
51
54
  end
55
+ rescue NodeNotFound
56
+ Log.warn "#{node.name} not found, removed while collecting?"
52
57
  end
58
+
53
59
  end
54
60
  end
data/oxidized.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'oxidized'
3
- s.version = '0.3.0'
3
+ s.version = '0.4.0'
4
4
  s.licenses = %w( Apache-2.0 )
5
5
  s.platform = Gem::Platform::RUBY
6
6
  s.authors = [ 'Saku Ytti', 'Samer Abdel-Hafez' ]
@@ -17,4 +17,5 @@ Gem::Specification.new do |s|
17
17
  s.add_runtime_dependency 'asetus', '~> 0.1'
18
18
  s.add_runtime_dependency 'slop', '~> 3.5'
19
19
  s.add_runtime_dependency 'net-ssh', '~> 2.8'
20
+ s.add_runtime_dependency 'rugged', '~> 0.21.4'
20
21
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: oxidized
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Saku Ytti
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-02-13 00:00:00.000000000 Z
12
+ date: 2015-03-06 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: asetus
@@ -53,6 +53,20 @@ dependencies:
53
53
  - - "~>"
54
54
  - !ruby/object:Gem::Version
55
55
  version: '2.8'
56
+ - !ruby/object:Gem::Dependency
57
+ name: rugged
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - "~>"
61
+ - !ruby/object:Gem::Version
62
+ version: 0.21.4
63
+ type: :runtime
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: 0.21.4
56
70
  description: software to fetch configuration from network devices and store them
57
71
  email:
58
72
  - saku@ytti.fi
@@ -68,6 +82,7 @@ files:
68
82
  - Rakefile
69
83
  - TODO.md
70
84
  - bin/oxidized
85
+ - extra/nagios_check_failing_nodes.rb
71
86
  - extra/oxidized.init
72
87
  - extra/rest_client.rb
73
88
  - extra/syslog.rb