oxidized 0.34.0 → 0.34.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0c03871264e842280577898104fee04193865836f6a36f9e271fc899723c0490
4
- data.tar.gz: f63f80d3220f6112f5e20955d7f519628d86a358502b907ebe196ad85126fdc3
3
+ metadata.gz: f51898465cc98bf27a9bb2259b1e359f7f52f2c31b23eac63e7730f0eabbb8b8
4
+ data.tar.gz: 6c45f1b142609bc44b99025b4485b25fde43844738bd489dc2994df77ecf47d7
5
5
  SHA512:
6
- metadata.gz: 6f2a29dd10a0ecdfd43a5b4607e237a778ad7776d017d0c09f6cbe35bb01d2a20b1eefe733a995630355346b876ec0c15a504e72f6200a2362b5597da01ca0cf
7
- data.tar.gz: 5030d36380278ad562d7242d090dcd12b73572b0c97d1ac9f0d6b654a3f530349923b8d83561fc2ccd2f7b68d1b4b503e0ba405a72589ad9bd916f50b74e7e8c
6
+ metadata.gz: c613a1c2c21144f6c064cb2dfaf94e7fa88248c499c43d3408cbce0e286bee477b09623c6432852b839c8c7f2c3a1511f9634d07ebc3bcbba5037032157f991a
7
+ data.tar.gz: 2cb4692eab7ebbd916264bae356d08b6f437a6f514da5a815bd1c79242d9a2cd558fcef13ad0f56eb6bb9ba74f054deba661a46b563c4a805ad4be4ede34808d
@@ -19,10 +19,8 @@ jobs:
19
19
  runs-on: ubuntu-latest
20
20
  strategy:
21
21
  matrix:
22
- ruby-version: ['3.1', '3.2', '3.3', '3.4']
23
- # ruby-head disabled because of problem with bundler (2025-06-27)
24
- # ruby-version: ['3.1', '3.2', '3.3', '3.4', 'ruby-head']
25
- # continue-on-error: ${{ matrix.ruby-version == 'ruby-head' }}
22
+ ruby-version: ['3.1', '3.2', '3.3', '3.4', 'ruby-head']
23
+ continue-on-error: ${{ matrix.ruby-version == 'ruby-head' }}
26
24
 
27
25
  steps:
28
26
  - uses: actions/checkout@v4
data/.rubocop_todo.yml CHANGED
@@ -1,6 +1,6 @@
1
1
  # This configuration was generated by
2
2
  # `rubocop --auto-gen-config`
3
- # on 2025-07-15 08:50:44 UTC using RuboCop version 1.78.0.
3
+ # on 2025-08-01 14:00:10 UTC using RuboCop version 1.79.1.
4
4
  # The point is for the user to remove these configuration records
5
5
  # one by one as the offenses are removed from the code base.
6
6
  # Note that changes in the inspected code, or installation of new
data/CHANGELOG.md CHANGED
@@ -4,11 +4,47 @@ All notable changes to this project will be documented in this file.
4
4
 
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
6
6
 
