oxidized 0.25.1 → 0.26.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (105) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +30 -9
  3. data/.rubocop_todo.yml +16 -637
  4. data/.travis.yml +2 -3
  5. data/CHANGELOG.md +14 -0
  6. data/Dockerfile +7 -5
  7. data/README.md +18 -14
  8. data/Rakefile +2 -2
  9. data/bin/console +1 -1
  10. data/bin/oxidized +2 -2
  11. data/docs/Configuration.md +6 -0
  12. data/docs/Model-Notes/README.md +1 -0
  13. data/docs/Model-Notes/SmartAX-Huawei.md +35 -0
  14. data/docs/Supported-OS-Types.md +12 -0
  15. data/extra/nagios_check_failing_nodes.rb +1 -1
  16. data/extra/rest_client.rb +6 -8
  17. data/extra/syslog.rb +33 -33
  18. data/lib/oxidized/cli.rb +25 -26
  19. data/lib/oxidized/config.rb +9 -9
  20. data/lib/oxidized/config/vars.rb +3 -7
  21. data/lib/oxidized/core.rb +4 -7
  22. data/lib/oxidized/hook.rb +16 -17
  23. data/lib/oxidized/hook/awssns.rb +4 -4
  24. data/lib/oxidized/hook/exec.rb +16 -20
  25. data/lib/oxidized/hook/githubrepo.rb +8 -14
  26. data/lib/oxidized/hook/noophook.rb +1 -1
  27. data/lib/oxidized/hook/xmppdiff.rb +1 -1
  28. data/lib/oxidized/input/cli.rb +12 -12
  29. data/lib/oxidized/input/ftp.rb +8 -8
  30. data/lib/oxidized/input/http.rb +37 -14
  31. data/lib/oxidized/input/input.rb +6 -6
  32. data/lib/oxidized/input/ssh.rb +31 -31
  33. data/lib/oxidized/input/telnet.rb +24 -24
  34. data/lib/oxidized/input/tftp.rb +9 -10
  35. data/lib/oxidized/jobs.rb +7 -7
  36. data/lib/oxidized/manager.rb +13 -13
  37. data/lib/oxidized/model/acos.rb +2 -2
  38. data/lib/oxidized/model/aireos.rb +3 -3
  39. data/lib/oxidized/model/aos7.rb +1 -1
  40. data/lib/oxidized/model/aosw.rb +12 -14
  41. data/lib/oxidized/model/apc_aos.rb +1 -1
  42. data/lib/oxidized/model/aricentiss.rb +6 -8
  43. data/lib/oxidized/model/asa.rb +1 -1
  44. data/lib/oxidized/model/audiocodesmp.rb +28 -0
  45. data/lib/oxidized/model/awplus.rb +9 -9
  46. data/lib/oxidized/model/boss.rb +1 -1
  47. data/lib/oxidized/model/ciscosmb.rb +1 -1
  48. data/lib/oxidized/model/ciscovpn3k.rb +11 -0
  49. data/lib/oxidized/model/comware.rb +1 -1
  50. data/lib/oxidized/model/cumulus.rb +3 -1
  51. data/lib/oxidized/model/dellx.rb +5 -5
  52. data/lib/oxidized/model/edgeos.rb +1 -1
  53. data/lib/oxidized/model/edgeswitch.rb +1 -1
  54. data/lib/oxidized/model/fabricos.rb +1 -1
  55. data/lib/oxidized/model/fortios.rb +5 -5
  56. data/lib/oxidized/model/ftos.rb +1 -1
  57. data/lib/oxidized/model/gcombnps.rb +7 -7
  58. data/lib/oxidized/model/grandstream.rb +9 -0
  59. data/lib/oxidized/model/hatteras.rb +8 -8
  60. data/lib/oxidized/model/ios.rb +22 -40
  61. data/lib/oxidized/model/ironware.rb +1 -1
  62. data/lib/oxidized/model/junos.rb +1 -1
  63. data/lib/oxidized/model/mlnxos.rb +1 -1
  64. data/lib/oxidized/model/model.rb +32 -38
  65. data/lib/oxidized/model/netgearxs716.rb +23 -0
  66. data/lib/oxidized/model/netonix.rb +1 -1
  67. data/lib/oxidized/model/netscaler.rb +1 -1
  68. data/lib/oxidized/model/nos.rb +2 -2
  69. data/lib/oxidized/model/nxos.rb +1 -1
  70. data/lib/oxidized/model/openbsd.rb +3 -2
  71. data/lib/oxidized/model/outputs.rb +4 -4
  72. data/lib/oxidized/model/planet.rb +4 -4
  73. data/lib/oxidized/model/powerconnect.rb +8 -8
  74. data/lib/oxidized/model/procurve.rb +2 -1
  75. data/lib/oxidized/model/quantaos.rb +3 -3
  76. data/lib/oxidized/model/raisecom.rb +19 -0
  77. data/lib/oxidized/model/siklu.rb +1 -1
  78. data/lib/oxidized/model/slxos.rb +1 -1
  79. data/lib/oxidized/model/smartax.rb +25 -0
  80. data/lib/oxidized/model/sros.rb +4 -4
  81. data/lib/oxidized/model/tdre.rb +30 -0
  82. data/lib/oxidized/model/tmos.rb +3 -0
  83. data/lib/oxidized/model/trango.rb +17 -37
  84. data/lib/oxidized/model/voltaire.rb +1 -1
  85. data/lib/oxidized/model/voss.rb +1 -1
  86. data/lib/oxidized/model/vyatta.rb +1 -1
  87. data/lib/oxidized/model/xos.rb +1 -1
  88. data/lib/oxidized/model/zhoneolt.rb +1 -1
  89. data/lib/oxidized/node.rb +42 -46
  90. data/lib/oxidized/node/stats.rb +6 -6
  91. data/lib/oxidized/nodes.rb +42 -42
  92. data/lib/oxidized/output/file.rb +16 -20
  93. data/lib/oxidized/output/git.rb +68 -78
  94. data/lib/oxidized/output/gitcrypt.rb +77 -91
  95. data/lib/oxidized/output/http.rb +17 -19
  96. data/lib/oxidized/output/output.rb +1 -1
  97. data/lib/oxidized/source/csv.rb +3 -3
  98. data/lib/oxidized/source/http.rb +11 -14
  99. data/lib/oxidized/source/source.rb +3 -3
  100. data/lib/oxidized/source/sql.rb +16 -18
  101. data/lib/oxidized/string.rb +10 -10
  102. data/lib/oxidized/version.rb +4 -4
  103. data/lib/oxidized/worker.rb +15 -15
  104. data/oxidized.gemspec +6 -9
  105. metadata +32 -25
