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
@@ -36,7 +36,7 @@ module Oxidized
36
36
  end
37
37
  end
38
38
 
39
- def crypt_init repo
39
+ def crypt_init(repo)
40
40
  repo.chdir do
41
41
  system(@gitcrypt_init)
42
42
  @cfg.users.each do |user|
@@ -48,22 +48,22 @@ module Oxidized
48
48
  end
49
49
  end
50
50
 
51
- def lock repo
51
+ def lock(repo)
52
52
  repo.chdir do
53
53
  system(@gitcrypt_lock)
54
54
  end
55
55
  end
56
56
 
57
- def unlock repo
57
+ def unlock(repo)
58
58
  repo.chdir do
59
59
  system(@gitcrypt_unlock)
60
60
  end
61
61
  end
62
62
 
63
- def store file, outputs, opt = {}
63
+ def store(file, outputs, opt = {})
64
64
  @msg = opt[:msg]
65
- @user = (opt[:user] or @cfg.user)
66
- @email = (opt[:email] or @cfg.email)
65
+ @user = (opt[:user] || @cfg.user)
66
+ @email = (opt[:email] || @cfg.email)
67
67
  @opt = opt
68
68
  @commitref = nil
69
69
  repo = @cfg.repo
@@ -72,7 +72,7 @@ module Oxidized
72
72
  type_cfg = ''
73
73
  type_repo = File.join(File.dirname(repo), type + '.git')
74
74
  outputs.type(type).each do |output|
75
- (type_cfg << output; next) if not output.name
75
+ (type_cfg << output; next) unless output.name # rubocop:disable Style/Semicolon
76
76
  type_file = file + '--' + output.name
77
77
  if @cfg.type_as_directory?
78
78
  type_file = type + '/' + type_file
@@ -86,97 +86,85 @@ module Oxidized
86
86
  update repo, file, outputs.to_cfg
87
87
  end
88
88
 
89
- def fetch node, group
90
- begin
91
- repo, path = yield_repo_and_path(node, group)
92
- repo = Git.open repo
93
- unlock repo
94
- index = repo.index
95
- # Empty repo ?
96
- empty = File.exists? index.path
97
- if empty
98
- raise 'Empty git repo'
99
- else
100
- File.read path
101
- end
102
-
103
- lock repo
104
- rescue
105
- 'node not found'
106
- end
89
+ def fetch(node, group)
90
+ repo, path = yield_repo_and_path(node, group)
91
+ repo = Git.open repo
92
+ unlock repo
93
+ index = repo.index
94
+ # Empty repo ?
95
+ raise 'Empty git repo' if File.exist?(index.path)
96
+
97
+ File.read path
98
+ lock repo
99
+ rescue StandardError
100
+ 'node not found'
107
101
  end
108
102
 
109
103
  # give a hash of all oid revision for the given node, and the date of the commit
110
- def version node, group
111
- begin
112
- repo, path = yield_repo_and_path(node, group)
113
-
114
- repo = Git.open repo
115
- unlock repo
116
- walker = repo.log.path(path)
117
- i = -1
118
- tab = []
119
- walker.each do |commit|
120
- hash = {}
121
- hash[:date] = commit.date.to_s
122
- hash[:oid] = commit.objectish
123
- hash[:author] = commit.author
124
- hash[:message] = commit.message
125
- tab[i += 1] = hash
126
- end
127
- walker.reset
128
- tab
129
- rescue
130
- 'node not found'
104
+ def version(node, group)
105
+ repo, path = yield_repo_and_path(node, group)
106
+
107
+ repo = Git.open repo
108
+ unlock repo
109
+ walker = repo.log.path(path)
110
+ i = -1
111
+ tab = []
112
+ walker.each do |commit|
113
+ hash = {}
114
+ hash[:date] = commit.date.to_s
115
+ hash[:oid] = commit.objectish
116
+ hash[:author] = commit.author
117
+ hash[:message] = commit.message
118
+ tab[i += 1] = hash
131
119
  end
120
+ walker.reset
121
+ tab
122
+ rescue StandardError
123
+ 'node not found'
132
124
  end
133
125
 
134
126
  # give the blob of a specific revision
135
- def get_version node, group, oid
136
- begin
137
- repo, path = yield_repo_and_path(node, group)
138
- repo = Git.open repo
139
- unlock repo
140
- repo.gtree(oid).files[path].contents
141
- rescue
142
- 'version not found'
143
- ensure
144
- lock repo
145
- end
127
+ def get_version(node, group, oid)
128
+ repo, path = yield_repo_and_path(node, group)
129
+ repo = Git.open repo
130
+ unlock repo
131
+ repo.gtree(oid).files[path].contents
132
+ rescue StandardError
133
+ 'version not found'
134
+ ensure
135
+ lock repo
146
136
  end
