oxidized 0.29.1 → 0.37.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.
Files changed (236) hide show
  1. checksums.yaml +4 -4
  2. data/.coderabbit.yaml +21 -0
  3. data/.github/ISSUE_TEMPLATE/bug_report.md +45 -0
  4. data/.github/ISSUE_TEMPLATE/feature_request.md +22 -0
  5. data/.github/ISSUE_TEMPLATE/support-request.md +39 -0
  6. data/.github/workflows/codeql.yml +4 -4
  7. data/.github/workflows/publishdocker.yml +108 -13
  8. data/.github/workflows/ruby.yml +3 -12
  9. data/.github/workflows/stale.yml +6 -1
  10. data/.gitignore +2 -0
  11. data/.rubocop.yml +69 -13
  12. data/.rubocop_todo.yml +13 -143
  13. data/CHANGELOG.md +431 -4
  14. data/CONTRIBUTING.md +189 -0
  15. data/Dockerfile +89 -34
  16. data/README.md +59 -188
  17. data/Rakefile +58 -12
  18. data/bin/oxidized +2 -5
  19. data/docs/Configuration.md +382 -149
  20. data/docs/Creating-Models.md +262 -10
  21. data/docs/DeviceSimulation.md +196 -0
  22. data/docs/Docker.md +246 -0
  23. data/docs/Hooks.md +146 -51
  24. data/docs/Inputs.md +237 -0
  25. data/docs/Issues.md +123 -0
  26. data/docs/Model-Notes/APC.md +72 -0
  27. data/docs/Model-Notes/Cumulus.md +5 -0
  28. data/docs/Model-Notes/EatonNetwork.md +18 -0
  29. data/docs/Model-Notes/ExaLink.md +43 -0
  30. data/docs/Model-Notes/FSOS.md +17 -0
  31. data/docs/Model-Notes/Fortinet.md +75 -0
  32. data/docs/Model-Notes/GrandstreamHT8xx.md +8 -0
  33. data/docs/Model-Notes/HPEAruba.md +32 -0
  34. data/docs/Model-Notes/IvantiConnectSecure.md +59 -0
  35. data/docs/Model-Notes/OS6.md +10 -0
  36. data/docs/Model-Notes/README.md +1 -20
  37. data/docs/Model-Notes/RouterOS.md +28 -0
  38. data/docs/Model-Notes/SikluMHTG.md +7 -0
  39. data/docs/Model-Notes/TrueNAS.md +23 -0
  40. data/docs/Model-Notes/XGS4600-Zyxel.md +5 -0
  41. data/docs/ModelUnitTests.md +219 -0
  42. data/docs/Outputs.md +102 -5
  43. data/docs/Release.md +102 -0
  44. data/docs/Ruby-API.md +135 -2
  45. data/docs/Sources.md +34 -0
  46. data/docs/Supported-OS-Types.md +207 -270
  47. data/docs/Troubleshooting.md +43 -1
  48. data/extra/device2yaml.rb +259 -0
  49. data/extra/gitdiff-msteams.sh +32 -5
  50. data/extra/hooks/modelrules.rb +55 -0
  51. data/extra/hooks/modelrulesadvanced.rb +167 -0
  52. data/extra/hooks/srcipmap.rb +54 -0
  53. data/extra/nagios_check_failing_nodes.rb +1 -1
  54. data/extra/oxidized.runit +1 -1
  55. data/extra/rest_client.rb +5 -4
  56. data/extra/syslog.rb +11 -6
  57. data/lib/oxidized/cli/support.rb +152 -0
  58. data/lib/oxidized/cli.rb +21 -6
  59. data/lib/oxidized/config/vars.rb +33 -14
  60. data/lib/oxidized/config.rb +28 -17
  61. data/lib/oxidized/core.rb +50 -8
  62. data/lib/oxidized/hook/ciscosparkdiff.rb +11 -9
  63. data/lib/oxidized/hook/exec.rb +5 -4
  64. data/lib/oxidized/hook/githubrepo.rb +55 -18
  65. data/lib/oxidized/hook/noophook.rb +2 -2
  66. data/lib/oxidized/hook/slackdiff.rb +50 -14
  67. data/lib/oxidized/hook/xmppdiff.rb +9 -9
  68. data/lib/oxidized/hook.rb +68 -16
  69. data/lib/oxidized/input/cli.rb +8 -3
  70. data/lib/oxidized/input/debugtext.rb +40 -0
  71. data/lib/oxidized/input/debugyaml.rb +82 -0
  72. data/lib/oxidized/input/exec.rb +2 -11
  73. data/lib/oxidized/input/ftp.rb +2 -19
  74. data/lib/oxidized/input/http.rb +67 -17
  75. data/lib/oxidized/input/input.rb +35 -14
  76. data/lib/oxidized/input/scp.rb +27 -0
  77. data/lib/oxidized/input/ssh.rb +59 -83
  78. data/lib/oxidized/input/sshbase.rb +102 -0
  79. data/lib/oxidized/input/telnet.rb +20 -19
  80. data/lib/oxidized/input/tftp.rb +8 -8
  81. data/lib/oxidized/job.rb +18 -7
  82. data/lib/oxidized/jobs.rb +11 -1
  83. data/lib/oxidized/logger.rb +51 -0
  84. data/lib/oxidized/manager.rb +18 -17
  85. data/lib/oxidized/model/acos.rb +2 -1
  86. data/lib/oxidized/model/addpack.rb +26 -0
  87. data/lib/oxidized/model/adtran.rb +5 -1
  88. data/lib/oxidized/model/adva.rb +3 -3
  89. data/lib/oxidized/model/airfiber.rb +1 -1
  90. data/lib/oxidized/model/aos7.rb +11 -0
  91. data/lib/oxidized/model/aoscx.rb +37 -29
  92. data/lib/oxidized/model/aosw.rb +39 -29
  93. data/lib/oxidized/model/apc_aos.rb +7 -2
  94. data/lib/oxidized/model/apcaos.rb +39 -0
  95. data/lib/oxidized/model/aricentiss.rb +9 -2
  96. data/lib/oxidized/model/arubainstant.rb +93 -0
  97. data/lib/oxidized/model/asa.rb +11 -10
  98. data/lib/oxidized/model/asternos.rb +22 -0
  99. data/lib/oxidized/model/asyncos.rb +3 -3
  100. data/lib/oxidized/model/audiocodes.rb +2 -2
  101. data/lib/oxidized/model/awplus.rb +15 -12
  102. data/lib/oxidized/model/axos.rb +1 -1
  103. data/lib/oxidized/model/bdcom.rb +1 -0
  104. data/lib/oxidized/model/c4cmts.rb +1 -2
  105. data/lib/oxidized/model/ciscosma.rb +1 -1
  106. data/lib/oxidized/model/ciscosmb.rb +6 -1
  107. data/lib/oxidized/model/cnos.rb +13 -10
  108. data/lib/oxidized/model/comtrol.rb +1 -1
  109. data/lib/oxidized/model/comware.rb +5 -3
  110. data/lib/oxidized/model/cumulus.rb +14 -2
  111. data/lib/oxidized/model/defacto.rb +26 -0
  112. data/lib/oxidized/model/dellx.rb +1 -1
  113. data/lib/oxidized/model/dlink.rb +5 -2
  114. data/lib/oxidized/model/dlinknextgen.rb +55 -0
  115. data/lib/oxidized/model/dnos.rb +3 -0
  116. data/lib/oxidized/model/dslcommands.rb +93 -0
  117. data/lib/oxidized/model/dslsetup.rb +102 -0
  118. data/lib/oxidized/model/eatonnetwork.rb +70 -0
  119. data/lib/oxidized/model/edgecos.rb +3 -1
  120. data/lib/oxidized/model/edgeos.rb +7 -6
  121. data/lib/oxidized/model/edgeswitch.rb +3 -1
  122. data/lib/oxidized/model/efos.rb +41 -0
  123. data/lib/oxidized/model/eltex.rb +4 -2
  124. data/lib/oxidized/model/enterasys800.rb +2 -2
  125. data/lib/oxidized/model/enterprise_sonic.rb +46 -0
  126. data/lib/oxidized/model/eos.rb +3 -1
  127. data/lib/oxidized/model/exalink.rb +36 -0
  128. data/lib/oxidized/model/f5os.rb +17 -0
  129. data/lib/oxidized/model/fabricos.rb +2 -2
  130. data/lib/oxidized/model/fastiron.rb +5 -3
  131. data/lib/oxidized/model/firebrick.rb +2 -2
  132. data/lib/oxidized/model/firelinuxos.rb +13 -6
  133. data/lib/oxidized/model/firewareos.rb +10 -1
  134. data/lib/oxidized/model/fortigate.rb +160 -0
  135. data/lib/oxidized/model/fortios.rb +38 -48
  136. data/lib/oxidized/model/fsos.rb +46 -0
  137. data/lib/oxidized/model/gaiaos.rb +4 -4
  138. data/lib/oxidized/model/garderos.rb +38 -0
  139. data/lib/oxidized/model/grandstreamht8xx.rb +19 -0
  140. data/lib/oxidized/model/h3c.rb +1 -1
  141. data/lib/oxidized/model/ibos.rb +1 -0
  142. data/lib/oxidized/model/ingate.rb +47 -0
  143. data/lib/oxidized/model/ios.rb +57 -30
  144. data/lib/oxidized/model/iosxr.rb +2 -2
  145. data/lib/oxidized/model/ironware.rb +7 -5
  146. data/lib/oxidized/model/ivanti.rb +54 -0
  147. data/lib/oxidized/model/junos.rb +12 -5
  148. data/lib/oxidized/model/kornfeldos.rb +33 -0
  149. data/lib/oxidized/model/lenovonos.rb +2 -0
  150. data/lib/oxidized/model/linksyssrw.rb +3 -3
  151. data/lib/oxidized/model/linuxgeneric.rb +4 -2
  152. data/lib/oxidized/model/macros.rb +60 -0
  153. data/lib/oxidized/model/mimosab11.rb +34 -0
  154. data/lib/oxidized/model/ml66.rb +33 -0
  155. data/lib/oxidized/model/mlnxos.rb +18 -14
  156. data/lib/oxidized/model/model.rb +98 -103
  157. data/lib/oxidized/model/mtrlrfs.rb +1 -0
  158. data/lib/oxidized/model/ndms.rb +6 -0
  159. data/lib/oxidized/model/netgear.rb +14 -3
  160. data/lib/oxidized/model/netonix.rb +1 -1
  161. data/lib/oxidized/model/netscaler.rb +1 -1
  162. data/lib/oxidized/model/nodegrid.rb +1 -1
  163. data/lib/oxidized/model/nsxdfw.rb +31 -0
  164. data/lib/oxidized/model/nsxfirewall.rb +2 -1
  165. data/lib/oxidized/model/nxos.rb +20 -15
  166. data/lib/oxidized/model/ocnos.rb +42 -0
  167. data/lib/oxidized/model/onefinity.rb +18 -0
  168. data/lib/oxidized/model/openbsd.rb +1 -1
  169. data/lib/oxidized/model/opengear.rb +36 -1
  170. data/lib/oxidized/model/openwrt.rb +6 -6
  171. data/lib/oxidized/model/opnsense.rb +9 -1
  172. data/lib/oxidized/model/os6.rb +48 -0
  173. data/lib/oxidized/model/outputs.rb +5 -0
  174. data/lib/oxidized/model/panos.rb +2 -0
  175. data/lib/oxidized/model/perle.rb +41 -0
  176. data/lib/oxidized/model/pfsense.rb +9 -0
  177. data/lib/oxidized/model/powerconnect.rb +32 -11
  178. data/lib/oxidized/model/procurve.rb +6 -2
  179. data/lib/oxidized/model/qtech.rb +3 -1
  180. data/lib/oxidized/model/quantaos.rb +8 -6
  181. data/lib/oxidized/model/rgos.rb +33 -0
  182. data/lib/oxidized/model/riverbed.rb +104 -0
  183. data/lib/oxidized/model/routeros.rb +18 -11
  184. data/lib/oxidized/model/saos.rb +18 -1
  185. data/lib/oxidized/model/saos10.rb +38 -0
  186. data/lib/oxidized/model/siklu.rb +1 -1
  187. data/lib/oxidized/model/siklumhtg.rb +22 -0
  188. data/lib/oxidized/model/sixwind.rb +28 -0
  189. data/lib/oxidized/model/slxos.rb +3 -3
  190. data/lib/oxidized/model/smartbyte.rb +48 -0
  191. data/lib/oxidized/model/sonicos.rb +27 -20
  192. data/lib/oxidized/model/speedtouch.rb +1 -1
  193. data/lib/oxidized/model/sros.rb +3 -3
  194. data/lib/oxidized/model/srosmd.rb +1 -1
  195. data/lib/oxidized/model/supermicro.rb +1 -1
  196. data/lib/oxidized/model/telco.rb +1 -1
  197. data/lib/oxidized/model/tmos.rb +1 -0
  198. data/lib/oxidized/model/tnsr.rb +57 -0
  199. data/lib/oxidized/model/tplink.rb +5 -5
  200. data/lib/oxidized/model/trango.rb +4 -2
  201. data/lib/oxidized/model/truenas.rb +64 -3
  202. data/lib/oxidized/model/ucs.rb +1 -1
  203. data/lib/oxidized/model/unifiap.rb +144 -0
  204. data/lib/oxidized/model/uplinkolt.rb +46 -0
  205. data/lib/oxidized/model/voltaire.rb +1 -1
  206. data/lib/oxidized/model/voss.rb +3 -0
  207. data/lib/oxidized/model/vrp.rb +5 -1
  208. data/lib/oxidized/model/vyatta.rb +9 -3
  209. data/lib/oxidized/model/vyos.rb +37 -0
  210. data/lib/oxidized/model/xos.rb +10 -1
  211. data/lib/oxidized/model/zhoneolt.rb +4 -2
  212. data/lib/oxidized/model/zynos.rb +67 -3
  213. data/lib/oxidized/model/zynosadsl.rb +14 -0
  214. data/lib/oxidized/model/zynoscli.rb +1 -1
  215. data/lib/oxidized/model/zynosgs.rb +2 -0
  216. data/lib/oxidized/model/zynosmgs.rb +32 -0
  217. data/lib/oxidized/node.rb +99 -64
  218. data/lib/oxidized/nodes.rb +40 -19
  219. data/lib/oxidized/output/file.rb +80 -43
  220. data/lib/oxidized/output/git.rb +295 -151
  221. data/lib/oxidized/output/gitcrypt.rb +193 -185
  222. data/lib/oxidized/output/http.rb +63 -51
  223. data/lib/oxidized/output/output.rb +20 -4
  224. data/lib/oxidized/signals.rb +44 -0
  225. data/lib/oxidized/source/csv.rb +49 -49
  226. data/lib/oxidized/source/http.rb +76 -63
  227. data/lib/oxidized/source/jsonfile.rb +68 -0
  228. data/lib/oxidized/source/source.rb +73 -18
  229. data/lib/oxidized/source/sql.rb +71 -59
  230. data/lib/oxidized/version.rb +6 -4
  231. data/lib/oxidized/worker.rb +57 -29
  232. data/lib/oxidized.rb +4 -24
  233. data/lib/refinements.rb +21 -1
  234. data/oxidized.gemspec +45 -21
  235. metadata +248 -41
  236. data/lib/oxidized/model/timos.rb +0 -10
