oxidized 0.28.0 → 0.29.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (140) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/publishdocker.yml +8 -1
  3. data/.github/workflows/ruby.yml +42 -0
  4. data/.rubocop.yml +30 -10
  5. data/.rubocop_todo.yml +95 -41
  6. data/CHANGELOG.md +139 -2
  7. data/Dockerfile +13 -9
  8. data/README.md +66 -32
  9. data/Rakefile +2 -0
  10. data/docs/Configuration.md +49 -7
  11. data/docs/Creating-Models.md +10 -4
  12. data/docs/Hooks.md +35 -6
  13. data/docs/Model-Notes/ADVA.md +12 -0
  14. data/docs/Model-Notes/Cumulus.md +7 -1
  15. data/docs/Model-Notes/IOS.md +36 -0
  16. data/docs/Model-Notes/JunOS.md +3 -3
  17. data/docs/Model-Notes/LenovoNOS.md +29 -0
  18. data/docs/Model-Notes/LinksysSRW.md +15 -0
  19. data/docs/Model-Notes/Nokia.md +3 -0
  20. data/docs/Model-Notes/OS10.md +33 -0
  21. data/docs/Model-Notes/PanOS_API.md +28 -0
  22. data/docs/Model-Notes/README.md +2 -0
  23. data/docs/Sources.md +18 -0
  24. data/docs/Supported-OS-Types.md +51 -6
  25. data/docs/Troubleshooting.md +1 -1
  26. data/extra/gitdiff-msteams.sh +91 -0
  27. data/extra/nagios_check_failing_nodes.rb +6 -9
  28. data/extra/oxidized-report-git-commits +71 -14
  29. data/extra/oxidized.init +2 -5
  30. data/extra/oxidized.logrotate +1 -0
  31. data/extra/oxidized.runit +4 -1
  32. data/extra/oxidized.service +5 -8
  33. data/extra/rest_client.rb +1 -1
  34. data/extra/syslog.rb +2 -2
  35. data/lib/oxidized/cli.rb +1 -1
  36. data/lib/oxidized/config/vars.rb +5 -2
  37. data/lib/oxidized/config.rb +6 -3
  38. data/lib/oxidized/core.rb +1 -1
  39. data/lib/oxidized/hook/exec.rb +6 -6
  40. data/lib/oxidized/hook/githubrepo.rb +42 -11
  41. data/lib/oxidized/hook/slackdiff.rb +2 -2
  42. data/lib/oxidized/hook/xmppdiff.rb +45 -25
  43. data/lib/oxidized/hook.rb +4 -8
  44. data/lib/oxidized/input/exec.rb +1 -1
  45. data/lib/oxidized/input/input.rb +1 -0
  46. data/lib/oxidized/input/ssh.rb +23 -20
  47. data/lib/oxidized/input/telnet.rb +52 -44
  48. data/lib/oxidized/job.rb +1 -0
  49. data/lib/oxidized/jobs.rb +11 -6
  50. data/lib/oxidized/manager.rb +1 -0
  51. data/lib/oxidized/model/acmepacket.rb +38 -0
  52. data/lib/oxidized/model/adtran.rb +5 -3
  53. data/lib/oxidized/model/adva.rb +66 -0
  54. data/lib/oxidized/model/airfiber.rb +1 -1
  55. data/lib/oxidized/model/aoscx.rb +96 -0
  56. data/lib/oxidized/model/aosw.rb +1 -1
  57. data/lib/oxidized/model/asa.rb +2 -0
  58. data/lib/oxidized/model/awplus.rb +1 -1
  59. data/lib/oxidized/model/bdcom.rb +49 -0
  60. data/lib/oxidized/model/cambiumepmp.rb +17 -0
  61. data/lib/oxidized/model/casa.rb +4 -1
  62. data/lib/oxidized/model/ciscoce.rb +12 -0
  63. data/lib/oxidized/model/ciscosmb.rb +2 -0
  64. data/lib/oxidized/model/comware.rb +16 -1
  65. data/lib/oxidized/model/cumulus.rb +58 -44
  66. data/lib/oxidized/model/dellx.rb +1 -3
  67. data/lib/oxidized/model/dlink.rb +2 -1
  68. data/lib/oxidized/model/edgecos.rb +22 -2
  69. data/lib/oxidized/model/edgeswitch.rb +4 -4
  70. data/lib/oxidized/model/eltex.rb +48 -0
  71. data/lib/oxidized/model/enterasys.rb +18 -3
  72. data/lib/oxidized/model/enterasys800.rb +29 -0
  73. data/lib/oxidized/model/eos.rb +2 -1
  74. data/lib/oxidized/model/fabricos.rb +1 -1
  75. data/lib/oxidized/model/fastiron.rb +3 -2
  76. data/lib/oxidized/model/fortios.rb +24 -11
  77. data/lib/oxidized/model/fortiwlc.rb +24 -0
  78. data/lib/oxidized/model/gaiaos.rb +40 -3
  79. data/lib/oxidized/model/h3c.rb +40 -0
  80. data/lib/oxidized/model/hatteras.rb +2 -2
  81. data/lib/oxidized/model/hios.rb +38 -0
  82. data/lib/oxidized/model/hpebladesystem.rb +1 -1
  83. data/lib/oxidized/model/ios.rb +13 -10
  84. data/lib/oxidized/model/iosxe.rb +1 -1
  85. data/lib/oxidized/model/ironware.rb +8 -4
  86. data/lib/oxidized/model/junos.rb +5 -1
  87. data/lib/oxidized/model/lancom.rb +23 -0
  88. data/lib/oxidized/model/lenovonos.rb +82 -0
  89. data/lib/oxidized/model/linksyssrw.rb +71 -0
  90. data/lib/oxidized/model/mlnxos.rb +2 -0
  91. data/lib/oxidized/model/model.rb +29 -3
  92. data/lib/oxidized/model/necix.rb +30 -0
  93. data/lib/oxidized/model/netgear.rb +5 -2
  94. data/lib/oxidized/model/netscaler.rb +38 -1
  95. data/lib/oxidized/model/nodegrid.rb +23 -0
  96. data/lib/oxidized/model/nxos.rb +3 -2
  97. data/lib/oxidized/model/openbsd.rb +9 -0
  98. data/lib/oxidized/model/opengear.rb +1 -1
  99. data/lib/oxidized/model/opnsense.rb +12 -4
  100. data/lib/oxidized/model/panos_api.rb +71 -0
  101. data/lib/oxidized/model/pfsense.rb +12 -7
  102. data/lib/oxidized/model/powerconnect.rb +1 -3
  103. data/lib/oxidized/model/procurve.rb +2 -2
  104. data/lib/oxidized/model/purityos.rb +8 -1
  105. data/lib/oxidized/model/quantaos.rb +1 -5
  106. data/lib/oxidized/model/routeros.rb +15 -2
  107. data/lib/oxidized/model/slxos.rb +1 -0
  108. data/lib/oxidized/model/smartcs.rb +40 -0
  109. data/lib/oxidized/model/sonicos.rb +9 -1
  110. data/lib/oxidized/model/srosmd.rb +97 -0
  111. data/lib/oxidized/model/stoneos.rb +6 -2
  112. data/lib/oxidized/model/supermicro.rb +1 -1
  113. data/lib/oxidized/model/swos.rb +9 -0
  114. data/lib/oxidized/model/timos.rb +1 -1
  115. data/lib/oxidized/model/tmos.rb +2 -1
  116. data/lib/oxidized/model/tplink.rb +2 -0
  117. data/lib/oxidized/model/trango.rb +11 -11
  118. data/lib/oxidized/model/truenas.rb +20 -0
  119. data/lib/oxidized/model/vrp.rb +1 -1
  120. data/lib/oxidized/model/xos.rb +4 -3
  121. data/lib/oxidized/model/yamaha.rb +57 -0
  122. data/lib/oxidized/model/zteolt.rb +52 -0
  123. data/lib/oxidized/model/zy1308.rb +11 -0
  124. data/lib/oxidized/node/stats.rb +1 -0
  125. data/lib/oxidized/node.rb +16 -11
  126. data/lib/oxidized/nodes.rb +7 -6
  127. data/lib/oxidized/output/file.rb +2 -1
  128. data/lib/oxidized/output/git.rb +4 -3
  129. data/lib/oxidized/output/gitcrypt.rb +5 -8
  130. data/lib/oxidized/output/http.rb +2 -0
  131. data/lib/oxidized/source/csv.rb +1 -0
  132. data/lib/oxidized/source/http.rb +4 -0
  133. data/lib/oxidized/source/source.rb +7 -2
  134. data/lib/oxidized/source/sql.rb +15 -5
  135. data/lib/oxidized/string.rb +9 -3
  136. data/lib/oxidized/version.rb +2 -2
  137. data/lib/oxidized/worker.rb +5 -5
  138. data/oxidized.gemspec +22 -16
  139. metadata +116 -29
  140. data/.travis.yml +0 -10