7
+ ## [0.34.2 – 2025-08-01]
8
+ This release mainly fixes a bug in input/scp that made ssh raise an error when
9
+ closing a closed connection (Issue #3583).
10
+
11
+ A fix for config vars (Issue #3536) changes the way oxidized stores its
12
+ vars internally (symblos => strings). Libraries depending on oxidized internal
13
+ structures may have problem with this. oxidized-web was fixed in Release 0.17.1.
14
+
15
+ ### Added
16
+ - Absolute time limit for a fetch job (default: 300 seconds) (@robertcheramy)
17
+
18
+ ### Changed
19
+ - slackdiff: Attempt to join the channel if Errors::NotInChannel is encountered (@varesa)
20
+
21
+ ### Fixed
22
+ - SSH raises error when closing a closed connection. Fixes #3583 (@ytti)
23
+ - Config vars will not fall back to less specific. Fixes #3536 (@ytti)
24
+ - input/scp: make common errors produce a warning, not a crashfile (@robertcheramy)
25
+ - input/scp: implement timeouts. Fixes #3590 (@robertcheramy, @ytti)
26
+ - model/mtrlrfs: add missing prompt (@R3thos)
27
+ - slackdiff: Respect the HTTP proxy configuration while uploading the file. Fixes #3534 (@varesa)
28
+ - logging (syslog): do not write two timestamps (Fixed in semanticlogger) (@robertcheramy)
29
+
30
+
31
+ ## [0.34.1 - 2025-07-18]
32
+ This release contains small fixes and will include the new version of oxidized-web (0.17.0) in the docker container.
33
+
34
+ ### Changed
35
+ - github: run ruby CI against ruby-head (@robertcheramy)
36
+
37
+ ### Fixed
38
+ - input/ssh: hide Net::SSH errors and only display fatal logs unless input.debug = true. Fixes: #3574 (@robertcheramy)
39
+ - junos: fix unfrozen literal strings (@robertcheramy)
40
+ - spec/model: fix unfrozen literal strings and set a default prompt (@robertcheramy)
41
+
42
+
7
43
  ## [0.34.0 - 2025-07-15]
8
44
  :warning: This release introduces a [new logging system](docs/Configuration.md#logging),
9
45
  based on [semantic logger](https://logger.rocketjob.io/). The old configuration
10
46
  (`log`, `syslog`) is still supported but obsolete and will be removed in a
11
- future release, so be sure to migrate your configureation.
47
+ future release, so be sure to migrate your configuration.
12
48
 
13
49
  ### Added
14
50
  - add iosxr support to SyslogMonitor (@deesel)
data/Dockerfile CHANGED
@@ -79,15 +79,14 @@ RUN apt-get -qy update && \
79
79
  # docker automated build gets shallow copy, but non-shallow copy cannot be unshallowed
80
80
  git fetch --unshallow || true && \
81
81
  rake install && \
82
+ # install oxidized-web
83
+ gem install oxidized-web --no-document && \
82
84
  # remove the packages we do not need.
83
85
  apt-get -qy remove build-essential ruby-dev && \
84
86
  apt-get -qy autoremove && \
85
87
  apt-get clean && \
86
88
  rm -rf /var/lib/apt/lists/*
87
89
 
88
- # install oxidized-web
89
- RUN gem install oxidized-web --no-document
90
-
91
90
  # clean up
92
91
  WORKDIR /
93
92
  RUN rm -rf /tmp/oxidized
data/Rakefile CHANGED
@@ -26,6 +26,7 @@ task :test do
26
26
  Rake::TestTask.new do |t|
27
27
  t.libs << 'spec'
28
28
  t.test_files = FileList['spec/**/*_spec.rb']
29
+ t.ruby_opts = ['-W:deprecated']
29
30
  # Don't display ambiguity warning between regexp and division in models
30
31
  t.warning = false
31
32
  t.verbose = true
@@ -47,7 +48,7 @@ end
47
48
 
48
49
  desc 'Tag the release'
49
50
  task :tag do
50
- system "git tag #{gemspec.version}"
51
+ system "git tag #{gemspec.version} -m 'Release #{gemspec.version}'"
51
52
  end
52
53
 
53
54
  desc 'Push to rubygems'
@@ -1,30 +1,11 @@
1
1
  # Configuration
2
2
 
3
- ## Debugging
4
-
5
- In case a model plugin doesn't work correctly (ios, procurve, etc.), you can
6
- enable live debugging of SSH/Telnet sessions. Just add a `debug` option
7
- containing the value true to the `input` section. The log files will be created
8
- depending on the parent directory of the logfile option.
9
-
10
- The following example will log an active ssh/telnet session
11
- `/home/oxidized/.config/oxidized/log/<IP-Address>-<PROTOCOL>`. The file will be
12
- truncated on each consecutive ssh/telnet session, so you need to put a `tailf`
13
- or `tail -f` on that file!
14
-
15
- ```yaml
16
- log: /home/oxidized/.config/oxidized/log
17
-
18
- # ...
19
-
20
- input:
21
- default: ssh, telnet
22
- debug: true
23
- ssh:
24
- secure: false
25
- http:
26
- ssl_verify: true
27
- ```
3
+ ## Modules
4
+ The configuration of each module is described in its respective sub-configuration file:
5
+ * [Inputs.md](Inputs.md)
6
+ * [Outputs.md](Outputs.md)
7
+ * [Sources.md](Sources.md)
8
+ * [Hooks.md](Hooks.md)
28
9
 
29
10
  ## Privileged mode
30
11
 
@@ -65,142 +46,22 @@ The above strips out snmp community strings from your saved configs.
65
46
 
66
47
  **NOTE:** Removing secrets reduces the usefulness as a full configuration backup, but it may make sharing configs easier.
67
48
 
68
- ## Disabling SSH exec channels
69
-
70
- Oxidized uses exec channels to make information extraction simpler, but there
71
- are some situations where this doesn't work well, e.g. configuring devices. This
72
- feature can be turned off by setting the `ssh_no_exec`
73
- variable.
74
-
75
- ```yaml
76
- vars:
77
- ssh_no_exec: true
78
- ```
79
-
80
- ## Disabling SSH keepalives
81
-
82
- Oxidized SSH input makes use of SSH keepalives to prevent timeouts from slower
83
- devices and to quickly tear down stale sessions in larger deployments. There
84
- have been reports of SSH keepalives breaking compatibility with certain OS
85
- types. They can be disabled using the `ssh_no_keepalive` variable on a per-node
86
- basis (by specifying it in the source) or configured application-wide.
87
-
88
- ```yaml
89
- vars:
90
- ssh_no_keepalive: true
91
- ```
92
-
93
- ## SSH Auth Methods
94
-
95
- By default, Oxidized registers the following auth methods: `none`, `publickey` and `password`. However you can configure this globally, by groups, models or nodes.
96
-
97
- ```yaml
98
- vars:
99
- auth_methods: [ "none", "publickey", "password", "keyboard-interactive" ]
100
- ```
101
-
102
- ## Public Key Authentication with SSH
103
-
104
- Instead of password-based login, Oxidized can make use of key-based SSH
105
- authentication.
49
+ ## Timeout and Time limit
50
+ You can configure when oxidized will `timeout` while fetching a configuration
51
+ (default: 20 seconds), and how much absolute time (`timelimit`) the fetching
52
+ is allowed to last (default: 300 seconds, or 5 minutes):
106
53
 
107
- You can tell Oxidized to use one or more private keys globally, or specify the
108
- key to be used on a per-node basis. The latter can be done by mapping the
109
- `ssh_keys` variable through the active source.
54
+ * `timeout`: Maximum time to wait for a single operation during config fetching.
55
+ Not every input module has an implemented timeout.
56
+ * `timelimit`: Maximum total time allowed for the entire fetch job. It is
57
+ independent of input modules and will always be enforced.
110
58
 
111
- Global:
59
+ If `timelimit`is reached, the fetch job will be killed and will produce a
60
+ warning. The job status will be set to `timelimit`.
112
61
 
113
62
  ```yaml
114
- vars:
115
- ssh_keys: "~/.ssh/id_rsa"
116
- ```
117
-
118
- Per-Node:
119
-
120
- ```yaml
121
- # ...
122
- map:
123
- name: 0
124
- model: 1
125
- vars_map:
126
- enable: 2
127
- ssh_keys: 3
128
- # ...
129
- ```
130
-
131
- If you are using a non-standard path, especially when copying the private key
132
- via a secured channel, make sure that the permissions are set correctly:
133
-
134
- ```bash
135
- foo@bar:~$ ls -la ~/.ssh/
136
- total 20
137
- drwx------ 2 oxidized oxidized 4096 Mar 13 17:03 .
138
- drwx------ 5 oxidized oxidized 4096 Mar 13 21:40 ..
139
- -r-------- 1 oxidized oxidized 103 Mar 13 17:03 authorized_keys
140
- -rw------- 1 oxidized oxidized 399 Mar 13 17:02 id_ed25519
141
- -rw-r--r-- 1 oxidized oxidized 94 Mar 13 17:02 id_ed25519.pub
142
- ```
143
-
144
- Finally, multiple private keys can be specified as an array of file paths, such
145
- as `["~/.ssh/id_rsa", "~/.ssh/id_another_rsa"]`.
146
-
147
- ## SSH Proxy Command
148
-
149
- Oxidized can `ssh` through a proxy as well. To do so we just need to set
150
- `ssh_proxy` variable with the proxy host information and optionally set the
151
- `ssh_proxy_port` with the SSH port if it is not listening on port 22.
152
-
153
- This can be provided on a per-node basis by mapping the proper fields from your
154
- source.
155
-
156
- An example for a `csv` input source that maps the 4th field as the `ssh_proxy`
157
- value and the 5th field as `ssh_proxy_port`.
158
-
159
- ```yaml
160
- # ...
161
- map:
162
- name: 0
163
- model: 1
164
- vars_map:
165
- enable: 2
166
- ssh_proxy: 3
167
- ssh_proxy_port: 4
168
- # ...
169
- ```
170
-
171
- ## SSH enabling legacy algorithms
172
-
173
- When connecting to older firmware over SSH, it is sometimes necessary to enable
174
- legacy/disabled settings like KexAlgorithms, HostKeyAlgorithms, MAC or the
175
- Encryption.
176
-
177
- These settings can be provided on a per-node basis by mapping the ssh_kex,
178
- ssh_host_key, ssh_hmac and the ssh_encryption fields from you source.
179
-
180
- ```yaml
181
- # ...
182
- map:
183
- name: 0
184
- model: 1
185
- vars_map:
186
- enable: 2
187
- ssh_kex: 3
188
- ssh_host_key: 4
189
- ssh_hmac: 5
190
- ssh_encryption: 6
191
- # ...
192
- ```
193
-
194
- ## FTP Passive Mode
195
-
196
- Oxidized uses ftp passive mode by default. Some devices require passive mode to
197
- be disabled. To do so, we can set `input.ftp.passive` to false - this will make
198
- use of FTP active mode.
199
-
200
- ```yaml
201
- input:
202
- ftp:
203
- passive: false
63
+ timeout: 20
64
+ timelimit: 300
204
65
  ```
205
66
 
206
67
  ## Advanced Configuration
@@ -230,6 +91,7 @@ threads: 30 # maximum number of threads
230
91
  # true - always use the maximum number of threads
231
92
  use_max_threads: false
232
93
  timeout: 20
94
+ timelimit: 300
233
95
  retries: 3
234
96
  prompt: !ruby/regexp /^([\w.@-]+[#>]\s?)$/
235
97
  crash:
@@ -372,7 +234,7 @@ models:
372
234
  password: pass
373
235
  ```
374
236
 
375
- ### Options (credentials, vars, etc.) precedence:
237
+ ## Options (credentials, vars, etc.) precedence:
376
238
  From least to most important:
377
239
  - global options
378
240
  - model specific options
@@ -513,9 +375,6 @@ following appenders are currently supported:
513
375
  > `stderr` and `stdout` are mutually exclusive and will produce a warning if used
514
376
  > simultaneously.
515
377
 
516
- > Note: `syslog` currently produces two timestamps because of an issue in
517
- > [Sematic Logger](https://github.com/reidmorrison/semantic_logger/issues/316).
518
-
519
378
  > You can configure as many file appenders as you wish.
520
379
 
521
380
  You can set a log level globally and/or for each appender.
@@ -577,9 +436,8 @@ It will rotate between the log levels and log a warning with the new level
577
436
  If you specified a log level for an appender, this log level won't be
578
437
  changed.
579
438
 
580
- > :warning: **Warning** This currently does not work when oxidized-web is used
581
- > and will kill the whole oxidized application. This will be corrected in a
582
- > future release of oxidized-web.
439
+ > :warning: **Warning** You need oxidized-web 0.17.0 and above for this or
440
+ > it will kill the whole oxidized application.
583
441
 
584
442
  ### Dump running threads
585
443
  With the SIGTTIN signal, oxidized will log a backtrace for each of its threads.
data/docs/Hooks.md CHANGED
@@ -249,7 +249,7 @@ Your AWS credentials should be stored in `~/.aws/credentials`.
249
249
 
250
250
  ## Hook type: slackdiff
251
251
 
252
- The `slackdiff` hook posts colorized config diffs to a [Slack](https://www.slack.com) channel of your choice. It only triggers for `post_store` events.
252
+ The `slackdiff` hook posts colorized config diffs to a [Slack](https://www.slack.com) channel of your choice. It only triggers for `post_store` events. The used output must be capable of generating a diff. E.g. file output is not usable while git/gitcrypt will work.
253
253
 
254
254
  You will need to manually install the `slack-ruby-client` gem on your system:
255
255
 
@@ -270,7 +270,7 @@ hooks:
270
270
  channel: "CHANNEL_ID"
271
271
  ```
272
272
 
273
- The token parameter is a Slack API token that can be generated following [this tutorial](https://api.slack.com/tutorials/tracks/getting-a-token). Until Slack stops supporting them, legacy tokens can also be used.
273
+ The token parameter is a Slack API token that can be generated following [this tutorial](https://api.slack.com/tutorials/tracks/getting-a-token). Until Slack stops supporting them, legacy tokens can also be used. If the token has channels:join permission, the bot will attempt to automatically join the configured channel if necessary.
274
274
 
275
275
  Optionally you can disable snippets and post a formatted message, for instance linking to a commit in a git repo. Named parameters `%{node}`, `%{group}`, `%{model}` and `%{commitref}` are available.
276
276
 
data/docs/Inputs.md ADDED
@@ -0,0 +1,205 @@
1
+ # Inputs
2
+ ## Index
3
+ * Configuration
4
+ * [SSH](#ssh)
5
+ * [SCP](#scp)
6
+ * [FTP](#ftp)
7
+ * telnet
8
+ * http
9
+ * tftp
10
+ * exec
11
+ * [Debugging](#debugging)
12
+
13
+ ## SSH
14
+ ### Disabling SSH exec channels
15
+
16
+ Oxidized uses exec channels to make information extraction simpler, but there
17
+ are some situations where this doesn't work well, e.g. configuring devices. This
18
+ feature can be turned off by setting the `ssh_no_exec`
19
+ variable.
20
+
21
+ ```yaml
22
+ vars:
23
+ ssh_no_exec: true
24
+ ```
25
+
26
+ ### Disabling SSH keepalives
27
+
28
+ Oxidized SSH input makes use of SSH keepalives to prevent timeouts from slower
29
+ devices and to quickly tear down stale sessions in larger deployments. There
30
+ have been reports of SSH keepalives breaking compatibility with certain OS
31
+ types. They can be disabled using the `ssh_no_keepalive` variable on a per-node
32
+ basis (by specifying it in the source) or configured application-wide.
33
+
34
+ ```yaml
35
+ vars:
36
+ ssh_no_keepalive: true
37
+ ```
38
+
39
+ ### SSH Auth Methods
40
+
41
+ By default, Oxidized registers the following auth methods: `none`, `publickey` and `password`. However you can configure this globally, by groups, models or nodes.
42
+
43
+ ```yaml
44
+ vars:
45
+ auth_methods: [ "none", "publickey", "password", "keyboard-interactive" ]
46
+ ```
47
+
48
+ ### Public Key Authentication with SSH
49
+
50
+ Instead of password-based login, Oxidized can make use of key-based SSH
51
+ authentication.
52
+
53
+ You can tell Oxidized to use one or more private keys globally, or specify the
54
+ key to be used on a per-node basis. The latter can be done by mapping the
55
+ `ssh_keys` variable through the active source.
56
+
57
+ Global:
58
+
59
+ ```yaml
60
+ vars:
61
+ ssh_keys: "~/.ssh/id_rsa"
62
+ ```
63
+
64
+ Per-Node:
65
+
66
+ ```yaml
67
+ # ...
68
+ map:
69
+ name: 0
70
+ model: 1
71
+ vars_map:
72
+ enable: 2
73
+ ssh_keys: 3
74
+ # ...
75
+ ```
76
+
77
+ If you are using a non-standard path, especially when copying the private key
78
+ via a secured channel, make sure that the permissions are set correctly:
79
+
80
+ ```bash
81
+ foo@bar:~$ ls -la ~/.ssh/
82
+ total 20
83
+ drwx------ 2 oxidized oxidized 4096 Mar 13 17:03 .
84
+ drwx------ 5 oxidized oxidized 4096 Mar 13 21:40 ..
85
+ -r-------- 1 oxidized oxidized 103 Mar 13 17:03 authorized_keys
86
+ -rw------- 1 oxidized oxidized 399 Mar 13 17:02 id_ed25519
87
+ -rw-r--r-- 1 oxidized oxidized 94 Mar 13 17:02 id_ed25519.pub
88
+ ```
89
+
90
+ Finally, multiple private keys can be specified as an array of file paths, such
91
+ as `["~/.ssh/id_rsa", "~/.ssh/id_another_rsa"]`.
92
+
93
+ ### SSH Proxy Command
94
+
95
+ Oxidized can `ssh` through a proxy as well. To do so we just need to set
96
+ `ssh_proxy` variable with the proxy host information and optionally set the
97
+ `ssh_proxy_port` with the SSH port if it is not listening on port 22.
98
+
99
+ This can be provided on a per-node basis by mapping the proper fields from your
100
+ source.
101
+
102
+ An example for a `csv` input source that maps the 4th field as the `ssh_proxy`
103
+ value and the 5th field as `ssh_proxy_port`.
104
+
105
+ ```yaml
106
+ # ...
107
+ map:
108
+ name: 0
109
+ model: 1
110
+ vars_map:
111
+ enable: 2
112
+ ssh_proxy: 3
113
+ ssh_proxy_port: 4
114
+ # ...
115
+ ```
116
+
117
+ ### SSH enabling legacy algorithms
118
+
119
+ When connecting to older firmware over SSH, it is sometimes necessary to enable
120
+ legacy/disabled settings like KexAlgorithms, HostKeyAlgorithms, MAC or the
121
+ Encryption.
122
+
123
+ These settings can be provided on a per-node basis by mapping the ssh_kex,
124
+ ssh_host_key, ssh_hmac and the ssh_encryption fields from you source.
125
+
126
+ ```yaml
127
+ # ...
128
+ map:
129
+ name: 0
130
+ model: 1
131
+ vars_map:
132
+ enable: 2
133
+ ssh_kex: 3
134
+ ssh_host_key: 4
135
+ ssh_hmac: 5
136
+ ssh_encryption: 6
137
+ # ...
138
+ ```
139
+
140
+ ### Custom SSH port
141
+ Set the variable `ssh_port` to the desired value (default is 22).
142
+
143
+ ### SSH Host key verification
144
+ With the configuration `secure', you can set the ssh key verification:
145
+ - `true`: strict host verification, looking up the known host files
146
+ - `false` (default): disable host verification, accept any ssh key
147
+
148
+ ```
149
+ input:
150
+ ssh:
151
+ secure: true
152
+ ```
153
+
154
+ ## SCP
155
+ ### SSH Host key verification (SCP)
156
+ Same as for [SSH host key verification](#ssh-host-key-verification)
157
+
158
+ ```
159
+ input:
160
+ scp:
161
+ secure: true
162
+ ```
163
+
164
+ ### Custom SCP port
165
+ Set the variable `ssh_port` to the desired value (default is 22).
166
+
167
+ ## FTP
168
+ ### FTP Passive Mode
169
+
170
+ Oxidized uses ftp passive mode by default. Some devices require passive mode to
171
+ be disabled. To do so, we can set `input.ftp.passive` to false - this will make
172
+ use of FTP active mode.
173
+
174
+ ```yaml
175
+ input:
176
+ ftp:
177
+ passive: false
178
+ ```
179
+
180
+
181
+ ## Debugging
182
+
183
+ In case a model plugin doesn't work correctly (ios, procurve, etc.), you can
184
+ enable live debugging of SSH/Telnet sessions. Just add a `debug` option
185
+ containing the value true to the `input` section. The log files will be created
186
+ depending on the parent directory of the logfile option.
187
+
188
+ The following example will log an active ssh/telnet session
189
+ `/home/oxidized/.config/oxidized/log/<IP-Address>-<PROTOCOL>`. The file will be
190
+ truncated on each consecutive ssh/telnet session, so you need to put a `tailf`
191
+ or `tail -f` on that file!
192
+
193
+ ```yaml
194
+ log: /home/oxidized/.config/oxidized/log
195
+
196
+ # ...
197
+
198
+ input:
199
+ default: ssh, telnet
200
+ debug: true
201
+ ssh:
202
+ secure: false
203
+ http:
204
+ ssl_verify: true
205
+ ```
data/docs/Release.md CHANGED
@@ -2,22 +2,27 @@
2
2
  This document is targeted at oxidized maintainers. It describes the release process.
3
3
 
4
4
  ## Version numbering
5
- Oxidized versions are nummered like major.minor.patch
5
+ Oxidized versions are numbered like major.minor.patch
6
6
  - currently, the major version is 0.
7
7
  - minor is incremented when releasing new features.
8
8
  - patch is incremented when releasing fixes only.
9
9
 
10
+ ## Create a release branch
11
+ Name the release branch `release/0.xx.yy`
12
+
10
13
  ## Review changes
11
- Run `git diff 0.30.0..master` (where `0.30.0` is to be changed to the last release) and review
14
+ Run `git diff 0.30.0` (where `0.30.0` is to be changed to the last release) and review
12
15
  all the changes that have been done. Have a specific look at changes you don't understand.
13
16
 
14
- For a graphical compare, use `git difftool -d 0.30.0..master`.
17
+ For a graphical compare, use `git difftool -d 0.30.0`.
18
+
19
+ Commit fixes to the release branch
15
20
 
16
21
  ## Update the gem dependencies to the latest versions
17
22
  ```
18
- bundle outaded
23
+ bundle outdated
19
24
  bundle update
20
- bundle outaded
25
+ bundle outdated
21
26
  ```
22
27
 
23
28
  ## Update rubocup .rubocop_todo.yml
@@ -29,9 +34,11 @@ If you change some code => Restart the release process at the beginning ;-)
29
34
  ## Make sure the file permissions are correct
30
35
  Run `bundle exec rake chmod`
31
36
 
32
- ## Create a release branch
33
- Name the release branch `release/0.xx.yy`
37
+ ## Test !
38
+ Test the git code and the container against as much device types and
39
+ environments as you can.
34
40
 
41
+ ## Bump the version
35
42
  Update CHANGELOG.md:
36
43
  - review it
37
44
  - add release notes
@@ -42,16 +49,13 @@ Change the version in `lib/oxidized/version.rb`
42
49
  Upload the branch to github, make a Pull Request for it.
43
50
 
44
51
  ## Make sure you pass all GitHub CI
45
- They test different ruby versions, the docker build process and codeql.
46
-
47
- ## Test !
48
- Test the git code and the container against as much device types and
49
- environments as you can.
52
+ They test different ruby versions an run security checks on the code (codeql).
50
53
 
51
54
  ## Prepare the release in your working repository
52
- 1. Merge the Pull Request into master
53
- 2. `git pull` master
54
- 3. Tag the commit with `git tag -a 0.xx.yy -m "Release 0.xx.yy"`
55
+ 1. Merge the Pull Request into master with the commit message
56
+ `chore(release): release version 0.3x.y`
57
+ 2. `git pull` on master
58
+ 3. Tag the commit with `git tag -a 0.xx.yy -m "Release 0.xx.yy"` or `rake tag`
55
59
  4. Build the gem with ‘rake build’
56
60
  5. Run `git diff` to check if there have been more changes (there shouldn't)
57
61
  6. Install an test the gem locally
data/extra/device2yaml.rb CHANGED
@@ -111,7 +111,7 @@ def yaml_output(prepend = '')
111
111
  end
112
112
 
113
113
  def cleanup
114
- (@ssh.close rescue true) unless @ssh.closed?
114
+ (@ssh.close rescue true) unless @ssh.closed? # rubocop:disable Style/RedundantParentheses
115
115
  @output&.close
116
116
  end
117
117
 
data/extra/syslog.rb CHANGED
@@ -141,7 +141,7 @@ module Oxidized
141
141
  if Oxidized::CFG.syslogd.resolve == false
142
142
  ipaddr
143
143
  else
144
- name = (Resolv.getname ipaddr.to_s rescue ipaddr)
144
+ name = (Resolv.getname ipaddr.to_s rescue ipaddr) # rubocop:disable Style/RedundantParentheses
145
145
  Oxidized::CFG.syslogd.dns_map.each { |re, sub| name.sub! Regexp.new(re.to_s), sub }
146
146
  name
147
147
  end
@@ -4,21 +4,32 @@ module Oxidized
4
4
  # convenience method for accessing node, group or global level user variables
5
5
  def vars(name)
6
6
  model_name = @node.model.class.name.to_s.downcase
7
- if @node.vars&.has_key?(name)
8
- @node.vars[name]
9
- elsif Oxidized.config.groups.has_key?(@node.group) &&
10
- Oxidized.config.groups[@node.group].models.has_key(model_name) &&
11
- Oxidized.config.groups[@node.group].models[model_name].vars.has_key?(name.to_s)
12
- Oxidized.config.groups[@node.group].models[model_name].vars[name.to_s]
13
- elsif Oxidized.config.groups.has_key?(@node.group) &&
14
- Oxidized.config.groups[@node.group].vars.has_key?(name.to_s)
15
- Oxidized.config.groups[@node.group].vars[name.to_s]
16
- elsif Oxidized.config.models.has_key(model_name) &&
17
- Oxidized.config.models[model_name].vars.has_key?(name.to_s)
18
- Oxidized.config.models[model_name].vars[name.to_s]
19
- elsif Oxidized.config.vars.has_key?(name.to_s)
20
- Oxidized.config.vars[name.to_s]
7
+ groups = Oxidized.config.groups
8
+ models = Oxidized.config.models
9
+ group = groups[@node.group] if groups.has_key?(@node.group)
10
+ model = models[model_name] if models.has_key?(model_name)
11
+ group_model = group.models[model_name] if group&.models&.has_key?(model_name)
12
+
13
+ scopes = {
14
+ node: @node.vars,
15
+ group_model: group_model&.vars,
16
+ group: group&.vars,
17
+ model: model&.vars,
18
+ vars: Oxidized.config.vars
19
+ }
20
+
21
+ scopes.each do |scope_name, scope|
22
+ next unless scope&.has_key?(name.to_s)
23
+
24
+ val = scope[name.to_s]
25
+ if val.nil?
26
+ Oxidized.logger.debug "vars.rb: scope #{scope_name} has key #{name} with value nil, ignoring scope"
27
+ else
28
+ Oxidized.logger.debug "vars.rb: scope #{scope_name} has key #{name} with value #{val}, using scope"
29
+ return val
30
+ end
21
31
  end
32
+ nil
22
33
  end
23
34
  end
24
35
  end
@@ -32,6 +32,7 @@ module Oxidized
32
32
  asetus.default.threads = 30
33
33
  asetus.default.use_max_threads = false
34
34
  asetus.default.timeout = 20
35
+ asetus.default.timelimit = 300
35
36
  asetus.default.retries = 3
36
37
  asetus.default.prompt = /^([\w.@-]+[#>]\s?)$/
37
38
  asetus.default.next_adds_job = false # if true, /next adds job, so device is fetched immmeiately
@@ -11,14 +11,20 @@ class SlackDiff < Oxidized::Hook
11
11
  raise KeyError, 'hook.channel is required' unless cfg.has_key?('channel')
12
12
  end
13
13
 
14
- def slack_upload(client, title, content, channel)
14
+ def slack_upload(client, title, content, channel, proxy)
15
15
  logger.info "Posting diff as snippet to #{channel}"
16
16
  upload_dest = client.files_getUploadURLExternal(filename: "change",
17
17
  length: content.length,
18
18
  snippet_type: "diff")
19
19
  file_uri = URI.parse(upload_dest[:upload_url])
20
20
 
21
- http = Net::HTTP.new(file_uri.host, file_uri.port)
21
+ proxy_uri = URI.parse(proxy) if proxy
22
+ proxy_address = proxy_uri ? proxy_uri.host : :ENV
23
+ proxy_port = proxy_uri&.port
24
+ proxy_user = proxy_uri&.user
25
+ proxy_pass = proxy_uri&.password
26
+
27
+ http = Net::HTTP.new(file_uri.host, file_uri.port, proxy_address, proxy_port, proxy_user, proxy_pass)
22
28
  http.use_ssl = true
23
29
 
24
30
  request = Net::HTTP::Post.new(file_uri.request_uri, { Host: file_uri.host })
@@ -31,8 +37,15 @@ class SlackDiff < Oxidized::Hook
31
37
  id: upload_dest[:file_id],
32
38
  title: title
33
39
  }]
34
- client.files_completeUploadExternal(channel_id: channel,
35
- files: files.to_json)
40
+ begin
41
+ client.files_completeUploadExternal(channel_id: channel,
42
+ files: files.to_json)
43
+ rescue Slack::Web::Api::Errors::NotInChannel
44
+ logger.info "Not in specified channel, attempting to join"
45
+ client.conversations_join(channel: channel)
46
+ client.files_completeUploadExternal(channel_id: channel,
47
+ files: files.to_json)
48
+ end
36
49
  end
37
50
 
38
51
  def run_hook(ctx)
@@ -53,7 +66,7 @@ class SlackDiff < Oxidized::Hook
53
66
  unless diff == "no diffs"
54
67
  title = "#{ctx.node.name} #{ctx.node.group} #{ctx.node.model.class.name.to_s.downcase}"
55
68
  content = diff[:patch].lines.to_a[4..-1].join
56
- slack_upload(client, title, content, cfg.channel)
69
+ slack_upload(client, title, content, cfg.channel, cfg.has_key?('proxy') ? cfg.proxy : nil)
57
70
  end
58
71
  end
59
72
  # message custom formatted - optional
@@ -7,11 +7,14 @@ module Oxidized
7
7
  class SCP < Input
8
8
  RESCUE_FAIL = {
9
9
  debug: [
10
- # Net::SSH::Disconnect,
10
+ Net::SSH::Disconnect,
11
+ Net::SSH::ConnectionTimeout
11
12
  ],
12
13
  warn: [
13
- # RuntimeError,
14
- # Net::SSH::AuthenticationFailed,
14
+ Net::SCP::Error,
15
+ Net::SSH::HostKeyUnknown,
16
+ Net::SSH::AuthenticationFailed,
17
+ Timeout::Error
15
18
  ]
16
19
  }.freeze
17
20
  include Input::CLI
@@ -20,17 +23,39 @@ module Oxidized
20
23
  @node = node
21
24
  @node.model.cfg['scp'].each { |cb| instance_exec(&cb) }
22
25
  @log = File.open(Oxidized::Config::LOG + "/#{@node.ip}-scp", 'w') if Oxidized.config.input.debug?
23
- @ssh = Net::SSH.start(@node.ip, @node.auth[:username], password: @node.auth[:password])
26
+ @ssh = Net::SSH.start(@node.ip, @node.auth[:username], make_ssh_opts)
24
27
  connected?
25
28
  end
26
29
 
30
+ def make_ssh_opts
31
+ secure = Oxidized.config.input.scp.secure?
32
+ ssh_opts = {
33
+ number_of_password_prompts: 0,
34
+ verify_host_key: secure ? :always : :never,
35
+ append_all_supported_algorithms: true,
36
+ password: @node.auth[:password],
37
+ timeout: Oxidized.config.timeout,
38
+ port: (vars(:ssh_port) || 22).to_i,
39
+ forward_agent: false
40
+ }
41
+
42
+ # Use our logger for Net::SSH
43
+ ssh_logger = SemanticLogger[Net::SSH]
44
+ ssh_logger.level = Oxidized.config.input.debug? ? :debug : :fatal
45
+ ssh_opts[:logger] = ssh_logger
46
+
47
+ ssh_opts
48
+ end
49
+
27
50
  def connected?
28
51
  @ssh && (not @ssh.closed?)
29
52
  end
30
53
 
31
54
  def cmd(file)
32
55
  logger.debug "SCP: #{file} @ #{@node.name}"
33
- @ssh.scp.download!(file)
56
+ Timeout.timeout(Oxidized.config.timeout) do
57
+ @ssh.scp.download!(file)
58
+ end
34
59
  end
35
60
 
36
61
  def send(my_proc)
@@ -44,7 +69,11 @@ module Oxidized
44
69
  private
45
70
 
46
71
  def disconnect
47
- @ssh.close
72
+ Timeout.timeout(Oxidized.config.timeout) do
73
+ @ssh.close
74
+ end
75
+ rescue Timeout::Error
76
+ logger.debug "#{@node.name} timed out while disconnecting"
48
77
  ensure
49
78
  @log.close if Oxidized.config.input.debug?
50
79
  end
@@ -14,6 +14,7 @@ module Oxidized
14
14
  ]
15
15
  }.freeze
16
16
  include Input::CLI
17
+
17
18
  class NoShell < OxidizedError; end
18
19
 
19
20
  def connect(node) # rubocop:disable Naming/PredicateMethod
@@ -81,12 +82,12 @@ module Oxidized
81
82
  Timeout.timeout(Oxidized.config.timeout) { @ssh.loop }
82
83
  rescue Errno::ECONNRESET, Net::SSH::Disconnect, IOError => e
83
84
  logger.debug 'The other side closed the connection while ' \
84
- "disconnecting, rasing #{e.class} with #{e.messages}"
85
+ "disconnecting, raising #{e.class} with #{e.message}"
85
86
  rescue Timeout::Error
86
87
  logger.debug "#{@node.name} timed out while disconnecting"
87
88
  ensure
88
89
  @log.close if Oxidized.config.input.debug?
89
- (@ssh.close rescue true) unless @ssh.closed?
90
+ (@ssh.close rescue true) unless @ssh.closed? # rubocop:disable Style/RedundantParentheses
90
91
  end
91
92
 
92
93
  def shell_open(ssh)
@@ -162,9 +163,9 @@ module Oxidized
162
163
  ssh_opts[:host_key] = vars(:ssh_host_key).split(/,\s*/) if vars(:ssh_host_key)
163
164
  ssh_opts[:hmac] = vars(:ssh_hmac).split(/,\s*/) if vars(:ssh_hmac)
164
165
 
165
- # Use our logger for Net:SSH
166
+ # Use our logger for Net::SSH
166
167
  ssh_logger = SemanticLogger[Net::SSH]
167
- ssh_logger.level = Oxidized.config.input.debug? ? :debug : :error
168
+ ssh_logger.level = Oxidized.config.input.debug? ? :debug : :fatal
168
169
  ssh_opts[:logger] = ssh_logger
169
170
 
170
171
  ssh_opts
@@ -4,6 +4,7 @@ module Oxidized
4
4
  class Telnet < Input
5
5
  RESCUE_FAIL = {}.freeze
6
6
  include Input::CLI
7
+
7
8
  attr_reader :telnet
8
9
 
9
10
  def connect(node) # rubocop:disable Naming/PredicateMethod
@@ -67,7 +68,7 @@ module Oxidized
67
68
  # This exception is intented and therefore not handled here
68
69
  ensure
69
70
  @log.close if Oxidized.config.input.debug?
70
- (@telnet.close rescue true) unless @telnet.sock.closed?
71
+ (@telnet.close rescue true) unless @telnet.sock.closed? # rubocop:disable Style/RedundantParentheses
71
72
  end
72
73
  end
73
74
  end
data/lib/oxidized/job.rb CHANGED
@@ -7,13 +7,21 @@ module Oxidized
7
7
  def initialize(node)
8
8
  @node = node
9
9
  @start = Time.now.utc
10
- self.name = "Oxidized::Job '#{@node.name}'"
10
+ self.name = "Job '#{@node.name}'"
11
11
  super do
12
- logger.debug "Starting fetching process for #{@node.name} at #{Time.now.utc}"
13
- @status, @config = @node.run
14
- @end = Time.now.utc
15
- @time = @end - @start
16
- logger.debug "Config fetched for #{@node.name} at #{@end}"
12
+ logger.debug "Starting fetching process for #{@node.name}"
13
+ begin
14
+ Timeout.timeout(Oxidized.config.timelimit) do
15
+ @status, @config = @node.run
16
+ end
17
+ logger.debug "Config fetched for #{@node.name}"
18
+ rescue Timeout::Error
19
+ logger.warn "Job timelimit reached for #{@node.name}"
20
+ @status = :timelimit
21
+ ensure
22
+ @end = Time.now.utc
23
+ @time = @end - @start
24
+ end
17
25
  end
18
26
  end
19
27
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class JunOS < Oxidized::Model
2
4
  using Refinements
3
5
  comment '# '
@@ -26,7 +28,7 @@ class JunOS < Oxidized::Model
26
28
  end
27
29
 
28
30
  post do
29
- out = String.new('')
31
+ out = String.new
30
32
  case @model
31
33
  when 'mx960'
32
34
  out << cmd('show chassis fabric reachability') { |cfg| comment cfg }
@@ -34,7 +36,7 @@ class JunOS < Oxidized::Model
34
36
  out << cmd('show virtual-chassis') { |cfg| comment cfg }
35
37
  when /^srx/
36
38
  out << cmd('show chassis cluster status') do |cfg|
37
- cfg.lines.count <= 1 && cfg.include?("error:") ? '' : comment(cfg)
39
+ cfg.lines.count <= 1 && cfg.include?("error:") ? String.new : comment(cfg)
38
40
  end
39
41
  end
40
42
  out
@@ -4,6 +4,7 @@ require_relative 'outputs'
4
4
  module Oxidized
5
5
  class Model
6
6
  include SemanticLogger::Loggable
7
+
7
8
  using Refinements
8
9
 
9
10
  include Oxidized::Config::Vars
@@ -3,6 +3,7 @@ class Mtrlrfs < Oxidized::Model
3
3
 
4
4
  # Motorola RFS/Extreme WM
5
5
 
6
+ prompt /^([\w.@-]+\*?[#>])\s?$/
6
7
  comment '# '
7
8
 
8
9
  cmd :all do |cfg|
data/lib/oxidized/node.rb CHANGED
@@ -1,6 +1,5 @@
1
1
  module Oxidized
2
2
  require 'resolv'
3
- require 'ostruct'
4
3
  require_relative 'node/stats'
5
4
  class MethodNotFound < OxidizedError; end
6
5
  class ModelNotFound < OxidizedError; end
@@ -38,8 +38,10 @@ module Oxidized
38
38
  def node_want?(node_want, node)
39
39
  return true unless node_want
40
40
 
41
+ # rubocop:disable Style/RedundantParentheses
41
42
  node_want_ip = (IPAddr.new(node_want) rescue false)
42
43
  name_is_ip = (IPAddr.new(node[:name]) rescue false)
44
+ # rubocop:enable Style/RedundantParentheses
43
45
  # rubocop:todo Lint/DuplicateBranch
44
46
  if name_is_ip && (node_want_ip == node[:name])
45
47
  true
@@ -43,7 +43,7 @@ module Oxidized
43
43
  # map node specific vars
44
44
  vars = {}
45
45
  @cfg.vars_map.each do |key, position|
46
- vars[key.to_sym] = node_var_interpolate data[position]
46
+ vars[key.to_s] = node_var_interpolate data[position]
47
47
  end
48
48
  keys[:vars] = vars unless vars.empty?
49
49
 
@@ -50,7 +50,7 @@ module Oxidized
50
50
  # map node specific vars
51
51
  vars = {}
52
52
  @cfg.vars_map.each do |key, want_position|
53
- vars[key.to_sym] = node_var_interpolate string_navigate_object(node, want_position)
53
+ vars[key.to_s] = node_var_interpolate string_navigate_object(node, want_position)
54
54
  end
55
55
  keys[:vars] = vars unless vars.empty?
56
56
 
@@ -42,7 +42,7 @@ module Oxidized
42
42
  # map node specific vars
43
43
  vars = {}
44
44
  @cfg.vars_map.each do |key, sql_column|
45
- vars[key.to_sym] = node_var_interpolate node[sql_column.to_sym]
45
+ vars[key.to_s] = node_var_interpolate node[sql_column.to_sym]
46
46
  end
47
47
  keys[:vars] = vars unless vars.empty?
48
48
 
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Oxidized
4
- VERSION = '0.34.0'
5
- VERSION_FULL = '0.34.0'
4
+ VERSION = '0.34.2'
5
+ VERSION_FULL = '0.34.2'
6
6
  def self.version_set
7
7
  version_full = %x(git describe --tags).chop rescue ""
8
8
  version = %x(git describe --tags --abbrev=0).chop rescue ""
data/oxidized.gemspec CHANGED
@@ -41,7 +41,7 @@ Gem::Specification.new do |s|
41
41
  s.add_dependency 'net-telnet', '~> 0.2'
42
42
  s.add_dependency 'psych', '~> 5.0'
43
43
  s.add_dependency 'rugged', '~> 1.6'
44
- s.add_dependency 'semantic_logger', '~> 4.16'
44
+ s.add_dependency 'semantic_logger', '~> 4.17.0'
45
45
  s.add_dependency 'slop', '~> 4.6'
46
46
  s.add_dependency 'syslog', '~> 0.3.0'
47
47
  s.add_dependency 'syslog_protocol', '~> 0.9.2'
@@ -53,13 +53,13 @@ Gem::Specification.new do |s|
53
53
  s.add_development_dependency 'mocha', '~> 2.1'
54
54
  s.add_development_dependency 'pry', '~> 0.15.0'
55
55
  s.add_development_dependency 'rake', '~> 13.0'
56
- s.add_development_dependency 'rubocop', '~> 1.78.0'
56
+ s.add_development_dependency 'rubocop', '~> 1.79.1'
57
57
  s.add_development_dependency 'rubocop-minitest', '~> 0.38.0'
58
58
  s.add_development_dependency 'rubocop-rake', '~> 0.7.0'
59
59
  s.add_development_dependency 'rubocop-sequel', '~> 0.4.0'
60
60
  s.add_development_dependency 'simplecov', '~> 0.22.0'
61
61
 
62
62
  # Dependencies on optional libraries, used for unit tests & development
63
- s.add_development_dependency 'oxidized-web', '~> 0.16'
63
+ s.add_development_dependency 'oxidized-web', '~> 0.17.1'
64
64
  s.add_development_dependency 'sequel', '>= 5.63.0', '<= 5.94.0'
65
65
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: oxidized
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.34.0
4
+ version: 0.34.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Saku Ytti
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2025-07-15 00:00:00.000000000 Z
13
+ date: 2025-08-01 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: asetus
@@ -158,14 +158,14 @@ dependencies:
158
158
  requirements:
159
159
  - - "~>"
160
160
  - !ruby/object:Gem::Version
161
- version: '4.16'
161
+ version: 4.17.0
162
162
  type: :runtime
163
163
  prerelease: false
164
164
  version_requirements: !ruby/object:Gem::Requirement
165
165
  requirements:
166
166
  - - "~>"
167
167
  - !ruby/object:Gem::Version
168
- version: '4.16'
168
+ version: 4.17.0
169
169
  - !ruby/object:Gem::Dependency
170
170
  name: slop
171
171
  requirement: !ruby/object:Gem::Requirement
@@ -304,14 +304,14 @@ dependencies:
304
304
  requirements:
305
305
  - - "~>"
306
306
  - !ruby/object:Gem::Version
307
- version: 1.78.0
307
+ version: 1.79.1
308
308
  type: :development
309
309
  prerelease: false
310
310
  version_requirements: !ruby/object:Gem::Requirement
311
311
  requirements:
312
312
  - - "~>"
313
313
  - !ruby/object:Gem::Version
314
- version: 1.78.0
314
+ version: 1.79.1
315
315
  - !ruby/object:Gem::Dependency
316
316
  name: rubocop-minitest
317
317
  requirement: !ruby/object:Gem::Requirement
@@ -374,14 +374,14 @@ dependencies:
374
374
  requirements:
375
375
  - - "~>"
376
376
  - !ruby/object:Gem::Version
377
- version: '0.16'
377
+ version: 0.17.1
378
378
  type: :development
379
379
  prerelease: false
380
380
  version_requirements: !ruby/object:Gem::Requirement
381
381
  requirements:
382
382
  - - "~>"
383
383
  - !ruby/object:Gem::Version
384
- version: '0.16'
384
+ version: 0.17.1
385
385
  - !ruby/object:Gem::Dependency
386
386
  name: sequel
387
387
  requirement: !ruby/object:Gem::Requirement
@@ -440,6 +440,7 @@ files:
440
440
  - docs/DeviceSimulation.md
441
441
  - docs/Docker.md
442
442
  - docs/Hooks.md
443
+ - docs/Inputs.md
443
444
  - docs/Issues.md
444
445
  - docs/Model-Notes/ADVA.md
445
446
  - docs/Model-Notes/APC_AOS.md