@@ -5,17 +5,17 @@ module Oxidized
5
5
 
6
6
  class FTP < Input
7
7
  RescueFail = {
8
- :debug => [
8
+ debug: [
9
9
  # Net::SSH::Disconnect,
10
10
  ],
11
- :warn => [
11
+ warn: [
12
12
  # RuntimeError,
13
13
  # Net::SSH::AuthenticationFailed,
14
- ],
15
- }
14
+ ]
15
+ }.freeze
16
16
  include Input::CLI
17
17
 
18
- def connect node
18
+ def connect(node)
19
19
  @node = node
20
20
  @node.model.cfg['ftp'].each { |cb| instance_exec(&cb) }
21
21
  @log = File.open(Oxidized::Config::Log + "/#{@node.ip}-ftp", 'w') if Oxidized.config.input.debug?
@@ -26,16 +26,16 @@ module Oxidized
26
26
  end
27
27
 
28
28
  def connected?
29
- @ftp and not @ftp.closed?
29
+ @ftp && (not @ftp.closed?)
30
30
  end
31
31
 
32
- def cmd file
32
+ def cmd(file)
33
33
  Oxidized.logger.debug "FTP: #{file} @ #{@node.name}"
34
34
  @ftp.getbinaryfile file, nil
35
35
  end
36
36
 
37
37
  # meh not sure if this is the best way, but perhaps better than not implementing send
38
- def send my_proc
38
+ def send(my_proc)
39
39
  my_proc.call
40
40
  end
41
41
 
@@ -1,35 +1,58 @@
1
1
  module Oxidized
2
- require_relative "cli"
3
-
4
- begin
5
- require "mechanize"
6
- rescue LoadError
7
- raise OxidizedError, "mechanize not found: sudo gem install mechanize"
8
- end
2
+ require "oxidized/input/cli"
3
+ require "net/http"
4
+ require "json"
9
5
 
10
6
  class HTTP < Input