147
137
 
148
138
  # give a hash with the patch of a diff between 2 revision and the stats (added and deleted lines)
149
- def get_diff node, group, oid1, oid2
150
- begin
151
- diff_commits = nil
152
- repo, path = yield_repo_and_path(node, group)
153
- repo = Git.open repo
154
- unlock repo
155
- commit = repo.gcommit(oid1)
156
-
157
- if oid2
158
- commit_old = repo.gcommit(oid2)
159
- diff = repo.diff(commit_old, commit)
160
- stats = [diff.stats[:files][node.name][:insertions], diff.stats[:files][node.name][:deletions]]
161
- diff.each do |patch|
162
- if /#{node.name}\s+/.match(patch.patch.to_s.lines.first)
163
- diff_commits = { :patch => patch.patch.to_s, :stat => stats }
164
- break
165
- end
139
+ def get_diff(node, group, oid1, oid2)
140
+ diff_commits = nil
141
+ repo, _path = yield_repo_and_path(node, group)
142
+ repo = Git.open repo
143
+ unlock repo
144
+ commit = repo.gcommit(oid1)
145
+
146
+ if oid2
147
+ commit_old = repo.gcommit(oid2)
148
+ diff = repo.diff(commit_old, commit)
149
+ stats = [diff.stats[:files][node.name][:insertions], diff.stats[:files][node.name][:deletions]]
150
+ diff.each do |patch|
151
+ if /#{node.name}\s+/ =~ patch.patch.to_s.lines.first
152
+ diff_commits = { patch: patch.patch.to_s, stat: stats }
153
+ break
166
154
  end
167
- else
168
- stat = commit.parents[0].diff(commit).stats
169
- stat = [stat[:files][node.name][:insertions], stat[:files][node.name][:deletions]]
170
- patch = commit.parents[0].diff(commit).patch
171
- diff_commits = { :patch => patch, :stat => stat }
172
155
  end
173
- lock repo
174
- diff_commits
175
- rescue
176
- 'no diffs'
177
- ensure
178
- lock repo
156
+ else
157
+ stat = commit.parents[0].diff(commit).stats
158
+ stat = [stat[:files][node.name][:insertions], stat[:files][node.name][:deletions]]
159
+ patch = commit.parents[0].diff(commit).patch
160
+ diff_commits = { patch: patch, stat: stat }
179
161
  end
162
+ lock repo
163
+ diff_commits
164
+ rescue StandardError
165
+ 'no diffs'
166
+ ensure
167
+ lock repo
180
168
  end
181
169
 
182
170
  private
@@ -184,14 +172,12 @@ module Oxidized
184
172
  def yield_repo_and_path(node, group)
185
173
  repo, path = node.repo, node.name
186
174
 
187
- if group and @cfg.single_repo?
188
- path = "#{group}/#{node.name}"
189
- end
175
+ path = "#{group}/#{node.name}" if group && @cfg.single_repo?
190
176
 
191
177
  [repo, path]
192
178
  end
193
179
 
194
- def update repo, file, data
180
+ def update(repo, file, data)
195
181
  return if data.empty?
196
182
 
197
183
  if @opt[:group]
@@ -213,14 +199,14 @@ module Oxidized
213
199
  begin
214
200
  grepo = Git.init repo
215
201
  crypt_init grepo
216
- rescue => create_error
202
+ rescue StandardError => create_error
217
203
  raise GitCryptError, "first '#{open_error.message}' was raised while opening git repo, then '#{create_error.message}' was while trying to create git repo"
218
204
  end
219
205
  retry
220
206
  end
221
207
  end
222
208
 
223
- def update_repo repo, file, data, msg, user, email
209
+ def update_repo(repo, file, data, msg, user, email)
224
210
  grepo = Git.open repo
225
211
  grepo.config('user.name', user)
226
212
  grepo.config('user.email', email)
@@ -6,25 +6,25 @@ module Oxidized
6
6
  end
7
7
 
8
8
  def setup
