oxidized 0.36.0 → 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 (41) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +3 -0
  3. data/CHANGELOG.md +26 -0
  4. data/Rakefile +1 -1
  5. data/docs/Configuration.md +10 -1
  6. data/docs/Creating-Models.md +1 -1
  7. data/docs/Hooks.md +92 -67
  8. data/docs/Inputs.md +15 -12
  9. data/docs/Model-Notes/GrandstreamHT8xx.md +8 -0
  10. data/docs/Model-Notes/RouterOS.md +13 -0
  11. data/docs/Model-Notes/TrueNAS.md +11 -7
  12. data/docs/Release.md +6 -1
  13. data/docs/Supported-OS-Types.md +1 -0
  14. data/extra/hooks/modelrulesadvanced.rb +0 -1
  15. data/lib/oxidized/cli/support.rb +152 -0
  16. data/lib/oxidized/cli.rb +9 -0
  17. data/lib/oxidized/hook.rb +2 -0
  18. data/lib/oxidized/input/debugtext.rb +40 -0
  19. data/lib/oxidized/input/debugyaml.rb +82 -0
  20. data/lib/oxidized/input/exec.rb +1 -6
  21. data/lib/oxidized/input/ftp.rb +0 -4
  22. data/lib/oxidized/input/http.rb +1 -8
  23. data/lib/oxidized/input/ssh.rb +28 -21
  24. data/lib/oxidized/input/sshbase.rb +7 -12
  25. data/lib/oxidized/input/telnet.rb +12 -9
  26. data/lib/oxidized/input/tftp.rb +0 -4
  27. data/lib/oxidized/model/aoscx.rb +13 -9
  28. data/lib/oxidized/model/cumulus.rb +3 -3
  29. data/lib/oxidized/model/dlinknextgen.rb +1 -0
  30. data/lib/oxidized/model/fortigate.rb +1 -1
  31. data/lib/oxidized/model/grandstreamht8xx.rb +19 -0
  32. data/lib/oxidized/model/ios.rb +2 -0
  33. data/lib/oxidized/model/junos.rb +2 -2
  34. data/lib/oxidized/model/linuxgeneric.rb +4 -2
  35. data/lib/oxidized/model/nxos.rb +4 -1
  36. data/lib/oxidized/model/routeros.rb +4 -0
  37. data/lib/oxidized/model/tplink.rb +4 -6
  38. data/lib/oxidized/model/truenas.rb +56 -5
  39. data/lib/oxidized/model/vyos.rb +1 -0
  40. data/lib/oxidized/version.rb +2 -2
  41. metadata +6 -1