@@ -1,22 +1,40 @@
1
1
  require 'strscan'
2
2
  require_relative 'outputs'
3
+ require_relative 'dslsetup'
4
+ require_relative 'dslcommands'
5
+ require_relative 'macros'
3
6
 
4
7
  module Oxidized
5
8
  class Model
9
+ include SemanticLogger::Loggable
10
+
6
11
  using Refinements
7
12
 
13
+ # Domain Specific Language for models
14
+ extend Oxidized::Model::DSLSetup
15
+ extend Oxidized::Model::DSLCommands
16
+ extend Oxidized::Model::Macros
17
+
8
18
  include Oxidized::Config::Vars
9
19
 
20
+ # rubocop:disable Style/FormatStringToken
21
+ METADATA_DEFAULT = "%{comment}Fetched by Oxidized with model %{model} " \
22
+ "from host %{name} [%{ip}]\n".freeze
23
+ # rubocop:enable Style/FormatStringToken
24
+
10
25
  class << self
11
26
  def inherited(klass)
12
27
  super
13
28
  if klass.superclass == Oxidized::Model
14
- klass.instance_variable_set '@cmd', (Hash.new { |h, k| h[k] = [] })
15
- klass.instance_variable_set '@cfg', (Hash.new { |h, k| h[k] = [] })
16
- klass.instance_variable_set '@procs', (Hash.new { |h, k| h[k] = [] })
29
+ klass.instance_variable_set('@cmd', Hash.new { |h, k| h[k] = [] })
30
+ klass.instance_variable_set('@cfg', Hash.new { |h, k| h[k] = [] })
31
+ klass.instance_variable_set('@procs', Hash.new { |h, k| h[k] = [] })
17
32
  klass.instance_variable_set '@expect', []
