oxidized 0.31.0 → 0.32.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/.github/workflows/ruby.yml +2 -3
- data/.rubocop.yml +1 -2
- data/.rubocop_todo.yml +6 -6
- data/CHANGELOG.md +32 -0
- data/Dockerfile +5 -2
- data/Rakefile +28 -0
- data/docs/Configuration.md +14 -2
- data/docs/Creating-Models.md +52 -22
- data/docs/DeviceSimulation.md +184 -0
- data/docs/Hooks.md +5 -5
- data/docs/Issues.md +15 -9
- data/docs/Model-Notes/APC_AOS.md +29 -16
- data/docs/Model-Notes/FSOS.md +1 -0
- data/docs/ModelUnitTests.md +186 -0
- data/docs/Supported-OS-Types.md +3 -2
- data/examples/podman-compose/Makefile +1 -2
- data/{examples/device-simulation → extra}/device2yaml.rb +32 -12
- data/extra/gitdiff-msteams.sh +32 -5
- data/extra/nagios_check_failing_nodes.rb +1 -1
- data/extra/rest_client.rb +1 -1
- data/lib/oxidized/config.rb +1 -1
- data/lib/oxidized/input/ssh.rb +13 -5
- data/lib/oxidized/model/aos7.rb +2 -0
- data/lib/oxidized/model/aosw.rb +1 -1
- data/lib/oxidized/model/apc_aos.rb +1 -1
- data/lib/oxidized/model/arubainstant.rb +1 -1
- data/lib/oxidized/model/asa.rb +2 -1
- data/lib/oxidized/model/asyncos.rb +1 -1
- data/lib/oxidized/model/cumulus.rb +16 -2
- data/lib/oxidized/model/enterprise_sonic.rb +46 -0
- data/lib/oxidized/model/fsos.rb +5 -1
- data/lib/oxidized/model/garderos.rb +4 -4
- data/lib/oxidized/model/junos.rb +1 -1
- data/lib/oxidized/model/kornfeldos.rb +33 -0
- data/lib/oxidized/model/model.rb +2 -2
- data/lib/oxidized/model/sonicos.rb +8 -2
- data/lib/oxidized/model/tplink.rb +1 -0
- data/lib/oxidized/model/xos.rb +1 -1
- data/lib/oxidized/source/source.rb +32 -2
- data/lib/oxidized/version.rb +2 -2
- data/oxidized.gemspec +7 -6
- metadata +33 -35
- data/examples/device-simulation/README.md +0 -173
- data/examples/device-simulation/cmdsets/aoscx +0 -9
- data/examples/device-simulation/cmdsets/arubainstant +0 -5
- data/examples/device-simulation/cmdsets/asa +0 -7
- data/examples/device-simulation/cmdsets/ios +0 -7
- data/examples/device-simulation/cmdsets/nxos +0 -5
- data/examples/device-simulation/cmdsets/routeros +0 -5
- data/examples/device-simulation/cmdsets/srosmd +0 -11
- data/examples/device-simulation/yaml/aoscx_R0X25A-6410_FL.10.10.1100.yaml +0 -2281
- data/examples/device-simulation/yaml/aoscx_R8N85A-C6000-48G-CL4_PL.10.08.1010.yaml +0 -451
- data/examples/device-simulation/yaml/arubainstant_IAP515_8.10.0.6_VWLC.yaml +0 -213
- data/examples/device-simulation/yaml/asa_5512_9.12-4-67_single-context.yaml +0 -531
- data/examples/device-simulation/yaml/asr920_16.8.1b.yaml +0 -1122
- data/examples/device-simulation/yaml/garderos_R7709_003_006_068.yaml +0 -101
- data/examples/device-simulation/yaml/iosxe_C9200L-24P-4G_17.09.04a.yaml +0 -514
- data/examples/device-simulation/yaml/iosxe_C9800-L-F-K9_17.06.05.yaml +0 -417
- data/examples/device-simulation/yaml/riverbed_915.yaml +0 -123
- data/examples/device-simulation/yaml/routeros_CHR_7.10.1.yaml +0 -145
- data/examples/device-simulation/yaml/routeros_CHR_7.16.yaml +0 -79
- data/examples/device-simulation/yaml/routeros_L009UiGS_7.15.2.yaml +0 -353
data/docs/Model-Notes/FSOS.md
CHANGED
|
@@ -7,6 +7,7 @@ This has been tested against the following models and OS versions
|
|
|
7
7
|
|S3400-48T4SP |Version 2.0.2J Build 81736 |
|
|
8
8
|
|S3400-48T4SP |Version 2.0.2J Build 95262 |
|
|
9
9
|
|S3400-48T6SP |Version 2.2.0F Build 109661 |
|
|
10
|
+
|S3400-48T4SP |Version 2.0.2J Build 120538 |
|
|
10
11
|
|S3410-24TS-P |S3410_FSOS 11.4(1)B74S5 |
|
|
11
12
|
|S5850-48T4Q |Version 7.0.4.34 |
|
|
12
13
|
|S5800-48MBQ |Version 7.0.4.21 |
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
# Model Unit Tests
|
|
2
|
+
Oxidized includes automated unit tests for its models, which require very little
|
|
3
|
+
effort to use. There are three different default unit tests for models:
|
|
4
|
+
- [Device Simulation](ModelUnitTests.md#device-simulation)
|
|
5
|
+
- [Device Prompt](ModelUnitTests.md#device-prompt)
|
|
6
|
+
- [Secrets](ModelUnitTests.md#secrets)
|
|
7
|
+
|
|
8
|
+
You only need to provide test files under [/spec/model/data](/spec/model/data),
|
|
9
|
+
and the tests will be run automatically with `rake test`. See
|
|
10
|
+
[CONTRIBUTING.md](/CONTRIBUTING.md) for explanations on how to set up a
|
|
11
|
+
development environment. In the following examples, we use
|
|
12
|
+
[Bundler](https://bundler.io/) and prefix all commands with `bundle exec`.
|
|
13
|
+
|
|
14
|
+
In addition, you can write [custom unit tests](ModelUnitTests.md#custom-tests)
|
|
15
|
+
for your model
|
|
16
|
+
|
|
17
|
+
## Device Simulation
|
|
18
|
+
### YAML Simulation File
|
|
19
|
+
You need a [YAML simulation file](/docs/DeviceSimulation.md) for your device.
|
|
20
|
+
See the link for instructions on how to produce it.
|
|
21
|
+
|
|
22
|
+
The YAML simulation files are stored under
|
|
23
|
+
[/spec/model/data/](/spec/model/data/), with the naming convention
|
|
24
|
+
`<model>:<description>:simulation.yaml`, where `<model>` is the lowercase name
|
|
25
|
+
of the Oxidized model and `<description>` is the name of the test case.
|
|
26
|
+
`<description>` is generally formatted as `<hardware>_<software>` or
|
|
27
|
+
`<hardware>_<software>_<information>`.
|
|
28
|
+
|
|
29
|
+
Using a correct name for the file is important to ensure it is included in
|
|
30
|
+
automatic model unit tests.
|
|
31
|
+
|
|
32
|
+
### Expected Output
|
|
33
|
+
You need a second file that contains the expected output, which has the same
|
|
34
|
+
name as the YAML simulation file but ends with `:output.txt` instead of
|
|
35
|
+
`:simulation.yaml`.
|
|
36
|
+
|
|
37
|
+
You can automatically produce an output file based on the current model for all
|
|
38
|
+
YAML simulation files missing an `:output.txt`:
|
|
39
|
+
```shell
|
|
40
|
+
bundle exec ruby spec/model/atoms_generate.rb
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
In the following example,
|
|
44
|
+
`spec/model/data/aoscx:R8N85A-C6000-48G-CL4_PL.10.08.1010:output.txt` (the
|
|
45
|
+
second file in the list) was missing:
|
|
46
|
+
|
|
47
|
+
```shell
|
|
48
|
+
oxidized$ bundle exec ruby spec/model/atoms_generate.rb
|
|
49
|
+
Run options: --seed 57811
|
|
50
|
+
|
|
51
|
+
# Running:
|
|
52
|
+
|
|
53
|
+
Generating output file for aoscx:R0X25A-6410_FL.10.10.1100:simulation... SKIP, output already exists
|
|
54
|
+
Generating output file for aoscx:R8N85A-C6000-48G-CL4_PL.10.08.1010:simulation... OK
|
|
55
|
+
Generating output file for arubainstant:IAP515_8.10.0.6_VWLC:simulation... SKIP, output already exists
|
|
56
|
+
Generating output file for asa:5512_9.12-4-67_single-context:simulation... SKIP, output already exists
|
|
57
|
+
Generating output file for garderos:R7709_003_006_068:simulation... SKIP, output already exists
|
|
58
|
+
Generating output file for ios:C8200L_16.12.1:simulation... FAIL, no simulation file
|
|
59
|
+
Generating output file for ios:C9200L-24P-4G_17.09.04a:simulation... SKIP, output already exists
|
|
60
|
+
Generating output file for ios:C9800-L-F-K9_17.06.05:simulation... SKIP, output already exists
|
|
61
|
+
Generating output file for ios:asr920_16.8.1b:simulation... SKIP, output already exists
|
|
62
|
+
Generating output file for junos:srx300_22.4:simulation... SKIP, output already exists
|
|
63
|
+
Generating output file for opnsense:nano_23.7:simulation... SKIP, output already exists
|
|
64
|
+
Generating output file for pfsense:CE_2.7.2:simulation... SKIP, output already exists
|
|
65
|
+
Generating output file for routeros:CHR_7.10.1:simulation... SKIP, output already exists
|
|
66
|
+
Generating output file for routeros:CHR_7.16:simulation... SKIP, output already exists
|
|
67
|
+
Generating output file for routeros:L009UiGS_7.15.2:simulation... SKIP, output already exists
|
|
68
|
+
.
|
|
69
|
+
|
|
70
|
+
Finished in 0.904792s, 1.1052 runs/s, 0.0000 assertions/s.
|
|
71
|
+
|
|
72
|
+
1 runs, 0 assertions, 0 failures, 0 errors, 0 skips
|
|
73
|
+
Coverage report generated for RSpec to /home/xxx/oxidized/coverage/coverage.xml. 651 / 1122 LOC (58.02%) covered
|
|
74
|
+
Coverage report generated for RSpec to /home/xxx/oxidized/coverage.
|
|
75
|
+
Line Coverage: 58.02% (651 / 1122)
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Running the Tests
|
|
79
|
+
You can modify the `:output.txt` file to match your expectations and modify the
|
|
80
|
+
model accordingly. Run `bundle exec rake` to run the tests.
|
|
81
|
+
|
|
82
|
+
Here is an example when the output of the VTP command is missing in the expected
|
|
83
|
+
output:
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
oxidized$ bundle exec rake test
|
|
87
|
+
/usr/bin/ruby3.1 -I"lib:spec" /home/xxx/oxidized/vendor/bundle/ruby/3.1.0/gems/rake-13.2.1/lib/rake/rake_test_loader.rb "spec/cli_spec.rb" "spec/config_spec.rb" "spec/hook/githubrepo_spec.rb" "spec/input/ssh_spec.rb" "spec/manager_spec.rb" "spec/model/apc_aos_spec.rb" "spec/model/model_atoms_spec.rb" "spec/model/model_helper_spec.rb" "spec/node_spec.rb" "spec/nodes_spec.rb" "spec/output/file_spec.rb" "spec/output/git_spec.rb" "spec/refinements_spec.rb" "spec/source/csv_spec.rb" "spec/source/http_spec.rb" "spec/source/jsonfile_spec.rb" "spec/source/sql_spec.rb"
|
|
88
|
+
Run options: --seed 31447
|
|
89
|
+
|
|
90
|
+
# Running:
|
|
91
|
+
|
|
92
|
+
...............................................................SS..................F.............................SS..
|
|
93
|
+
|
|
94
|
+
Finished in 7.963602s, 14.6918 runs/s, 48.7217 assertions/s.
|
|
95
|
+
|
|
96
|
+
1) Failure:
|
|
97
|
+
ATOMS tests#test_0006_ios:C9200L-24P-4G_17.09.04a:output has expected output [spec/model/model_atoms_spec.rb:12]:
|
|
98
|
+
--- expected
|
|
99
|
+
+++ actual
|
|
100
|
+
@@ -9,6 +9,21 @@
|
|
101
|
+
! CPU: ARM64
|
|
102
|
+
! Memory: nvram 2048K
|
|
103
|
+
!
|
|
104
|
+
+! VTP: VTP Version capable : 1 to 3
|
|
105
|
+
+! VTP: VTP version running : 1
|
|
106
|
+
+! VTP: VTP Domain Name : Oxidized
|
|
107
|
+
+! VTP: VTP Pruning Mode : Disabled (Operationally Disabled)
|
|
108
|
+
+! VTP: VTP Traps Generation : Disabled
|
|
109
|
+
+! VTP: Device ID : 40f0.7800.0000
|
|
110
|
+
+! VTP: Feature VLAN:
|
|
111
|
+
+! VTP: --------------
|
|
112
|
+
+! VTP: VTP Operating Mode : Transparent
|
|
113
|
+
+! VTP: Maximum VLANs supported locally : 1005
|
|
114
|
+
+! VTP: Number of existing VLANs : 10
|
|
115
|
+
+! VTP: Configuration Revision : 0
|
|
116
|
+
+! VTP: MD5 digest : 0x35 0x00 0x00 0x00 0x00 0x00 0x7F 0xB4
|
|
117
|
+
+! VTP: 0x07 0x00 0x00 0x00 0x00 0x00 0x09 0x6D
|
|
118
|
+
+!
|
|
119
|
+
! NAME: \"c92xxL Stack\", DESCR: \"c92xxL Stack\"
|
|
120
|
+
! PID: C9200L-24P-4G , VID: V01 , SN: JAE24FFFFFF
|
|
121
|
+
!
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
117 runs, 388 assertions, 1 failures, 0 errors, 4 skips
|
|
125
|
+
|
|
126
|
+
You have skipped tests. Run with --verbose for details.
|
|
127
|
+
Coverage report generated for RSpec to /home/xxx/oxidized/coverage/coverage.xml. 2167 / 3131 LOC (69.21%) covered
|
|
128
|
+
Coverage report generated for RSpec to /home/xxx/oxidized/coverage.
|
|
129
|
+
Line Coverage: 69.21% (2167 / 3131)
|
|
130
|
+
rake aborted!
|
|
131
|
+
Command failed with status (1): [ruby -I"lib:spec" /home/xxx/oxidized/vendor/bundle/ruby/3.1.0/gems/rake-13.2.1/lib/rake/rake_test_loader.rb "spec/cli_spec.rb" "spec/config_spec.rb" "spec/hook/githubrepo_spec.rb" "spec/input/ssh_spec.rb" "spec/manager_spec.rb" "spec/model/apc_aos_spec.rb" "spec/model/model_atoms_spec.rb" "spec/model/model_helper_spec.rb" "spec/node_spec.rb" "spec/nodes_spec.rb" "spec/output/file_spec.rb" "spec/output/git_spec.rb" "spec/refinements_spec.rb" "spec/source/csv_spec.rb" "spec/source/http_spec.rb" "spec/source/jsonfile_spec.rb" "spec/source/sql_spec.rb" ]
|
|
132
|
+
/home/xxx/oxidized/vendor/bundle/ruby/3.1.0/gems/rake-13.2.1/exe/rake:27:in `<top (required)>'
|
|
133
|
+
Tasks: TOP => test
|
|
134
|
+
(See full trace by running task with --trace)
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
If you want to be sure that your model has been tested, run
|
|
138
|
+
`bundle exec rake test TESTOPTS="--verbose"` and search for your models unter
|
|
139
|
+
`ATOMS tests`
|
|
140
|
+
|
|
141
|
+
## Device Prompt
|
|
142
|
+
You can specify device prompts to test in a YAML file named
|
|
143
|
+
`spec/model/data/<model>:generic:prompt.yaml`.
|
|
144
|
+
|
|
145
|
+
The YAML file has three sections containing a list of prompts to test:
|
|
146
|
+
- pass: these prompts will pass the prompt regexp.
|
|
147
|
+
- pass_with_expect: these prompts will pass the prompt regexp after having been
|
|
148
|
+
cleaned by the expect commands.
|
|
149
|
+
- fail: these prompts will fail the prompt regexp.
|
|
150
|
+
|
|
151
|
+
Here is an example:
|
|
152
|
+
```yaml
|
|
153
|
+
pass:
|
|
154
|
+
- "LAB-R1234_Garderos# "
|
|
155
|
+
pass_with_expect:
|
|
156
|
+
- "\e[4m\rLAB-R1234_Garderos#\e[m "
|
|
157
|
+
fail:
|
|
158
|
+
- "\e[4m\rLAB-R1234_Garderos#\e[m "
|
|
159
|
+
- "#LAB#"
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## Secrets
|
|
163
|
+
You can test if the model effectively removes secrets from your YAML simulation
|
|
164
|
+
file with a YAML file named like the YAML simulation, but with the suffix
|
|
165
|
+
`:secret.yaml`.
|
|
166
|
+
|
|
167
|
+
The YAML file has two sections containing a list of strings to test:
|
|
168
|
+
- fail: the test will fail if the output contains these strings.
|
|
169
|
+
- pass: the test will pass only if the output contains these strings.
|
|
170
|
+
|
|
171
|
+
```yaml
|
|
172
|
+
fail:
|
|
173
|
+
- 'AAAAAAAAAABBBBBBBBBBCCCCCCCCCC'
|
|
174
|
+
pass:
|
|
175
|
+
- 'snmp-server host 10.10.42.12 version 2c <secret removed> inform'
|
|
176
|
+
- 'hash-mgmt-user oxidized password hash <secret removed>'
|
|
177
|
+
- 'hash-mgmt-user rocks password hash <secret removed> usertype read-only'
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
## Custom tests
|
|
181
|
+
When you write custom tests for your models, please do not use the filenames
|
|
182
|
+
mentioned above, as it will interfere with the standard tests. If you need to
|
|
183
|
+
store a custom simulation file, use `model:description:custom_simulation.yaml`.
|
|
184
|
+
|
|
185
|
+
The [cumulus test](/spec/model/cumulus_spec.rb) is an example of a custom
|
|
186
|
+
test.
|
data/docs/Supported-OS-Types.md
CHANGED
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
|AddPack |AddPack |[addpack](/lib/oxidized/model/addpack.rb)
|
|
9
9
|
|Adtran |Total Access (AOS) |[adtran](/lib/oxidized/model/adtran.rb)
|
|
10
10
|
| |ADVA |[adva](/lib/oxidized/model/adva.rb) | |[ADVA](Model-Notes/ADVA.md)
|
|
11
|
-
|Alcatel-Lucent |AOS |[aos](/lib/oxidized/model/aos.rb)
|
|
12
|
-
| |AOS7 |[aos7](/lib/oxidized/model/aos7.rb)
|
|
11
|
+
|Alcatel-Lucent |AOS |[aos](/lib/oxidized/model/aos.rb) | |AOS6 - vxworks-based
|
|
12
|
+
| |AOS7 |[aos7](/lib/oxidized/model/aos7.rb) | |AOS7 and AOS8 - linux-based
|
|
13
13
|
| |ISAM |[isam](/lib/oxidized/model/isam.rb)
|
|
14
14
|
| |SR OS (Formerly TiMOS) |[sros](/lib/oxidized/model/sros.rb)
|
|
15
15
|
| |Wireless |[aosw](/lib/oxidized/model/aosw.rb) | |Same model as Aruba Wireless
|
|
@@ -175,6 +175,7 @@
|
|
|
175
175
|
| |NSX Distributed Firewall |[nsxdfw](/lib/oxidized/model/nsxdfw.rb)
|
|
176
176
|
|Watchguard |Fireware OS |[firewareos](/lib/oxidized/model/firewareos.rb)
|
|
177
177
|
|Westell |Westell 8178G, Westell 8266G |[weos](/lib/oxidized/model/weos.rb)
|
|
178
|
+
|Yadro |KornfeldOS |[kornfeldos](/lib/oxidized/model/kornfeldos.rb)
|
|
178
179
|
|YAMAHA |YAMAHA NVR/RTX Series |[yamaha](/lib/oxidized/model/yamaha.rb)
|
|
179
180
|
|Zhone |Zhone (OLT and MX) |[zhoneolt](/lib/oxidized/model/zhoneolt.rb)
|
|
180
181
|
|ZPE |Nodegrid OS |[nodegrid](/lib/oxidized/model/nodegrid.rb)
|
|
@@ -71,8 +71,7 @@ images: model-image gitserver-image oxidized-image
|
|
|
71
71
|
|
|
72
72
|
# build the oxidized image from the curent repository
|
|
73
73
|
oxidized-image:
|
|
74
|
-
|
|
75
|
-
podman build -t local/oxidized ../../
|
|
74
|
+
podman build -t oxidized:`git describe --tags` -t oxidized:latest ../../
|
|
76
75
|
|
|
77
76
|
# removes the oxidized image
|
|
78
77
|
oxidized-image-clean:
|
|
@@ -8,6 +8,7 @@ require 'timeout'
|
|
|
8
8
|
|
|
9
9
|
# This scripts logs in a network device and outputs a yaml file that can be
|
|
10
10
|
# used for model unit tests in spec/model/
|
|
11
|
+
# For more information, see docs/DeviceSimulation.md
|
|
11
12
|
|
|
12
13
|
# This script is quick & dirty - it grew with the time an could be a project
|
|
13
14
|
# for its own. It works, and that should be enough ;-)
|
|
@@ -113,15 +114,29 @@ end
|
|
|
113
114
|
# Define options
|
|
114
115
|
options = {}
|
|
115
116
|
optparse = OptionParser.new do |opts|
|
|
116
|
-
opts.banner =
|
|
117
|
+
opts.banner = <<~HEREDOC
|
|
118
|
+
Usages:
|
|
119
|
+
- device2yaml.rb [user@]host -i file [options]
|
|
120
|
+
- device2yaml.rb [user@]host -c "command1
|
|
121
|
+
command2
|
|
122
|
+
command3" [options]
|
|
117
123
|
|
|
118
|
-
|
|
119
|
-
|
|
124
|
+
-i and -c are mutualy exclusive, one must be specified
|
|
125
|
+
|
|
126
|
+
[options]:
|
|
127
|
+
HEREDOC
|
|
128
|
+
|
|
129
|
+
opts.on('-c', '--commands "command list"', 'specify the commands to be run') do |cmds|
|
|
130
|
+
options[:commands] = cmds
|
|
131
|
+
end
|
|
132
|
+
opts.on('-i', '--input file', 'Specify an input file for commands to be run') do |file|
|
|
133
|
+
options[:input] = file
|
|
120
134
|
end
|
|
121
135
|
opts.on('-o', '--output file', 'Specify an output YAML-file') do |file|
|
|
122
136
|
options[:output] = file
|
|
123
137
|
end
|
|
124
|
-
opts.on('-t', '--timeout value', Integer,
|
|
138
|
+
opts.on('-t', '--timeout value', Integer,
|
|
139
|
+
'Specify the idle timeout beween commands (default: 5 seconds)') do |timeout|
|
|
125
140
|
options[:timeout] = timeout
|
|
126
141
|
end
|
|
127
142
|
opts.on('-e', '--exec-mode', 'Run ssh in exec mode (without tty)') { @exec_mode = true }
|
|
@@ -151,14 +166,22 @@ end
|
|
|
151
166
|
optparse.parse!
|
|
152
167
|
|
|
153
168
|
# Get the commands to be run against ssh_host
|
|
154
|
-
|
|
155
|
-
|
|
169
|
+
# ^ = xor = exclusive or
|
|
170
|
+
unless options[:commands].nil? ^ options[:input].nil?
|
|
171
|
+
puts "Please provide commands to be run against #{ssh_host} with either option -c or -i"
|
|
156
172
|
puts
|
|
157
173
|
puts optparse
|
|
158
174
|
exit 1
|
|
159
175
|
end
|
|
160
|
-
|
|
161
|
-
|
|
176
|
+
|
|
177
|
+
if options[:commands]
|
|
178
|
+
ssh_commands = []
|
|
179
|
+
options[:commands].each_line(chomp: true) { |command| ssh_commands << command }
|
|
180
|
+
elsif options[:input]
|
|
181
|
+
ssh_commands = File.read(options[:input]).split(/\n+|\r+/)
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
puts "Running #{ssh_commands} on #{ssh_user}@#{ssh_host}"
|
|
162
185
|
|
|
163
186
|
# Defaut idle timeout: 5 seconds, as tests showed that 2 seconds is too short
|
|
164
187
|
@idle_timeout = options[:timeout] || 5
|
|
@@ -209,7 +232,7 @@ else
|
|
|
209
232
|
yaml_output ' '
|
|
210
233
|
end
|
|
211
234
|
|
|
212
|
-
@output&.puts
|
|
235
|
+
@output&.puts 'commands:'
|
|
213
236
|
|
|
214
237
|
begin
|
|
215
238
|
ssh_commands.each do |cmd|
|
|
@@ -219,7 +242,4 @@ rescue Errno::ECONNRESET, Net::SSH::Disconnect, IOError => e
|
|
|
219
242
|
puts "### Connection closed with message: #{e.message}"
|
|
220
243
|
end
|
|
221
244
|
|
|
222
|
-
@output&.puts 'oxidized_output: |'
|
|
223
|
-
@output&.puts ' !! needs to be written by hand or copy & paste from model output'
|
|
224
|
-
|
|
225
245
|
cleanup
|
data/extra/gitdiff-msteams.sh
CHANGED
|
@@ -15,12 +15,31 @@
|
|
|
15
15
|
# timeout: 120
|
|
16
16
|
#
|
|
17
17
|
# Add webhook to your MS Teams channel and set the next variable to the full url
|
|
18
|
+
# If INCLUDE_GITHUB_LINK is set to true, there will be a button that links to GITURL in the bottom of each teams post. the commit id is added at the end of the url.
|
|
19
|
+
# MAXSIZE is set to respect the 28 KB limit for teams webhooks, but you might need to change it if you modify the Adaptive Card
|
|
18
20
|
|
|
19
21
|
weburl="https://contoso.webhook.office.com/webhookb2/etc etc etc"
|
|
22
|
+
GITURL="https://github.example.com/My-org/oxidized/commit/"
|
|
23
|
+
INCLUDE_GITHUB_LINK=false
|
|
24
|
+
# Max size for summary text.
|
|
25
|
+
MAXSIZE=24500
|
|
26
|
+
|
|
27
|
+
if [ "$INCLUDE_GITHUB_LINK" = true ]; then
|
|
28
|
+
github_action=",
|
|
29
|
+
{ \"type\": \"ActionSet\",
|
|
30
|
+
\"actions\":
|
|
31
|
+
[
|
|
32
|
+
{
|
|
33
|
+
\"type\": \"Action.OpenUrl\",
|
|
34
|
+
\"title\": \"Click to see diff in github\",
|
|
35
|
+
\"url\": \"${GITURL}${OX_REPO_COMMITREF}\"
|
|
36
|
+
}
|
|
37
|
+
]
|
|
38
|
+
}"
|
|
39
|
+
fi
|
|
20
40
|
|
|
21
41
|
postdata()
|
|
22
42
|
{
|
|
23
|
-
COMMIT=$(git --bare --git-dir="${OX_REPO_NAME}" show --pretty='' --no-color "${OX_REPO_COMMITREF}" | jq --raw-input --slurp --compact-output)
|
|
24
43
|
cat <<EOF
|
|
25
44
|
{
|
|
26
45
|
"type":"message",
|
|
@@ -77,7 +96,7 @@ postdata()
|
|
|
77
96
|
"size": "small"
|
|
78
97
|
}
|
|
79
98
|
]
|
|
80
|
-
}
|
|
99
|
+
}${github_action}
|
|
81
100
|
]
|
|
82
101
|
}
|
|
83
102
|
}
|
|
@@ -86,6 +105,14 @@ postdata()
|
|
|
86
105
|
EOF
|
|
87
106
|
}
|
|
88
107
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
108
|
+
COMMIT=$(git --bare --git-dir="${OX_REPO_NAME}" show --pretty='' --no-color "${OX_REPO_COMMITREF}" | jq --raw-input --slurp --compact-output)
|
|
109
|
+
URL=""
|
|
110
|
+
|
|
111
|
+
size=$(postdata | wc -c)
|
|
112
|
+
if [ "$size" -gt "$MAXSIZE" ]; then
|
|
113
|
+
COMMIT=$(git --bare --git-dir="${OX_REPO_NAME}" show --pretty='' --no-color "${OX_REPO_COMMITREF}" | head -c $MAXSIZE)
|
|
114
|
+
COMMIT+="$NEWLINE...$NEWLINE Shortened because of length"
|
|
115
|
+
COMMIT=$(echo "${COMMIT}" | jq --raw-input --slurp --compact-output )
|
|
116
|
+
fi
|
|
117
|
+
|
|
118
|
+
curl -i -H "Content-Type: application/json" -X POST --data "$(postdata)" "${weburl}"
|
|
@@ -10,7 +10,7 @@ pending = false
|
|
|
10
10
|
critical_nodes = []
|
|
11
11
|
pending_nodes = []
|
|
12
12
|
|
|
13
|
-
json = JSON.parse(
|
|
13
|
+
json = JSON.parse(URI("http://localhost:8888/nodes.json").open(&:read))
|
|
14
14
|
json.each do |node|
|
|
15
15
|
next if !ARGV.empty? && (ARGV[0] != node['name'])
|
|
16
16
|
|
data/extra/rest_client.rb
CHANGED
|
@@ -6,7 +6,7 @@ module Oxidized
|
|
|
6
6
|
require 'asetus'
|
|
7
7
|
|
|
8
8
|
class Config
|
|
9
|
-
Root =
|
|
9
|
+
Root = ENV['OXIDIZED_HOME'] || File.join(Dir.home, '.config', 'oxidized')
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
CFGS = Asetus.new name: 'oxidized', load: false, key_to_s: true
|
data/lib/oxidized/config.rb
CHANGED
|
@@ -19,7 +19,7 @@ module Oxidized
|
|
|
19
19
|
cfgfile = cmd_opts[:config_file] || 'config'
|
|
20
20
|
# configuration file with full path as a class instance variable
|
|
21
21
|
@configfile = File.join(usrdir, cfgfile)
|
|
22
|
-
asetus = Asetus.new(name: 'oxidized', load: false,
|
|
22
|
+
asetus = Asetus.new(name: 'oxidized', load: false, usrdir: usrdir, cfgfile: cfgfile)
|
|
23
23
|
Oxidized.asetus = asetus
|
|
24
24
|
|
|
25
25
|
asetus.default.username = 'username'
|
data/lib/oxidized/input/ssh.rb
CHANGED
|
@@ -18,10 +18,14 @@ module Oxidized
|
|
|
18
18
|
|
|
19
19
|
def connect(node)
|
|
20
20
|
@node = node
|
|
21
|
-
@output = ''
|
|
21
|
+
@output = String.new('')
|
|
22
22
|
@pty_options = { term: "vt100" }
|
|
23
23
|
@node.model.cfg['ssh'].each { |cb| instance_exec(&cb) }
|
|
24
|
-
|
|
24
|
+
if Oxidized.config.input.debug?
|
|
25
|
+
logfile = Oxidized::Config::LOG + "/#{@node.ip}-ssh"
|
|
26
|
+
@log = File.open(logfile, 'w')
|
|
27
|
+
Oxidized.logger.debug "lib/oxidized/input/ssh.rb: I/O Debuging to #{logfile}"
|
|
28
|
+
end
|
|
25
29
|
|
|
26
30
|
Oxidized.logger.debug "lib/oxidized/input/ssh.rb: Connecting to #{@node.name}"
|
|
27
31
|
@ssh = Net::SSH.start(@node.ip, @node.auth[:username], make_ssh_opts)
|
|
@@ -41,7 +45,11 @@ module Oxidized
|
|
|
41
45
|
end
|
|
42
46
|
|
|
43
47
|
def cmd(cmd, expect = node.prompt)
|
|
44
|
-
Oxidized.logger.debug "lib/oxidized/input/ssh.rb #{cmd} @ #{node.name} with expect: #{expect.inspect}"
|
|
48
|
+
Oxidized.logger.debug "lib/oxidized/input/ssh.rb #{cmd.dump} @ #{node.name} with expect: #{expect.inspect}"
|
|
49
|
+
if Oxidized.config.input.debug?
|
|
50
|
+
@log.puts "sent #{cmd.dump}"
|
|
51
|
+
@log.flush
|
|
52
|
+
end
|
|
45
53
|
cmd_output = if @exec
|
|
46
54
|
@ssh.exec! cmd
|
|
47
55
|
else
|
|
@@ -78,7 +86,7 @@ module Oxidized
|
|
|
78
86
|
@ses = ssh.open_channel do |ch|
|
|
79
87
|
ch.on_data do |_ch, data|
|
|
80
88
|
if Oxidized.config.input.debug?
|
|
81
|
-
@log.
|
|
89
|
+
@log.puts "received #{data.dump}"
|
|
82
90
|
@log.flush
|
|
83
91
|
end
|
|
84
92
|
@output << data
|
|
@@ -101,7 +109,7 @@ module Oxidized
|
|
|
101
109
|
end
|
|
102
110
|
|
|
103
111
|
def cmd_shell(cmd, expect_re)
|
|
104
|
-
@output = ''
|
|
112
|
+
@output = String.new('')
|
|
105
113
|
@ses.send_data cmd + "\n"
|
|
106
114
|
@ses.process
|
|
107
115
|
expect expect_re if expect_re
|
data/lib/oxidized/model/aos7.rb
CHANGED
data/lib/oxidized/model/aosw.rb
CHANGED
|
@@ -117,7 +117,7 @@ class AOSW < Oxidized::Model
|
|
|
117
117
|
next if line =~ /Output \d Config/i
|
|
118
118
|
next if line =~ /(Tachometers|Temperatures|Voltages)/
|
|
119
119
|
next if line =~ /((Card|CPU) Temperature|Chassis Fan|VMON1[0-9])/
|
|
120
|
-
next if line =~ /[0-9]+\s+(RPMS?|m?V|C)/i
|
|
120
|
+
next if line =~ /[0-9]+\s+(RPMS?|m?V|C|W)/i
|
|
121
121
|
|
|
122
122
|
out << line.strip
|
|
123
123
|
end
|
data/lib/oxidized/model/asa.rb
CHANGED
|
@@ -15,7 +15,7 @@ class ASA < Oxidized::Model
|
|
|
15
15
|
cfg.gsub! /enable password (\S+) (.*)/, 'enable password <secret hidden> \2'
|
|
16
16
|
cfg.gsub! /^passwd (\S+) (.*)/, 'passwd <secret hidden> \2'
|
|
17
17
|
cfg.gsub! /username (\S+) password (\S+) (.*)/, 'username \1 password <secret hidden> \3'
|
|
18
|
-
cfg.gsub! /(ikev[12] ((remote|local)-authentication )?pre-shared-key) (\S+)/, '\1 <secret hidden>'
|
|
18
|
+
cfg.gsub! /(ikev[12] ((remote|local)-authentication )?pre-shared-key( hex)?) (\S+)/, '\1 <secret hidden>'
|
|
19
19
|
cfg.gsub! /^(aaa-server TACACS\+? \(\S+\) host[^\n]*\n(\s+[^\n]+\n)*\skey) \S+$/mi, '\1 <secret hidden>'
|
|
20
20
|
cfg.gsub! /^(aaa-server \S+ \(\S+\) host[^\n]*\n(\s+[^\n]+\n)*\s+key) \S+$/mi, '\1 <secret hidden>'
|
|
21
21
|
cfg.gsub! /ldap-login-password (\S+)/, 'ldap-login-password <secret hidden>'
|
|
@@ -38,6 +38,7 @@ class ASA < Oxidized::Model
|
|
|
38
38
|
cfg = cfg.join
|
|
39
39
|
cfg.gsub! /^Configuration has not been modified since last system restart.*\n/, ''
|
|
40
40
|
cfg.gsub! /^Configuration last modified by.*\n/, ''
|
|
41
|
+
cfg.gsub! /^Start-up time.*\n/, ''
|
|
41
42
|
comment cfg
|
|
42
43
|
end
|
|
43
44
|
|
|
@@ -1,7 +1,19 @@
|
|
|
1
1
|
class Cumulus < Oxidized::Model
|
|
2
2
|
using Refinements
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
# Remove ANSI escape codes
|
|
5
|
+
expect /\e\[[0-?]*[ -\/]*[@-~]\r?/ do |data, re|
|
|
6
|
+
data.gsub re, ''
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
# The prompt contains ANSI escape codes, which have already been removed
|
|
10
|
+
# from the expect call above
|
|
11
|
+
# ^ : match begin of line, to have the most specific prompt
|
|
12
|
+
# [\w.-]+@[\w.-]+ : user@hostname
|
|
13
|
+
# (:mgmt)? : optional when logged in out of band
|
|
14
|
+
# :~[#$] $ : end of prompt, containing the linux path,
|
|
15
|
+
# which is always "~" in our context
|
|
16
|
+
prompt /^[\w.-]+@[\w.-]+(:mgmt)?:~[#$] $/
|
|
5
17
|
comment '# '
|
|
6
18
|
|
|
7
19
|
# add a comment in the final conf
|
|
@@ -79,7 +91,9 @@ class Cumulus < Oxidized::Model
|
|
|
79
91
|
cfg += cmd 'cat /etc/cumulus/switchd.conf'
|
|
80
92
|
|
|
81
93
|
cfg += add_comment 'PORTS'
|
|
82
|
-
|
|
94
|
+
# in some configurations, ports.conf has no trailing Line Feed,
|
|
95
|
+
# which breaks the prompt, so we add one
|
|
96
|
+
cfg += cmd "cat /etc/cumulus/ports.conf; echo"
|
|
83
97
|
|
|
84
98
|
cfg += add_comment 'TRAFFIC'
|
|
85
99
|
cfg += cmd 'cat /etc/cumulus/datapath/traffic.conf'
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
class Enterprise_SONiC < Oxidized::Model # rubocop:disable Naming/ClassAndModuleCamelCase
|
|
2
|
+
using Refinements
|
|
3
|
+
|
|
4
|
+
# Remove ANSI escape codes
|
|
5
|
+
expect /\e\[[0-?]*[ -\/]*[@-~]\r?/ do |data, re|
|
|
6
|
+
data.gsub re, ''
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
# Matches both sonic-cli and linux terminal
|
|
10
|
+
prompt /^(?:[\w.-]+@[\w.-]+:[~\w\/-]+\$|[\w.-]+#)\s*/
|
|
11
|
+
comment "# "
|
|
12
|
+
|
|
13
|
+
def add_comment(comment)
|
|
14
|
+
"\n##### #{comment} #####\n"
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
post do
|
|
18
|
+
cmd 'show running-configuration' do |cfg|
|
|
19
|
+
add_comment('CONFIGURATION') + cfg
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
cmd 'show version' do |cfg|
|
|
24
|
+
cfg = cfg.each_line.reject { |line| line.match /Uptime/ }.join
|
|
25
|
+
add_comment('VERSION') + cfg
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
cmd 'show platform syseeprom' do |cfg|
|
|
29
|
+
add_comment('SYSEEPROM') + cfg
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
cmd :all do |cfg|
|
|
33
|
+
cfg.cut_both
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
cfg :ssh do
|
|
37
|
+
# if user logs in to linux == has admin rights
|
|
38
|
+
if vars(:admin) == true
|
|
39
|
+
post_login do
|
|
40
|
+
cmd "sonic-cli\n"
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
post_login 'terminal length 0'
|
|
44
|
+
pre_logout 'exit'
|
|
45
|
+
end
|
|
46
|
+
end
|
data/lib/oxidized/model/fsos.rb
CHANGED
|
@@ -2,6 +2,7 @@ class FSOS < Oxidized::Model
|
|
|
2
2
|
# Fiberstore / fs.com
|
|
3
3
|
using Refinements
|
|
4
4
|
comment '! '
|
|
5
|
+
prompt /^([\w.@()-]+[#>]\s?)$/
|
|
5
6
|
|
|
6
7
|
# Handle paging
|
|
7
8
|
expect /^ --More--.*$/ do |data, re|
|
|
@@ -13,6 +14,9 @@ class FSOS < Oxidized::Model
|
|
|
13
14
|
cfg.gsub! /(secret \w+) (\S+).*/, '\\1 <secret hidden>'
|
|
14
15
|
cfg.gsub! /(password \d+) (\S+).*/, '\\1 <secret hidden>'
|
|
15
16
|
cfg.gsub! /(snmp-server community \d+) (\S+).*/, '\\1 <secret hidden>'
|
|
17
|
+
cfg.gsub! /^(snmp-server host \S+( udp-port \d+)?( permit|deny \d+)?( informs?)?( traps?)?(( version v3 (priv|auth|noauth))|( version (v1|v2c))?)) +\S+( .*)?$*/, '\\1 <secret hidden>'
|
|
18
|
+
cfg.gsub! /^(snmp-server user \S+ \S+ v3( priv (des|aes128|aes256|aes256-c))?( auth (md5|sha|sha256) \d+)) +\S+( .*)?$*/, '\\1 <secret hidden>'
|
|
19
|
+
cfg.gsub! /^(.*key \d+) (\S+).*/, '\\1 <secret hidden>'
|
|
16
20
|
cfg
|
|
17
21
|
end
|
|
18
22
|
|
|
@@ -37,7 +41,7 @@ class FSOS < Oxidized::Model
|
|
|
37
41
|
cfg :telnet, :ssh do
|
|
38
42
|
post_login 'enable'
|
|
39
43
|
post_login 'terminal length 0'
|
|
40
|
-
post_login 'terminal width
|
|
44
|
+
post_login 'terminal width 512'
|
|
41
45
|
pre_logout 'exit'
|
|
42
46
|
pre_logout 'exit'
|
|
43
47
|
end
|
|
@@ -4,12 +4,12 @@ class Garderos < Oxidized::Model
|
|
|
4
4
|
# Routers for harsh environments
|
|
5
5
|
# grs = Garderos Router Software
|
|
6
6
|
|
|
7
|
-
#
|
|
8
|
-
|
|
9
|
-
expect /\e\[\d*m\r?/ do |data, re|
|
|
7
|
+
# Remove ANSI escape codes
|
|
8
|
+
expect /\e\[[0-?]*[ -\/]*[@-~]\r?/ do |data, re|
|
|
10
9
|
data.gsub re, ''
|
|
11
10
|
end
|
|
12
11
|
|
|
12
|
+
# the prompt does not need to match escape codes, as they have been removed above
|
|
13
13
|
prompt /[\w-]+# /
|
|
14
14
|
comment '# '
|
|
15
15
|
|
|
@@ -29,7 +29,7 @@ class Garderos < Oxidized::Model
|
|
|
29
29
|
# If we have a radio modem installed, we'd like to list the SIM Card
|
|
30
30
|
cmd 'show hardware wwan wwan0 sim' do |cfg|
|
|
31
31
|
if cfg.start_with? 'Unknown command'
|
|
32
|
-
''
|
|
32
|
+
String.new('')
|
|
33
33
|
else
|
|
34
34
|
comment "#{cfg}\n"
|
|
35
35
|
end
|