@@ -0,0 +1,40 @@
1
+ module Oxidized
2
+ class DebugText
3
+ include SemanticLogger::Loggable
4
+
5
+ def initialize(config_debug, node, input_name)
6
+ return unless config_debug == true ||
7
+ (config_debug.is_a?(String) && config_debug.downcase.include?('text'))
8
+
9
+ @log = File.open(logfile(node, input_name), 'w')
10
+ end
11
+
12
+ # Separate method to ease unit tests
13
+ def logfile(node, input_name)
14
+ timestamp = Time.now.strftime('%Y%m%d-%H%M%S')
15
+ file = Oxidized::Config::LOG + "/#{node&.ip}-#{input_name}-#{timestamp}.txt"
16
+ logger.debug "Writing I/O Debugging to #{file}"
17
+ file
18
+ end
19
+
20
+ def send_data(data)
21
+ return unless @log
22
+
23
+ @log.puts "sent cmd #{data.dump}"
24
+ @log.flush
25
+ end
26
+
27
+ def receive_data(data)
28
+ return unless @log
29
+
30
+ @log.puts "received #{data.dump}"
31
+ @log.flush
32
+ end
33
+
34
+ def close
35
+ return unless @log
36
+
37
+ @log.close
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,82 @@
1
+ module Oxidized
2
+ class DebugYAML
3
+ include SemanticLogger::Loggable
4
+
5
+ def initialize(config_debug, node, input_name)
6
+ return unless config_debug == true ||
7
+ (config_debug.is_a?(String) && config_debug.downcase.include?('yaml'))
8
+
9
+ @log = File.open(logfile(node, input_name), 'w')
10
+
11
+ @partial_line = false
12
+ @first_line = true
13
+ @commands_started = false
14
+
15
+ @log.puts '---'
16
+ @log.puts 'init_prompt: |-'
17
+ @log.flush
18
+ end
19
+
20
+ # Separate method to ease unit tests
21
+ def logfile(node, input_name)
22
+ timestamp = Time.now.strftime('%Y%m%d-%H%M%S')
23
+ file = Oxidized::Config::LOG + "/#{node&.ip}-#{input_name}-#{timestamp}.yaml"
24
+ logger.debug "Writing YAML Simulation to #{file}"
25
+ file
26
+ end
27
+
28
+ def send_data(data)
29
+ return unless @log
30
+
31
+ @log.puts
32
+ @log.puts 'commands:' unless @commands_started
33
+ @log.puts " - #{data.dump}: |-"
34
+ @first_line = true
35
+ @partial_line = false
36
+ @commands_started = true
37
+ @log.flush
38
+ end
39
+
40
+ def receive_data(data)
41
+ return unless @log
42
+ return if data.empty?
43
+
44
+ lines = data.split("\n", -1)
45
+
46
+ lines.each_with_index do |line, idx|
47
+ is_last = idx == lines.length - 1
48
+ full_line = is_last ? (data[-1] == "\n") : true
49
+ # Escape line and strip surrounding double quotes
50
+ line = line.dump[1..-2]
51
+ if @first_line
52
+ # Make sure the leading space of the first line (if present)
53
+ # is coded with \0x20 or YAML block scalars won't work
54
+ line.sub!(/^ /, '\x20')
55
+ @first_line = false
56
+ end
57
+
58
+ # Make sure trailing white spaces are coded with \0x20
59
+ line.gsub!(/ $/, '\x20')
60
+
61
+ output = @partial_line ? line : (' ' + line)
62
+ @partial_line = false
63
+
64
+ if full_line
65
+ @log.puts output
66
+ else
67
+ @log.write output
68
+ end
69
+ end
70
+
71
+ @partial_line = data[-1] != "\n"
72
+
73
+ @log.flush
74
+ end
75
+
76
+ def close
77
+ return unless @log
78
+
79
+ @log.close
80
+ end
81
+ end
82
+ end
@@ -2,7 +2,6 @@ module Oxidized
2
2
  class Exec < Input
3
3
  def connect(node)
4
4
  @node = node
5
- @log = File.open(Oxidized::Config::LOG + "/#{@node.ip}-exec", "w") if Oxidized.config.input.debug?
6
5
  @node.model.cfg["exec"].each { |cb| instance_exec(&cb) }
7
6
  end
8
7
 
@@ -15,10 +14,6 @@ module Oxidized
15
14
 
16
15
  private
17
16
 
18
- def disconnect
19
- true
20
- ensure
21
- @log.close if Oxidized.config.input.debug?
22
- end
17
+ def disconnect; end
23
18
  end
24
19
  end
@@ -5,7 +5,6 @@ module Oxidized
5
5
  def connect(node) # rubocop:disable Naming/PredicateMethod
6
6
  @node = node
7
7
  @node.model.cfg['ftp'].each { |cb| instance_exec(&cb) }
8
- @log = File.open(Oxidized::Config::LOG + "/#{@node.ip}-ftp", 'w') if Oxidized.config.input.debug?
9
8
  @ftp = Net::FTP.new(@node.ip)
10
9
  @ftp.passive = Oxidized.config.input.ftp.passive
11
10
  @ftp.login @node.auth[:username], @node.auth[:password]
@@ -34,9 +33,6 @@ module Oxidized
34
33
 
35
34
  def disconnect
36
35
  @ftp.close
37
- # rescue Errno::ECONNRESET, IOError
38
- ensure
39
- @log.close if Oxidized.config.input.debug?
40
36
  end
41
37
  end
42
38
  end
@@ -10,7 +10,6 @@ module Oxidized
10
10
  @username = nil