18
33
  klass.instance_variable_set '@comment', nil
19
34
  klass.instance_variable_set '@prompt', nil
35
+ klass.instance_variable_set '@metadata', {}
36
+ klass.instance_variable_set '@inputs', nil
37
+
20
38
  else # we're subclassing some existing model, take its variables
21
39
  instance_variables.each do |var|
22
40
  iv = instance_variable_get(var)
@@ -25,101 +43,20 @@ module Oxidized
25
43
  end
26
44
  end
27
45
  end
28
-
29
- def comment(str = "# ")
30
- @comment = if block_given?
31
- yield
32
- elsif not @comment
33
- str
34
- else
35
- @comment
36
- end
37
- end
38
-
39
- def prompt(regex = nil)
40
- @prompt = regex || @prompt
41
- end
42
-
43
- def cfg(*methods, **args, &block)
44
- [methods].flatten.each do |method|
45
- process_args_block(@cfg[method.to_s], args, block)
46
- end
47
- end
48
-
49
- def cfgs
50
- @cfg
51
- end
52
-
53
- def cmd(cmd_arg = nil, **args, &block)
54
- if cmd_arg.instance_of?(Symbol)
55
- process_args_block(@cmd[cmd_arg], args, block)
56
- else
57
- process_args_block(@cmd[:cmd], args, [cmd_arg, block])
58
- end
59
- Oxidized.logger.debug "lib/oxidized/model/model.rb Added #{cmd_arg} to the commands list"
60
- end
61
-
62
- def cmds
63
- @cmd
64
- end
65
-
66
- def expect(regex, **args, &block)
67
- process_args_block(@expect, args, [regex, block])
68
- end
69
-
70
- def expects
71
- @expect
72
- end
73
-
74
- # calls the block at the end of the model, prepending the output of the
75
- # block to the output string
76
- #
77
- # @author Saku Ytti <saku@ytti.fi>
78
- # @since 0.0.39
79
- # @yield expects block which should return [String]
80
- # @return [void]
81
- def pre(**args, &block)
82
- process_args_block(@procs[:pre], args, block)
83
- end
84
-
85
- # calls the block at the end of the model, adding the output of the block
86
- # to the output string
87
- #
88
- # @author Saku Ytti <saku@ytti.fi>
89
- # @since 0.0.39
90
- # @yield expects block which should return [String]
91
- # @return [void]
92
- def post(**args, &block)
93
- process_args_block(@procs[:post], args, block)
94
- end
95
-
96
- # @author Saku Ytti <saku@ytti.fi>
97
- # @since 0.0.39
98
- # @return [Hash] hash proc procs :pre+:post to be prepended/postfixed to output
99
- attr_reader :procs
100
-
101
- private
102
-
103
- def process_args_block(target, args, block)
104
- if args[:clear]
105
- if block.instance_of?(Array)
106
- target.reject! { |k, _| k == block[0] }
107
- target.push(block)
108
- else
109
- target.replace([block])
110
- end
111
- else
112
- method = args[:prepend] ? :unshift : :push
113
- target.send(method, block)
114
- end
115
- end
116
46
  end