9
- if @cfg.empty?
10
- CFGS.user.output.http.user = 'Oxidized'
11
- CFGS.user.output.http.pasword = 'secret'
12
- CFGS.user.output.http.url = 'http://localhost/web-api/oxidized'
13
- CFGS.save :user
14
- raise NoConfig, 'no output http config, edit ~/.config/oxidized/config'
15
- end
9
+ return unless @cfg.empty?
10
+
11
+ CFGS.user.output.http.user = 'Oxidized'
12
+ CFGS.user.output.http.pasword = 'secret'
13
+ CFGS.user.output.http.url = 'http://localhost/web-api/oxidized'
14
+ CFGS.save :user
15
+ raise NoConfig, 'no output http config, edit ~/.config/oxidized/config'
16
16
  end
17
17
 
18
18
  require "net/http"
19
19
  require "uri"
20
20
  require "json"
21
21
 
22
- def store node, outputs, opt = {}
22
+ def store(node, outputs, opt = {})
23
23
  @commitref = nil
24
24
  uri = URI.parse @cfg.url
25
25
  http = Net::HTTP.new uri.host, uri.port
26
26
  # http.use_ssl = true if uri.scheme = 'https'
27
- req = Net::HTTP::Post.new(uri.request_uri, initheader = { 'Content-Type' => 'application/json' })
27
+ req = Net::HTTP::Post.new(uri.request_uri, 'Content-Type' => 'application/json')
28
28
  req.basic_auth @cfg.user, @cfg.password
29
29
  req.body = generate_json(node, outputs, opt)
30
30
  response = http.request req
@@ -44,17 +44,15 @@ module Oxidized
44
44
 
45
45
  private
46
46
 
47
- def generate_json node, outputs, opt
47
+ def generate_json(node, outputs, opt)
48
48
  JSON.pretty_generate(
49
- {
50
- 'msg' => opt[:msg],
51
- 'user' => opt[:user],
52
- 'email' => opt[:email],
53
- 'group' => opt[:group],
54
- 'node' => node,
55
- 'config' => outputs.to_cfg,
56
- # actually we need to also iterate outputs, for other types like in gitlab. But most people don't use 'type' functionality.
57
- }
49
+ 'msg' => opt[:msg],
50
+ 'user' => opt[:user],
51
+ 'email' => opt[:email],
52
+ 'group' => opt[:group],
53
+ 'node' => node,
54
+ 'config' => outputs.to_cfg
55
+ # actually we need to also iterate outputs, for other types like in gitlab. But most people don't use 'type' functionality.
58
56
  )
59
57
  end
60
58
  end
@@ -2,7 +2,7 @@ module Oxidized
2
2
  class Output
3
3
  class NoConfig < OxidizedError; end
4
4
 
5
- def cfg_to_str cfg
5
+ def cfg_to_str(cfg)
6
6
  cfg.select { |h| h[:type] == 'cfg' }.map { |h| h[:data] }.join
7
7
  end
8
8
  end
@@ -18,10 +18,10 @@ module Oxidized
18
18
  require 'gpgme' if @cfg.gpg?
19
19
  end
20
20
 
21
- def load _node_want = nil
21
+ def load(_node_want = nil)
22
22
  nodes = []
23
23
  open_file.each_line do |line|