11
11
  @password = nil
12
12
  @headers = {}
13
- @log = File.open(Oxidized::Config::LOG + "/#{@node.ip}-http", "w") if Oxidized.config.input.debug?
14
13
  @node.model.cfg["http"].each { |cb| instance_exec(&cb) }
15
14
 
16
15
  return true unless @main_page && defined?(login)
@@ -110,13 +109,7 @@ module Oxidized
110
109
  "Basic " + ["#{@username}:#{@password}"].pack('m').delete("\r\n")
111
110
  end
112
111
 
113
- def log(str)
114
- @log&.write(str)
115
- end
116
-
117
- def disconnect
118
- @log.close if Oxidized.config.input.debug?
119
- end
112
+ def disconnect; end
120
113
 
121
114
  def get_uri(path)
122
115
  path = URI.parse(path)
@@ -1,7 +1,9 @@
1
- module Oxidized
2
- require 'timeout'
3
- require_relative 'sshbase'
1
+ require 'timeout'
2
+ require_relative 'sshbase'
3
+ require_relative 'debugyaml'
4
+ require_relative 'debugtext'
4
5
 
6
+ module Oxidized
5
7
  class SSH < SSHBase
6
8
  class NoShell < OxidizedError; end
7
9
 
@@ -18,11 +20,9 @@ module Oxidized
18
20
  @output = String.new('')
19
21
  @pty_options = { term: "vt100" }
20
22
  @node.model.cfg['ssh'].each { |cb| instance_exec(&cb) }
21
- if Oxidized.config.input.debug?
22
- logfile = Oxidized::Config::LOG + "/#{@node.ip}-ssh"
23
- @log = File.open(logfile, 'w')
24
- logger.debug "I/O Debuging to #{logfile}"
25
- end
23
+
24
+ @yaml_debug = DebugYAML.new(Oxidized.config.input.debug, @node, config_name)
25
+ @text_debug = DebugText.new(Oxidized.config.input.debug, @node, config_name)
26
26
 
27
27
  logger.debug "Connecting to #{@node.name}"
28
28
  @ssh = Net::SSH.start(@node.ip, @node.auth[:username], make_ssh_opts)
@@ -38,25 +38,30 @@ module Oxidized
38
38
  end
39
39
 
40
40
  def cmd(cmd, expect = node.prompt)
41
- logger.debug "Sending '#{cmd.dump}' @ #{node.name} with expect: #{expect.inspect}"
42
- if Oxidized.config.input.debug?
43
- @log.puts "sent cmd #{@exec ? cmd.dump : (cmd + newline).dump}"
44
- @log.flush
41
+ unless cmd.is_a?(String)
42
+ logger.error "cmd must be a String (#{cmd.class}): #{cmd.inspect} @ #{node.name}"
43
+ raise ArgumentError, "cmd must be a String"
45
44
  end
45
+ logger.debug "Sending '#{cmd.dump}' @ #{node.name} with expect: #{expect.inspect}"
46
46
  cmd_output = if @exec
47
+ @yaml_debug&.send_data(cmd)
48
+ @text_debug&.send_data(cmd)
47
49
  @ssh.exec! cmd
48
50
  else
49
51
  cmd_shell(cmd, expect).gsub("\r\n", "\n")
50
52
  end
53
+
54
+ # only logging @exec as cmd_shell is handled in the ssh loop
55
+ @yaml_debug&.receive_data(cmd_output) if @exec
56
+ @text_debug&.receive_data(cmd_output) if @exec
57
+
51
58
  # Make sure we return a String
52
59
  cmd_output.to_s
53
60
  end
54
61
 
55
62
  def send(data)
56
- if Oxidized.config.input.debug?
57
- @log.puts "sent data #{data.dump}"
58
- @log.flush
59
- end
63
+ @yaml_debug&.send_data(data)
64
+ @text_debug&.send_data(data)
60
65
  @ses.send_data data
61
66
  end
62
67
 
@@ -79,17 +84,16 @@ module Oxidized
79
84
  rescue Timeout::Error
