oxidized 0.30.1 → 0.31.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +2 -2
  3. data/.github/workflows/stale.yml +4 -2
  4. data/.rubocop.yml +18 -2
  5. data/.rubocop_todo.yml +5 -12
  6. data/CHANGELOG.md +61 -1
  7. data/CONTRIBUTING.md +5 -0
  8. data/Dockerfile +82 -21
  9. data/README.md +5 -21
  10. data/Rakefile +3 -2
  11. data/docs/Configuration.md +36 -12
  12. data/docs/Creating-Models.md +45 -4
  13. data/docs/Hooks.md +34 -0
  14. data/docs/Issues.md +91 -0
  15. data/docs/Model-Notes/Cumulus.md +5 -0
  16. data/docs/Model-Notes/FSOS.md +5 -0
  17. data/docs/Model-Notes/FortiOS.md +21 -5
  18. data/docs/Model-Notes/HPEAruba.md +31 -0
  19. data/docs/Model-Notes/OS6.md +10 -0
  20. data/docs/Model-Notes/RouterOS.md +15 -0
  21. data/docs/Model-Notes/SikluMHTG.md +7 -0
  22. data/docs/Outputs.md +2 -0
  23. data/docs/Release.md +18 -15
  24. data/docs/Sources.md +21 -0
  25. data/docs/Supported-OS-Types.md +11 -5
  26. data/docs/Troubleshooting.md +35 -0
  27. data/examples/device-simulation/README.md +173 -0
  28. data/examples/device-simulation/cmdsets/aoscx +9 -0
  29. data/examples/device-simulation/cmdsets/arubainstant +5 -0
  30. data/examples/device-simulation/cmdsets/asa +7 -0
  31. data/examples/device-simulation/cmdsets/ios +7 -0
  32. data/examples/device-simulation/cmdsets/nxos +5 -0
  33. data/examples/device-simulation/cmdsets/routeros +5 -0
  34. data/examples/device-simulation/cmdsets/srosmd +11 -0
  35. data/examples/device-simulation/device2yaml.rb +225 -0
  36. data/examples/device-simulation/yaml/aoscx_R0X25A-6410_FL.10.10.1100.yaml +2281 -0
  37. data/examples/device-simulation/yaml/aoscx_R8N85A-C6000-48G-CL4_PL.10.08.1010.yaml +451 -0
  38. data/examples/device-simulation/yaml/arubainstant_IAP515_8.10.0.6_VWLC.yaml +213 -0
  39. data/examples/device-simulation/yaml/asa_5512_9.12-4-67_single-context.yaml +531 -0
  40. data/examples/device-simulation/yaml/asr920_16.8.1b.yaml +1122 -0
  41. data/examples/device-simulation/yaml/garderos_R7709_003_006_068.yaml +101 -0
  42. data/examples/device-simulation/yaml/iosxe_C9200L-24P-4G_17.09.04a.yaml +514 -0
  43. data/examples/device-simulation/yaml/iosxe_C9800-L-F-K9_17.06.05.yaml +417 -0
  44. data/examples/device-simulation/yaml/riverbed_915.yaml +123 -0
  45. data/examples/device-simulation/yaml/routeros_CHR_7.10.1.yaml +145 -0
  46. data/examples/device-simulation/yaml/routeros_CHR_7.16.yaml +79 -0
  47. data/examples/device-simulation/yaml/routeros_L009UiGS_7.15.2.yaml +353 -0
  48. data/examples/podman-compose/Makefile +60 -17
  49. data/examples/podman-compose/README.md +63 -27
  50. data/examples/podman-compose/docker-compose.yml +11 -2
  51. data/examples/podman-compose/gitserver/.gitignore +1 -0
  52. data/examples/podman-compose/gitserver/Dockerfile +14 -0
  53. data/examples/podman-compose/model-simulation/Dockerfile-model +1 -1
  54. data/examples/podman-compose/model-simulation/asternos.sh +2 -0
  55. data/examples/podman-compose/oxidized-config/.gitignore +2 -0
  56. data/examples/podman-compose/oxidized-config/config +1 -1
  57. data/examples/podman-compose/oxidized-config/config_csv-file +46 -0
  58. data/examples/podman-compose/oxidized-config/config_csv-gitserver +56 -0
  59. data/examples/podman-compose/oxidized-ssh/.gitignore +1 -0
  60. data/lib/oxidized/config.rb +7 -1
  61. data/lib/oxidized/hook/githubrepo.rb +37 -7
  62. data/lib/oxidized/hook/slackdiff.rb +29 -7
  63. data/lib/oxidized/input/http.rb +1 -0
  64. data/lib/oxidized/input/telnet.rb +1 -1
  65. data/lib/oxidized/manager.rb +17 -16
  66. data/lib/oxidized/model/aoscx.rb +16 -2
  67. data/lib/oxidized/model/aosw.rb +7 -1
  68. data/lib/oxidized/model/arubainstant.rb +90 -0
  69. data/lib/oxidized/model/audiocodes.rb +2 -2
  70. data/lib/oxidized/model/cnos.rb +13 -10
  71. data/lib/oxidized/model/cumulus.rb +3 -0
  72. data/lib/oxidized/model/dlink.rb +1 -0
  73. data/lib/oxidized/model/dlinknextgen.rb +3 -0
  74. data/lib/oxidized/model/edgecos.rb +2 -1
  75. data/lib/oxidized/model/eos.rb +2 -0
  76. data/lib/oxidized/model/f5os.rb +17 -0
  77. data/lib/oxidized/model/firewareos.rb +10 -1
  78. data/lib/oxidized/model/fortios.rb +24 -1
  79. data/lib/oxidized/model/garderos.rb +43 -0
  80. data/lib/oxidized/model/h3c.rb +1 -1
  81. data/lib/oxidized/model/ibos.rb +1 -0
  82. data/lib/oxidized/model/ios.rb +20 -12
  83. data/lib/oxidized/model/iosxr.rb +1 -1
  84. data/lib/oxidized/model/lenovonos.rb +2 -0
  85. data/lib/oxidized/model/linuxgeneric.rb +1 -1
  86. data/lib/oxidized/model/netgear.rb +1 -1
  87. data/lib/oxidized/model/nodegrid.rb +1 -1
  88. data/lib/oxidized/model/nsxdfw.rb +30 -0
  89. data/lib/oxidized/model/nxos.rb +2 -1
  90. data/lib/oxidized/model/os6.rb +48 -0
  91. data/lib/oxidized/model/rgos.rb +1 -1
  92. data/lib/oxidized/model/riverbed.rb +104 -0
  93. data/lib/oxidized/model/routeros.rb +2 -2
  94. data/lib/oxidized/model/saos.rb +18 -1
  95. data/lib/oxidized/model/siklumhtg.rb +22 -0
  96. data/lib/oxidized/model/uplinkolt.rb +46 -0
  97. data/lib/oxidized/model/vyatta.rb +2 -2
  98. data/lib/oxidized/model/xos.rb +7 -0
  99. data/lib/oxidized/node.rb +30 -18
  100. data/lib/oxidized/nodes.rb +13 -5
  101. data/lib/oxidized/output/file.rb +45 -42
  102. data/lib/oxidized/output/git.rb +185 -160
  103. data/lib/oxidized/output/gitcrypt.rb +188 -186
  104. data/lib/oxidized/output/http.rb +53 -51
  105. data/lib/oxidized/output/output.rb +6 -4
  106. data/lib/oxidized/source/csv.rb +44 -49
  107. data/lib/oxidized/source/http.rb +63 -81
  108. data/lib/oxidized/source/jsonfile.rb +63 -0
  109. data/lib/oxidized/source/source.rb +43 -18
  110. data/lib/oxidized/source/sql.rb +66 -59
  111. data/lib/oxidized/version.rb +2 -2
  112. data/oxidized.gemspec +22 -16
  113. metadata +111 -15