117
47
 
118
48
  attr_accessor :input, :node
119
49
 
120
- def cmd(string, &block)
121
- Oxidized.logger.debug "lib/oxidized/model/model.rb Executing #{string}"
122
- out = @input.cmd(string)
50
+ # input specifies to run this command only with this input type
51
+ # if input is not specified, always run the command
52
+ def cmd(string, input: nil, &block)
53
+ logger.debug "Executing #{string}"
54
+ out = if input.nil? || input.include?(@input.to_sym)
55
+ out = @input.cmd(string)
56
+ else
57
+ # Do not run this command
58
+ return ''
59
+ end
123
60
  return false unless out
124
61
 
125
62
  out = out.b unless Oxidized.config.input.utf8_encoded?
@@ -135,6 +72,44 @@ module Oxidized
135
72
  process_cmd_output out, string
136
73
  end
137
74
 
75
+ def metadata(position)
76
+ return unless %i[top bottom].include? position
77
+
78
+ model_metadata = self.class.instance_variable_get(:@metadata)
79
+ var_position = { top: "metadata_top", bottom: "metadata_bottom" }
80
+ if model_metadata[:top] || model_metadata[:bottom]
81
+ # the model defines metadata at :top ot :bottom, use the model
82
+ value = model_metadata[position]
83
+ value.is_a?(Proc) ? instance_eval(&value) : interpolate_string(value)
84
+ elsif vars("metadata_top") || vars("metadata_bottom")
85
+ # vars defines metadata_top or metadata bottom, use the vars
86
+ interpolate_string(vars(var_position[position]))
87
+ elsif position == :top
88
+ # default: use METADATA_DEFAULT for top
89
+ interpolate_string(METADATA_DEFAULT)
90
+ end
91
+ end
92
+
93
+ def interpolate_string(template)
94
+ return nil unless template
95
+
96
+ time = Time.now
97
+ template_variables = {
98
+ model: self.class.name,
99
+ name: node.name,
100
+ ip: node.ip,
101
+ group: node.group,
102
+ comment: self.class.comment,
103
+ year: time.year,
104
+ month: "%02d" % time.month,
105
+ day: "%02d" % time.day,
106
+ hour: "%02d" % time.hour,
107
+ minute: "%02d" % time.min,
108
+ second: "%02d" % time.sec
109
+ }
110
+ template % template_variables
111
+ end
112
+
138
113
  def output