11
7
  include Input::CLI
12
8
 
13
- def connect node
9
+ def connect(node)
14
10
  @node = node
15
- @m = Mechanize.new
16
- @log = File.open(Oxidized::Config::Log + "/#{@node.ip}-http", "w") if Oxidized.config.input.debug?
17
-
11
+ @secure = false
12
+ @log = File.open(Oxidized::Config::Log + "/#{@node.ip}-http", "w") if Oxidized.config.input.debug?
18
13
  @node.model.cfg["http"].each { |cb| instance_exec(&cb) }
19
14
 
15
+ return true unless @main_page && defined?(login)
16
+
17
+ begin
18
+ require "mechanize"
19
+ rescue LoadError
20
+ raise OxidizedError, "mechanize not found: sudo gem install mechanize"
21
+ end
22
+
23
+ @m = Mechanize.new
20
24
  url = URI::HTTP.build host: @node.ip, path: @main_page
21
25
  @m_page = @m.get(url.to_s)
22
26
  login
23
27
  end
24
28
 
25
- def cmd callback
29
+ def cmd(callback_or_string)
30
+ return cmd_cb callback_or_string if callback_or_string.is_a?(Proc)
31
+
32
+ cmd_str callback_or_string
33
+ end
34
+
35
+ def cmd_cb(callback)
26
36
  instance_exec(&callback)
27
37
  end
28
38
 
39
+ def cmd_str(string)
40
+ path = string % { password: @node.auth[:password] }
41
+ get_http path
42
+ end
43
+
29
44
  private
30
45
 
31
- def log str
32
- @log.write(str) if @log
46
+ def get_http(path)
47
+ schema = @secure ? "https://" : "http://"
48
+ uri = URI.join schema + @node.ip, path
49
+ http = Net::HTTP.new uri.host, uri.port
50
+ http.use_ssl = true if uri.scheme == "https"
51
+ http.get(uri).body
52
+ end
53
+
54
+ def log(str)
55
+ @log&.write(str)
33
56
  end
34
57
 
35
58
  def disconnect
@@ -4,10 +4,10 @@ module Oxidized
4
4
  include Oxidized::Config::Vars
5
5
 
6
6
  RescueFail = {
7
- :debug => [
8
- Errno::ECONNREFUSED,
7
+ debug: [
8
+ Errno::ECONNREFUSED
9
9
  ],
10
- :warn => [
10
+ warn: [
11
11
  IOError,
12
12
  PromptUndetect,
13
13
  Timeout::Error,
@@ -15,8 +15,8 @@ module Oxidized
15
15
  Errno::EHOSTUNREACH,
16
16
  Errno::ENETUNREACH,
17
17
  Errno::EPIPE,
18
- Errno::ETIMEDOUT,
19
- ],
20
- }
18
+ Errno::ETIMEDOUT
19
+ ]
20
+ }.freeze
21
21
  end
22
22
  end
@@ -5,18 +5,18 @@ module Oxidized
5
5
  require 'oxidized/input/cli'
6
6
  class SSH < Input
7
7
  RescueFail = {
8
- :debug => [
9
- Net::SSH::Disconnect,
8
+ debug: [
9
+ Net::SSH::Disconnect
10
10
  ],
11
- :warn => [
11
+ warn: [
12
12
  RuntimeError,
13
- Net::SSH::AuthenticationFailed,
14
- ],
15
- }
13
+ Net::SSH::AuthenticationFailed
14
+ ]
15
+ }.freeze
16
16
  include Input::CLI
17
17
  class NoShell < OxidizedError; end
18
18
 
19
- def connect node
19
+ def connect(node)
20
20
  @node = node
21
21
  @output = ''
22
22
  @pty_options = { term: "vt100" }
@@ -37,10 +37,10 @@ module Oxidized
37
37
  end
38
38
 
39
39
  def connected?
40
- @ssh and not @ssh.closed?
40
+ @ssh && (not @ssh.closed?)
41
41
  end
42
42
 
43
- def cmd cmd, expect = node.prompt
43
+ def cmd(cmd, expect = node.prompt)
44
44
  Oxidized.logger.debug "lib/oxidized/input/ssh.rb #{cmd} @ #{node.name} with expect: #{expect.inspect}"
45
45
  if @exec
46
46
  @ssh.exec! cmd
