oxidized 0.29.1 → 0.37.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.coderabbit.yaml +21 -0
- data/.github/ISSUE_TEMPLATE/bug_report.md +45 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +22 -0
- data/.github/ISSUE_TEMPLATE/support-request.md +39 -0
- data/.github/workflows/codeql.yml +4 -4
- data/.github/workflows/publishdocker.yml +108 -13
- data/.github/workflows/ruby.yml +3 -12
- data/.github/workflows/stale.yml +6 -1
- data/.gitignore +2 -0
- data/.rubocop.yml +69 -13
- data/.rubocop_todo.yml +13 -143
- data/CHANGELOG.md +431 -4
- data/CONTRIBUTING.md +189 -0
- data/Dockerfile +89 -34
- data/README.md +59 -188
- data/Rakefile +58 -12
- data/bin/oxidized +2 -5
- data/docs/Configuration.md +382 -149
- data/docs/Creating-Models.md +262 -10
- data/docs/DeviceSimulation.md +196 -0
- data/docs/Docker.md +246 -0
- data/docs/Hooks.md +146 -51
- data/docs/Inputs.md +237 -0
- data/docs/Issues.md +123 -0
- data/docs/Model-Notes/APC.md +72 -0
- data/docs/Model-Notes/Cumulus.md +5 -0
- data/docs/Model-Notes/EatonNetwork.md +18 -0
- data/docs/Model-Notes/ExaLink.md +43 -0
- data/docs/Model-Notes/FSOS.md +17 -0
- data/docs/Model-Notes/Fortinet.md +75 -0
- data/docs/Model-Notes/GrandstreamHT8xx.md +8 -0
- data/docs/Model-Notes/HPEAruba.md +32 -0
- data/docs/Model-Notes/IvantiConnectSecure.md +59 -0
- data/docs/Model-Notes/OS6.md +10 -0
- data/docs/Model-Notes/README.md +1 -20
- data/docs/Model-Notes/RouterOS.md +28 -0
- data/docs/Model-Notes/SikluMHTG.md +7 -0
- data/docs/Model-Notes/TrueNAS.md +23 -0
- data/docs/Model-Notes/XGS4600-Zyxel.md +5 -0
- data/docs/ModelUnitTests.md +219 -0
- data/docs/Outputs.md +102 -5
- data/docs/Release.md +102 -0
- data/docs/Ruby-API.md +135 -2
- data/docs/Sources.md +34 -0
- data/docs/Supported-OS-Types.md +207 -270
- data/docs/Troubleshooting.md +43 -1
- data/extra/device2yaml.rb +259 -0
- data/extra/gitdiff-msteams.sh +32 -5
- data/extra/hooks/modelrules.rb +55 -0
- data/extra/hooks/modelrulesadvanced.rb +167 -0
- data/extra/hooks/srcipmap.rb +54 -0
- data/extra/nagios_check_failing_nodes.rb +1 -1
- data/extra/oxidized.runit +1 -1
- data/extra/rest_client.rb +5 -4
- data/extra/syslog.rb +11 -6
- data/lib/oxidized/cli/support.rb +152 -0
- data/lib/oxidized/cli.rb +21 -6
- data/lib/oxidized/config/vars.rb +33 -14
- data/lib/oxidized/config.rb +28 -17
- data/lib/oxidized/core.rb +50 -8
- data/lib/oxidized/hook/ciscosparkdiff.rb +11 -9
- data/lib/oxidized/hook/exec.rb +5 -4
- data/lib/oxidized/hook/githubrepo.rb +55 -18
- data/lib/oxidized/hook/noophook.rb +2 -2
- data/lib/oxidized/hook/slackdiff.rb +50 -14
- data/lib/oxidized/hook/xmppdiff.rb +9 -9
- data/lib/oxidized/hook.rb +68 -16
- data/lib/oxidized/input/cli.rb +8 -3
- data/lib/oxidized/input/debugtext.rb +40 -0
- data/lib/oxidized/input/debugyaml.rb +82 -0
- data/lib/oxidized/input/exec.rb +2 -11
- data/lib/oxidized/input/ftp.rb +2 -19
- data/lib/oxidized/input/http.rb +67 -17
- data/lib/oxidized/input/input.rb +35 -14
- data/lib/oxidized/input/scp.rb +27 -0
- data/lib/oxidized/input/ssh.rb +59 -83
- data/lib/oxidized/input/sshbase.rb +102 -0
- data/lib/oxidized/input/telnet.rb +20 -19
- data/lib/oxidized/input/tftp.rb +8 -8
- data/lib/oxidized/job.rb +18 -7
- data/lib/oxidized/jobs.rb +11 -1
- data/lib/oxidized/logger.rb +51 -0
- data/lib/oxidized/manager.rb +18 -17
- data/lib/oxidized/model/acos.rb +2 -1
- data/lib/oxidized/model/addpack.rb +26 -0
- data/lib/oxidized/model/adtran.rb +5 -1
- data/lib/oxidized/model/adva.rb +3 -3
- data/lib/oxidized/model/airfiber.rb +1 -1
- data/lib/oxidized/model/aos7.rb +11 -0
- data/lib/oxidized/model/aoscx.rb +37 -29
- data/lib/oxidized/model/aosw.rb +39 -29
- data/lib/oxidized/model/apc_aos.rb +7 -2
- data/lib/oxidized/model/apcaos.rb +39 -0
- data/lib/oxidized/model/aricentiss.rb +9 -2
- data/lib/oxidized/model/arubainstant.rb +93 -0
- data/lib/oxidized/model/asa.rb +11 -10
- data/lib/oxidized/model/asternos.rb +22 -0
- data/lib/oxidized/model/asyncos.rb +3 -3
- data/lib/oxidized/model/audiocodes.rb +2 -2
- data/lib/oxidized/model/awplus.rb +15 -12
- data/lib/oxidized/model/axos.rb +1 -1
- data/lib/oxidized/model/bdcom.rb +1 -0
- data/lib/oxidized/model/c4cmts.rb +1 -2
- data/lib/oxidized/model/ciscosma.rb +1 -1
- data/lib/oxidized/model/ciscosmb.rb +6 -1
- data/lib/oxidized/model/cnos.rb +13 -10
- data/lib/oxidized/model/comtrol.rb +1 -1
- data/lib/oxidized/model/comware.rb +5 -3
- data/lib/oxidized/model/cumulus.rb +14 -2
- data/lib/oxidized/model/defacto.rb +26 -0
- data/lib/oxidized/model/dellx.rb +1 -1
- data/lib/oxidized/model/dlink.rb +5 -2
- data/lib/oxidized/model/dlinknextgen.rb +55 -0
- data/lib/oxidized/model/dnos.rb +3 -0
- data/lib/oxidized/model/dslcommands.rb +93 -0
- data/lib/oxidized/model/dslsetup.rb +102 -0
- data/lib/oxidized/model/eatonnetwork.rb +70 -0
- data/lib/oxidized/model/edgecos.rb +3 -1
- data/lib/oxidized/model/edgeos.rb +7 -6
- data/lib/oxidized/model/edgeswitch.rb +3 -1
- data/lib/oxidized/model/efos.rb +41 -0
- data/lib/oxidized/model/eltex.rb +4 -2
- data/lib/oxidized/model/enterasys800.rb +2 -2
- data/lib/oxidized/model/enterprise_sonic.rb +46 -0
- data/lib/oxidized/model/eos.rb +3 -1
- data/lib/oxidized/model/exalink.rb +36 -0
- data/lib/oxidized/model/f5os.rb +17 -0
- data/lib/oxidized/model/fabricos.rb +2 -2
- data/lib/oxidized/model/fastiron.rb +5 -3
- data/lib/oxidized/model/firebrick.rb +2 -2
- data/lib/oxidized/model/firelinuxos.rb +13 -6
- data/lib/oxidized/model/firewareos.rb +10 -1
- data/lib/oxidized/model/fortigate.rb +160 -0
- data/lib/oxidized/model/fortios.rb +38 -48
- data/lib/oxidized/model/fsos.rb +46 -0
- data/lib/oxidized/model/gaiaos.rb +4 -4
- data/lib/oxidized/model/garderos.rb +38 -0
- data/lib/oxidized/model/grandstreamht8xx.rb +19 -0
- data/lib/oxidized/model/h3c.rb +1 -1
- data/lib/oxidized/model/ibos.rb +1 -0
- data/lib/oxidized/model/ingate.rb +47 -0
- data/lib/oxidized/model/ios.rb +57 -30
- data/lib/oxidized/model/iosxr.rb +2 -2
- data/lib/oxidized/model/ironware.rb +7 -5
- data/lib/oxidized/model/ivanti.rb +54 -0
- data/lib/oxidized/model/junos.rb +12 -5
- data/lib/oxidized/model/kornfeldos.rb +33 -0
- data/lib/oxidized/model/lenovonos.rb +2 -0
- data/lib/oxidized/model/linksyssrw.rb +3 -3
- data/lib/oxidized/model/linuxgeneric.rb +4 -2
- data/lib/oxidized/model/macros.rb +60 -0
- data/lib/oxidized/model/mimosab11.rb +34 -0
- data/lib/oxidized/model/ml66.rb +33 -0
- data/lib/oxidized/model/mlnxos.rb +18 -14
- data/lib/oxidized/model/model.rb +98 -103
- data/lib/oxidized/model/mtrlrfs.rb +1 -0
- data/lib/oxidized/model/ndms.rb +6 -0
- data/lib/oxidized/model/netgear.rb +14 -3
- data/lib/oxidized/model/netonix.rb +1 -1
- data/lib/oxidized/model/netscaler.rb +1 -1
- data/lib/oxidized/model/nodegrid.rb +1 -1
- data/lib/oxidized/model/nsxdfw.rb +31 -0
- data/lib/oxidized/model/nsxfirewall.rb +2 -1
- data/lib/oxidized/model/nxos.rb +20 -15
- data/lib/oxidized/model/ocnos.rb +42 -0
- data/lib/oxidized/model/onefinity.rb +18 -0
- data/lib/oxidized/model/openbsd.rb +1 -1
- data/lib/oxidized/model/opengear.rb +36 -1
- data/lib/oxidized/model/openwrt.rb +6 -6
- data/lib/oxidized/model/opnsense.rb +9 -1
- data/lib/oxidized/model/os6.rb +48 -0
- data/lib/oxidized/model/outputs.rb +5 -0
- data/lib/oxidized/model/panos.rb +2 -0
- data/lib/oxidized/model/perle.rb +41 -0
- data/lib/oxidized/model/pfsense.rb +9 -0
- data/lib/oxidized/model/powerconnect.rb +32 -11
- data/lib/oxidized/model/procurve.rb +6 -2
- data/lib/oxidized/model/qtech.rb +3 -1
- data/lib/oxidized/model/quantaos.rb +8 -6
- data/lib/oxidized/model/rgos.rb +33 -0
- data/lib/oxidized/model/riverbed.rb +104 -0
- data/lib/oxidized/model/routeros.rb +18 -11
- data/lib/oxidized/model/saos.rb +18 -1
- data/lib/oxidized/model/saos10.rb +38 -0
- data/lib/oxidized/model/siklu.rb +1 -1
- data/lib/oxidized/model/siklumhtg.rb +22 -0
- data/lib/oxidized/model/sixwind.rb +28 -0
- data/lib/oxidized/model/slxos.rb +3 -3
- data/lib/oxidized/model/smartbyte.rb +48 -0
- data/lib/oxidized/model/sonicos.rb +27 -20
- data/lib/oxidized/model/speedtouch.rb +1 -1
- data/lib/oxidized/model/sros.rb +3 -3
- data/lib/oxidized/model/srosmd.rb +1 -1
- data/lib/oxidized/model/supermicro.rb +1 -1
- data/lib/oxidized/model/telco.rb +1 -1
- data/lib/oxidized/model/tmos.rb +1 -0
- data/lib/oxidized/model/tnsr.rb +57 -0
- data/lib/oxidized/model/tplink.rb +5 -5
- data/lib/oxidized/model/trango.rb +4 -2
- data/lib/oxidized/model/truenas.rb +64 -3
- data/lib/oxidized/model/ucs.rb +1 -1
- data/lib/oxidized/model/unifiap.rb +144 -0
- data/lib/oxidized/model/uplinkolt.rb +46 -0
- data/lib/oxidized/model/voltaire.rb +1 -1
- data/lib/oxidized/model/voss.rb +3 -0
- data/lib/oxidized/model/vrp.rb +5 -1
- data/lib/oxidized/model/vyatta.rb +9 -3
- data/lib/oxidized/model/vyos.rb +37 -0
- data/lib/oxidized/model/xos.rb +10 -1
- data/lib/oxidized/model/zhoneolt.rb +4 -2
- data/lib/oxidized/model/zynos.rb +67 -3
- data/lib/oxidized/model/zynosadsl.rb +14 -0
- data/lib/oxidized/model/zynoscli.rb +1 -1
- data/lib/oxidized/model/zynosgs.rb +2 -0
- data/lib/oxidized/model/zynosmgs.rb +32 -0
- data/lib/oxidized/node.rb +99 -64
- data/lib/oxidized/nodes.rb +40 -19
- data/lib/oxidized/output/file.rb +80 -43
- data/lib/oxidized/output/git.rb +295 -151
- data/lib/oxidized/output/gitcrypt.rb +193 -185
- data/lib/oxidized/output/http.rb +63 -51
- data/lib/oxidized/output/output.rb +20 -4
- data/lib/oxidized/signals.rb +44 -0
- data/lib/oxidized/source/csv.rb +49 -49
- data/lib/oxidized/source/http.rb +76 -63
- data/lib/oxidized/source/jsonfile.rb +68 -0
- data/lib/oxidized/source/source.rb +73 -18
- data/lib/oxidized/source/sql.rb +71 -59
- data/lib/oxidized/version.rb +6 -4
- data/lib/oxidized/worker.rb +57 -29
- data/lib/oxidized.rb +4 -24
- data/lib/refinements.rb +21 -1
- data/oxidized.gemspec +45 -21
- metadata +248 -41
- data/lib/oxidized/model/timos.rb +0 -10
data/docs/Creating-Models.md
CHANGED
|
@@ -1,33 +1,96 @@
|
|
|
1
1
|
# Creating and Extending Models
|
|
2
2
|
|
|
3
|
-
Oxidized supports a growing list of
|
|
3
|
+
Oxidized supports a growing list of
|
|
4
|
+
[operating system types](Supported-OS-Types.md). Out of the box, most model
|
|
5
|
+
implementations collect configuration data. Some implementations also include a
|
|
6
|
+
conservative set of additional commands that collect basic device information
|
|
7
|
+
(device make and model, software version, licensing information, ...) which are
|
|
8
|
+
appended to the configuration as comments.
|
|
9
|
+
|
|
10
|
+
A user may wish to extend an existing model to collect the output of additional
|
|
11
|
+
commands. Oxidized offers smart loading of models in order to facilitate this
|
|
12
|
+
with ease, without the need to introduce changes to the upstream source code.
|
|
13
|
+
|
|
14
|
+
This methodology allows local site changes to be preserved during Oxidized
|
|
15
|
+
version updates / gem updates. It also enables convenient local development
|
|
16
|
+
of new models.
|
|
17
|
+
|
|
18
|
+
## Index
|
|
19
|
+
- [Creating a new model](#creating-a-new-model)
|
|
20
|
+
- [Typical Tasks and Solutions](#typical-tasks-and-solutions)
|
|
21
|
+
- [Handling 'enable' mode](#handling-enable-mode)
|
|
22
|
+
- [Remove ANSI escape codes](#remove-ansi-escape-codes)
|
|
23
|
+
- [Conditional commands](#conditional-commands)
|
|
24
|
+
- [Extending an existing model with a new command](#extending-an-existing-model-with-a-new-command)
|
|
25
|
+
- [Create unit tests for the model](#create-unit-tests-for-the-model)
|
|
26
|
+
- [Advanced features](#advanced-features)
|
|
27
|
+
- [Monkey-patching blocks in existing models](#monkey-patching-blocks-in-existing-models)
|
|
28
|
+
- [Help](#help)
|
|
4
29
|
|
|
5
|
-
|
|
30
|
+
## Creating a new model
|
|
31
|
+
### Use the defacto model
|
|
32
|
+
Before you create a new model, check the
|
|
33
|
+
[defacto model](/lib/oxidized/model/defacto.rb). It aims to work with a lot of
|
|
34
|
+
devices copying the defacto standard set by the cisco CLI:
|
|
35
|
+
- login per ssh or telnet
|
|
36
|
+
- disable pager
|
|
37
|
+
- execute `show running-config`
|
|
38
|
+
- run both `exit` and `logout`
|
|
39
|
+
|
|
40
|
+
If you want to extend the defacto model, you can define your own model file,
|
|
41
|
+
and inherit from `Defacto`:
|
|
42
|
+
```ruby
|
|
43
|
+
require 'oxidized/model/defacto'
|
|
6
44
|
|
|
7
|
-
|
|
45
|
+
class OxiWare < Defacto
|
|
46
|
+
# Redefine how to process show running-config
|
|
47
|
+
def process_config(cfg)
|
|
48
|
+
cfg.gsub(/.*service timestamps.*/, '')
|
|
49
|
+
end
|
|
8
50
|
|
|
9
|
-
|
|
51
|
+
# run more commands. They will be run before 'show running-config'
|
|
52
|
+
cmd "show cdp neighbors" do |cfg|
|
|
53
|
+
comment cfg
|
|
54
|
+
end
|
|
10
55
|
|
|
56
|
+
# Send "enable" password if defined in vars("enable")
|
|
57
|
+
macro :enable
|
|
58
|
+
end
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
If your model doesn't support "show running-config", or if you prefer to avoid
|
|
62
|
+
the dependency of the defacto model, you will need to write a model "from
|
|
63
|
+
scratch" as explained in the next section.
|
|
64
|
+
|
|
65
|
+
### Create a new model from scratch
|
|
11
66
|
An Oxidized model, at minimum, requires just three elements:
|
|
12
67
|
|
|
13
68
|
* A model file, this file should be placed in the ~/.config/oxidized/model directory and named after the target OS type.
|
|
14
69
|
* A class defined within this file with the same name as the file itself that inherits from `Oxidized::Model`, the base model class.
|
|
15
70
|
* At least one command that will be executed and the output of which will be collected by Oxidized.
|
|
16
71
|
|
|
17
|
-
A bare-bone example for a fictional model running the OS type `rootware` could
|
|
72
|
+
A bare-bone example for a fictional model running the OS type `rootware` could
|
|
73
|
+
be introduced by creating the file `~/.config/oxidized/model/rootware.rb`, with
|
|
74
|
+
the following content:
|
|
18
75
|
|
|
19
76
|
```ruby
|
|
20
77
|
class RootWare < Oxidized::Model
|
|
21
78
|
using Refinements
|
|
22
79
|
|
|
23
80
|
cmd 'show complete-config'
|
|
81
|
+
|
|
82
|
+
cfg :ssh do
|
|
83
|
+
pre_logout 'exit'
|
|
84
|
+
end
|
|
85
|
+
end
|
|
24
86
|
```
|
|
25
87
|
|
|
26
88
|
This model, as-is will:
|
|
27
89
|
|
|
28
|
-
* Log into the device and expect the default prompt.
|
|
90
|
+
* Log into the device with ssh and expect the default prompt.
|
|
29
91
|
* Upon matching it, execute the command `show complete-config`
|
|
30
92
|
* Collect the output.
|
|
93
|
+
* Logout with the command `exit`
|
|
31
94
|
|
|
32
95
|
It is often useful to, at minimum, define the following additional elements for any newly introduced module:
|
|
33
96
|
|
|
@@ -40,6 +103,184 @@ The API documentation contains a list of [methods](https://github.com/ytti/oxidi
|
|
|
40
103
|
|
|
41
104
|
A more fleshed out example can be found in the `IOS` and `JunOS` models.
|
|
42
105
|
|
|
106
|
+
## Typical Tasks and Solutions
|
|
107
|
+
|
|
108
|
+
### Keep or Remove Lines Returned from a Command
|
|
109
|
+
To make command output cleaner, you can remove unwanted lines or keep only
|
|
110
|
+
specific ones.
|
|
111
|
+
|
|
112
|
+
Most devices echo the executed command on the first line and display a
|
|
113
|
+
prompt on the last line. To remove these for all commands, use
|
|
114
|
+
[cut_both](Ruby-API.md#cut_both):
|
|
115
|
+
```ruby
|
|
116
|
+
cmd :all do |cfg|
|
|
117
|
+
cfg.cut_both
|
|
118
|
+
end
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
You can also use the macro `clean :cut`, which does the same:
|
|
122
|
+
```ruby
|
|
123
|
+
clean :cut
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
If you want to keep only relevant lines, use
|
|
127
|
+
[keep_lines](Ruby-API.md#keep_lines):
|
|
128
|
+
```ruby
|
|
129
|
+
cmd 'show interfaces transceiver' do |cfg|
|
|
130
|
+
cfg = cfg.keep_lines [
|
|
131
|
+
'SFP Information',
|
|
132
|
+
/Vendor (Name|Serial Number)/
|
|
133
|
+
]
|
|
134
|
+
comment cfg + "\n"
|
|
135
|
+
end
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
If you want to suppress specific lines,
|
|
139
|
+
use [reject_lines](Ruby-API.md#reject_lines):
|
|
140
|
+
```ruby
|
|
141
|
+
cmd 'show running-config' do |cfg|
|
|
142
|
+
cfg.reject_lines [
|
|
143
|
+
'System Up Time',
|
|
144
|
+
/Current .* Time:/
|
|
145
|
+
]
|
|
146
|
+
end
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Handling 'enable' mode
|
|
150
|
+
Some devices need to send an 'enable' command and an enable password.
|
|
151
|
+
|
|
152
|
+
You can use the `macro :enable` command to implement this:
|
|
153
|
+
```ruby
|
|
154
|
+
class IOS < Oxidized::Model
|
|
155
|
+
using Refinements
|
|
156
|
+
# ... Code ...
|
|
157
|
+
macro :enable
|
|
158
|
+
end
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
`macro :enable` takes options:
|
|
162
|
+
- `regex`; the regex to match the password prompt (default: `/password/i`)
|
|
163
|
+
- `inputs`: a symbol or a list of symbols for which inputs enable should be activated (default: %i[telnet ssh])
|
|
164
|
+
- `command`: the command needed to access privileged mode (default: `enable`)
|
|
165
|
+
|
|
166
|
+
If one would want to access a german linux box as root, a minimal model would be:
|
|
167
|
+
```ruby
|
|
168
|
+
class GermanLinux < Oxidized::Model
|
|
169
|
+
using Refinements
|
|
170
|
+
|
|
171
|
+
prompt /^(\w.*|\W.*)[:#$] /
|
|
172
|
+
comment '# '
|
|
173
|
+
|
|
174
|
+
cmd "id"
|
|
175
|
+
|
|
176
|
+
cfg :ssh do
|
|
177
|
+
pre_logout 'exit'
|
|
178
|
+
pre_logout 'exit'
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
macro :enable, inputs: :ssh, command: "su -", regex: /Passwort: /
|
|
182
|
+
end
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
The macro (with defaults) implements following code:
|
|
186
|
+
```ruby
|
|
187
|
+
cfg :telnet, :ssh do
|
|
188
|
+
post_login do
|
|
189
|
+
if vars(:enable) == true
|
|
190
|
+
cmd "enable"
|
|
191
|
+
elsif vars(:enable)
|
|
192
|
+
cmd "enable", /password/i
|
|
193
|
+
cmd vars(:enable)
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
### Remove ANSI Escape Codes
|
|
201
|
+
Some devices produce [ANSI escape codes](https://en.wikipedia.org/wiki/ANSI_escape_code#Control_Sequence_Introducer_commands)
|
|
202
|
+
to enhance the appearance of their output.
|
|
203
|
+
However, this can make prompt matching difficult and some of these ANSI escape
|
|
204
|
+
codes might end up in the resulting configuration.
|
|
205
|
+
|
|
206
|
+
You can remove most ANSI escape codes by inserting the following line in your
|
|
207
|
+
model:
|
|
208
|
+
```ruby
|
|
209
|
+
clean :escape_codes
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
When using clean `:escape_codes`, you don't have to worry about escape codes
|
|
213
|
+
in your prompt regexp, as they will be removed before the prompt detection runs.
|
|
214
|
+
|
|
215
|
+
If it doesn't work for your model, please open an issue and provide a
|
|
216
|
+
[device simulation file](/docs/DeviceSimulation.md) so that we can adapt the
|
|
217
|
+
code.
|
|
218
|
+
|
|
219
|
+
### Conditional commands
|
|
220
|
+
Some times, you have to run commands depending on the output of the device or
|
|
221
|
+
a configured variable. For this, there are at least three solutions.
|
|
222
|
+
|
|
223
|
+
#### Nested `cmd`
|
|
224
|
+
You can nest `cmd` inside [`cmd` blocks](Ruby-API.md#cmd), the following example
|
|
225
|
+
is taken from [nxos.rb](/lib/oxidized/model/nxos.rb):
|
|
226
|
+
```ruby
|
|
227
|
+
cmd 'show inventory all' do |cfg|
|
|
228
|
+
if cfg.match? /^% Invalid .* at '\^' marker\./
|
|
229
|
+
# 'show inventory all' isn't supported on older versions (See Issues #3657, #3779)
|
|
230
|
+
cfg = cmd 'show inventory'
|
|
231
|
+
end
|
|
232
|
+
comment cfg
|
|
233
|
+
end
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
#### pre/post blocks
|
|
237
|
+
After all the [`cmd` blocks](Ruby-API.md#cmd) have been run, the [`pre`
|
|
238
|
+
and `post` blocks](Ruby-API.md#pre--post) are run. The following example is
|
|
239
|
+
taken from [junos.rb](/lib/oxidized/model/junos.rb):
|
|
240
|
+
```ruby
|
|
241
|
+
post do
|
|
242
|
+
out = String.new
|
|
243
|
+
case @model
|
|
244
|
+
when 'mx960'
|
|
245
|
+
out << cmd('show chassis fabric reachability') { |cfg| comment cfg }
|
|
246
|
+
when /^(ex22|ex3[34]|ex4|ex8|qfx)/
|
|
247
|
+
out << cmd('show virtual-chassis') { |cfg| comment cfg }
|
|
248
|
+
when /^srx/
|
|
249
|
+
out << cmd('show chassis cluster status') do |cfg|
|
|
250
|
+
cfg.lines.count <= 1 && cfg.include?("error:") ? String.new : comment(cfg)
|
|
251
|
+
end
|
|
252
|
+
end
|
|
253
|
+
out
|
|
254
|
+
end
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
In [pre/post blocks](Ruby-API.md#pre--post), you can also use dynamic generated
|
|
258
|
+
commands, for example in [eatonnetwok.rb](/lib/oxidized/model/eatonnetwork.rb):
|
|
259
|
+
```ruby
|
|
260
|
+
post do
|
|
261
|
+
cmd "save_configuration -p #{@node.auth[:password]}"
|
|
262
|
+
end
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
#### Conditional `cmd`
|
|
266
|
+
The `cmd "string"` method for accepts a lambda function via the `:if` argument
|
|
267
|
+
to execute the command only when the lambda evaluates to true.
|
|
268
|
+
The lambda function is evaluated at runtime in the instance context.
|
|
269
|
+
|
|
270
|
+
```ruby
|
|
271
|
+
cmd 'conditional command', if: lambda {
|
|
272
|
+
# Use lambda when multiple lines are needed
|
|
273
|
+
vars("condition")
|
|
274
|
+
} do |cfg|
|
|
275
|
+
@run_second_command = "go"
|
|
276
|
+
comment cfg
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
cmd 'second command', if: -> { @run_second_command == "go" } do |cfg|
|
|
280
|
+
comment cfg
|
|
281
|
+
end
|
|
282
|
+
```
|
|
283
|
+
|
|
43
284
|
## Extending an existing model with a new command
|
|
44
285
|
|
|
45
286
|
The example below can be used to extend the `JunOS` model to collect the output of `show interfaces diagnostics optics` and append the output to the configuration file as a comment. This command retrieves DOM information on pluggable optics present in a `JunOS`-powered chassis.
|
|
@@ -72,7 +313,18 @@ Intuitively, it is also possible to:
|
|
|
72
313
|
* Create a completely new model, with a new name, for a new operating system type.
|
|
73
314
|
* Testing/validation of an updated model from the [Oxidized GitHub repo models](https://github.com/ytti/oxidized/tree/master/lib/oxidized/model) by placing an updated model in the proper location without disrupting the gem-supplied model files.
|
|
74
315
|
|
|
75
|
-
##
|
|
316
|
+
## Create Unit Tests for the Model
|
|
317
|
+
If you want the model to be integrated into Oxidized, you can
|
|
318
|
+
[submit a pull request on GitHub](https://github.com/ytti/oxidized/pulls).
|
|
319
|
+
This is a greatly appreciated submission, as there are probably other users
|
|
320
|
+
using the same network device as you are.
|
|
321
|
+
|
|
322
|
+
A good (and optional) practice for submissions is to provide a
|
|
323
|
+
[unit test for your model](/docs/ModelUnitTests.md). This reduces the risk that
|
|
324
|
+
further developments could break it, and facilitates debugging issues without
|
|
325
|
+
having access to a physical network device for the model.
|
|
326
|
+
|
|
327
|
+
## Advanced feature: output type
|
|
76
328
|
|
|
77
329
|
The loosely-coupled architecture of Oxidized allows for easy extensibility in more advanced use cases as well.
|
|
78
330
|
|
|
@@ -124,19 +376,19 @@ Examples:
|
|
|
124
376
|
|
|
125
377
|
```ruby
|
|
126
378
|
cmd :secret, clear: true do
|
|
127
|
-
... "(new code for secret removal which replaces the existing :secret definition in the model)" ...
|
|
379
|
+
# ... "(new code for secret removal which replaces the existing :secret definition in the model)" ...
|
|
128
380
|
end
|
|
129
381
|
```
|
|
130
382
|
|
|
131
383
|
```ruby
|
|
132
384
|
cmd 'show version', clear: true do |cfg|
|
|
133
|
-
... "(new code for parsing 'show version', replaces the existing definition in the model)" ...
|
|
385
|
+
# ... "(new code for parsing 'show version', replaces the existing definition in the model)" ...
|
|
134
386
|
end
|
|
135
387
|
```
|
|
136
388
|
|
|
137
389
|
```ruby
|
|
138
390
|
cmd :ssh, prepend: true do
|
|
139
|
-
... "(code that should run first, before any code in the existing :ssh definition in the model)" ...
|
|
391
|
+
# ... "(code that should run first, before any code in the existing :ssh definition in the model)" ...
|
|
140
392
|
end
|
|
141
393
|
```
|
|
142
394
|
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
# Device Simulation
|
|
2
|
+
Oxidized supports [150+ devices](/docs/Supported-OS-Types.md).
|
|
3
|
+
|
|
4
|
+
No developer has access to all of these devices, which makes the task of
|
|
5
|
+
maintaining Oxidized difficult:
|
|
6
|
+
|
|
7
|
+
- Issues can't be resolved because the developer has no access to the device.
|
|
8
|
+
- Further developments can produce regressions.
|
|
9
|
+
|
|
10
|
+
In order to address this, we can simulate the devices. An example of a
|
|
11
|
+
simulation is the [model unit tests](/spec/model), but one could also simulate a
|
|
12
|
+
device within an SSH server.
|
|
13
|
+
|
|
14
|
+
The simulation of devices is currently focused on SSH-based devices. This may be
|
|
15
|
+
extended to other inputs like Telnet or FTP in the future.
|
|
16
|
+
|
|
17
|
+
## YAML Simulation Data
|
|
18
|
+
The underlying data for the simulation is a [YAML](https://yaml.org/) file in
|
|
19
|
+
which we store all relevant information about the device. The most important
|
|
20
|
+
information is the responses to the commands used in the Oxidized models.
|
|
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
|
+
### Creating a YAML Simulation File with device2yaml.rb
|
|
30
|
+
A device does not only output the ASCII text we can see in the console.
|
|
31
|
+
It adds ANSI escape codes for nice colors, bold and underline, \r, and so on.
|
|
32
|
+
These are key factors in prompt issues, so they must be represented in the YAML
|
|
33
|
+
file. We use the Ruby string format with interpolations like \r, \e, and so on.
|
|
34
|
+
Another important point is trailing spaces at the end of lines. Some text
|
|
35
|
+
editors automatically remove trailing spaces, so we code them with \x20.
|
|
36
|
+
|
|
37
|
+
Although a YAML file could be written by hand, this is quite a tedious task to
|
|
38
|
+
catch all the extra codes and code them into YAML. This can be automated with
|
|
39
|
+
the Ruby script [extra/device2yaml.rb](/extra/device2yaml.rb).
|
|
40
|
+
|
|
41
|
+
`device2yaml.rb` needs Ruby and the gem
|
|
42
|
+
[net-ssh](https://rubygems.org/gems/net-ssh/) to run. On Debian, you can install
|
|
43
|
+
them with `sudo apt install ruby-net-ssh`.
|
|
44
|
+
|
|
45
|
+
Run `extra/device2yaml.rb`, the online help tells you the options.
|
|
46
|
+
```
|
|
47
|
+
oxidized$ extra/device2yaml.rb
|
|
48
|
+
Missing a host to connect to...
|
|
49
|
+
|
|
50
|
+
Usages:
|
|
51
|
+
- device2yaml.rb [user@]host -i file [options]
|
|
52
|
+
- device2yaml.rb [user@]host -c "command1
|
|
53
|
+
command2
|
|
54
|
+
command3" [options]
|
|
55
|
+
|
|
56
|
+
-i and -c are mutualy exclusive, one must be specified
|
|
57
|
+
|
|
58
|
+
[options]:
|
|
59
|
+
-c, --commands "command list" specify the commands to be run
|
|
60
|
+
-i, --input file Specify an input file for commands to be run
|
|
61
|
+
-o, --output file Specify an output YAML-file
|
|
62
|
+
-t, --timeout value Specify the idle timeout beween commands (default: 5 seconds)
|
|
63
|
+
-e, --exec-mode Run ssh in exec mode (without tty)
|
|
64
|
+
-u, --unordered The YAML simulation should not enforce an order of the commands
|
|
65
|
+
-h, --help Print this help
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
- `[user@]host` specifies the user and host to connect to the device. The
|
|
69
|
+
password will be prompted interactively by the script. If you do not specify a
|
|
70
|
+
user, it will use the user executing the script.
|
|
71
|
+
- The commands that will be run on the device must be defined in
|
|
72
|
+
`deviceyaml.rb`. You can give the commands online with `-c` or read them from a
|
|
73
|
+
file (one line per command) with `-i`. The commands should match exactly the
|
|
74
|
+
ones of the model (no abbreviations) and include the commands of the
|
|
75
|
+
`post_login` and `pre_logout` sections. When using `-c` and editing the shell
|
|
76
|
+
command line, `CTRL-V CTRL-J` is very useful to add a line break.
|
|
77
|
+
- `device2yaml.rb` waits an idle timeout after the last received data
|
|
78
|
+
before sending the next command. The default is 5 seconds. If your device makes
|
|
79
|
+
a longer pause than 5 seconds before or within a command, you will see that the
|
|
80
|
+
output of the command is shortened or slips into the next command in the YAML
|
|
81
|
+
file. You will have to change the idle timeout to a greater value to address
|
|
82
|
+
this.
|
|
83
|
+
- When run without the output argument, `device2yaml.rb` will only print the SSH
|
|
84
|
+
output to the standard output. You must use `-o <model#HW_SW#simulation.yaml>`
|
|
85
|
+
to store the collected data in a YAML file.
|
|
86
|
+
- If your Oxidized model uses SSH exec mode (look for `exec true` in the model),
|
|
87
|
+
you will have to use the option `-e` to run `device2yaml.rb` in SSH exec mode.
|
|
88
|
+
- The default behavior is to create a YAML file in which the commands must
|
|
89
|
+
appear in the order used in the Oxidized model. This is useful for simulating
|
|
90
|
+
devices that paginate output. To allow any order or include more commands than
|
|
91
|
+
the model uses, use the option `-u`. Note that the `unordered` mode may not
|
|
92
|
+
produce a useful YAML file when combined with user input (see
|
|
93
|
+
[Interactive Mode](#interactive-mode) below).
|
|
94
|
+
|
|
95
|
+
Note that `device2yaml.rb` takes some time to run because of the idle timeout of
|
|
96
|
+
(default) 5 seconds between each command. You can press the "Escape" key if you
|
|
97
|
+
know there is no more data to come for the current command (when you see the
|
|
98
|
+
prompt for the next command), and the script will stop waiting and directly
|
|
99
|
+
process the next command.
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
Running the script against an ios device would look like:
|
|
103
|
+
```shell
|
|
104
|
+
extra/device2yaml.rb oxidized@r61 -c "terminal length 0
|
|
105
|
+
terminal width 0
|
|
106
|
+
show version
|
|
107
|
+
show vtp status
|
|
108
|
+
show inventory
|
|
109
|
+
show running-config
|
|
110
|
+
exit" -o spec/model/data/ios#C8200L_16.12.1#simulation.yaml
|
|
111
|
+
```
|
|
112
|
+
### Publishing the YAML Simulation File to Oxidized
|
|
113
|
+
Publishing the YAML simulation file of your device helps maintain Oxidized. This
|
|
114
|
+
task may take some time, and we are very grateful that you take this time for
|
|
115
|
+
the community!
|
|
116
|
+
|
|
117
|
+
You should pay attention to removing or replacing anything you don't want to
|
|
118
|
+
share with the rest of the world, for example:
|
|
119
|
+
|
|
120
|
+
- Passwords
|
|
121
|
+
- IP Addresses
|
|
122
|
+
- Serial numbers
|
|
123
|
+
|
|
124
|
+
You can also shorten the configuration if you want - we don't need 48 times the
|
|
125
|
+
same configuration for each interface, but it doesn't hurt either.
|
|
126
|
+
|
|
127
|
+
Take your time, this is an important task: after you have uploaded your file on
|
|
128
|
+
GitHub, it may be impossible to remove it.
|
|
129
|
+
You can use search/replace to make consistent and faster changes, for example
|
|
130
|
+
change the hostname everywhere.
|
|
131
|
+
|
|
132
|
+
The YAML simulation files are stored under
|
|
133
|
+
[/spec/model/data/](/spec/model/data/), with the naming convention
|
|
134
|
+
`<model>#<description>#simulation.yaml`, where `<model>` is the lowercase name
|
|
135
|
+
of the Oxidized model and `<description>` is the name of the test case.
|
|
136
|
+
`<description>` is generally formatted as `<hardware>_<software>` or
|
|
137
|
+
`<hardware>_<software>_<information>`.
|
|
138
|
+
|
|
139
|
+
Using a correct name for the file is important to ensure it is included in
|
|
140
|
+
automatic model unit tests.
|
|
141
|
+
|
|
142
|
+
Examples:
|
|
143
|
+
|
|
144
|
+
- spec/model/data/aoscx#R0X25A-6410_FL.10.10.1100#simulation.yaml
|
|
145
|
+
- spec/model/data/asa#5512_9.12-4-67_single-context#simulation.yaml
|
|
146
|
+
- spec/model/data/ios#C9200L-24P-4G_17.09.04a#simulation.yaml
|
|
147
|
+
|
|
148
|
+
When you are finished, commit and push to your forked repository on GitHub, and
|
|
149
|
+
submit a Pull Request. Thank you for your help!
|
|
150
|
+
|
|
151
|
+
### Interactive Mode
|
|
152
|
+
The `device2yaml.rb` script is basic and sometimes needs some help, especially
|
|
153
|
+
when dealing with a device that sends its output page by page and requires you
|
|
154
|
+
to press space for the next page. `device2yaml.rb` does not know how to handle
|
|
155
|
+
this.
|
|
156
|
+
|
|
157
|
+
While `device2yaml.rb` is running, you can type anything on the keyboard, and it
|
|
158
|
+
will be sent to the remote device. So you can press space or 'n' to get the next
|
|
159
|
+
page.
|
|
160
|
+
|
|
161
|
+
You can also use this to enter an enable password.
|
|
162
|
+
|
|
163
|
+
Every key press will be recorded in the YAML file, so that it can be used
|
|
164
|
+
in the simulation afterwards, especialy for devices that paginate output. You
|
|
165
|
+
may need to clean the YAML file manually if you don't want some input (such
|
|
166
|
+
as passwords) to be included.
|
|
167
|
+
|
|
168
|
+
If you press the "Esc" key, `device2yaml.rb` will not wait for the idle timeout
|
|
169
|
+
and will process the next command right away.
|
|
170
|
+
|
|
171
|
+
### YAML Format
|
|
172
|
+
The YAML file has two sections:
|
|
173
|
+
- init_prompt: describing the lines sent by the device before we can send a
|
|
174
|
+
command. It usually includes MOTD banners and must include the first prompt.
|
|
175
|
+
- commands: the commands the Oxidized model sends to the network device and
|
|
176
|
+
their outputs.
|
|
177
|
+
|
|
178
|
+
The outputs are multiline and use YAML block scalars (`|`), with the trailing \n
|
|
179
|
+
removed (`-` after `|`). The outputs include the echo of the given command and
|
|
180
|
+
the next prompt. Escape characters are coded in Ruby style (\n, \r...).
|
|
181
|
+
|
|
182
|
+
Here is a shortened example of a YAML file:
|
|
183
|
+
```yaml
|
|
184
|
+
---
|
|
185
|
+
init_prompt: |-
|
|
186
|
+
\e[4m\rLAB-R1234_Garderos#\e[m\x20
|
|
187
|
+
commands:
|
|
188
|
+
show system version: |-
|
|
189
|
+
show system version
|
|
190
|
+
grs-gwuz-armel/003_005_068 (Garderos; 2021-04-30 16:19:35)
|
|
191
|
+
\e[4m\rLAB-R1234_Garderos#\e[m\x20
|
|
192
|
+
# ...
|
|
193
|
+
exit: ""
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
|