139
114
  @input.output
140
115
  end
@@ -143,8 +118,8 @@ module Oxidized
143
118
  @input.send data
144
119
  end
145
120
 
146
- def expect(regex, &block)
147
- self.class.expect regex, &block
121
+ def expect(...)
122
+ self.class.expect(...)
148
123
  end
149
124
 
150
125
  def cfg
@@ -164,27 +139,40 @@ module Oxidized
164
139
  data
165
140
  end
166
141
 
142
+ # Get the commands from the model
167
143
  def get
168
- Oxidized.logger.debug 'lib/oxidized/model/model.rb Collecting commands\' outputs'
144
+ logger.debug 'Collecting commands\' outputs'
169
145
  outputs = Outputs.new
170
- procs = self.class.procs
171
- self.class.cmds[:cmd].each do |command, block|
172
- out = cmd command, &block
146
+ self.class.cmds[:cmd].each do |data|
147
+ command = data[:cmd]
148
+ args = data[:args]
149
+ block = data[:block]
150
+
151
+ next if args.include?(:if) && !instance_exec(&args[:if])
152
+
153
+ out = cmd command, input: args[:input], &block
173
154
  return false unless out
174
155
 
175
156
  outputs << out
176
157
  end
158
+ procs = self.class.procs
177
159
  procs[:pre].each do |pre_proc|
178
160
  outputs.unshift process_cmd_output(instance_eval(&pre_proc), '')
179
161
  end
180
162
  procs[:post].each do |post_proc|
181
163
  outputs << process_cmd_output(instance_eval(&post_proc), '')
182
164
  end
165
+ if vars("metadata") == true
166
+ metadata_top = metadata(:top)
167
+ metadata_bottom = metadata(:bottom)
168
+ outputs.unshift metadata_top if metadata_top
169
+ outputs << metadata_bottom if metadata_bottom
170
+ end
183
171
  outputs
184
172
  end
185
173
 
186
174
  def comment(str)
187
- data = ''
175
+ data = String.new('')
188
176
  str.each_line do |line|
189
177
  data << self.class.comment << line
190
178
  end
@@ -202,7 +190,7 @@ module Oxidized
202
190
  # Also, XML Comments must not contain --. So we put a space between
203
191
  # any double hyphens, by replacing any - that is followed by another -
204
192
  # with '- '
205
- data = ''
193
+ data = String.new('')
206
194
  str.each_line do |_line|
207
195
  data << '<!-- ' << str.gsub(/-(?=-)/, '- ').chomp << " -->\n"
208
196
  end
@@ -213,11 +201,18 @@ module Oxidized
213
201
  @input.class.to_s.match(/Telnet/) || vars(:ssh_no_exec)
214
202
  end
215
203
 
204
+ def significant_changes(config)
205
+ self.class.cmds[:significant_changes].each do |block|
206
+ config = instance_exec config, &block
207
+ end
208
+ config
209
+ end
210
+
216
211
  private
217
212
 
218
213
  def process_cmd_output(output, name)
219
214
  output = String.new('') unless output.instance_of?(String)
220
- output.set_cmd(name)
215
+ output.process_cmd(name)
221
216
  output
222
217
  end
223
218
  end
@@ -3,6 +3,7 @@ class Mtrlrfs < Oxidized::Model
3
3
 
4
4
  # Motorola RFS/Extreme WM
5
5
 