24
- next if line.match(/^\s*#/)
24
+ next if line =~ /^\s*#/
25
25
 
26
26
  data = line.chomp.split(@cfg.delimiter, -1)
27
27
  next if data.empty?
@@ -53,7 +53,7 @@ module Oxidized
53
53
  crypto = GPGME::Crypto.new password: @cfg.gpg_password
54
54
  crypto.decrypt(File.open(file)).to_s
55
55
  else
56
- open(file)
56
+ File.open(file)
57
57
  end
58
58
  end
59
59
  end
@@ -6,9 +6,9 @@ module Oxidized
6
6
  end
7
7
 
8
8
  def setup
9
- if @cfg.url.empty?
10
- raise NoConfig, 'no source http url config, edit ~/.config/oxidized/config'
11
- end
9
+ return unless @cfg.url.empty?
10
+
11
+ raise NoConfig, 'no source http url config, edit ~/.config/oxidized/config'
12
12
  end
13
13
 
14
14
  require "net/http"
@@ -16,7 +16,7 @@ module Oxidized
16
16
  require "uri"
17
17
  require "json"
18
18
 
19
- def load node_want = nil
19
+ def load(node_want = nil)
20
20
  nodes = []
21
21
  data = JSON.parse(read_http(node_want))
22
22
  data = string_navigate(data, @cfg.hosts_location) if @cfg.hosts_location?
@@ -44,17 +44,18 @@ module Oxidized
44
44
 
45
45
  private
46
46
 
47
- def string_navigate object, wants
48
- wants.split(".").map do |want|
47
+ def string_navigate(object, wants)
48
+ wants = wants.split(".").map do |want|
49
49
  head, match, _tail = want.partition(/\[\d+\]/)
50
50
  match.empty? ? head : [head, match[1..-2].to_i]
51
- end.flatten.each do |want|
51
+ end
52
+ wants.flatten.each do |want|
52
53
  object = object[want] if object.respond_to? :each
53
54
  end
54
55
  object
55
56
  end
56
57
 
57
- def read_http node_want
58
+ def read_http(node_want)
58
59
  uri = URI.parse(@cfg.url)
59
60
  http = Net::HTTP.new(uri.host, uri.port)
60
61
  http.use_ssl = true if uri.scheme == 'https'
@@ -67,13 +68,9 @@ module Oxidized
67
68
  end
68
69
 
69
70
  req_uri = uri.request_uri
70
- if node_want
71
- req_uri = "#{req_uri}/#{node_want}"
72
- end
71
+ req_uri = "#{req_uri}/#{node_want}" if node_want
73
72
  request = Net::HTTP::Get.new(req_uri, headers)
74
- if (@cfg.user? && @cfg.pass?)
75
- request.basic_auth(@cfg.user, @cfg.pass)
76
- end
73
+ request.basic_auth(@cfg.user, @cfg.pass) if @cfg.user? && @cfg.pass?
77
74
  http.request(request).body
78
75
  end
79
76
  end
@@ -3,14 +3,14 @@ module Oxidized
3
3
  class NoConfig < OxidizedError; end
4
4
 
5
5
  def initialize
6
- @map = (Oxidized.config.model_map or {})
6
+ @map = (Oxidized.config.model_map || {})
7
7
  end
8
8
 
9
- def map_model model
9
+ def map_model(model)
10
10
  @map.has_key?(model) ? @map[model] : model
11
11
  end
12
12
 
13
- def node_var_interpolate var
13
+ def node_var_interpolate(var)
14
14
  case var
15
15
  when "nil" then nil
16
16
  when "false" then false
@@ -7,26 +7,24 @@ module Oxidized
7
7
  end
8
8
 
9
9
  def setup
10
- if @cfg.empty?
11
- Oxidized.asetus.user.source.sql.adapter = 'sqlite'
12
- Oxidized.asetus.user.source.sql.database = File.join(Config::Root, 'sqlite.db')
13
- Oxidized.asetus.user.source.sql.table = 'devices'
14
- Oxidized.asetus.user.source.sql.map.name = 'name'
15
- Oxidized.asetus.user.source.sql.map.model = 'rancid'
16
- Oxidized.asetus.save :user
17
- raise NoConfig, 'no source sql config, edit ~/.config/oxidized/config'
18
- end
10
+ return unless @cfg.empty?
11
+
12
+ Oxidized.asetus.user.source.sql.adapter = 'sqlite'
13
+ Oxidized.asetus.user.source.sql.database = File.join(Config::Root, 'sqlite.db')
14
+ Oxidized.asetus.user.source.sql.table = 'devices'
15
+ Oxidized.asetus.user.source.sql.map.name = 'name'
16
+ Oxidized.asetus.user.source.sql.map.model = 'rancid'
17
+ Oxidized.asetus.save :user
18
+ raise NoConfig, 'no source sql config, edit ~/.config/oxidized/config'
19
19
  end
20
20
 
21
- def load node_want = nil
21
+ def load(node_want = nil)
22
22
  nodes = []
23
23
  db = connect
24
24
  query = db[@cfg.table.to_sym]
25
25
  query = query.with_sql(@cfg.query) if @cfg.query?
26
26
 
27
- if node_want
28
- query = query.where(@cfg.map.name.to_sym => node_want)
29
- end
27
+ query = query.where(@cfg.map.name.to_sym => node_want) if node_want
30
28
 
31
29
  query.each do |node|
32
30
  # map node parameters
@@ -55,11 +53,11 @@ module Oxidized
55
53
  end
56
54
 
57
55
  def connect
58
- Sequel.connect(:adapter => @cfg.adapter,
59
- :host => @cfg.host?,
60
- :user => @cfg.user?,
61
- :password => @cfg.password?,
62
- :database => @cfg.database)
56
+ Sequel.connect(adapter: @cfg.adapter,
57
+ host: @cfg.host?,
58
+ user: @cfg.user?,
59
+ password: @cfg.password?,
60
+ database: @cfg.database)
63
61
  rescue Sequel::AdapterNotFound => error
64
62
  raise OxidizedError, "SQL adapter gem not installed: " + error.message
65
63
  end