80
85
  logger.debug "#{@node.name} timed out while disconnecting"
81
86
  ensure
82
- @log.close if Oxidized.config.input.debug?
87
+ @yaml_debug&.close
88
+ @text_debug&.close
83
89
  (@ssh.close rescue true) unless @ssh.closed? # rubocop:disable Style/RedundantParentheses
84
90
  end
85
91
 
86
92
  def shell_open(ssh)
87
93
  @ses = ssh.open_channel do |ch|
88
94
  ch.on_data do |_ch, data|
89
- if Oxidized.config.input.debug?
90
- @log.puts "received #{data.dump}"
91
- @log.flush
92
- end
95
+ @yaml_debug&.receive_data(data)
96
+ @text_debug&.receive_data(data)
93
97
  @output << data
94
98
  @output = @node.model.expects @output
95
99
  end
@@ -111,6 +115,9 @@ module Oxidized
111
115
 
112
116
  def cmd_shell(cmd, expect_re)
113
117
  @output = String.new('')
118
+
119
+ @yaml_debug&.send_data(cmd + newline)
120
+ @text_debug&.send_data(cmd + newline)
114
121
  @ses.send_data cmd + newline
115
122
  @ses.process
116
123
  expect expect_re if expect_re
@@ -18,7 +18,6 @@ module Oxidized
18
18
  def connect(node) # rubocop:disable Naming/PredicateMethod
19
19
  @node = node
20
20
  @node.model.cfg[config_name].each { |cb| instance_exec(&cb) }
21
- setup_debug_logging
22
21
  logger.debug "Connecting to #{@node.name}"
23
22
  @ssh = Net::SSH.start(@node.ip, @node.auth[:username], make_ssh_opts)
24
23
  connected?
@@ -28,14 +27,6 @@ module Oxidized
28
27
  @ssh && (not @ssh.closed?)
29
28
  end
30
29
 
31
- def setup_debug_logging
32
- return unless Oxidized.config.input.debug?
33
-
34
- logfile = Oxidized::Config::LOG + "/#{@node.ip}-#{config_name}"
35
- @log = File.open(logfile, 'w')
36
- logger.debug "I/O Debugging to #{logfile}"
37
- end
38
-
39
30
  def make_ssh_opts