6
+ prompt /^([\w.@-]+\*?[#>])\s?$/
6
7
  comment '# '
7
8
 
8
9
  cmd :all do |cfg|
@@ -22,4 +22,10 @@ class NDMS < Oxidized::Model
22
22
  password /^Password:/
23
23
  pre_logout 'exit'
24
24
  end
25
+
26
+ cmd :significant_changes do |cfg|
27
+ cfg.reject_lines [
28
+ 'Last change:'
29
+ ]
30
+ end
25
31
  end
@@ -2,7 +2,14 @@ class Netgear < Oxidized::Model
2
2
  using Refinements
3
3
 
4
4
  comment '!'
5
- prompt /^(\([\w\s\-.]+\)\s[#>])$/
5
+ prompt /^\(?[\w \-+.]+\)? ?[#>] ?$/
6
+ clean :escape_codes
7
+
8
+ # Handle pager for "show version" on old Netgear models: #2394
9
+ expect /^--More--(?: or \(q\)uit)?$/ do |data, re|
10
+ send ' '
11
+ data.sub re, ''
12
+ end
6
13
 
7
14
  cmd :secret do |cfg|
8
15
  cfg.gsub!(/password (\S+)/, 'password <hidden>')
@@ -13,7 +20,7 @@ class Netgear < Oxidized::Model
13
20
  end
14
21
 
15
22
  cfg :telnet do
16
- username /^(User:|Applying Interface configuration, please wait ...)/
23
+ username /^(Username:|User:|Applying Interface configuration, please wait ...)/
17
24
  password /^Password:/i
18
25
  end
19
26
 
@@ -51,7 +58,11 @@ class Netgear < Oxidized::Model
51
58
  comment cfg
52
59
  end
53
60
  cmd 'show running-config' do |cfg|
54
- cfg.gsub! /(System Up Time\s+).*/, '\\1 <removed>'
61
+ cfg.gsub! /(System Up Time:?\s+).*/, '\\1 <removed>'
55
62
  cfg.gsub! /(Current SNTP Synchronized Time:).*/, '\\1 <removed>'
63
+ cfg.gsub! /(Current System Time:).*/, '\\1 <removed>'
64
+ # Remove standalone backspace lines
65
+ cfg.gsub!(/(?:\r?\n)?\x08(?:\r?\n)?/, "\n")
66
+ cfg
56
67
  end
57
68
  end
@@ -1,7 +1,7 @@
1
1
  class Netonix < Oxidized::Model
2
2
  using Refinements
3
3
 
4
- prompt /^[\w\s\(\).@_\/:-]+#/
4
+ prompt /^[\w\s().@_\/:-]+#/
5
5
 
6
6
  cmd :all do |cfg|
7
7
  cfg.cut_both
@@ -1,7 +1,7 @@
1
1
  class NetScaler < Oxidized::Model
2
2
  using Refinements
3
3
 
4
- prompt /^([\w\.-]*>\s?)$/
4
+ prompt /^(.*[\w.-]*>\s?)$/
5
5
  comment '# '
6
6
 
7
7
  cmd :all do |cfg|
@@ -4,7 +4,7 @@ class Nodegrid < Oxidized::Model
4
4
  # ZPE Nodegrid (Tested with Nodegrid Gate/Bold/NSR)
5
5
  # https://www.zpesystems.com/products/
6
6
 
7
- prompt(%r{(?<!@)\[(.*?\s/)\]#})
7
+ prompt /(?<!@)\[(.*?\s\/)\]#/
8
8
  comment '# '
9
9
 
10
10
  cmd 'show system/about/' do |cfg|
@@ -0,0 +1,31 @@
1
+ require 'net/http'
2
+ class NSXDfw < Oxidized::Model
3
+ using Refinements
4
+
5
+ cmd "/policy/api/v1/infra/domains/" do |cfg|
6
+ domains = JSON.parse(cfg.encode('UTF-8', { invalid: :replace, undef: :replace, replace: '?' }))["results"]
7
+ domain_config = {}
8
+ domains.each do |domain|
9
+ domain_config[domain['id']] = {}
10
+ policies_data = cmd "/policy/api/v1/infra/domains/#{domain['id']}/security-policies/"
11
+ policies = JSON.parse(policies_data.encode('UTF-8',
12
+ { invalid: :replace, undef: :replace, replace: '?' }))["results"]
13
+ policies_config = {}
14
+ policies.each do |policy|
15
+ rules_data = cmd "/policy/api/v1/infra/domains/#{domain['id']}/security-policies/#{policy['id']}/rules"
16
+ rules = JSON.parse(rules_data.encode('UTF-8', { invalid: :replace, undef: :replace, replace: '?' }))["results"]
17
+ policies_config[policy['id']] = rules
18
+ end
19
+ domain_config[domain['id']] = policies_config
20
+ end
21
+ JSON.pretty_generate(domain_config)
22
+ end
23
+
24
+ cfg :http do
25
+ @username = @node.auth[:username]
26
+ @password = @node.auth[:password]
27
+ @headers['Content-Type'] = 'application/json'
28
+ @headers['Accept'] = 'application/json'
29
+ @secure = true
30
+ end
31
+ end
@@ -8,7 +8,8 @@ class NSXFirewall < Oxidized::Model
8
8
  edges.each do |edge|
9
9
  firewall_config = cmd "/api/4.0/edges/#{edge['id']}/firewall/config"
10
10
  json_config = {}
11
- json_config["#{edge['id']} #{edge['name']}"] = JSON.parse(firewall_config.encode('UTF-8', { invalid: :replace, undef: :replace, replace: '?' }))
11
+ json_config["#{edge['id']} #{edge['name']}"] =
12
+ JSON.parse(firewall_config.encode('UTF-8', { invalid: :replace, undef: :replace, replace: '?' }))
12
13
  data.push(json_config)
13
14
  end
14
15
  JSON.pretty_generate(data)
@@ -1,39 +1,44 @@
1
1
  class NXOS < Oxidized::Model
2
2
  using Refinements
3
3
 
4
- prompt /^(\r?[\w.@_()-]+[#]\s?)$/
4
+ prompt /^(\r?[\w.@_()-]+\#\s?)$/
5
5
  comment '! '
6
6
 
7
- def filter(cfg)
8
- cfg.gsub! /\r\n?/, "\n"
9
- cfg.gsub! prompt, ''
7
+ cmd :all do |cfg|
8
+ cfg.cut_both
10
9
  end
11
10
 
12
11
  cmd :secret do |cfg|
13
- cfg.gsub! /^(snmp-server community).*/, '\\1 <configuration removed>'
14
- cfg.gsub! /^(snmp-server user (\S+) (\S+) auth (\S+)) (\S+) (priv) (\S+)/, '\\1 <configuration removed> '
12
+ cfg.gsub! /^(snmp-server community).*/, '\\1 <secret hidden>'
13
+ cfg.gsub!(
14
+ /^(snmp-server user \S+ \S+ auth \S+) \S+ (priv \S+) \S+ /,
15
+ '\\1 <secret hidden> \\2 <secret hidden> '
16
+ )
17
+ cfg.gsub! /^(snmp-server host.*? )\S+( udp-port \d+)?$/, '\\1<secret hidden>\\2'
18
+ cfg.gsub! /^(snmp-server mib community-map) \S+ ?(.*)/, '\\1 <secret hidden> \\2'
15
19
  cfg.gsub! /(password \d+) (\S+)/, '\\1 <secret hidden>'
16
- cfg.gsub! /^(radius-server key).*/, '\\1 <secret hidden>'
17
- cfg.gsub! /^(tacacs-server host .+ key(?: \d+)?) \S+/, '\\1 <secret hidden>'
20
+ cfg.gsub! /^(radius-server .*key(?: \d+)?) \S+/, '\\1 <secret hidden>'
21
+ cfg.gsub! /^(tacacs-server .*key(?: \d+)?) \S+/, '\\1 <secret hidden>'
18
22
  cfg
19
23
  end
20
24
 
21
25
  cmd 'show version' do |cfg|
22
- cfg = filter cfg
23
- cfg = cfg.each_line.take_while { |line| not line.match(/uptime/i) }
24
- comment cfg.join
26
+ cfg = cfg.each_line.take_while { |line| not line.match(/uptime|bootflash:\s+\d+\skB|sysmgrcli_show_flash_size/i) }
27
+ comment cfg.join + "\n"
25
28
  end
26
29
 
27
- cmd 'show inventory' do |cfg|
28
- cfg = filter cfg
30
+ cmd 'show inventory all' do |cfg|
31
+ if cfg.match? /^% Invalid .* at '\^' marker\./
32
+ # 'show inventory all' isn't supported on older versions (See Issues #3657, #3779)
33
+ cfg = cmd 'show inventory'
34
+ end
29
35
  comment cfg
30
36
  end
31
37
 
32
38
  cmd 'show running-config' do |cfg|
33
- cfg = filter cfg
34
39
  cfg.gsub! /^(show run.*)$/, '! \1'
35
40
  cfg.gsub! /^!Time:[^\n]*\n/, ''
36
- cfg.gsub! /^[\w.@_()-]+[#].*$/, ''
41
+ cfg.gsub! /^[\w.@_()-]+\#.*$/, ''
37
42
  cfg
38
43
  end
39
44
 
@@ -0,0 +1,42 @@
1
+ class OcNOS < Oxidized::Model
2
+ using Refinements
3
+
4
+ prompt /([\w.@-]+[#>]\s?)$/
5
+ comment '# '
6
+
7
+ cfg :ssh do
8
+ post_login 'terminal length 0'
9
+ pre_logout do
10
+ send "disable\r"
11
+ send "logout\r"
12
+ end
13
+ end
14
+
15
+ cmd :all do |cfg|
16
+ cfg.lines.to_a[1..-2].join
17
+ end
18
+
19
+ cmd 'show version' do |cfg|
20
+ comment cfg
21
+ end
22
+
23
+ cmd 'show system fru' do |cfg|
24
+ comment cfg
25
+ end
26
+
27
+ cmd 'show system-information board-info' do |cfg|
28
+ comment cfg
29
+ end
30
+
31
+ cmd 'show forwarding profile limit' do |cfg|
32
+ comment cfg
33
+ end
34
+
35
+ cmd 'show license' do |cfg|
36
+ comment cfg
37
+ end
38
+
39
+ cmd 'show running-config' do |cfg|
40
+ cfg
41
+ end
42
+ end
@@ -0,0 +1,18 @@
1
+ class OneFinity < Oxidized::Model
2
+ using Refinements
3
+
4
+ # Fujitsu 1finity
5
+
6
+ prompt /(\r?[\w.@_()-]+>\s?)$/
7
+
8
+ cmd :all do |cfg|
9
+ cfg.each_line.to_a[1..-3].join
10
+ end
11
+
12
+ cmd 'show configuration | display set | nomore'
13
+
14
+ cfg :ssh do
15
+ pre_logout 'exit'
16
+ exec true
17
+ end
18
+ end
@@ -5,7 +5,7 @@ class Openbsd < Oxidized::Model
5
5
  # you can edit the one that your user uses, with root would be /root/.profile using the next PS1 def
6
6
  # export PS1="\033[32m\u@\h\033[00m:\033[36m\w\033[00m$ "
7
7
 
8
- prompt /^.+@.+\:.+\$/
8
+ prompt /^.+@.+:.+\$/
9
9
  comment '# '
10
10
 
11
11
  # Add a comment between files/configs
@@ -8,12 +8,47 @@ class OpenGear < Oxidized::Model
8
8
  cmd :secret do |cfg|
9
9
  cfg.gsub!(/password (\S+)/, 'password <secret removed>')
10
10
  cfg.gsub!(/community (\S+)/, 'community <secret removed>')
11
+ cfg.gsub!(/community=(\S+)/, 'community=<secret removed>')
12
+ cfg.gsub!(/private_key=(\S+)/, 'private_key=<secret removed>')
13
+ cfg.gsub!(/ key=(\S+)/, ' key=<secret removed>')
14
+ cfg.gsub!(/hashed_password=(\S+)/, 'hashed_password=<secret removed>')
11
15
  cfg
12
16
  end
13
17
 
14
18
  cmd('cat /etc/version') { |cfg| comment cfg }
15
19
 
16
- cmd('config -g config') { |cfg| cfg }
20
+ # newer opengear firmware versions
21
+ cmd 'ogdeviceinfo -r' do |cfg|
22
+ comment cfg unless cfg.include? "ogdeviceinfo: command not found"
23
+ end
24
+
25
+ cmd 'config export' do |cfg|
26
+ unless cfg.include? "usage: config"
27
+ out = ''
28
+ cfg.each_line do |line|
29
+ out << line
30
+ end
31
+ out
32
+ end
33
+ end
34
+
35
+ # older opengear firmware versions
36
+ cmd 'showserial' do |cfg|
37
+ unless cfg.include? "showserial: command not found"
38
+ cfg.gsub! /^/, 'Serial Number: '
39
+ comment cfg
40
+ end
41
+ end
42
+
43
+ cmd 'config -g config' do |cfg|
44
+ unless cfg.include? "config: error: argument"
45
+ out = ''
46
+ cfg.each_line do |line|
47
+ out << line
48
+ end
49
+ out
50
+ end
51
+ end
17
52
 
18
53
  cfg :ssh do
19
54
  exec true # don't run shell, run each command in exec channel
@@ -38,26 +38,26 @@ class OpenWrt < Oxidized::Model
38
38
  filename = sysupgradefile.split('/')[-1]
39
39
  cfg << comment("#### File: #{sysupgradefile} #####")
40
40
  uciexport = cmd("uci export #{filename}")
41
- Oxidized.logger.debug "Exporting uci config - #{filename}"
41
+ logger.debug "Exporting uci config - #{filename}"
42
42
  if vars(:remove_secret) && !(non_sensitive_files.include? filename)
43
- Oxidized.logger.debug "Scrubbing uci config - #{filename}"
43
+ logger.debug "Scrubbing uci config - #{filename}"
44
44
  uciexport.gsub!(/^(\s+option\s+(password|key)\s+')[^']+'/, '\\1<secret hidden>\'')
45
45
  end
46
46
  cfg << uciexport
47
47
  end
48
48
  elsif binary_files.include? sysupgradefile
49
- Oxidized.logger.debug "Exporting binary file - #{sysupgradefile}"
49
+ logger.debug "Exporting binary file - #{sysupgradefile}"
50
50
  cfg << comment("#### Binary file: #{sysupgradefile} #####")
51
51
  cfg << comment("Decode using 'echo -en <data> | gzip -dc > #{sysupgradefile}'")
52
52
  cfg << cmd("gzip -c #{sysupgradefile} | hexdump -ve '1/1 \"_x%.2x\"' | tr _ \\")
53
53
  elsif vars(:remove_secret) && sysupgradefile == '/etc/shadow'
54
- Oxidized.logger.debug 'Exporting and scrubbing /etc/shadow'
54
+ logger.debug 'Exporting and scrubbing /etc/shadow'
55
55
  cfg << comment("#### File: #{sysupgradefile} #####")
56
56
  shadow = cmd("cat #{sysupgradefile}")
57
57
  shadow.gsub!(/^([^:]+:)[^:]*(:[^:]*:[^:]*:[^:]*:[^:]*:[^:]*:[^:]*:)/, '\\1\\2')
58
58
  cfg << shadow
59
59
  else
60
- Oxidized.logger.debug "Exporting file - #{sysupgradefile}"
60
+ logger.debug "Exporting file - #{sysupgradefile}"
61
61
  cfg << comment("#### File: #{sysupgradefile} #####")
62
62
  cfg << cmd("cat #{sysupgradefile}")
63
63
  end
@@ -65,7 +65,7 @@ class OpenWrt < Oxidized::Model
65
65
  @mtdpartitions.scan(/(\w+):\s+\w+\s+\w+\s+"(.*)"/).each do |partition, name|
66
66
  next unless vars(:openwrt_backup_partitions) && partitions_to_backup.include?(name)
67
67
 
68
- Oxidized.logger.debug "Exporting partition - #{name}(#{partition})"
68
+ logger.debug "Exporting partition - #{name}(#{partition})"
69
69
  cfg << comment("#### Partition: #{name} /dev/#{partition} #####")
70
70
  cfg << comment("Decode using 'echo -en <data> | gzip -dc > #{name}'")
71
71
  cfg << cmd("dd if=/dev/#{partition} 2>/dev/null | gzip -c | hexdump -ve '1/1 \"%.2x\"'")
@@ -18,10 +18,18 @@ class OpnSense < Oxidized::Model
18
18
  # that lack the opnsense-version command. Newer versions of OPNsense no longer
19
19
  # store the version information in this file, so both versions have to be
20
20
  # supported here for now.
21
- cmd 'opnsense-version 2>/dev/null || echo "OPNsense "`cat /usr/local/opnsense/version/opnsense`' do |version|
21
+ cmd 'opnsense-version || echo "OPNsense "`cat /usr/local/opnsense/version/opnsense`' do |version|
22
22
  xmlcomment version
23
23
  end
24
24
 
25
+ metadata :bottom do
26
+ xmlcomment interpolate_string(
27
+ vars("metadata_bottom") ||
28
+ vars("metadata_top") ||
29
+ Oxidized::Model::METADATA_DEFAULT
30
+ )
31
+ end
32
+
25
33
  cfg :ssh do
26
34
  exec true
27
35
  pre_logout 'exit'