@@ -0,0 +1,173 @@
1
+ # Device simulation
2
+ Oxidized supports [150+ devices](/docs/Supported-OS-Types.md).
3
+ No developer has access to all of these devices, which makes the task of
4
+ maintaining Oxidized difficult:
5
+
6
+ - issues can't be resolved because the developer has no access to the device.
7
+ - further developments can produce regressions.
8
+
9
+ In order to address this, we can simulate the devices. An example for a
10
+ simulation are the [model unit tests](/spec/model) but one could also simulate
11
+ a device within a ssh server.
12
+
13
+ The simulation of devices is currently focused on ssh-based devices. This may
14
+ be extended to other inputs like telnet or ftp in the future.
15
+
16
+ ## YAML Simulation Data
17
+ The underlying data for the simulation is a [YAML](https://yaml.org/) file in
18
+ which we store all relevant information about the device. The most important
19
+ information is the responses to the commands used in the oxidized models.
20
+
21
+ The YAML simulation files are stored under
22
+ [/examples/device-simulation/yaml/](/examples/device-simulation/yaml/).
23
+
24
+ ### Creating a YAML file with device2yaml.rb
25
+ A device does not only output the ASCII text we can see in the console.
26
+ It adds ANSI-escape code for nice colors, bold and underline, \r and so on.
27
+ These are key factors in prompt issues so they must be represented in the YAML
28
+ file. We use the ruby string format with interpolations like \r \e and so on.
29
+ Another important point is trailing spaces at the end of lines. Some text
30
+ editors automatically remove trailing spaces, so we code them with \x20.
31
+
32
+ Although a YAML file could be written by hand, this is quite a tedious task to
33
+ catch all the extra codes and code them into YAML. This can be
34
+ automated with the ruby script
35
+ [device2yaml.rb](/examples/device-simulation/device2yaml.rb).
36
+
37
+ `device2yaml.rb` needs ruby and the gem
38
+ [net-ssh](https://rubygems.org/gems/net-ssh/) to run. On debian, you can install
39
+ them with `sudo apt install ruby-net-ssh`
40
+
41
+ Run `device2yaml.rb` in the directory `/examples/device-simulation/`, the
42
+ online help tells you the options.
43
+ ```
44
+ device-simulation$ ./device2yaml.rb
45
+ Missing a host to connect to...
46
+
47
+ Usage: device2yaml.rb [user@]host [options]
48
+ -c, --cmdset file Mandatory: specify the commands to be run
49
+ -o, --output file Specify an output YAML-file
50
+ -t, --timeout value Specify the idle timeout beween commands (default: 5 seconds)
51
+ -e, --exec-mode Run ssh in exec mode (without tty)
52
+ -h, --help Print this help
53
+ ```
54
+
55
+ - `[user@]host` specifies the user and host to connect to the device. The
56
+ password will be prompted interactively by the script. If you do not specify a
57
+ user, it will use the user executing the script.
58
+ - You must list the commands you want to run on the device in a file. Just
59
+ enter one command per line. It is important that you enter exactly the commands
60
+ used by the oxidized model, and no abbreviation like `sh run`. Do not forget
61
+ to insert the `post_login` commands at the beginning if the model has some and
62
+ also the `pre_logout`commands at the end.
63
+ Predefined command sets for some models are stored in
64
+ `/examples/device-simulation/cmdsets`.
65
+ - `device2yaml.rb` waits an idle timeout after the last received data before
66
+ sending the next command. The default is 5 seconds. If your device makes a
67
+ longer pause than 5 seconds before or within a command, you will see that the
68
+ output of the command is shortened or slips into the next command in the yaml
69
+ file. You will have to change the idle timeout to a greater value to address
70
+ this.
71
+ - When run without the output argument, `device2yaml.rb` will only print the ssh
72
+ output to the standard output. You must use `-o <model_HW_SW.yaml>` to store the
73
+ collected data in a YAML file.
74
+ - If your oxidized model uses ssh exec mode (look for `exec true` in the model),
75
+ you will have to use the option `-e` to run device2yaml in ssh exec mode.
76
+
77
+ Note that `device2yaml.rb` takes some time to run because of the idle
78
+ timeout of (default) 5 seconds between each command. You can press the "Escape"
79
+ key if you know there is no more data to come for the current command (when you
80
+ see the prompt for the next command), and the script will stop waiting and
81
+ directly process the next command.
82
+
83
+ Here are two examples of how to run the script:
84
+ ```shell
85
+ ./device2yaml.rb OX-SW123.sample.domain -c cmdsets/aoscx -o yaml/aoscx_R8N85A-C6000-48G-CL4_PL.10.08.1010.yaml
86
+ ./device2yaml.rb admin@r7 -c cmdsets/routeros -e -o yaml/routeros_CHR_7.10.1.yaml
87
+ ```
88
+
89
+ ### Publishing the YAML simulation file to oxidized
90
+ Publishing the YAML simulation file of your device helps maintain oxidized.
91
+ This task may take some time, and we are very grateful that you take this time
92
+ for the community!
93
+
94
+ You should pay attention to removing or replacing anything you don't want to
95
+ share with the rest of the world, for example:
96
+
97
+ - Passwords
98
+ - IP Adresses
99
+ - Serial numbers
100
+
101
+ You can also shorten the configuration if you want - we don't need 48 times the
102
+ same config for each interface, but it doesn't hurt either.
103
+
104
+ Take your time, this is an important task: after you have
105
+ uploaded your file on github, it may be impossible to remove it. You can use
106
+ search/replace to make consistent and faster changes (change the hostname).
107
+
108
+ You can leave the section `oxidized_output` unchanged, it is only used for
109
+ [model unit tests](/spec/model). You will find an explanation of how to produce
110
+ the `oxidized_output`-section in the README.md there.
111
+
112
+ The YAML simulation file should be stored under
113
+ [/examples/device-simulation/yaml/](/examples/device-simulation/yaml/. It
114
+ should be named so that it can be easily recognized: model, hardware type,
115
+ software version and optionally a description if you need to differentiate two
116
+ YAML files:
117
+
118
+ - #model_#hardware_#software.yaml
119
+ - #model_#hardware_#software_#description.yaml
120
+
121
+ Examples:
122
+
123
+ - garderos_R7709_003_006_068.yaml
124
+ - iosxe_C9200L-24P-4G_17.09.04a.yaml
125
+ - asa_5512_9.12-4-67_single-context.yaml
126
+
127
+ ### Interactive mode
128
+ The `device2yaml.rb` script is a little dumb and needs some help, especially
129
+ when having a device sending its output page by page and requiring you to press
130
+ space for the next page. `device2yaml.rb` does not know how to handle this.
131
+
132
+ While `device2yaml.rb` is running, you can type anything to the keyboard, it
133
+ will be send to the remote device. So you can press space or 'n' to get the
134
+ next page.
135
+
136
+ You can also use this to enter an enable password.
137
+
138
+ If you press the "Esc" key, `device2yaml.rb` will not wait for the idle timeout
139
+ and will process the next command right away.
140
+
141
+ ### YAML Format
142
+ The yaml file has three sections:
143
+ - init_prompt: describing the lines send by the device before we can send a
144
+ command. It usually includes MOTD banners, and must include the first prompt.
145
+ - commands: the commands the oxidized model sends to the network device and the
146
+ expected output.
147
+ - oxidized_output: the expected output of oxidized, so that you can compare it
148
+ to the output generated by the unit test. This is optional and only used for
149
+ unit tests.
150
+
151
+ The outputs are multiline and use YAML block scalars (`|`), with the trailing \n
152
+ removed (`-` after `|`). The outputs include the echo of the given command and
153
+ the next prompt. Escape characters are coded in Ruby style (\n, \r...).
154
+
155
+ Here is a shortened example of a YAML file:
156
+ ```yaml
157
+ ---
158
+ init_prompt: |-
159
+ \e[4m\rLAB-R1234_Garderos#\e[m\x20
160
+ commands:
161
+ show system version: |-
162
+ show system version
163
+ grs-gwuz-armel/003_005_068 (Garderos; 2021-04-30 16:19:35)
164
+ \e[4m\rLAB-R1234_Garderos#\e[m\x20
165
+ # ...
166
+ exit: ""
167
+ oxidized_output: |
168
+ # grs-gwuz-armel/003_005_068 (Garderos; 2021-04-30 16:19:35)
169
+ #\x20
170
+ # ...
171
+ ```
172
+
173
+
@@ -0,0 +1,9 @@
1
+ no page
2
+ show version
3
+ show environment
4
+ show module
5
+ show interface transceiver
6
+ show system | exclude "Up Time" | exclude "CPU" | exclude "Memory" | exclude "Pkts .x" | exclude "Lowest" | exclude "Missed"
7
+ show running-config
8
+ show system
9
+ exit
@@ -0,0 +1,5 @@
1
+ show version
2
+ show activate status
3
+ show aps
4
+ show running-config no-encrypt
5
+ exit
@@ -0,0 +1,7 @@
1
+ enable
2
+ terminal pager 0
3
+ show mode
4
+ show version
5
+ show inventory
6
+ more system:running-config
7
+ exit
@@ -0,0 +1,7 @@
1
+ terminal length 0
2
+ terminal width 0
3
+ show version
4
+ show vtp status
5
+ show inventory
6
+ show running-config
7
+ exit
@@ -0,0 +1,5 @@
1
+ terminal length 0
2
+ show version
3
+ show inventory
4
+ show running-config
5
+ exit
@@ -0,0 +1,5 @@
1
+ /system resource print
2
+ /system package update print
3
+ /system history print without-paging
4
+ /export show-sensitive
5
+ quit
@@ -0,0 +1,11 @@
1
+ environment more false
2
+ show system information
3
+ show card state
4
+ show chassis
5
+ file show bootlog.txt
6
+ admin show configuration debug full-context
7
+ file show config.dbg
8
+ admin show configuration configure | match persistent-indices post-lines 10000
9
+ admin show configuration bof full-context
10
+ admin show configuration configure full-context
11
+ logout
@@ -0,0 +1,225 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'net/ssh'
5
+ require 'optparse'
6
+ require 'etc'
7
+ require 'timeout'
8
+
9
+ # This scripts logs in a network device and outputs a yaml file that can be
10
+ # used for model unit tests in spec/model/
11
+
12
+ # This script is quick & dirty - it grew with the time an could be a project
13
+ # for its own. It works, and that should be enough ;-)
14
+
15
+ ################# Methods
16
+ # Runs cmd in the ssh session, either im exec mode or with a tty
17
+ # saves the output to @output
18
+ def ssh_exec(cmd)
19
+ puts "\n### Sending #{cmd}..."
20
+ @output&.puts " #{cmd}: |-"
21
+
22
+ if @exec_mode
23
+ @ssh_output = @ssh.exec! cmd + "\n"
24
+ else
25
+ @ses.send_data cmd + "\n"
26
+ shell_wait
27
+ end
28
+ yaml_output(' ')
29
+ end
30
+
31
+ # Wait for the ssh command to be executed, with an idle timout @idle_timeout
32
+ # Pressing CTRL-C exits the script
33
+ # Pressing ESC termiates the idle timeout
34
+ def shell_wait
35
+ @ssh_output = ''
36
+ # ssh_output gets appended by chanel.on-data (below)
37
+ # We store the current length of @ssh_output in @ssh_output_length
38
+ # if @ssh_output.length is bigger than @ssh_output_length, we got new data
39
+ @ssh_output_length = 0
40
+
41
+ # Keep track of time for idle timeout
42
+ start_time = Time.now
43
+
44
+ # Loop & wait for @idle_timeout seconds after last output
45
+ # 0.1 means that the loop should run at least once per 0.1 second
46
+ @ssh.loop(0.1) do
47
+ # if @ssh_output is longer than our saved length, we got new output
48
+ if @ssh_output_length < @ssh_output.length
49
+ # reset the timer and save the new output length
50
+ start_time = Time.now
51
+ @ssh_output_length = @ssh_output.length
52
+ end
53
+
54
+ # We wait for 0.1 seconds if a key was pressed
55
+ begin
56
+ Timeout.timeout(0.1) do
57
+ # Get input // this is a blocking call
58
+ char = $stdin.getch
59
+ # If ctrl-c is pressed, exit the script
60
+ if char == "\u0003"
61
+ puts '### CTRL-C pressed, exiting'
62
+ cleanup
63
+ exit
64
+ end
65
+ # If escape is pressed, terminate idle timeout
66
+ if char == "\e"
67
+ puts "\n### ESC pressed, skipping idle timeout"
68
+ return false
69
+ else
70
+ # if not, send the char through ssh
71
+ @ses.send_data char
72
+ end
73
+ end
74
+ rescue Timeout::Error
75
+ # No key pressed
76
+ end
77
+
78
+ # exit the loop when the @idle_timeout has been reached (false = exit)
79
+ Time.now - start_time < @idle_timeout
80
+ end
81
+ end
82
+
83
+ def yaml_output(prepend = '')
84
+ # Now print the collected output to @output
85
+ firstline = true
86
+
87
+ # as we want to prepend 'prepend' to each line, we need each_line and chomp
88
+ # chomp removes the trainling \n
89
+ @ssh_output.each_line(chomp: true) do |line|
90
+ # encode line and remove the first and the trailing double quote
91
+ line = line.dump[1..-2]
92
+ if firstline
93
+ # Make sure the leading space of the first line (if present)
94
+ # is coded with \0x20 or YAML block scalars won't work
95
+ line.sub!(/^\A /, '\x20')
96
+ firstline = false
97
+ end
98
+ # Make sure trailing white spaces are coded with \0x20
99
+ line.gsub!(/ $/, '\x20')
100
+ # prepend white spaces for the yaml block scalar
101
+ line = prepend + line
102
+ @output&.puts line
103
+ end
104
+ end
105
+
106
+ def cleanup
107
+ (@ssh.close rescue true) unless @ssh.closed?
108
+ @output&.close
109
+ end
110
+
111
+ ################# Main loop
112
+
113
+ # Define options
114
+ options = {}
115
+ optparse = OptionParser.new do |opts|
116
+ opts.banner = "Usage: device2yaml.rb [user@]host [options]"
117
+
118
+ opts.on('-c', '--cmdset file', 'Mandatory: specify the commands to be run') do |file|
119
+ options[:cmdset] = file
120
+ end
121
+ opts.on('-o', '--output file', 'Specify an output YAML-file') do |file|
122
+ options[:output] = file
123
+ end
124
+ opts.on('-t', '--timeout value', Integer, 'Specify the idle timeout beween commands (default: 5 seconds)') do |timeout|
125
+ options[:timeout] = timeout
126
+ end
127
+ opts.on('-e', '--exec-mode', 'Run ssh in exec mode (without tty)') { @exec_mode = true }
128
+ opts.on '-h', '--help', 'Print this help' do
129
+ puts opts
130
+ exit
131
+ end
132
+ end
133
+
134
+ # Catch and parse the first argument
135
+ if ARGV[0] && ARGV[0][0] != '-'
136
+ argument = ARGV.shift
137
+ if argument.include?('@')
138
+ ssh_user, ssh_host = argument.split('@')
139
+ else
140
+ ssh_user = Etc.getlogin
141
+ ssh_host = argument
142
+ end
143
+ else
144
+ puts 'Missing a host to connect to...'
145
+ puts
146
+ puts optparse
147
+ exit 1
148
+ end
149
+
150
+ # Parse the options
151
+ optparse.parse!
152
+
153
+ # Get the commands to be run against ssh_host
154
+ unless options[:cmdset]
155
+ puts 'Missing a command set, use option -c'
156
+ puts
157
+ puts optparse
158
+ exit 1
159
+ end
160
+ # make an array of commands to send, ignore empty lines
161
+ ssh_commands = File.read(options[:cmdset]).split(/\n+|\r+/)
162
+
163
+ # Defaut idle timeout: 5 seconds, as tests showed that 2 seconds is too short
164
+ @idle_timeout = options[:timeout] || 5
165
+
166
+ # We will use safe navifation (&.) to call the methods on @output only
167
+ # if @output is not nil
168
+ @output = options[:output] ? File.open(options[:output], 'w') : nil
169
+
170
+ @ssh = Net::SSH.start(ssh_host,
171
+ ssh_user,
172
+ { timeout: 10,
173
+ append_all_supported_algorithms: true })
174
+
175
+ @ssh_output = ''
176
+
177
+ unless @exec_mode
178
+ @ses = @ssh.open_channel do |ch|
179
+ ch.on_data do |_ch, data|
180
+ @ssh_output += data
181
+ # Output the data to stdout for interactive control
182
+ # remove ANSI escape codes, as they can produce problems
183
+ # The code will be printed as '\e[123m' in the output
184
+ print data.gsub("\e", '\e')
185
+ end
186
+ ch.request_pty(term: 'vt100') do |_ch, success_pty|
187
+ raise "Can't get PTY" unless success_pty
188
+
189
+ ch.send_channel_request 'shell' do |_ch, success_shell|
190
+ raise "Can't get shell" unless success_shell
191
+ end
192
+ end
193
+ ch.on_extended_data do |_ch, _type, data|
194
+ $stderr.print "Error: #{data}\n"
195
+ end
196
+ end
197
+ end
198
+
199
+ # YAML begin of file
200
+ @output&.puts '---'
201
+
202
+ if @exec_mode
203
+ # init prompt does not exist and is empty in exec mode
204
+ @output&.puts 'init_prompt:'
205
+ else
206
+ # get motd and first prompt
207
+ @output&.puts 'init_prompt: |-'
208
+ shell_wait
209
+ yaml_output ' '
210
+ end
211
+
212
+ @output&.puts "commands:"
213
+
214
+ begin
215
+ ssh_commands.each do |cmd|
216
+ ssh_exec cmd
217
+ end
218
+ rescue Errno::ECONNRESET, Net::SSH::Disconnect, IOError => e
219
+ puts "### Connection closed with message: #{e.message}"
220
+ end
221
+
222
+ @output&.puts 'oxidized_output: |'
223
+ @output&.puts ' !! needs to be written by hand or copy & paste from model output'
224
+
225
+ cleanup