40
31
  ssh_opts = {
41
32
  number_of_password_prompts: 0,
@@ -65,7 +56,13 @@ module Oxidized
65
56
 
66
57
  # Use our logger for Net::SSH
67
58
  ssh_logger = SemanticLogger[Net::SSH]
68
- ssh_logger.level = Oxidized.config.input.debug? ? :debug : :fatal
59
+ config_debug = Oxidized.config.input.debug
60
+ if config_debug == true ||
61
+ (config_debug.is_a?(String) && config_debug.downcase.include?('library'))
62
+ ssh_logger.level = :debug
63
+ else
64
+ ssh_logger.level = :fatal
65
+ end
69
66
  ssh_opts[:logger] = ssh_logger
70
67
 
71
68
  ssh_opts
@@ -95,8 +92,6 @@ module Oxidized
95
92
  "disconnecting, raising #{e.class} with #{e.message}"
96
93
  rescue Timeout::Error
97
94
  logger.debug "#{@node.name} timed out while disconnecting"
98
- ensure
99
- @log.close if Oxidized.config.input.debug?
100
95
  end
101
96
 
102
97
  # Methods to implement in subclasses
@@ -1,3 +1,5 @@
1
+ require_relative 'debugtext'
2
+
1
3
  module Oxidized
2
4
  require 'net/telnet'
3
5
  class Telnet < Input
@@ -7,7 +9,9 @@ module Oxidized
7
9
  @node = node
8
10
  @timeout = @node.timeout
9
11
  @node.model.cfg['telnet'].each { |cb| instance_exec(&cb) }
10
- @log = File.open(Oxidized::Config::LOG + "/#{@node.ip}-telnet", 'w') if Oxidized.config.input.debug?
12
+
13
+ @text_debug = DebugText.new(Oxidized.config.input.debug, @node, config_name)
14
+
11
15
  port = vars(:telnet_port) || 23
12
16
 
13
17
  telnet_opts = {
@@ -15,7 +19,7 @@ module Oxidized
15
19
  'Port' => port.to_i,
16
20
  'Timeout' => @timeout,
17
21
  'Model' => @node.model,
18
- 'Log' => @log
22
+ 'Log' => @text_debug
19
23
  }
20
24
 
21
25
  @telnet = Net::Telnet.new telnet_opts
@@ -38,12 +42,14 @@ module Oxidized
38
42
  # create a string to be passed to oxidized_expect and modified _there_
39
43
  # default to a single space so it shouldn't be coerced to nil by any models.
40
44
  out = String(' ')
45
+ @text_debug&.send_data(cmd_str)
41
46
  @telnet.puts(cmd_str)
42
47
  @telnet.oxidized_expect(timeout: @timeout, expect: expect, out: out)
43
48
  out
44
49
  end
45
50
 
46
51
  def send(data)
52
+ @text_debug&.send_data(data)
47
53
  @telnet.write data
48
54
  end
49
55
 
@@ -63,7 +69,7 @@ module Oxidized
63
69
  rescue Errno::ECONNRESET, IOError
64
70
  # This exception is intented and therefore not handled here
65
71
  ensure
66
- @log.close if Oxidized.config.input.debug?
72
+ @text_debug&.close
67
73
  (@telnet.close rescue true) unless @telnet.sock.closed? # rubocop:disable Style/RedundantParentheses
68
74
  end
69
75
  end
@@ -76,8 +82,8 @@ module Net
76
82
  attr_reader :output
77
83
 
78
84
  def oxidized_expect(options)
79
- model = @options["Model"]
80
- @log = @options["Log"]
85
+ model = @options["Model"]
86
+ text_debug = @options["Log"]
81
87
 
82
88
  expects = [options[:expect]].flatten
83
89
  time_out = options[:timeout] || @options["Timeout"]
@@ -103,10 +109,7 @@ module Net
103
109
  buf = preprocess(c)
104
110
  rest = ''
105
111
  end
106
- if Oxidized.config.input.debug?
107
- @log.print buf
108
- @log.flush
109
- end
112
+ text_debug&.receive_data buf
110
113
  line += buf
111
114
  line = model.expects line
112
115
  # match is a regexp object. we need to return that for logins to work.
@@ -20,7 +20,6 @@ module Oxidized
20
20
  @node = node
21
21
 
22
22
  @node.model.cfg['tftp'].each { |cb| instance_exec(&cb) }
23
- @log = File.open(Oxidized::Config::LOG + "/#{@node.ip}-tftp", 'w') if Oxidized.config.input.debug?
24
23
  @tftp = Net::TFTP.new @node.ip
25
24
  end
26
25
 
@@ -36,9 +35,6 @@ module Oxidized
36
35
 
37
36
  def disconnect
38
37
  # TFTP uses UDP, there is no connection to close
39
- true
40
- ensure
41
- @log.close if Oxidized.config.input.debug?
42
38
  end
43
39
  end
44
40
  end
@@ -37,22 +37,23 @@ class Aoscx < Oxidized::Model
37
37
  comment cfg
38
38
  end
39
39
 
40
- cmd 'show environment' do |cfg|
41
- def with_section(cfg, section, &block)
42
- cfg.sub!(/(show environment #{section}.*?-{10,}\n)(.*?)(?=\nshow environment|\z)/m) do
43
- header = ::Regexp.last_match(1)
44
- content = ::Regexp.last_match(2)
45
- block.call(content) if block_given?
46
- header + content
47
- end
40
+ def with_section(cfg, section, &block)
41
+ cfg.sub!(/(show environment #{section}.*?-{10,}\n)(.*?)(?=\nshow environment|\z)/m) do
42
+ header = ::Regexp.last_match(1)
43
+ content = ::Regexp.last_match(2)
44
+ block.call(content) if block_given?
45
+ header + content
48
46
  end
47
+ end
49
48
 
49
+ cmd 'show environment' do |cfg|
50
50
  with_section(cfg, 'fan') do |content|
51
51
  content.gsub!(/^((?:\S+ +){3})(slow |normal|medium|fast |max |N\/A ) (.*?)\d+ +$/, '\\1<speed> \\3<rpm>')
52
52
  end
53
53
 
54
54
  with_section(cfg, 'power-consumption') do |content|
55
55
  content.gsub!(/^(.*?) (?:\d+\.\d+ +)+\d+\.\d+$/, '\\1 <power hidden>')
56
+ content.gsub!(/^(Total Power Consumption +)\d+\.\d+$/, '\\1<power hidden>')
56
57
  end
57
58
 
58
59
  with_section(cfg, 'power-allocation') do |content|
@@ -73,7 +74,10 @@ class Aoscx < Oxidized::Model
73
74
  comment cfg
74
75
  end
75
76
 
76
- cmd 'show system | exclude "Up Time" | exclude "CPU" | exclude "Memory" | exclude "Pkts .x" | exclude "Lowest" | exclude "Missed"' do |cfg|
77
+ cmd 'show system' do |cfg|
78
+ cfg = cfg.reject_lines [
79
+ "Up Time", "CPU", "Memory", /Pkts .x/, "Lowest", "Missed"
80
+ ]
77
81
  comment cfg
78
82
  end
79
83
 
@@ -5,9 +5,9 @@ class Cumulus < Oxidized::Model
5
5
  # ^ : match begin of line, to have the most specific prompt
6
6
  # [\w.-]+@[\w.-]+ : user@hostname
7
7
  # (:mgmt)? : optional when logged in out of band
8
- # :~[#$] $ : end of prompt, containing the linux path,
9
- # which is always "~" in our context
10
- prompt /^[\w.-]+@[\w.-]+(:mgmt)?:~[#$] $/
8
+ # :?~[#$] ?$ : end of prompt, containing the linux path,
9
+ # which is always "~" in our context.
10
+ prompt /^[\w.-]+@[\w.-]+(:mgmt)?:?~[#$] ?$/
11
11
  clean :escape_codes
12
12
  comment '# '
13
13
 
@@ -8,6 +8,7 @@ class DlinkNextGen < Oxidized::Model
8
8
  comment '# '
9
9
 
10
10
  cmd :all do |cfg|
11
+ cfg.gsub!("\0", "") # Remove NULL bytes that cause Git to detect the file as binary
11
12
  cfg.each_line.to_a[2..-2].map { |line| line.delete("\r").rstrip }.join("\n") + "\n"
12
13
  end
13
14
 
@@ -103,7 +103,7 @@ class FortiGate < Oxidized::Model
103
103
  cfg = cfg.keep_lines [
104
104
  /^Interface \w/,
105
105
  "Vendor Name",
106
- "Part No./",
106
+ "Part No.",
107
107
  "Serial No."
108
108
  ]
109
109
  cfg = cfg.reject_lines ["Transceiver is not detected"]
@@ -0,0 +1,19 @@
1
+ class GrandstreamHT8xx < Oxidized::Model
2
+ using Refinements
3
+
4
+ # Anchored prompt to avoid matching XML content
5
+ prompt /^(GS|CONFIG)>\s?$/
6
+ comment '# '
7
+
8
+ cfg :ssh do
9
+ # After login go to configuration submenu (looks like enabled in other devices)
10
+ post_login 'config'
11
+ # When logout use double exit - first from configuration submenu, and second to disconnect from device
12
+ pre_logout 'exit'
13
+ pre_logout 'exit'
14
+ end
15
+
16
+ cmd 'export' do |cfg|
17
+ cfg.cut_both
18
+ end
19
+ end
@@ -112,6 +112,8 @@ class IOS < Oxidized::Model
112
112
  comments << "CPU:#{slave} #{cpu}#{cpuxtra}#{slaveslot}"
113
113
  end
114
114
 
115
+ comments << line.chomp if line.start_with?('Motherboard')
116
+
115
117
  comments << "Image: #{Regexp.last_match(1)}" if line =~ /^System image file is "([^"]*)"$/
116
118
  end
117
119
  comments << "\n"
@@ -44,8 +44,8 @@ class JunOS < Oxidized::Model
44
44
 
45
45
  cmd('show chassis hardware') { |cfg| comment cfg }
46
46
  cmd('show system license') do |cfg|
47
- cfg.gsub!(/ fib-scale\s+(\d+)/, ' fib-scale <count>')
48
- cfg.gsub!(/ rib-scale\s+(\d+)/, ' rib-scale <count>')
47
+ cfg.gsub!(/ fib[-\s]scale\s+(\d+)/i, ' fib-scale <count>')
48
+ cfg.gsub!(/ rib[-\s]scale\s+(\d+)/i, ' rib-scale <count>')
49
49
  comment cfg
50
50
  end
51
51
  cmd('show system license keys') { |cfg| comment cfg }
@@ -1,8 +1,9 @@
1
1
  class LinuxGeneric < Oxidized::Model
2
2
  using Refinements
3
3
 
4
- prompt /^(\w.*|\W.*)[:#$] /
4
+ prompt /^\S.*[#$] $/
5
5
  comment '# '
6
+ clean :escape_codes
6
7
 
7
8
  # add a comment in the final conf
8
9
  def add_comment(comment)
@@ -53,7 +54,7 @@ class LinuxGeneric < Oxidized::Model
53
54
  end
54
55
 
55
56
  cfg :telnet do
56
- username /^Username:/
57
+ username /(Username|[Ll]ogin):/
57
58
  password /^Password:/
58
59
  end
59
60
 
@@ -63,6 +64,7 @@ class LinuxGeneric < Oxidized::Model
63
64
  cmd "sudo su -", /^\[sudo\] password/
64
65
  cmd @node.auth[:password]
65
66
  elsif vars(:enable)
67
+ # This will only work without localisation (de: "Passwort:", fr: "Mot de passe :"...)
66
68
  cmd "su -", /^Password:/
67
69
  cmd vars(:enable)
68
70
  end
@@ -10,7 +10,10 @@ class NXOS < Oxidized::Model
10
10
 
11
11
  cmd :secret do |cfg|
12
12
  cfg.gsub! /^(snmp-server community).*/, '\\1 <secret hidden>'
13
- cfg.gsub! /^(snmp-server user (\S+) (\S+) auth (\S+)) (\S+) (priv) (\S+)/, '\\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
+ )
14
17
  cfg.gsub! /^(snmp-server host.*? )\S+( udp-port \d+)?$/, '\\1<secret hidden>\\2'
15
18
  cfg.gsub! /^(snmp-server mib community-map) \S+ ?(.*)/, '\\1 <secret hidden> \\2'
16
19
  cfg.gsub! /(password \d+) (\S+)/, '\\1 <secret hidden>'
@@ -29,6 +29,10 @@ class RouterOS < Oxidized::Model
29
29
  comment cfg
30
30
  end
31
31
 
32
+ cmd :significant_changes do |cfg|
33
+ cfg.gsub(/^(#\s+installed-version: [^\n]+\n).*?^(?=# software id)/m, '\1')
34
+ end
35
+
32
36
  post do
33
37
  logger.debug "Running /export for routeros version #{@ros_version}"
34
38
  run_cmd = if vars(:remove_secret)
@@ -48,19 +48,17 @@ class TPLink < Oxidized::Model
48
48
  lines[0..lines.index("end\n")].join
49
49
  end
50
50
 
51
+ macro :enable, regex: /^[pP]assword:/
52
+
51
53
  cfg :telnet, :ssh do
52
54
  username /^User ?[nN]ame:/
53
55
  password /^\r?Password:/
56
+ newline "\r\n"
54
57
  end
55
58
 
56
59
  cfg :telnet, :ssh do
57
60
  post_login do
58
- if vars(:enable) == true
59
- cmd "enable"
60
- elsif vars(:enable)
61
- cmd "enable", /^[pP]assword:/
62
- cmd vars(:enable)
63
- end
61
+ cmd 'terminal length 0'
64
62
  end
65
63
 
66
64
  pre_logout do