oxidized 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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