@@ -49,15 +49,13 @@ module Oxidized
49
49
  end
50
50
  end
51
51
 
52
- def send data
52
+ def send(data)
53
53
  @ses.send_data data
54
54
  end
55
55
 
56
- def output
57
- @output
58
- end
56
+ attr_reader :output
59
57
 
60
- def pty_options hash
58
+ def pty_options(hash)
61
59
  @pty_options = @pty_options.merge hash
62
60
  end
63
61
 
@@ -66,14 +64,14 @@ module Oxidized
66
64
  def disconnect
67
65
  disconnect_cli
68
66
  # if disconnect does not disconnect us, give up after timeout
69
- Timeout::timeout(Oxidized.config.timeout) { @ssh.loop }
70
- rescue Errno::ECONNRESET, Net::SSH::Disconnect, IOError
67
+ Timeout.timeout(Oxidized.config.timeout) { @ssh.loop }
68
+ rescue Errno::ECONNRESET, Net::SSH::Disconnect, IOError # rubocop:disable Lint/HandleExceptions
71
69
  ensure
72
70
  @log.close if Oxidized.config.input.debug?
73
71
  (@ssh.close rescue true) unless @ssh.closed?
74
72
  end
75
73
 
76
- def shell_open ssh
74
+ def shell_open(ssh)
77
75
  @ses = ssh.open_channel do |ch|
78
76
  ch.on_data do |_ch, data|
79
77
  if Oxidized.config.input.debug?
@@ -83,7 +81,7 @@ module Oxidized
83
81
  @output << data
84
82
  @output = @node.model.expects @output
85
83
  end
86
- ch.request_pty (@pty_options) do |_ch, success_pty|
84
+ ch.request_pty(@pty_options) do |_ch, success_pty|
87
85
  raise NoShell, "Can't get PTY" unless success_pty
88
86
 
89
87
  ch.send_channel_request 'shell' do |_ch, success_shell|
@@ -93,8 +91,10 @@ module Oxidized
93
91
  end
94
92
  end
95
93
 
96
- def exec state = nil
97
- state == nil ? @exec : (@exec = state) unless vars :ssh_no_exec
94
+ def exec(state = nil)
95
+ return nil if vars(:ssh_no_exec)
96
+
97
+ state.nil? ? @exec : (@exec = state)
98
98
  end
99
99
 
100
100
  def cmd_shell(cmd, expect_re)
@@ -105,10 +105,10 @@ module Oxidized
105
105
  @output
106
106
  end
107
107
 
108
- def expect *regexps
108
+ def expect(*regexps)
109
109
  regexps = [regexps].flatten
110
110
  Oxidized.logger.debug "lib/oxidized/input/ssh.rb: expecting #{regexps.inspect} at #{node.name}"
111
- Timeout::timeout(Oxidized.config.timeout) do
111
+ Timeout.timeout(Oxidized.config.timeout) do
112
112
  @ssh.loop(0.1) do
113
113
  sleep 0.1
114
114
  match = regexps.find { |regexp| @output.match regexp }
@@ -122,22 +122,22 @@ module Oxidized
122
122
  def make_ssh_opts
123
123
  secure = Oxidized.config.input.ssh.secure?
124
124
  ssh_opts = {
125
- port: (vars(:ssh_port) || 22).to_i,
126
- paranoid: secure,
127
- keepalive: vars(:ssh_no_keepalive) ? false : true,
128
- password: @node.auth[:password],
129
- timeout: Oxidized.config.timeout,
130
- number_of_password_prompts: 0
125
+ number_of_password_prompts: 0,
126
+ keepalive: vars(:ssh_no_keepalive) ? false : true,
127
+ paranoid: secure,
128
+ password: @node.auth[:password],
129
+ timeout: Oxidized.config.timeout,
130
+ port: (vars(:ssh_port) || 22).to_i
131
131
  }
132
132
 
133
- auth_methods = vars(:auth_methods) || %w(none publickey password)
133
+ auth_methods = vars(:auth_methods) || %w[none publickey password]
134
134
  ssh_opts[:auth_methods] = auth_methods
135
135
  Oxidized.logger.debug "AUTH METHODS::#{auth_methods}"
136
136
 
137
- if proxy_host = vars(:ssh_proxy)
137
+ if (proxy_host = vars(:ssh_proxy))
138
138
  proxy_command = "ssh "