@@ -0,0 +1,20 @@
1
+ class TrueNAS < Oxidized::Model
2
+ comment '# '
3
+
4
+ cmd('uname -a') { |cfg| comment cfg }
5
+ cmd('cat /etc/version') { |cfg| comment cfg }
6
+ cmd('sqlite3 "file:///data/freenas-v1.db?mode=ro&immutable=1" .dump') do |cfg|
7
+ cfg.lines.reject do |line|
8
+ line.match(/^INSERT INTO storage_replication /) ||
9
+ line.match(/^INSERT INTO system_alert /)
10
+ end.join
11
+ end
12
+
13
+ cfg :ssh do
14
+ exec true # don't run shell, run each command in exec channel
15
+ end
16
+
17
+ cfg :ssh do
18
+ pre_logout 'exit'
19
+ end
20
+ end
@@ -1,7 +1,7 @@
1
1
  class VRP < Oxidized::Model
2
2
  # Huawei VRP
3
3
 
4
- prompt /^(<[\w.-]+>)$/
4
+ prompt /^.*(<[\w.-]+>)$/
5
5
  comment '# '
6
6
 
7
7
  cmd :secret do |cfg|
@@ -1,7 +1,7 @@
1
1
  class XOS < Oxidized::Model
2
2
  # Extreme Networks XOS
