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/asa.rb
CHANGED
|
@@ -32,13 +32,13 @@ class ASA < Oxidized::Model
|
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
cmd 'show version' do |cfg|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
35
|
+
comment cfg.reject_lines [
|
|
36
|
+
# avoid commits due to uptime / ixo-router01 up 2 mins 28 secs / ixo-router01 up 1 days 2 hours
|
|
37
|
+
/(\s+up\s+\d+\s+)|(.*days.*)/,
|
|
38
|
+
/^Configuration has not been modified since last system restart.*/,
|
|
39
|
+
/^Configuration last modified by.*/,
|
|
40
|
+
/^Start-up time.*/
|
|
41
|
+
]
|
|
42
42
|
end
|
|
43
43
|
|
|
44
44
|
cmd 'show inventory' do |cfg|
|
|
@@ -21,8 +21,10 @@ class Comware < Oxidized::Model
|
|
|
21
21
|
|
|
22
22
|
cmd :secret do |cfg|
|
|
23
23
|
cfg.gsub! /^( snmp-agent community).*/, '\\1 <configuration removed>'
|
|
24
|
-
cfg.gsub!
|
|
24
|
+
cfg.gsub! /(password hash).*/, '\\1 <configuration removed>'
|
|
25
25
|
cfg.gsub! /^( password cipher).*/, '\\1 <configuration removed>'
|
|
26
|
+
cfg.gsub! /(key (authentication )?cipher) \S+/, '\\1 <configuration removed>'
|
|
27
|
+
cfg.gsub! /(cipher authentication-mode (md5|sha)).\S+ (privacy-mode (des56|3des|aes\d{0,3})) .\S+/, '\\1 <auth-pass> \\3 <priv-pass>'
|
|
26
28
|
cfg
|
|
27
29
|
end
|
|
28
30
|
|
|
@@ -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
|
-
#
|
|
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
|
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
class Defacto < Oxidized::Model
|
|
2
|
+
prompt /^(\r*[\w.:@()\/_-]+[#>]\s?)$/
|
|
3
|
+
comment '! '
|
|
4
|
+
|
|
5
|
+
clean :cut
|
|
6
|
+
|
|
7
|
+
post do
|
|
8
|
+
cmd "show running-config" do |cfg|
|
|
9
|
+
process_config cfg
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
cfg :telnet do
|
|
14
|
+
username /^(user ?name|login|user)/i
|
|
15
|
+
password /^password/i
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
cfg :telnet, :ssh do
|
|
19
|
+
post_login 'terminal length 0'
|
|
20
|
+
post_login 'terminal width 0'
|
|
21
|
+
pre_logout 'exit'
|
|
22
|
+
pre_logout 'logout'
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def process_config(cfg) = cfg
|
|
26
|
+
end
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
module Oxidized
|
|
2
|
+
class Model
|
|
3
|
+
# Domain Specific Language for model commands
|
|
4
|
+
module DSLCommands
|
|
5
|
+
# Store a command to be run against the device
|
|
6
|
+
# cmd_arg can be:
|
|
7
|
+
# - a string (the command to be run)
|
|
8
|
+
# - a symbol:
|
|
9
|
+
# - :all - run the block against each command output
|
|
10
|
+
# - :secret - run the block against each command output when
|
|
11
|
+
# vars :remove_secret is true
|
|
12
|
+
# - :significant_changes - use the block to remove unsignificant
|
|
13
|
+
# changes
|
|
14
|
+
# Optional arguments (**args):
|
|
15
|
+
# - clear: true
|
|
16
|
+
# replace all the stored blocks for this command (monkey patching)
|
|
17
|
+
# - prepend: true
|
|
18
|
+
# prepend the block to the stored blocks for this command (monkey
|
|
19
|
+
# patching)
|
|
20
|
+
# - if: lambda
|
|
21
|
+
# run the command only if the lambda evaluates to true
|
|
22
|
+
# - input: symbol or array of symbols
|
|
23
|
+
# for the inputs this command is to run against (default - run
|
|
24
|
+
# every command)
|
|
25
|
+
def cmd(cmd_arg = nil, **args, &block)
|
|
26
|
+
if cmd_arg.instance_of?(Symbol)
|
|
27
|
+
process_args_block(@cmd[cmd_arg], args, block)
|
|
28
|
+
else
|
|
29
|
+
return unless valid_cmd_args?(cmd_arg, args)
|
|
30
|
+
|
|
31
|
+
# Always use an array for :input
|
|
32
|
+
args[:input] = Array(args[:input]) if args.include?(:input)
|
|
33
|
+
process_args_block(@cmd[:cmd], args,
|
|
34
|
+
{ cmd: cmd_arg, args: args, block: block })
|
|
35
|
+
end
|
|
36
|
+
logger.debug "Added #{cmd_arg} to the commands list"
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def cmds
|
|
40
|
+
@cmd
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# calls the block at the end of the model, prepending the output of the
|
|
44
|
+
# block to the output string
|
|
45
|
+
def pre(**args, &block)
|
|
46
|
+
process_args_block(@procs[:pre], args, block)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# calls the block at the end of the model, adding the output of the block
|
|
50
|
+
# to the output string
|
|
51
|
+
def post(**args, &block)
|
|
52
|
+
process_args_block(@procs[:post], args, block)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# @procs is a hash of procs (:pre+:post) to be prepended/postfixed to
|
|
56
|
+
# output
|
|
57
|
+
attr_reader :procs
|
|
58
|
+
|
|
59
|
+
private
|
|
60
|
+
|
|
61
|
+
def process_args_block(target, args, block)
|
|
62
|
+
if args[:clear]
|
|
63
|
+
if block.instance_of?(Array)
|
|
64
|
+
target.reject! { |k, _| k == block[0] }
|
|
65
|
+
target.push(block)
|
|
66
|
+
elsif block.instance_of?(Hash)
|
|
67
|
+
target.reject! { |item| item[:cmd] == block[:cmd] }
|
|
68
|
+
target.push(block)
|
|
69
|
+
else
|
|
70
|
+
target.replace([block])
|
|
71
|
+
end
|
|
72
|
+
else
|
|
73
|
+
method = args[:prepend] ? :unshift : :push
|
|
74
|
+
target.send(method, block)
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def valid_cmd_args?(cmd_arg, args)
|
|
79
|
+
if args.include?(:if) && !(args[:if].is_a?(Proc) && args[:if].lambda?)
|
|
80
|
+
logger.error "cmd #{cmd_arg.dump}: if must be a lambda"
|
|
81
|
+
return false
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
if args.include?(:input) && ![Symbol, Array].include?(args[:input].class)
|
|
85
|
+
logger.error "cmd #{cmd_arg.dump}: input must be a symbol or an array of symbols"
|
|
86
|
+
return false
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
true
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
module Oxidized
|
|
2
|
+
class Model
|
|
3
|
+
# Domain Specific Language for model setup
|
|
4
|
+
module DSLSetup
|
|
5
|
+
def prompt(regex = nil)
|
|
6
|
+
@prompt = regex || @prompt
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def comment(str = "# ")
|
|
10
|
+
@comment = if block_given?
|
|
11
|
+
yield
|
|
12
|
+
elsif not @comment
|
|
13
|
+
str
|
|
14
|
+
else
|
|
15
|
+
@comment
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def expect(regex, **args, &block)
|
|
20
|
+
process_args_block(@expect, args, [regex, block])
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def expects
|
|
24
|
+
@expect
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def cfg(*methods, **args, &block)
|
|
28
|
+
[methods].flatten.each do |method|
|
|
29
|
+
process_args_block(@cfg[method.to_s], args, block)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def cfgs
|
|
34
|
+
@cfg
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Define multiple inputs as a sequence of equivalent options
|
|
38
|
+
# Example: use ssh or telnet, then scp or ftp:
|
|
39
|
+
# [:ssh, [:scp, :ftp]]
|
|
40
|
+
def inputs(list = nil)
|
|
41
|
+
return @inputs if list.nil?
|
|
42
|
+
|
|
43
|
+
validate_inputs(list)
|
|
44
|
+
@inputs = list
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Returns the input sequence for the model as an array of arrays of input
|
|
48
|
+
# classes, filtered and ordered according to the provided +input_classes+
|
|
49
|
+
# (as specified in the oxidized configuration file).
|
|
50
|
+
def input_sequence(input_classes)
|
|
51
|
+
model_inputs = inputs || [
|
|
52
|
+
@cfg.filter_map do |input, block_list|
|
|
53
|
+
input.to_sym unless block_list.empty?
|
|
54
|
+
end
|
|
55
|
+
]
|
|
56
|
+
|
|
57
|
+
model_inputs.map do |sequence|
|
|
58
|
+
sequence = [sequence] unless sequence.is_a? Array
|
|
59
|
+
selected = input_classes.select { |input| sequence.include?(input.to_sym) }
|
|
60
|
+
logger.error "Needs one of #{sequence.inspect} to be configured" if selected.empty?
|
|
61
|
+
|
|
62
|
+
selected
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def metadata(position, value = nil, &block)
|
|
67
|
+
return unless %i[top bottom].include? position
|
|
68
|
+
|
|
69
|
+
if block_given?
|
|
70
|
+
@metadata[position] = block
|
|
71
|
+
else
|
|
72
|
+
@metadata[position] = value
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
private
|
|
77
|
+
|
|
78
|
+
def validate_inputs(list)
|
|
79
|
+
message = "inputs must be an array containing symbols or " \
|
|
80
|
+
"arrays of symbols"
|
|
81
|
+
|
|
82
|
+
raise ArgumentError, message unless list.is_a? Array
|
|
83
|
+
raise ArgumentError, message if list.empty?
|
|
84
|
+
|
|
85
|
+
list.each do |group|
|
|
86
|
+
case group
|
|
87
|
+
when Symbol
|
|
88
|
+
# Everything is fine
|
|
89
|
+
when Array
|
|
90
|
+
raise ArgumentError, message if group.empty?
|
|
91
|
+
|
|
92
|
+
group.each do |input|
|
|
93
|
+
raise ArgumentError, message unless input.is_a? Symbol
|
|
94
|
+
end
|
|
95
|
+
else
|
|
96
|
+
raise ArgumentError, message
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
data/lib/oxidized/model/efos.rb
CHANGED
|
@@ -19,11 +19,11 @@ class EFOS < Oxidized::Model
|
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
cmd 'show running-config' do |cfg|
|
|
22
|
-
cfg.
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
22
|
+
cfg.reject_lines [
|
|
23
|
+
'System Up Time',
|
|
24
|
+
'Current System Time:',
|
|
25
|
+
'Current SNTP Synchronized Time:'
|
|
26
|
+
]
|
|
27
27
|
end
|
|
28
28
|
|
|
29
29
|
cfg :telnet, :ssh do
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
class Exalink < Oxidized::Model
|
|
2
|
+
using Refinements
|
|
3
|
+
|
|
4
|
+
prompt /^([\w.@()-]+[#>]\s?)$/
|
|
5
|
+
comment '! '
|
|
6
|
+
|
|
7
|
+
cmd :all do |cfg|
|
|
8
|
+
cfg.gsub! /\r\n?/, "\n"
|
|
9
|
+
cfg.cut_both
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
cmd 'show version' do |cfg|
|
|
13
|
+
comment cfg.reject_lines /uptime/i
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
cmd 'show port' do |cfg|
|
|
17
|
+
comment cfg
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
cmd 'show running-config' do |cfg|
|
|
21
|
+
cfg.gsub! /^(show run.*)$/, '! \1'
|
|
22
|
+
cfg.gsub! /^!Time:[^\n]*\n/, ''
|
|
23
|
+
cfg
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
cfg :telnet do
|
|
27
|
+
username /^login:/
|
|
28
|
+
password /^Password:/
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
cfg :ssh, :telnet do
|
|
32
|
+
post_login 'terminal length 0'
|
|
33
|
+
post_login 'terminal width 0'
|
|
34
|
+
pre_logout 'logout'
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
class FastIron < Oxidized::Model
|
|
2
2
|
using Refinements
|
|
3
3
|
|
|
4
|
-
prompt /^([\w
|
|
4
|
+
prompt /^([\w.@\/()-]+[#>]\s?)$/
|
|
5
5
|
comment '! '
|
|
6
6
|
|
|
7
7
|
cmd :all do |cfg|
|
|
@@ -43,7 +43,7 @@ class FastIron < Oxidized::Model
|
|
|
43
43
|
comment cfg
|
|
44
44
|
end
|
|
45
45
|
|
|
46
|
-
cmd 'show stack' do |cfg|
|
|
46
|
+
cmd 'show stack | exclude T=' do |cfg|
|
|
47
47
|
comment cfg
|
|
48
48
|
end
|
|
49
49
|
|
|
@@ -31,9 +31,7 @@ class FireLinuxOS < Oxidized::Model
|
|
|
31
31
|
end
|
|
32
32
|
|
|
33
33
|
cmd 'show version system' do |cfg|
|
|
34
|
-
|
|
35
|
-
cfg = cfg.join
|
|
36
|
-
comment cfg
|
|
34
|
+
comment cfg.reject_lines [/(\s+up\s+\d+\s+)|(.*days.*)/]
|
|
37
35
|
end
|
|
38
36
|
|
|
39
37
|
cmd 'show inventory' do |cfg|
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
class FortiGate < Oxidized::Model
|
|
2
|
+
using Refinements
|
|
3
|
+
|
|
4
|
+
comment '# '
|
|
5
|
+
|
|
6
|
+
prompt /^(\(\w\) )?([-\w.~]+(\s[(\w\-.)]+)?~?\s?[#>$]\s?)$/
|
|
7
|
+
|
|
8
|
+
# When a post-login-banner is enabled, you have to press "a" to log in
|
|
9
|
+
expect /^\(Press\s'a'\sto\saccept\):/ do |data, re|
|
|
10
|
+
send 'a'
|
|
11
|
+
data.sub re, ''
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
expect /^--More--\s$/ do |data, re|
|
|
15
|
+
send ' '
|
|
16
|
+
data.sub re, ''
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
cmd :all do |cfg|
|
|
20
|
+
# Remove junk after --More-- pager
|
|
21
|
+
cfg = cfg.gsub(/\r +\r/, '')
|
|
22
|
+
# Remove \r\n after command echo
|
|
23
|
+
cfg = cfg.gsub("\r\n", "\n")
|
|
24
|
+
# remove command echo and prompt
|
|
25
|
+
cfg.cut_both
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
cmd :secret do |cfg|
|
|
29
|
+
# Remove private key for encrypted configs
|
|
30
|
+
cfg.gsub! /^(\#private-encryption-key=).+/, '\\1 <configuration removed>'
|
|
31
|
+
# ENC indicates an encrypted password, and secret indicates a secret string
|
|
32
|
+
cfg.gsub! /(set .+ ENC) .+/, '\\1 <configuration removed>'
|
|
33
|
+
cfg.gsub! /(set .*secret) .+/, '\\1 <configuration removed>'
|
|
34
|
+
# A number of other statements also contains sensitive strings
|
|
35
|
+
cfg.gsub! /(set (?:passwd|password|key|group-password|auth-password-l1|auth-password-l2|rsso|history0|history1)) .+/, '\\1 <configuration removed>'
|
|
36
|
+
cfg.gsub! /(set md5-key [0-9]+) .+/, '\\1 <configuration removed>'
|
|
37
|
+
cfg.gsub! /(set private-key ).*?-+END (ENCRYPTED|RSA|OPENSSH) PRIVATE KEY-+\n?"$/m, '\\1<configuration removed>'
|
|
38
|
+
cfg.gsub! /(set privatekey ).*?-+END (ENCRYPTED|RSA|OPENSSH) PRIVATE KEY-+\n?"$/m, '\\1<configuration removed>'
|
|
39
|
+
cfg.gsub! /(set ca )"-+BEGIN.*?-+END CERTIFICATE-+"$/m, '\\1<configuration removed>'
|
|
40
|
+
cfg.gsub! /(set csr ).*?-+END CERTIFICATE REQUEST-+"$/m, '\\1<configuration removed>'
|
|
41
|
+
cfg
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
cmd 'get system status' do |cfg|
|
|
45
|
+
@vdom_enabled = cfg.match(/^Virtual domain configuration: (enable|multiple)/)
|
|
46
|
+
@ha_cluster = cfg.match(/^Current HA mode: a-/) # a-p or a-a
|
|
47
|
+
cfg = cfg.keep_lines [
|
|
48
|
+
"Version: ",
|
|
49
|
+
"Security Level: ",
|
|
50
|
+
"Serial-Number: ",
|
|
51
|
+
"BIOS version: ",
|
|
52
|
+
"System Part-Number: ",
|
|
53
|
+
"Hostname: ",
|
|
54
|
+
"Operation Mode: ",
|
|
55
|
+
"Current virtual domain: ",
|
|
56
|
+
"Max number of virtual domains: ",
|
|
57
|
+
"Virtual domains status:",
|
|
58
|
+
"Virtual domain configuration: ",
|
|
59
|
+
"FIPS-CC mode: ",
|
|
60
|
+
"Current HA mode: ",
|
|
61
|
+
"Private Encryption: ",
|
|
62
|
+
# Lines in FortiGate-VM64
|
|
63
|
+
"License Expiration Date: ",
|
|
64
|
+
"License Status: ",
|
|
65
|
+
"VM Resources: "
|
|
66
|
+
]
|
|
67
|
+
comment cfg + "\n"
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
cmd 'config global', if: -> { @vdom_enabled } do |_cfg|
|
|
71
|
+
''
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
cmd 'get system ha status', if: -> { @ha_cluster } do |cfg|
|
|
75
|
+
cfg = cfg.keep_lines [
|
|
76
|
+
"HA Health Status:",
|
|
77
|
+
"Model: ",
|
|
78
|
+
"Mode: ",
|
|
79
|
+
"number of member: ",
|
|
80
|
+
/^(Master|Slave|Primary|Secondary): /
|
|
81
|
+
]
|
|
82
|
+
comment cfg + "\n"
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
cmd 'get hardware status' do |cfg|
|
|
86
|
+
comment cfg
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
cmd "diagnose hardware deviceinfo psu" do |cfg|
|
|
90
|
+
skip_patterns = [
|
|
91
|
+
/Command fail\./, # The device doesn't support this command
|
|
92
|
+
/Power Supply +Status/ # We only get a status, but no serial numbers
|
|
93
|
+
]
|
|
94
|
+
if skip_patterns.any? { |p| cfg.match?(p) }
|
|
95
|
+
logger.debug "No PSU serial numbers available"
|
|
96
|
+
''
|
|
97
|
+
else
|
|
98
|
+
comment cfg
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
cmd "get system interface transceiver" do |cfg|
|
|
103
|
+
cfg = cfg.keep_lines [
|
|
104
|
+
/^Interface \w/,
|
|
105
|
+
"Vendor Name",
|
|
106
|
+
"Part No.",
|
|
107
|
+
"Serial No."
|
|
108
|
+
]
|
|
109
|
+
cfg = cfg.reject_lines ["Transceiver is not detected"]
|
|
110
|
+
comment cfg + "\n"
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
cmd 'diagnose autoupdate version', if: -> { vars(:fortios_autoupdate) || vars(:fortigate_autoupdate) } do |cfg|
|
|
114
|
+
if vars(:fortios_autoupdate)
|
|
115
|
+
logger.warn("The variable fortios_autoupdate is deprecated. Migrate to fortigate_autoupdate")
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
cfg = cfg.sub(/FDS Address\n---------\n.*\n/, '')
|
|
119
|
+
comment cfg.reject_lines ["Last Update", "Result :"]
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
cmd 'end', if: -> { @vdom_enabled } do |_cfg|
|
|
123
|
+
''
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def clean_config(cfg)
|
|
127
|
+
cfg = cfg.reject_lines ['#conf_file_ver=']
|
|
128
|
+
cfg.gsub!(/(set comments "Error \(No order found for account ID \d+\) on).*/,
|
|
129
|
+
'\\1 <stripped>')
|
|
130
|
+
cfg
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# If vars fullconfig is set to true, we get the full config (including default
|
|
134
|
+
# values)
|
|
135
|
+
cmd "show full-configuration | grep .", if: -> { vars(:fullconfig) } do |cfg|
|
|
136
|
+
clean_config cfg
|
|
137
|
+
end
|
|
138
|
+
# else backup as in Fortigate GUI
|
|
139
|
+
cmd "show | grep .", if: -> { !vars(:fullconfig) } do |cfg|
|
|
140
|
+
clean_config cfg
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
cmd :significant_changes do |cfg|
|
|
144
|
+
cfg = cfg.reject_lines [
|
|
145
|
+
/^ +set \S+ ENC \S+$/
|
|
146
|
+
]
|
|
147
|
+
cfg.gsub!(/(config firewall internet-service-name\n).*?(\nend\n)/m, '')
|
|
148
|
+
cfg.gsub!(/set private-key .*?-+END \S+ PRIVATE KEY-+\n?"$/m, '')
|
|
149
|
+
cfg
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
cfg :telnet do
|
|
153
|
+
username /^[lL]ogin:/
|
|
154
|
+
password /^Password:/
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
cfg :telnet, :ssh do
|
|
158
|
+
pre_logout "exit"
|
|
159
|
+
end
|
|
160
|
+
end
|
|
@@ -16,9 +16,13 @@ class FortiOS < Oxidized::Model
|
|
|
16
16
|
data.sub re, ''
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
-
cmd :all do |cfg
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
cmd :all do |cfg|
|
|
20
|
+
# Remove junk after --More-- pager
|
|
21
|
+
cfg = cfg.gsub(/\r +\r/, '')
|
|
22
|
+
# Remove \r\n after command echo
|
|
23
|
+
cfg = cfg.gsub("\r\n", "\n")
|
|
24
|
+
# remove command echo and prompt
|
|
25
|
+
cfg.cut_both
|
|
22
26
|
end
|
|
23
27
|
|
|
24
28
|
cmd :secret do |cfg|
|
|
@@ -38,74 +42,29 @@ class FortiOS < Oxidized::Model
|
|
|
38
42
|
end
|
|
39
43
|
|
|
40
44
|
cmd 'get system status' do |cfg|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
45
|
+
cfg = cfg.reject_lines [
|
|
46
|
+
"Current Time",
|
|
47
|
+
"Disk Usage",
|
|
48
|
+
"Release Version Information",
|
|
49
|
+
"Branch Point",
|
|
50
|
+
"Daylight Time Saving",
|
|
51
|
+
"Time Zone",
|
|
52
|
+
"x86-64 Applications",
|
|
53
|
+
"File System",
|
|
54
|
+
"Image Signature"
|
|
55
|
+
]
|
|
56
|
+
comment cfg + "\n"
|
|
52
57
|
end
|
|
53
58
|
|
|
54
|
-
|
|
55
|
-
cfg =
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
cfg << cmd('get system ha status') do |cfg_ha|
|
|
59
|
-
cfg_ha = cfg_ha.each_line.select { |line| line.match /^(HA Health Status|Mode|Model|Master|Slave|Primary|Secondary|# COMMAND)(\s+)?:/ }.join
|
|
60
|
-
comment cfg_ha
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
cfg << cmd('get hardware status') do |cfg_hw|
|
|
64
|
-
comment cfg_hw
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
# default behaviour: include autoupdate output (backwards compatibility)
|
|
68
|
-
# do not include if variable "show_autoupdate" is set to false
|
|
69
|
-
if defined?(vars(:fortios_autoupdate)).nil? || vars(:fortios_autoupdate)
|
|
70
|
-
cfg << cmd('diagnose autoupdate version') do |cfg_auto|
|
|
71
|
-
cfg_auto.gsub! /(FDS Address\n---------\n).*/, '\\1IP Address removed'
|
|
72
|
-
comment cfg_auto.each_line.reject { |line| line.match /Last Update|Result/ }.join
|
|
73
|
-
end
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
cfg << cmd('end') if @vdom_enabled
|
|
77
|
-
|
|
78
|
-
# Different OS have different commands - we use the first that works
|
|
79
|
-
# - For fortigate > 7 and possibly earlier versions, we use:
|
|
80
|
-
# show | grep . # backup as in fortigate GUI
|
|
81
|
-
# show full-configuration | grep . # bakup including default values
|
|
82
|
-
# | grep is used to avoid the --More-- prompt
|
|
83
|
-
# - It is not documented which systems need the commands without | grep:
|
|
84
|
-
# show full-configuration
|
|
85
|
-
# show
|
|
86
|
-
# Document it here and make a PR on github if you know!
|
|
87
|
-
# By default, we use the configuration without default values
|
|
88
|
-
# If fullconfig: true is set in the configuration, we get the full config
|
|
89
|
-
commandlist = if vars(:fullconfig)
|
|
90
|
-
['show full-configuration | grep .',
|
|
91
|
-
'show full-configuration', 'show']
|
|
92
|
-
else
|
|
93
|
-
['show | grep .',
|
|
94
|
-
'show full-configuration', 'show']
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
commandlist.each do |fullcmd|
|
|
98
|
-
fullcfg = cmd(fullcmd)
|
|
99
|
-
# Don't show for unsupported devices (e.g. FortiAnalyzer, FortiManager, FortiMail)
|
|
100
|
-
next if fullcfg.lines[1..3].join =~ /(Parsing error at|command parse error)/
|
|
101
|
-
|
|
102
|
-
fullcfg.gsub! /(set comments "Error \(No order (found )?for (account )?ID \d+\) on).*/, '\\1 <stripped>"'
|
|
103
|
-
|
|
104
|
-
cfg << fullcfg
|
|
105
|
-
break
|
|
106
|
-
end
|
|
59
|
+
cmd "show" do |cfg|
|
|
60
|
+
cfg.reject_lines ['#config-version=']
|
|
61
|
+
end
|
|
107
62
|
|
|
108
|
-
|
|
63
|
+
cmd :significant_changes do |cfg|
|
|
64
|
+
cfg = cfg.reject_lines [
|
|
65
|
+
/^ +set \S+ ENC \S+$/
|
|
66
|
+
]
|
|
67
|
+
cfg.gsub(/set private-key .*?-+END \S+ PRIVATE KEY-+\n?"$/m, '')
|
|
109
68
|
end
|
|
110
69
|
|
|
111
70
|
cfg :telnet do
|
|
@@ -114,6 +73,6 @@ class FortiOS < Oxidized::Model
|
|
|
114
73
|
end
|
|
115
74
|
|
|
116
75
|
cfg :telnet, :ssh do
|
|
117
|
-
pre_logout "exit
|
|
76
|
+
pre_logout "exit"
|
|
118
77
|
end
|
|
119
78
|
end
|
data/lib/oxidized/model/fsos.rb
CHANGED
|
@@ -22,9 +22,7 @@ class FSOS < Oxidized::Model
|
|
|
22
22
|
|
|
23
23
|
cmd 'show version' do |cfg|
|
|
24
24
|
# Remove uptime so the result doesn't change every time
|
|
25
|
-
cfg.
|
|
26
|
-
cfg.gsub! /.*System uptime.*\n/, ''
|
|
27
|
-
comment cfg
|
|
25
|
+
comment cfg.reject_lines ['uptime is', 'System uptime']
|
|
28
26
|
end
|
|
29
27
|
|
|
30
28
|
cmd 'show running-config' do |cfg|
|
|
@@ -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
|