139
139
  proxy_command += "-o StrictHostKeyChecking=no " unless secure
140
- if proxy_port = vars(:ssh_proxy_port)
140
+ if (proxy_port = vars(:ssh_proxy_port))
141
141
  proxy_command += "-p #{proxy_port} "
142
142
  end
143
143
  proxy_command += "#{proxy_host} -W %h:%p"
@@ -2,22 +2,24 @@ module Oxidized
2
2
  require 'net/telnet'
3
3
  require 'oxidized/input/cli'
4
4
  class Telnet < Input
5
- RescueFail = {}
5
+ RescueFail = {}.freeze
6
6
  include Input::CLI
7
7
  attr_reader :telnet
8
8
 
9
- def connect node
9
+ def connect(node)
10
10
  @node = node
11
11
  @timeout = Oxidized.config.timeout
12
12
  @node.model.cfg['telnet'].each { |cb| instance_exec(&cb) }
13
13
  @log = File.open(Oxidized::Config::Log + "/#{@node.ip}-telnet", 'w') if Oxidized.config.input.debug?
14
14
  port = vars(:telnet_port) || 23
15
15
 
16
- telnet_opts = { 'Host' => @node.ip,
17
- 'Port' => port.to_i,
18
- 'Timeout' => @timeout,
19
- 'Model' => @node.model,
20
- 'Log' => @log }
16
+ telnet_opts = {
17
+ 'Host' => @node.ip,
18
+ 'Port' => port.to_i,
19
+ 'Timeout' => @timeout,
20
+ 'Model' => @node.model,
21
+ 'Log' => @log
22
+ }
21
23
 
22
24
  @telnet = Net::Telnet.new telnet_opts
23
25
  begin
@@ -29,10 +31,10 @@ module Oxidized
29
31
  end
30
32
 
31
33
  def connected?
32
- @telnet and not @telnet.sock.closed?
34
+ @telnet && (not @telnet.sock.closed?)
33
35
  end
34
36
 
35
- def cmd cmd_str, expect = @node.prompt
37
+ def cmd(cmd_str, expect = @node.prompt)
36
38
  return send(cmd_str + "\n") unless expect
37
39
 
38
40
  Oxidized.logger.debug "Telnet: #{cmd_str} @#{@node.name}"
@@ -42,7 +44,7 @@ module Oxidized
42
44
  @telnet.cmd args
43
45
  end
44
46
 
45
- def send data
47
+ def send(data)
46
48
  @telnet.write data
47
49
  end
48
50
 
@@ -52,19 +54,17 @@ module Oxidized
52
54
 
53
55
  private
54
56
 
55
- def expect re
56
- @telnet.oxidized_expect expect: re, timeout: @timeout
57
+ def expect(regex)
58
+ @telnet.oxidized_expect expect: regex, timeout: @timeout
57
59
  end
58
60
 
59
61
  def disconnect
60
- begin
61
- disconnect_cli
62
- @telnet.close
63
- rescue Errno::ECONNRESET
64
- ensure
65
- @log.close if Oxidized.config.input.debug?
66
- (@telnet.close rescue true) unless @telnet.sock.closed?
67
- end
62
+ disconnect_cli
63
+ @telnet.close
64
+ rescue Errno::ECONNRESET # rubocop:disable Lint/HandleExceptions
65
+ ensure
66
+ @log.close if Oxidized.config.input.debug?
67
+ (@telnet.close rescue true) unless @telnet.sock.closed?
68
68
  end
69
69
  end
70
70
  end
@@ -73,14 +73,14 @@ class Net::Telnet
73
73
  ## how to do this, without redefining the whole damn thing
74
74
  ## FIXME: we also need output (not sure I'm going to support this)
75
75
  attr_reader :output
76
- def oxidized_expect(options) # :yield: recvdata
76
+ def oxidized_expect(options)
77
77
  model = @options["Model"]
78
78
  @log = @options["Log"]
79
79
 
80
80
  expects = [options[:expect]].flatten
81
81
  time_out = options[:timeout] || @options["Timeout"] || Oxidized.config.timeout?
82
82
 
83
- Timeout::timeout(time_out) do
83
+ Timeout.timeout(time_out) do
84
84
  line = ""
85
85
  rest = ""
86
86
  buf = ""
