oxidized 0.35.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.
- checksums.yaml +4 -4
- data/.coderabbit.yaml +21 -0
- data/.github/workflows/publishdocker.yml +11 -9
- data/.github/workflows/ruby.yml +1 -3
- data/.rubocop.yml +16 -2
- data/.rubocop_todo.yml +21 -2
- data/CHANGELOG.md +76 -3
- data/README.md +2 -3
- data/Rakefile +1 -1
- data/docs/Configuration.md +40 -2
- data/docs/Creating-Models.md +129 -14
- data/docs/Docker.md +2 -1
- data/docs/Hooks.md +92 -67
- data/docs/Inputs.md +44 -12
- data/docs/Model-Notes/APC.md +72 -0
- data/docs/Model-Notes/ExaLink.md +43 -0
- data/docs/Model-Notes/Fortinet.md +75 -0
- data/docs/Model-Notes/GrandstreamHT8xx.md +8 -0
- data/docs/Model-Notes/IvantiConnectSecure.md +59 -0
- data/docs/Model-Notes/RouterOS.md +13 -0
- data/docs/Model-Notes/TrueNAS.md +23 -0
- data/docs/ModelUnitTests.md +23 -0
- data/docs/Outputs.md +18 -4
- data/docs/Release.md +7 -2
- data/docs/Ruby-API.md +86 -5
- data/docs/Supported-OS-Types.md +21 -9
- data/docs/Troubleshooting.md +1 -1
- data/extra/device2yaml.rb +2 -3
- data/extra/hooks/modelrules.rb +55 -0
- data/extra/hooks/modelrulesadvanced.rb +167 -0
- data/extra/hooks/srcipmap.rb +54 -0
- data/lib/oxidized/cli/support.rb +152 -0
- data/lib/oxidized/cli.rb +9 -0
- data/lib/oxidized/hook/githubrepo.rb +2 -1
- data/lib/oxidized/hook.rb +58 -8
- data/lib/oxidized/input/debugtext.rb +40 -0
- data/lib/oxidized/input/debugyaml.rb +82 -0
- data/lib/oxidized/input/exec.rb +1 -10
- data/lib/oxidized/input/ftp.rb +0 -17
- data/lib/oxidized/input/http.rb +39 -21
- data/lib/oxidized/input/input.rb +33 -13
- data/lib/oxidized/input/scp.rb +10 -64
- data/lib/oxidized/input/ssh.rb +36 -79
- data/lib/oxidized/input/sshbase.rb +102 -0
- data/lib/oxidized/input/telnet.rb +12 -13
- data/lib/oxidized/input/tftp.rb +7 -7
- data/lib/oxidized/model/aoscx.rb +18 -12
- data/lib/oxidized/model/aosw.rb +10 -11
- data/lib/oxidized/model/apc_aos.rb +4 -0
- data/lib/oxidized/model/apcaos.rb +39 -0
- data/lib/oxidized/model/arubainstant.rb +11 -20
- data/lib/oxidized/model/asa.rb +7 -7
- data/lib/oxidized/model/comware.rb +3 -1
- data/lib/oxidized/model/cumulus.rb +3 -3
- data/lib/oxidized/model/defacto.rb +26 -0
- data/lib/oxidized/model/dlinknextgen.rb +1 -0
- data/lib/oxidized/model/dslcommands.rb +93 -0
- data/lib/oxidized/model/dslsetup.rb +102 -0
- data/lib/oxidized/model/efos.rb +5 -5
- data/lib/oxidized/model/exalink.rb +36 -0
- data/lib/oxidized/model/fastiron.rb +2 -2
- data/lib/oxidized/model/firelinuxos.rb +1 -3
- data/lib/oxidized/model/fortigate.rb +160 -0
- data/lib/oxidized/model/fortios.rb +28 -69
- data/lib/oxidized/model/fsos.rb +1 -3
- data/lib/oxidized/model/grandstreamht8xx.rb +19 -0
- data/lib/oxidized/model/h3c.rb +1 -1
- data/lib/oxidized/model/ios.rb +23 -15
- data/lib/oxidized/model/ironware.rb +5 -3
- data/lib/oxidized/model/ivanti.rb +54 -0
- data/lib/oxidized/model/junos.rb +2 -2
- data/lib/oxidized/model/linuxgeneric.rb +4 -2
- data/lib/oxidized/model/macros.rb +60 -0
- data/lib/oxidized/model/mlnxos.rb +11 -7
- data/lib/oxidized/model/model.rb +28 -126
- data/lib/oxidized/model/ndms.rb +6 -0
- data/lib/oxidized/model/netgear.rb +5 -3
- data/lib/oxidized/model/nxos.rb +6 -3
- data/lib/oxidized/model/outputs.rb +5 -0
- data/lib/oxidized/model/perle.rb +14 -8
- data/lib/oxidized/model/routeros.rb +4 -0
- data/lib/oxidized/model/smartbyte.rb +48 -0
- data/lib/oxidized/model/tplink.rb +4 -6
- data/lib/oxidized/model/truenas.rb +63 -3
- data/lib/oxidized/model/voss.rb +3 -0
- data/lib/oxidized/model/vyos.rb +4 -1
- data/lib/oxidized/node.rb +25 -23
- data/lib/oxidized/nodes.rb +2 -0
- data/lib/oxidized/output/file.rb +7 -1
- data/lib/oxidized/output/git.rb +11 -1
- data/lib/oxidized/output/gitcrypt.rb +1 -1
- data/lib/oxidized/output/http.rb +12 -3
- data/lib/oxidized/source/csv.rb +5 -0
- data/lib/oxidized/source/jsonfile.rb +5 -0
- data/lib/oxidized/source/sql.rb +5 -0
- data/lib/oxidized/version.rb +2 -2
- data/lib/oxidized/worker.rb +36 -15
- data/lib/refinements.rb +18 -0
- data/oxidized.gemspec +28 -24
- metadata +103 -55
- data/docs/Model-Notes/APC_AOS.md +0 -65
- data/docs/Model-Notes/FortiOS.md +0 -44
data/lib/oxidized/model/h3c.rb
CHANGED
data/lib/oxidized/model/ios.rb
CHANGED
|
@@ -54,6 +54,13 @@ class IOS < Oxidized::Model
|
|
|
54
54
|
cfg
|
|
55
55
|
end
|
|
56
56
|
|
|
57
|
+
cmd :significant_changes do |cfg|
|
|
58
|
+
cfg.reject_lines [
|
|
59
|
+
/^! (Last|No) configuration change (at|since)/,
|
|
60
|
+
'! NVRAM config last updated at'
|
|
61
|
+
]
|
|
62
|
+
end
|
|
63
|
+
|
|
57
64
|
cmd 'show version' do |cfg|
|
|
58
65
|
comments = []
|
|
59
66
|
comments << cfg.lines.first
|
|
@@ -105,6 +112,8 @@ class IOS < Oxidized::Model
|
|
|
105
112
|
comments << "CPU:#{slave} #{cpu}#{cpuxtra}#{slaveslot}"
|
|
106
113
|
end
|
|
107
114
|
|
|
115
|
+
comments << line.chomp if line.start_with?('Motherboard')
|
|
116
|
+
|
|
108
117
|
comments << "Image: #{Regexp.last_match(1)}" if line =~ /^System image file is "([^"]*)"$/
|
|
109
118
|
end
|
|
110
119
|
comments << "\n"
|
|
@@ -126,12 +135,17 @@ class IOS < Oxidized::Model
|
|
|
126
135
|
cmd_line = 'show running-config'
|
|
127
136
|
cmd_line += ' view full' if vars(:ios_rbac)
|
|
128
137
|
cmd cmd_line do |cfg|
|
|
129
|
-
cfg = cfg.
|
|
130
|
-
cfg = cfg.
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
138
|
+
cfg = cfg.cut_head(3)
|
|
139
|
+
cfg = cfg.reject_lines [
|
|
140
|
+
/^ntp clock-period /,
|
|
141
|
+
/^Current configuration : \S+/
|
|
142
|
+
]
|
|
143
|
+
unless vars("output_store_mode") == "on_significant"
|
|
144
|
+
cfg = cfg.reject_lines [
|
|
145
|
+
# Only store the line "configuration change" when a user is specified
|
|
146
|
+
/^! (Last|No) configuration change (at|since)(?!.*\d+ by \S+$)/
|
|
147
|
+
]
|
|
148
|
+
end
|
|
135
149
|
cfg.gsub! /^ tunnel mpls traffic-eng bandwidth[^\n]*\n*(
|
|
136
150
|
(?: [^\n]*\n*)*
|
|
137
151
|
tunnel mpls traffic-eng auto-bw)/mx, '\1'
|
|
@@ -147,17 +161,11 @@ class IOS < Oxidized::Model
|
|
|
147
161
|
end
|
|
148
162
|
|
|
149
163
|
cfg :telnet, :ssh do
|
|
150
|
-
# preferred way to handle additional passwords
|
|
151
|
-
post_login do
|
|
152
|
-
if vars(:enable) == true
|
|
153
|
-
cmd "enable"
|
|
154
|
-
elsif vars(:enable)
|
|
155
|
-
cmd "enable", /^[pP]assword:/
|
|
156
|
-
cmd vars(:enable)
|
|
157
|
-
end
|
|
158
|
-
end
|
|
159
164
|
post_login 'terminal length 0'
|
|
160
165
|
post_login 'terminal width 0'
|
|
161
166
|
pre_logout 'exit'
|
|
162
167
|
end
|
|
168
|
+
|
|
169
|
+
# preferred way to handle additional passwords (enable)
|
|
170
|
+
macro :enable
|
|
163
171
|
end
|
|
@@ -22,9 +22,11 @@ class IronWare < Oxidized::Model
|
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
cmd 'show version' do |cfg|
|
|
25
|
-
cfg.
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
cfg = cfg.reject_lines [
|
|
26
|
+
/(^((.*)[Ss]ystem uptime(.*))$)/,
|
|
27
|
+
/(^((.*)[Tt]he system started at(.*))$)/,
|
|
28
|
+
/[Uu]p\s?[Tt]ime is .*/
|
|
29
|
+
]
|
|
28
30
|
|
|
29
31
|
comment cfg
|
|
30
32
|
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'json'
|
|
4
|
+
|
|
5
|
+
class Ivanti < Oxidized::Model
|
|
6
|
+
BINARY_CONFIG_PATH = '/api/v1/system/binary-configuration'
|
|
7
|
+
REALM_AUTH_PATH = '/api/v1/realm_auth'
|
|
8
|
+
DEFAULT_REALM = 'Users'
|
|
9
|
+
|
|
10
|
+
cmd BINARY_CONFIG_PATH do |b64|
|
|
11
|
+
b64.to_s.lines.map(&:strip).join
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
cfg :http do
|
|
15
|
+
@secure = true
|
|
16
|
+
@port = 443
|
|
17
|
+
|
|
18
|
+
@username = @node.auth[:username]
|
|
19
|
+
@password = @node.auth[:password]
|
|
20
|
+
|
|
21
|
+
realm = vars(:realm) || DEFAULT_REALM
|
|
22
|
+
payload = { realm: realm }.to_json
|
|
23
|
+
|
|
24
|
+
response_body = post_http(
|
|
25
|
+
REALM_AUTH_PATH,
|
|
26
|
+
payload,
|
|
27
|
+
'Content-Type' => 'application/json',
|
|
28
|
+
'Authorization' => basic_auth_header
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
begin
|
|
32
|
+
login_data = JSON.parse(response_body)
|
|
33
|
+
rescue JSON::ParserError => e
|
|
34
|
+
logger.error(
|
|
35
|
+
"Failed to parse realm_auth response: #{e.class}: #{e.message}, body=#{response_body.inspect}"
|
|
36
|
+
)
|
|
37
|
+
raise Oxidized::OxidizedError, 'Ivanti: realm_auth returned invalid JSON'
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
api_key = login_data['api_key']
|
|
41
|
+
|
|
42
|
+
if api_key.nil? || api_key.empty?
|
|
43
|
+
logger.error(
|
|
44
|
+
"Failed to obtain api_key from realm_auth, response=#{response_body.inspect}"
|
|
45
|
+
)
|
|
46
|
+
raise Oxidized::OxidizedError, 'Ivanti: realm_auth did not return valid api_key'
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
@username = api_key
|
|
50
|
+
@password = ''
|
|
51
|
+
|
|
52
|
+
logger.debug "Obtained api_key #{api_key[0, 4]}... (len=#{api_key.length})"
|
|
53
|
+
end
|
|
54
|
+
end
|
data/lib/oxidized/model/junos.rb
CHANGED
|
@@ -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
|
|
48
|
-
cfg.gsub!(/ rib
|
|
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
|
|
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
|
|
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
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
module Oxidized
|
|
2
|
+
class Model
|
|
3
|
+
module Macros
|
|
4
|
+
using Refinements
|
|
5
|
+
VERBS = %i[
|
|
6
|
+
macro
|
|
7
|
+
clean
|
|
8
|
+
].freeze
|
|
9
|
+
|
|
10
|
+
VERBS.each do |verb|
|
|
11
|
+
define_method(verb) do |name, *args, **kwargs, &block|
|
|
12
|
+
send("#{verb}_#{name}", *args, **kwargs, &block)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
def macro_enable(regex: /password/i, inputs: %i[telnet ssh], command: "enable")
|
|
19
|
+
inputs = [inputs].flatten.map(&:to_sym)
|
|
20
|
+
cfg(*inputs) do
|
|
21
|
+
post_login do
|
|
22
|
+
if vars(:enable) == true
|
|
23
|
+
cmd command
|
|
24
|
+
elsif vars(:enable)
|
|
25
|
+
cmd command, regex
|
|
26
|
+
cmd vars(:enable)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def clean_escape_codes
|
|
33
|
+
ansi_escape_regex = /
|
|
34
|
+
\r? # Optional carriage return at start
|
|
35
|
+
\e # ESC character - starts escape sequence
|
|
36
|
+
(?: # Non-capturing group for different sequence types:
|
|
37
|
+
# Type 1: CSI (Control Sequence Introducer)
|
|
38
|
+
\[ # Literal '[' - starts CSI sequence
|
|
39
|
+
[0-?]* # Parameter bytes: digits (0-9), semicolon, colon, etc.
|
|
40
|
+
[ -\/]* # Intermediate bytes: space through slash characters
|
|
41
|
+
[@-~] # Final byte: determines the actual command
|
|
42
|
+
| # OR
|
|
43
|
+
# Type 2: Simple escape
|
|
44
|
+
[=>] # Single character commands after ESC
|
|
45
|
+
)
|
|
46
|
+
\r? # Optional carriage return at end
|
|
47
|
+
/x
|
|
48
|
+
expect ansi_escape_regex do |data, re|
|
|
49
|
+
data.gsub re, ''
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def clean_cut(head: 1, tail: 1)
|
|
54
|
+
cmd :all do |cfg|
|
|
55
|
+
cfg.cut_both(head, tail)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -15,10 +15,6 @@ class MLNXOS < Oxidized::Model
|
|
|
15
15
|
|
|
16
16
|
cmd :all do |cfg|
|
|
17
17
|
cfg.gsub! /.\x08/, '' # Remove Backspace char
|
|
18
|
-
cfg.gsub! /^CPU load averages:\s.+/, '' # Omit constantly changing CPU info
|
|
19
|
-
cfg.gsub! /^System memory:\s.+/, '' # Omit constantly changing memory info
|
|
20
|
-
cfg.gsub! /^Uptime:\s.+/, '' # Omit constantly changing uptime info
|
|
21
|
-
cfg.gsub! /.+Generated at\s\d+.+/, '' # Omit constantly changing generation time info
|
|
22
18
|
cfg.lines.to_a[2..-3].join
|
|
23
19
|
end
|
|
24
20
|
|
|
@@ -29,17 +25,25 @@ class MLNXOS < Oxidized::Model
|
|
|
29
25
|
end
|
|
30
26
|
|
|
31
27
|
cmd 'show version' do |cfg|
|
|
32
|
-
|
|
28
|
+
cfg = cfg.reject_lines [
|
|
29
|
+
/^CPU load averages:\s.+/, # Omit constantly changing CPU info
|
|
30
|
+
/^System memory:\s.+/, # Omit constantly changing memory info
|
|
31
|
+
/^Uptime:\s.+/ # Omit constantly changing uptime info
|
|
32
|
+
]
|
|
33
|
+
comment cfg + "\n"
|
|
33
34
|
end
|
|
34
35
|
|
|
35
36
|
cmd 'show inventory' do |cfg|
|
|
36
|
-
comment cfg
|
|
37
|
+
comment cfg + "\n"
|
|
37
38
|
end
|
|
38
39
|
|
|
39
40
|
cmd 'enable'
|
|
40
41
|
|
|
41
42
|
cmd 'show running-config' do |cfg|
|
|
42
|
-
cfg
|
|
43
|
+
cfg.reject_lines [
|
|
44
|
+
# Omit constantly changing generation time info
|
|
45
|
+
/.+Generated at\s\d+.+/
|
|
46
|
+
]
|
|
43
47
|
end
|
|
44
48
|
|
|
45
49
|
cfg :ssh do
|
data/lib/oxidized/model/model.rb
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
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
|
|
@@ -7,6 +10,11 @@ module Oxidized
|
|
|
7
10
|
|
|
8
11
|
using Refinements
|
|
9
12
|
|
|
13
|
+
# Domain Specific Language for models
|
|
14
|
+
extend Oxidized::Model::DSLSetup
|
|
15
|
+
extend Oxidized::Model::DSLCommands
|
|
16
|
+
extend Oxidized::Model::Macros
|
|
17
|
+
|
|
10
18
|
include Oxidized::Config::Vars
|
|
11
19
|
|
|
12
20
|
# rubocop:disable Style/FormatStringToken
|
|
@@ -25,6 +33,8 @@ module Oxidized
|
|
|
25
33
|
klass.instance_variable_set '@comment', nil
|
|
26
34
|
klass.instance_variable_set '@prompt', nil
|
|
27
35
|
klass.instance_variable_set '@metadata', {}
|
|
36
|
+
klass.instance_variable_set '@inputs', nil
|
|
37
|
+
|
|
28
38
|
else # we're subclassing some existing model, take its variables
|
|
29
39
|
instance_variables.each do |var|
|
|
30
40
|
iv = instance_variable_get(var)
|
|
@@ -33,136 +43,20 @@ module Oxidized
|
|
|
33
43
|
end
|
|
34
44
|
end
|
|
35
45
|
end
|
|
36
|
-
|
|
37
|
-
def comment(str = "# ")
|
|
38
|
-
@comment = if block_given?
|
|
39
|
-
yield
|
|
40
|
-
elsif not @comment
|
|
41
|
-
str
|
|
42
|
-
else
|
|
43
|
-
@comment
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
def prompt(regex = nil)
|
|
48
|
-
@prompt = regex || @prompt
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
def cfg(*methods, **args, &block)
|
|
52
|
-
[methods].flatten.each do |method|
|
|
53
|
-
process_args_block(@cfg[method.to_s], args, block)
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
def cfgs
|
|
58
|
-
@cfg
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
def cmd(cmd_arg = nil, **args, &block)
|
|
62
|
-
if cmd_arg.instance_of?(Symbol)
|
|
63
|
-
process_args_block(@cmd[cmd_arg], args, block)
|
|
64
|
-
else
|
|
65
|
-
# Normal command
|
|
66
|
-
process_args_block(@cmd[:cmd], args,
|
|
67
|
-
{ cmd: cmd_arg, args: args, block: block })
|
|
68
|
-
end
|
|
69
|
-
logger.debug "Added #{cmd_arg} to the commands list"
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
def metadata(position, value = nil, &block)
|
|
73
|
-
return unless %i[top bottom].include? position
|
|
74
|
-
|
|
75
|
-
if block_given?
|
|
76
|
-
@metadata[position] = block
|
|
77
|
-
else
|
|
78
|
-
@metadata[position] = value
|
|
79
|
-
end
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
def cmds
|
|
83
|
-
@cmd
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
def expect(regex, **args, &block)
|
|
87
|
-
process_args_block(@expect, args, [regex, block])
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
def expects
|
|
91
|
-
@expect
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
def clean(what)
|
|
95
|
-
case what
|
|
96
|
-
when :escape_codes
|
|
97
|
-
ansi_escape_regex = /
|
|
98
|
-
\r? # Optional carriage return at start
|
|
99
|
-
\e # ESC character - starts escape sequence
|
|
100
|
-
(?: # Non-capturing group for different sequence types:
|
|
101
|
-
# Type 1: CSI (Control Sequence Introducer)
|
|
102
|
-
\[ # Literal '[' - starts CSI sequence
|
|
103
|
-
[0-?]* # Parameter bytes: digits (0-9), semicolon, colon, etc.
|
|
104
|
-
[ -\/]* # Intermediate bytes: space through slash characters
|
|
105
|
-
[@-~] # Final byte: determines the actual command
|
|
106
|
-
| # OR
|
|
107
|
-
# Type 2: Simple escape
|
|
108
|
-
[=>] # Single character commands after ESC
|
|
109
|
-
)
|
|
110
|
-
\r? # Optional carriage return at end
|
|
111
|
-
/x
|
|
112
|
-
expect ansi_escape_regex do |data, re|
|
|
113
|
-
data.gsub re, ''
|
|
114
|
-
end
|
|
115
|
-
end
|
|
116
|
-
end
|
|
117
|
-
|
|
118
|
-
# calls the block at the end of the model, prepending the output of the
|
|
119
|
-
# block to the output string
|
|
120
|
-
#
|
|
121
|
-
# @yield expects block which should return [String]
|
|
122
|
-
# @return [void]
|
|
123
|
-
def pre(**args, &block)
|
|
124
|
-
process_args_block(@procs[:pre], args, block)
|
|
125
|
-
end
|
|
126
|
-
|
|
127
|
-
# calls the block at the end of the model, adding the output of the block
|
|
128
|
-
# to the output string
|
|
129
|
-
#
|
|
130
|
-
# @yield expects block which should return [String]
|
|
131
|
-
# @return [void]
|
|
132
|
-
def post(**args, &block)
|
|
133
|
-
process_args_block(@procs[:post], args, block)
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
# @author Saku Ytti <saku@ytti.fi>
|
|
137
|
-
# @since 0.0.39
|
|
138
|
-
# @return [Hash] hash proc procs :pre+:post to be prepended/postfixed to output
|
|
139
|
-
attr_reader :procs
|
|
140
|
-
|
|
141
|
-
private
|
|
142
|
-
|
|
143
|
-
def process_args_block(target, args, block)
|
|
144
|
-
if args[:clear]
|
|
145
|
-
if block.instance_of?(Array)
|
|
146
|
-
target.reject! { |k, _| k == block[0] }
|
|
147
|
-
target.push(block)
|
|
148
|
-
elsif block.instance_of?(Hash)
|
|
149
|
-
target.reject! { |item| item[:cmd] == block[:cmd] }
|
|
150
|
-
target.push(block)
|
|
151
|
-
else
|
|
152
|
-
target.replace([block])
|
|
153
|
-
end
|
|
154
|
-
else
|
|
155
|
-
method = args[:prepend] ? :unshift : :push
|
|
156
|
-
target.send(method, block)
|
|
157
|
-
end
|
|
158
|
-
end
|
|
159
46
|
end
|
|
160
47
|
|
|
161
48
|
attr_accessor :input, :node
|
|
162
49
|
|
|
163
|
-
|
|
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)
|
|
164
53
|
logger.debug "Executing #{string}"
|
|
165
|
-
out = @input.
|
|
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
|
|
166
60
|
return false unless out
|
|
167
61
|
|
|
168
62
|
out = out.b unless Oxidized.config.input.utf8_encoded?
|
|
@@ -245,6 +139,7 @@ module Oxidized
|
|
|
245
139
|
data
|
|
246
140
|
end
|
|
247
141
|
|
|
142
|
+
# Get the commands from the model
|
|
248
143
|
def get
|
|
249
144
|
logger.debug 'Collecting commands\' outputs'
|
|
250
145
|
outputs = Outputs.new
|
|
@@ -255,7 +150,7 @@ module Oxidized
|
|
|
255
150
|
|
|
256
151
|
next if args.include?(:if) && !instance_exec(&args[:if])
|
|
257
152
|
|
|
258
|
-
out = cmd command, &block
|
|
153
|
+
out = cmd command, input: args[:input], &block
|
|
259
154
|
return false unless out
|
|
260
155
|
|
|
261
156
|
outputs << out
|
|
@@ -306,6 +201,13 @@ module Oxidized
|
|
|
306
201
|
@input.class.to_s.match(/Telnet/) || vars(:ssh_no_exec)
|
|
307
202
|
end
|
|
308
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
|
+
|
|
309
211
|
private
|
|
310
212
|
|
|
311
213
|
def process_cmd_output(output, name)
|
data/lib/oxidized/model/ndms.rb
CHANGED
|
@@ -6,7 +6,7 @@ class Netgear < Oxidized::Model
|
|
|
6
6
|
clean :escape_codes
|
|
7
7
|
|
|
8
8
|
# Handle pager for "show version" on old Netgear models: #2394
|
|
9
|
-
expect /^--More-- or \(q\)uit
|
|
9
|
+
expect /^--More--(?: or \(q\)uit)?$/ do |data, re|
|
|
10
10
|
send ' '
|
|
11
11
|
data.sub re, ''
|
|
12
12
|
end
|
|
@@ -20,7 +20,7 @@ class Netgear < Oxidized::Model
|
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
cfg :telnet do
|
|
23
|
-
username /^(User:|Applying Interface configuration, please wait ...)/
|
|
23
|
+
username /^(Username:|User:|Applying Interface configuration, please wait ...)/
|
|
24
24
|
password /^Password:/i
|
|
25
25
|
end
|
|
26
26
|
|
|
@@ -58,9 +58,11 @@ class Netgear < Oxidized::Model
|
|
|
58
58
|
comment cfg
|
|
59
59
|
end
|
|
60
60
|
cmd 'show running-config' do |cfg|
|
|
61
|
-
cfg.gsub! /(System Up Time
|
|
61
|
+
cfg.gsub! /(System Up Time:?\s+).*/, '\\1 <removed>'
|
|
62
62
|
cfg.gsub! /(Current SNTP Synchronized Time:).*/, '\\1 <removed>'
|
|
63
63
|
cfg.gsub! /(Current System Time:).*/, '\\1 <removed>'
|
|
64
|
+
# Remove standalone backspace lines
|
|
65
|
+
cfg.gsub!(/(?:\r?\n)?\x08(?:\r?\n)?/, "\n")
|
|
64
66
|
cfg
|
|
65
67
|
end
|
|
66
68
|
end
|
data/lib/oxidized/model/nxos.rb
CHANGED
|
@@ -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!
|
|
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>'
|
|
@@ -25,8 +28,8 @@ class NXOS < Oxidized::Model
|
|
|
25
28
|
end
|
|
26
29
|
|
|
27
30
|
cmd 'show inventory all' do |cfg|
|
|
28
|
-
if cfg.
|
|
29
|
-
# 'show inventory all' isn't supported on older versions (See
|
|
31
|
+
if cfg.match? /^% Invalid .* at '\^' marker\./
|
|
32
|
+
# 'show inventory all' isn't supported on older versions (See Issues #3657, #3779)
|
|
30
33
|
cfg = cmd 'show inventory'
|
|
31
34
|
end
|
|
32
35
|
comment cfg
|
data/lib/oxidized/model/perle.rb
CHANGED
|
@@ -5,7 +5,8 @@ class Perle < Oxidized::Model
|
|
|
5
5
|
comment '! '
|
|
6
6
|
|
|
7
7
|
cmd :all do |cfg|
|
|
8
|
-
cfg.cut_both
|
|
8
|
+
cfg = cfg.cut_both
|
|
9
|
+
cfg.delete "\r"
|
|
9
10
|
end
|
|
10
11
|
|
|
11
12
|
cmd 'show version verbose' do |cfg|
|
|
@@ -17,17 +18,22 @@ class Perle < Oxidized::Model
|
|
|
17
18
|
end
|
|
18
19
|
|
|
19
20
|
cmd 'show interfaces transceiver' do |cfg|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
comment out.join + "\n"
|
|
21
|
+
cfg = cfg.keep_lines [
|
|
22
|
+
'SFP Information',
|
|
23
|
+
'Vendor Name',
|
|
24
|
+
'Vendor Serial Number'
|
|
25
|
+
]
|
|
26
|
+
comment cfg + "\n"
|
|
27
27
|
end
|
|
28
28
|
|
|
29
29
|
cmd 'show running-config'
|
|
30
30
|
|
|
31
|
+
cmd :significant_changes do |cfg|
|
|
32
|
+
cfg.reject_lines [
|
|
33
|
+
/^tacacs-server key 7 \$0\$\S+==$/
|
|
34
|
+
]
|
|
35
|
+
end
|
|
36
|
+
|
|
31
37
|
cfg :ssh do
|
|
32
38
|
post_login 'terminal length 0'
|
|
33
39
|
pre_logout 'exit'
|
|
@@ -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)
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
class SmartByte < Oxidized::Model
|
|
2
|
+
using Refinements
|
|
3
|
+
|
|
4
|
+
comment '! '
|
|
5
|
+
|
|
6
|
+
cmd :secret do |cfg|
|
|
7
|
+
cfg.gsub!(/group (\S+) v2c/, 'group <hidden> v2c')
|
|
8
|
+
cfg.gsub!(/community (\S+)/, 'community <hidden>')
|
|
9
|
+
cfg
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
cmd :all do |cfg|
|
|
13
|
+
cfg = cfg.delete("\r")
|
|
14
|
+
cfg.cut_tail
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
cmd 'show running-config'
|
|
18
|
+
|
|
19
|
+
cmd 'show version' do |cfg|
|
|
20
|
+
comment cfg
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
cmd 'show interface optical-transceiver info' do |cfg|
|
|
24
|
+
cfg.gsub! /^\|Transceiver current alarm information: \|\s+\+-------------------------------------------------\+.*?\s+\+-------------------------------------------------\+\s+/m, ''
|
|
25
|
+
comment cfg
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
cmd 'show power' do |cfg|
|
|
29
|
+
comment cfg
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
cfg :telnet do
|
|
33
|
+
username /^.*? login:/
|
|
34
|
+
password /^Password:/
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
cfg :telnet, :ssh do
|
|
38
|
+
post_login do
|
|
39
|
+
if vars(:enable)
|
|
40
|
+
cmd "enable", /^[pP]assword:/
|
|
41
|
+
cmd vars(:enable)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
post_login 'terminal length 0'
|
|
46
|
+
pre_logout 'exit'
|
|
47
|
+
end
|
|
48
|
+
end
|