3
3
 
4
- prompt /^\*?\s?[-\w.~]+(:\d+)? [#>] $/
4
+ prompt /^\s?\*?\s?[-\w]+\s?[-\w.~]+(:\d+)? [#>] $/
5
5
  comment '# '
6
6
 
7
7
  cmd :all do |cfg|
@@ -23,7 +23,8 @@ class XOS < Oxidized::Model
23
23
  end
24
24
 
25
25
  cmd 'show switch' do |cfg|
26
- comment cfg.each_line.reject { |line| line.match(/Time:/) || line.match(/boot/i) }.join
26
+ cfg.gsub! /Next periodic save on.*/, ''
27
+ comment cfg.each_line.reject { |line| line.match(/Time:/) || line.match(/boot/i) || line.match(/Next periodic/) }.join
27
28
  end
28
29
 
29
30
  cmd 'show configuration' do |cfg|
@@ -43,7 +44,7 @@ class XOS < Oxidized::Model
43
44
  cfg :telnet, :ssh do
44
45
  post_login do
45
46
  data = cmd 'disable clipaging session'
46
- match = data.match /^disable clipaging session\n\*?[\w .-]+(:\d+)? [#>] $/m
47
+ match = data.match /^disable clipaging session\n\r?\*?\s?[-\w]+\s?[-\w.~]+(:\d+)? [#>] $/m
47
48
  next if match
48
49
 
49
50
  cmd 'disable clipaging'
@@ -0,0 +1,57 @@
1
+ class Yamaha < Oxidized::Model
2
+ prompt /^([\w.@()-]+[#>]\s?)$/
3
+ comment '# '
4
+
5
+ expect /^---more---$/ do |data, re|
6
+ send ' '
7
+ data.sub re, ''
8
+ end
9
+
10
+ # non-preferred way to handle additional PW prompt
11
+ # expect /^[\w.]+>$/ do |data|
12
+ # send "enable\n"
13
+ # send vars(:enable) + "\n"
14
+ # data
15
+ # end
16
+
17
+ expect /^Save new configuration/ do |data, re|
18
+ send "N\n"
19
+ data.sub re, ''
20
+ end
21
+
22
+ cmd :all do |cfg|
23
+ # cfg.gsub! /\cH+\s{8}/, '' # example how to handle pager
24
+ # cfg.gsub! /\cH+/, '' # example how to handle pager
25
+ # get rid of errors for commands that don't work on some devices
26
+ cfg.gsub! /^Error: Invalid command name$|^\s+\^$/, ''
27
+ cfg.cut_both
28
+ end
29
+
30
+ cmd 'show config' do |cfg|
31
+ cfg.gsub! /^(# Reporting Date:\s+)(.*)$/, '\1<stripped>'
32
+ cfg
33
+ end
34
+
35
+ cfg :telnet do
36
+ password /^Password:/i
37
+ end
38
+
39
+ cfg :telnet, :ssh do
40
+ # preferred way to handle additional passwords
41
+ post_login 'console lines infinity'
42
+ post_login 'console columns 200'
43
+ post_login 'console character ascii'
44
+ post_login do
45
+ if vars(:enable) == true
46
+ cmd "administrator"
47
+ elsif vars(:enable)
48
+ cmd "administrator", /^[pP]assword:/
49
+ cmd vars(:enable)
50
+ end
51
+ end
52
+ pre_logout do
53
+ cmd 'exit'
54
+ end
55
+ pre_logout 'exit'
56
+ end
57
+ end
@@ -0,0 +1,52 @@
1
+ class ZTEOLT < Oxidized::Model
2
+ # Tested with C320 and C300 olt, firware 1.2.5P3 and 2.1.0
3
+
4
+ prompt /^([\w.@()-]+[#>]\s?)$/
5
+ comment '! '
6
+
7
+ cmd :all do |cfg|
8
+ cfg.gsub! /^% Invalid input detected at '\^' marker\.$|^\s+\^$/, ''
9
+ cfg.cut_both
10
+ end
11
+
12
+ cmd :secret do |cfg|
13
+ cfg.gsub! /^(snmp-server community).*/, '\\1 <configuration removed>'
14
+ cfg.gsub! /^(tacacs-server (.+ )?key) .+/, '\\1 <secret hidden>'
15
+ cfg.gsub! /^username (\S+) privilege (\d+) (\S+).*/, '<secret hidden>'
16
+ cfg.gsub! /^(enable (password|secret)( level \d+)? \d) .+/, '\\1 <secret hidden>'
17
+ cfg
18
+ end
19
+
20
+ cmd 'show version-running' do |cfg|
21
+ comment cfg
22
+ end
23
+
24
+ cmd 'show patch-running' do |cfg|
25
+ comment cfg
26
+ end
27
+
28
+ cmd 'show running-config' do |cfg|
29
+ cfg.gsub! /^timestamp_write: .*\n/, ''
30
+ cfg
31
+ end
32
+
33
+ cfg :telnet do
34
+ username /^Username:/i
35
+ password /^Password:/i
36
+ end
37
+
38
+ cfg :telnet, :ssh do
39
+ # preferred way to handle additional passwords
40
+ post_login do
41
+ if vars(:enable) == true
42
+ cmd "enable"
43
+ elsif vars(:enable)
44
+ cmd "enable", /^[pP]assword:/
45
+ cmd vars(:enable)
46
+ end
47
+ end
48
+ post_login 'terminal length 0'
49
+ pre_logout 'disable'
50
+ pre_logout 'exit'
51
+ end
52
+ end
@@ -0,0 +1,11 @@
1
+ # For Zyxel OLTs series 1308
2
+ class Zy1308 < Oxidized::Model
3
+ # For Zyxel OLTs series 1308
4
+
5
+ cmd '/config_OLT-1308S-22.log'
6
+ cfg :http do
7
+ @username = @node.auth[:username]
8
+ @password = @node.auth[:password]
9
+ @secure = false
10
+ end
11
+ end
@@ -2,6 +2,7 @@ module Oxidized
2
2
  class Node
3
3
  class Stats
4
4
  attr_reader :mtimes
5
+
5
6
  MAX_STAT = 10
6
7
 
7
8
  # @param [Job] job job whose information add to stats
data/lib/oxidized/node.rb CHANGED
@@ -4,9 +4,10 @@ module Oxidized
4
4
  require_relative 'node/stats'
5
5
  class MethodNotFound < OxidizedError; end
6
6
  class ModelNotFound < OxidizedError; end
7
+
7
8
  class Node
8
9
  attr_reader :name, :ip, :model, :input, :output, :group, :auth, :prompt, :vars, :last, :repo
9
- attr_accessor :running, :user, :email, :msg, :from, :stats, :retry
10
+ attr_accessor :running, :user, :email, :msg, :from, :stats, :retry, :err_type, :err_reason
10
11
  alias running? running
11
12
 
12
13
  def initialize(opt)
@@ -28,6 +29,8 @@ module Oxidized
28
29
  @stats = Stats.new
29
30
  @retry = 0
30
31
  @repo = resolve_repo opt
32
+ @err_type = nil
33
+ @err_reason = nil
31
34
 
32
35
  # model instance needs to access node instance
33
36
  @model.node = self
@@ -73,6 +76,8 @@ module Oxidized
73
76
  resc = " (rescued #{resc})"
74
77
  end
75
78
  Oxidized.logger.send(level, '%s raised %s%s with msg "%s"' % [ip, err.class, resc, err.message])
79
+ @err_type = err.class.to_s
80
+ @err_reason = err.message.to_s
76
81
  false
77
82
  rescue StandardError => err
78
83
  crashdir = Oxidized.config.crash.directory
@@ -86,6 +91,8 @@ module Oxidized
86
91
  fh.puts err.backtrace
87
92
  end
88
93
  Oxidized.logger.error '%s raised %s with msg "%s", %s saved' % [ip, err.class, err.message, crashfile]
94
+ @err_type = err.class.to_s
95
+ @err_reason = err.message.to_s
89
96
  false
90
97
  end
91
98
  end
@@ -153,6 +160,7 @@ module Oxidized
153
160
  inputs = resolve_key :input, opt, Oxidized.config.input.default
154
161
  inputs.split(/\s*,\s*/).map do |input|
155
162
  Oxidized.mgr.add_input(input) || raise(MethodNotFound, "#{input} not found for node #{ip}") unless Oxidized.mgr.input[input]
163
+
156
164
  Oxidized.mgr.input[input]
157
165
  end
158
166
  end
@@ -160,6 +168,7 @@ module Oxidized
160
168
  def resolve_output(opt)
161
169
  output = resolve_key :output, opt, Oxidized.config.output.default
162
170
  Oxidized.mgr.add_output(output) || raise(MethodNotFound, "#{output} not found for node #{ip}") unless Oxidized.mgr.output[output]
171
+
163
172
  Oxidized.mgr.output[output]
164
173
  end
165
174
 
@@ -202,19 +211,15 @@ module Oxidized
202
211
  end
203
212
 
204
213
  # group
205
- if Oxidized.config.groups.has_key?(@group)
206
- if Oxidized.config.groups[@group].has_key?(key_str)
207
- value = Oxidized.config.groups[@group][key_str]
208
- Oxidized.logger.debug "node.rb: setting node key '#{key}' to value '#{value}' from group"
209
- end
214
+ if Oxidized.config.groups.has_key?(@group) && Oxidized.config.groups[@group].has_key?(key_str)
215
+ value = Oxidized.config.groups[@group][key_str]
216
+ Oxidized.logger.debug "node.rb: setting node key '#{key}' to value '#{value}' from group"
210
217
  end
211
218
 
212
219
  # model
213
- if Oxidized.config.models.has_key?(@model.class.name.to_s.downcase)
214
- if Oxidized.config.models[@model.class.name.to_s.downcase].has_key?(key_str)
215
- value = Oxidized.config.models[@model.class.name.to_s.downcase][key_str]
216
- Oxidized.logger.debug "node.rb: setting node key '#{key}' to value '#{value}' from model"
217
- end
220
+ if Oxidized.config.models.has_key?(@model.class.name.to_s.downcase) && Oxidized.config.models[@model.class.name.to_s.downcase].has_key?(key_str)
221
+ value = Oxidized.config.models[@model.class.name.to_s.downcase][key_str]
222
+ Oxidized.logger.debug "node.rb: setting node key '#{key}' to value '#{value}' from model"
218
223
  end
219
224
 
220
225
  # node
@@ -3,6 +3,7 @@ module Oxidized
3
3
  require 'oxidized/node'
4
4
  class Oxidized::NotSupported < OxidizedError; end
5
5
  class Oxidized::NodeNotFound < OxidizedError; end
6
+
6
7
  class Nodes < Array
7
8
  attr_accessor :source, :jobs
8
9
  alias put unshift
@@ -36,6 +37,7 @@ module Oxidized
36
37
 
37
38
  node_want_ip = (IPAddr.new(node_want) rescue false)
38
39
  name_is_ip = (IPAddr.new(node[:name]) rescue false)
40
+ # rubocop:todo Lint/DuplicateBranch
39
41
  if name_is_ip && (node_want_ip == node[:name])
40
42
  true
41
43
  elsif node[:ip] && (node_want_ip == node[:ip])
@@ -43,6 +45,7 @@ module Oxidized
43
45
  elsif node_want.match node[:name]
44
46
  true unless name_is_ip
45
47
  end
48
+ # rubocop:enable Lint/DuplicateBranch
46
49
  end
47
50
 
48
51
  def list
@@ -159,13 +162,11 @@ module Oxidized
159
162
  old = dup
160
163
  replace(nodes)
161
164
  each do |node|
162
- begin
163
- if (i = old.find_node_index(node.name))
164
- node.stats = old[i].stats
165
- node.last = old[i].last
166
- end
167
- rescue Oxidized::NodeNotFound
165
+ if (i = old.find_node_index(node.name))
166
+ node.stats = old[i].stats
167
+ node.last = old[i].last
168
168
  end
169
+ rescue Oxidized::NodeNotFound
169
170
  end
170
171
  sort_by! { |x| x.last.nil? ? Time.new(0) : x.last.end }
171
172
  end
@@ -5,6 +5,7 @@ module Oxidized
5
5
  attr_reader :commitref
6
6
 
7
7
  def initialize
8
+ super
8
9
  @cfg = Oxidized.config.output.file
9
10
  end
10
11
 
@@ -21,7 +22,7 @@ module Oxidized
21
22
  file = File.join File.dirname(file), opt[:group] if opt[:group]
22
23
  FileUtils.mkdir_p file
23
24
  file = File.join file, node
24
- File.open(file, 'w') { |fh| fh.write outputs.to_cfg }
25
+ File.write(file, outputs.to_cfg)
25
26
  @commitref = file
26
27
  end
27
28
 
@@ -10,6 +10,7 @@ module Oxidized
10
10
  attr_reader :commitref
11
11
 
12
12
  def initialize
13
+ super
13
14
  @cfg = Oxidized.config.output.git
14
15
  end
15
16
 
@@ -78,7 +79,7 @@ module Oxidized
78
79
  i = -1
79
80
  tab = []
80
81
  walker.each do |commit|
81
- next if commit.diff(paths: [path]).size.zero?
82
+ next if commit.diff(paths: [path]).empty?
82
83
 
83
84
  hash = {}
84
85
  hash[:date] = commit.time.to_s
@@ -158,11 +159,11 @@ module Oxidized
158
159
  begin
159
160
  repo = Rugged::Repository.new repo
160
161
  update_repo repo, file, data
161
- rescue Rugged::OSError, Rugged::RepositoryError => open_error
162
+ rescue Rugged::OSError, Rugged::RepositoryError => e
162
163
  begin
163
164
  Rugged::Repository.init_at repo, :bare
164
165
  rescue StandardError => create_error
165
- raise GitError, "first '#{open_error.message}' was raised while opening git repo, then '#{create_error.message}' was while trying to create git repo"
166
+ raise GitError, "first '#{e.message}' was raised while opening git repo, then '#{create_error.message}' was while trying to create git repo"
166
167
  end
167
168
  retry
168
169
  end
@@ -10,6 +10,7 @@ module Oxidized
10
10
  attr_reader :commitref
11
11
 
12
12
  def initialize
13
+ super
13
14
  @cfg = Oxidized.config.output.gitcrypt
14
15
  @gitcrypt_cmd = "/usr/bin/git-crypt"
15
16
  @gitcrypt_init = @gitcrypt_cmd + " init"
@@ -194,13 +195,13 @@ module Oxidized
194
195
 
195
196
  begin
196
197
  update_repo repo, file, data, @msg, @user, @email
197
- rescue Git::GitExecuteError, ArgumentError => open_error
198
- Oxidized.logger.debug "open_error #{open_error} #{file}"
198
+ rescue Git::GitExecuteError, ArgumentError => e
199
+ Oxidized.logger.debug "open_error #{e} #{file}"
199
200
  begin
200
201
  grepo = Git.init repo
201
202
  crypt_init grepo
202
203
  rescue StandardError => create_error
203
- raise GitCryptError, "first '#{open_error.message}' was raised while opening git repo, then '#{create_error.message}' was while trying to create git repo"
204
+ raise GitCryptError, "first '#{e.message}' was raised while opening git repo, then '#{create_error.message}' was while trying to create git repo"
204
205
  end
205
206
  retry
206
207
  end
@@ -214,11 +215,7 @@ module Oxidized
214
215
  unlock grepo
215
216
  File.write(file, data)
216
217
  grepo.add(file)
217
- if grepo.status[file].nil?
218
- grepo.commit(msg)
219
- @commitref = grepo.log(1).first.objectish
220
- true
221
- elsif !grepo.status[file].type.nil?
218
+ if grepo.status[file].nil? || !grepo.status[file].type.nil?
222
219
  grepo.commit(msg)
223
220
  @commitref = grepo.log(1).first.objectish
224
221
  true
@@ -1,7 +1,9 @@
1
1
  module Oxidized
2
2
  class Http < Output
3
3
  attr_reader :commitref
4
+
4
5
  def initialize
6
+ super
5
7
  @cfg = Oxidized.config.output.http
6
8
  end
7
9
 
@@ -32,6 +32,7 @@ module Oxidized
32
32
  keys[key.to_sym] = node_var_interpolate data[position]
33
33
  end
34
34
  keys[:model] = map_model keys[:model] if keys.has_key? :model
35
+ keys[:group] = map_group keys[:group] if keys.has_key? :group
35
36
 
36
37
  # map node specific vars
37
38
  vars = {}
@@ -29,6 +29,7 @@ module Oxidized
29
29
  keys[key.to_sym] = node_var_interpolate string_navigate(node, want_position)
30
30
  end
31
31
  keys[:model] = map_model keys[:model] if keys.has_key? :model
32
+ keys[:group] = map_group keys[:group] if keys.has_key? :group
32
33
 
33
34
  # map node specific vars
34
35
  vars = {}
@@ -61,6 +62,9 @@ module Oxidized
61
62
  http.use_ssl = true if uri.scheme == 'https'
62
63
  http.verify_mode = OpenSSL::SSL::VERIFY_NONE unless @cfg.secure
63
64
 
65
+ # Add read_timeout to handle case of big list of nodes (default value is 60 seconds)
66
+ http.read_timeout = Integer(@cfg.read_timeout) if @cfg.has_key? "read_timeout"
67
+
64
68
  # map headers
65
69
  headers = {}
66
70
  @cfg.headers.each do |header, value|
@@ -3,11 +3,16 @@ module Oxidized
3
3
  class NoConfig < OxidizedError; end
4
4
 
5
5
  def initialize
6
- @map = (Oxidized.config.model_map || {})
6
+ @model_map = (Oxidized.config.model_map || {})
7
+ @group_map = (Oxidized.config.group_map || {})
7
8
  end
8
9
 
9
10
  def map_model(model)
10
- @map.has_key?(model) ? @map[model] : model
11
+ @model_map.has_key?(model) ? @model_map[model] : model
12
+ end
13
+
14
+ def map_group(group)
15
+ @group_map.has_key?(group) ? @group_map[group] : group
11
16
  end
12
17
 
13
18
  def node_var_interpolate(var)
@@ -31,6 +31,7 @@ module Oxidized
31
31
  keys = {}
32
32
  @cfg.map.each { |key, sql_column| keys[key.to_sym] = node_var_interpolate node[sql_column.to_sym] }
33
33
  keys[:model] = map_model keys[:model] if keys.has_key? :model
34
+ keys[:group] = map_group keys[:group] if keys.has_key? :group
34
35
 
35
36
  # map node specific vars
36
37
  vars = {}
@@ -53,11 +54,20 @@ module Oxidized
53
54
  end
54
55
 
55
56
  def connect
56
- Sequel.connect(adapter: @cfg.adapter,
57
- host: @cfg.host?,
58
- user: @cfg.user?,
59
- password: @cfg.password?,
60
- database: @cfg.database)
57
+ options = {
58
+ adapter: @cfg.adapter,
59
+ host: @cfg.host?,
60
+ user: @cfg.user?,
61
+ password: @cfg.password?,
62
+ database: @cfg.database,
63
+ ssl_mode: @cfg.ssl_mode?
64
+ }
65
+ if @cfg.with_ssl?
66
+ options.merge!(sslca: @cfg.ssl_ca?,
67
+ sslcert: @cfg.ssl_cert?,
68
+ sslkey: @cfg.ssl_key?)
69
+ end
70
+ Sequel.connect(options)
61
71
  rescue Sequel::AdapterNotFound => error
62
72
  raise OxidizedError, "SQL adapter gem not installed: " + error.message
63
73
  end
@@ -5,17 +5,23 @@ module Oxidized
5
5
 
6
6
  # @return [Oxidized::String] copy of self with last line removed
7
7
  def cut_tail(lines = 1)
8
- Oxidized::String.new each_line.to_a[0..-1 - lines].join
8
+ return Oxidized::String.new("") if length.zero?
9
+
10
+ Oxidized::String.new each_line.to_a[0..(-1 - lines)].join
9
11
  end
10
12
 
11
13
  # @return [Oxidized::String] copy of self with first line removed
12
14
  def cut_head(lines = 1)
15
+ return Oxidized::String.new("") if length.zero?
16
+
13
17
  Oxidized::String.new each_line.to_a[lines..-1].join
14
18
  end
15
19
 
16
20
  # @return [Oxidized::String] copy of self with first and last lines removed
17
21
  def cut_both(head = 1, tail = 1)
18
- Oxidized::String.new each_line.to_a[head..-1 - tail].join
22
+ return Oxidized::String.new("") if length.zero?
23
+
24
+ Oxidized::String.new each_line.to_a[head..(-1 - tail)].join
19
25
  end
20
26
 
21
27
  # sets @cmd and @name unless @name is already set
@@ -26,7 +32,7 @@ module Oxidized
26
32
 
27
33
  def initialize(str = '')
28
34
  super
29
- return unless str.class == Oxidized::String
35
+ return unless str.instance_of?(Oxidized::String)
30
36
 
31
37
  @cmd = str.cmd
32
38
  @name = str.name
@@ -1,6 +1,6 @@
1
1
  module Oxidized
2
- VERSION = '0.28.0'.freeze
3
- VERSION_FULL = '0.28.0'.freeze
2
+ VERSION = '0.29.0'.freeze
3
+ VERSION_FULL = '0.29.0'.freeze
4
4
  def self.version_set
5
5
  version_full = %x(git describe --tags).chop rescue ""
6
6
  version = %x(git describe --tags --abbrev=0).chop rescue ""
@@ -5,7 +5,7 @@ module Oxidized
5
5
  def initialize(nodes)
6
6
  @jobs_done = 0
7
7
  @nodes = nodes
8
- @jobs = Jobs.new(Oxidized.config.threads, Oxidized.config.interval, @nodes)
8
+ @jobs = Jobs.new(Oxidized.config.threads, Oxidized.config.use_max_threads, Oxidized.config.interval, @nodes)
9
9
  @nodes.jobs = @jobs
10
10
  Thread.abort_on_exception = true
11
11
  end
@@ -56,7 +56,7 @@ module Oxidized
56
56
 
57
57
  def process_success(node, job)
58
58
  @jobs_done += 1 # needed for :nodes_done hook
59
- Oxidized.Hooks.handle :node_success, node: node,
59
+ Oxidized.hooks.handle :node_success, node: node,
60
60
  job: job
61
61
  msg = "update #{node.group}/#{node.name}"
62
62
  msg += " from #{node.from}" if node.from
@@ -66,7 +66,7 @@ module Oxidized
66
66
  msg: msg, email: node.email, user: node.user, group: node.group
67
67
  node.modified
68
68
  Oxidized.logger.info "Configuration updated for #{node.group}/#{node.name}"
69
- Oxidized.Hooks.handle :post_store, node: node,
69
+ Oxidized.hooks.handle :post_store, node: node,
70
70
  job: job,
71
71
  commitref: output.commitref
72
72
  end
@@ -87,7 +87,7 @@ module Oxidized
87
87
  @jobs_done += 1
88
88
  msg += ", retries exhausted, giving up"
89
89
  node.retry = 0
90
- Oxidized.Hooks.handle :node_fail, node: node,
90
+ Oxidized.hooks.handle :node_fail, node: node,
91
91
  job: job
92
92
  end
93
93
  Oxidized.logger.warn msg
@@ -103,7 +103,7 @@ module Oxidized
103
103
 
104
104
  def run_done_hook
105
105
  Oxidized.logger.debug "lib/oxidized/worker.rb: Running :nodes_done hook"
106
- Oxidized.Hooks.handle :nodes_done
106
+ Oxidized.hooks.handle :nodes_done
107
107
  rescue StandardError => e
108
108
  # swallow the hook erros and continue as normal
109
109
  Oxidized.logger.error "lib/oxidized/worker.rb: #{e.message}"
data/oxidized.gemspec CHANGED
@@ -17,22 +17,28 @@ Gem::Specification.new do |s|
17
17
  s.executables = %w[oxidized]
18
18
  s.require_path = 'lib'
19
19
 
20
- s.required_ruby_version = '>= 2.3'
21
- s.add_runtime_dependency 'asetus', '~> 0.1'
20
+ s.metadata['rubygems_mfa_required'] = 'true'
21
+
22
+ s.required_ruby_version = '>= 3.0'
23
+
24
+ s.add_runtime_dependency 'asetus', '~> 0.1'
22
25
  s.add_runtime_dependency 'bcrypt_pbkdf', '~> 1.0'
23
- s.add_runtime_dependency 'ed25519', '~> 1.2'
24
- s.add_runtime_dependency 'net-ssh', '~> 5'
25
- s.add_runtime_dependency 'net-telnet', '~> 0.2'
26
- s.add_runtime_dependency 'rugged', '~> 0.28.0'
27
- s.add_runtime_dependency 'slop', '~> 4.6'
26
+ s.add_runtime_dependency 'ed25519', '~> 1.2'
27
+ s.add_runtime_dependency 'net-ssh', '~> 7.1'
28
+ s.add_runtime_dependency 'net-telnet', '~> 0.2'
29
+ s.add_runtime_dependency 'rugged', '~> 1.6'
30
+ s.add_runtime_dependency 'slop', '~> 4.6'
28
31
 
29
- s.add_development_dependency 'bundler', '~> 2.0'
30
- s.add_development_dependency 'codecov' if ENV['CI'] == 'true'
31
- s.add_development_dependency 'git', '~> 1'
32
- s.add_development_dependency 'minitest', '~> 5.8'
33
- s.add_development_dependency 'mocha', '~> 1.1'
34
- s.add_development_dependency 'pry', '~> 0'
35
- s.add_development_dependency 'rake', '~> 10.0'
36
- s.add_development_dependency 'rubocop', '~> 0.80.0'
37
- s.add_development_dependency 'simplecov'
32
+ s.add_development_dependency 'bundler', '~> 2.2'
33
+ s.add_development_dependency 'git', '~> 1'
34
+ s.add_development_dependency 'minitest', '~> 5.18'
35
+ s.add_development_dependency 'mocha', '~> 1.2'
36
+ s.add_development_dependency 'pry', '~> 0.14.2'
37
+ s.add_development_dependency 'rake', '~> 13.0'
38
+ s.add_development_dependency 'rubocop', '~> 1.48.0'
39
+ s.add_development_dependency 'rubocop-minitest', '~> 0.29.0'
40
+ s.add_development_dependency 'rubocop-rake', '~> 0.6.0'
41
+ s.add_development_dependency 'simplecov', '~> 0.22.0'
42
+ s.add_development_dependency 'simplecov-cobertura', '~> 2.1.0'
43
+ s.add_development_dependency 'simplecov-html', '~> 0.12.3'
38
44
  end