@@ -93,8 +93,8 @@ class Net::Telnet
93
93
  Integer(c.rindex(/#{IAC}#{SB}/no) || 0)
94
94
  buf = preprocess(c[0...c.rindex(/#{IAC}#{SB}/no)])
95
95
  rest = c[c.rindex(/#{IAC}#{SB}/no)..-1]
96
- elsif pt = c.rindex(/#{IAC}[^#{IAC}#{AO}#{AYT}#{DM}#{IP}#{NOP}]?\z/no) ||
97
- c.rindex(/\r\z/no)
96
+ elsif (pt = c.rindex(/#{IAC}[^#{IAC}#{AO}#{AYT}#{DM}#{IP}#{NOP}]?\z/no) ||
97
+ c.rindex(/\r\z/no))
98
98
  buf = preprocess(c[0...pt])
99
99
  rest = c[pt..-1]
100
100
  else
@@ -1,41 +1,40 @@
1
1
  module Oxidized
2
2
  require 'stringio'
3
3
  require_relative 'cli'
4
-
4
+
5
5
  begin
6
6
  require 'net/tftp'
7
7
  rescue LoadError
8
8
  raise OxidizedError, 'net/tftp not found: sudo gem install net-tftp'
9
9
  end
10
-
10
+
11
11
  class TFTP < Input
12
-
13
12
  include Input::CLI
14
-
13
+
15
14
  # TFTP utilizes UDP, there is not a connection. We simply specify an IP and send/receive data.
16
- def connect node
17
- @node = node
15
+ def connect(node)
16
+ @node = node
18
17
 
19
18
  @node.model.cfg['tftp'].each { |cb| instance_exec(&cb) }
20
19
  @log = File.open(Oxidized::Config::Log + "/#{@node.ip}-tftp", 'w') if Oxidized.config.input.debug?
21
20
  @tftp = Net::TFTP.new @node.ip
22
21
  end
23
22
 
24
- def cmd file
23
+ def cmd(file)
25
24
  Oxidized.logger.debug "TFTP: #{file} @ #{@node.name}"
26
25
  config = StringIO.new
27
26
  @tftp.getbinary file, config
28
27
  config.rewind
29
28
  config.read
30
29
  end
31
-
30
+
32
31
  private
33
-
32
+
34
33
  def disconnect
35
34
  # TFTP uses UDP, there is no connection to close
35
+ true
36
36
  ensure
37
37
  @log.close if Oxidized.config.input.debug?
38
38
  end
39
-
40
39
  end
41
40
  end
@@ -4,11 +4,11 @@ module Oxidized
4
4
  MAX_INTER_JOB_GAP = 300 # add job if more than X from last job started
5
5
  attr_accessor :interval, :max, :want
6
6
 
7
- def initialize max, interval, nodes
7
+ def initialize(max, interval, nodes)
8
8
  @max = max
9
9
  # Set interval to 1 if interval is 0 (=disabled) so we don't break
10
10
  # the 'ceil' function
11
- @interval = interval == 0 ? 1 : interval
11
+ @interval = interval.zero? ? 1 : interval
12
12
  @nodes = nodes
13
13
  @last = Time.now.utc
14
14
  @durations = Array.new @nodes.size, AVERAGE_DURATION
@@ -16,12 +16,12 @@ module Oxidized
16
16
  super()
17
17
  end
18
18
 
19
- def push arg
19
+ def push(arg)
20
20
  @last = Time.now.utc
21
21
  super
22
22
  end
23
23
 
24
- def duration last
24
+ def duration(last)
25
25
  if @durations.size > @nodes.size
26
26
  @durations.slice! @nodes.size...@durations.size
27
27
  elsif @durations.size < @nodes.size
@@ -44,9 +44,9 @@ module Oxidized
44
44
  # and b) we want less threads running than the total amount of nodes
45
45
  # and c) there is more than MAX_INTER_JOB_GAP since last one was started
46
46
  # then we want one more thread (rationale is to fix hanging thread causing HOLB)
47
- if @want <= size and @want < @nodes.size
48
- @want += 1 if (Time.now.utc - @last) > MAX_INTER_JOB_GAP
49
- end
47
+ return unless @want <= size && @want < @nodes.size
48
+
49
+ @want += 1 if (Time.now.utc - @last) > MAX_INTER_JOB_GAP
50
50
  end
51
51
  end
52
52
  end