oxidized 0.36.0 → 0.37.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +3 -0
  3. data/CHANGELOG.md +26 -0
  4. data/Rakefile +1 -1
  5. data/docs/Configuration.md +10 -1
  6. data/docs/Creating-Models.md +1 -1
  7. data/docs/Hooks.md +92 -67
  8. data/docs/Inputs.md +15 -12
  9. data/docs/Model-Notes/GrandstreamHT8xx.md +8 -0
  10. data/docs/Model-Notes/RouterOS.md +13 -0
  11. data/docs/Model-Notes/TrueNAS.md +11 -7
  12. data/docs/Release.md +6 -1
  13. data/docs/Supported-OS-Types.md +1 -0
  14. data/extra/hooks/modelrulesadvanced.rb +0 -1
  15. data/lib/oxidized/cli/support.rb +152 -0
  16. data/lib/oxidized/cli.rb +9 -0
  17. data/lib/oxidized/hook.rb +2 -0
  18. data/lib/oxidized/input/debugtext.rb +40 -0
  19. data/lib/oxidized/input/debugyaml.rb +82 -0
  20. data/lib/oxidized/input/exec.rb +1 -6
  21. data/lib/oxidized/input/ftp.rb +0 -4
  22. data/lib/oxidized/input/http.rb +1 -8
  23. data/lib/oxidized/input/ssh.rb +28 -21
  24. data/lib/oxidized/input/sshbase.rb +7 -12
  25. data/lib/oxidized/input/telnet.rb +12 -9
  26. data/lib/oxidized/input/tftp.rb +0 -4
  27. data/lib/oxidized/model/aoscx.rb +13 -9
  28. data/lib/oxidized/model/cumulus.rb +3 -3
  29. data/lib/oxidized/model/dlinknextgen.rb +1 -0
  30. data/lib/oxidized/model/fortigate.rb +1 -1
  31. data/lib/oxidized/model/grandstreamht8xx.rb +19 -0
  32. data/lib/oxidized/model/ios.rb +2 -0
  33. data/lib/oxidized/model/junos.rb +2 -2
  34. data/lib/oxidized/model/linuxgeneric.rb +4 -2
  35. data/lib/oxidized/model/nxos.rb +4 -1
  36. data/lib/oxidized/model/routeros.rb +4 -0
  37. data/lib/oxidized/model/tplink.rb +4 -6
  38. data/lib/oxidized/model/truenas.rb +56 -5
  39. data/lib/oxidized/model/vyos.rb +1 -0
  40. data/lib/oxidized/version.rb +2 -2
  41. metadata +6 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f594c7328a0f47ff8623d8a025df44224af1e7addc71c57bd0c37ab2285c4f8f
4
- data.tar.gz: 837bb841353c080c93235ca4a46095d42335fa8e05623f3e6f7ef5fc9cc67a44
3
+ metadata.gz: 59eeea5dc9024b545f633379b4ab663cf5ea26fe478a4dafffe0e0b80909d2b7
4
+ data.tar.gz: 26363d11d322e4f797db86050dce16532b8cf2e0e5419de0b92b0dae0b8076df
5
5
  SHA512:
6
- metadata.gz: ce194d0b6353b929bdb14514d835a1500d846c50491d30782d89c1c3ccc2a6e0f0cdc34aa0b9385c8ca2ce82f0c759a917f252076fc8675169d5eb40694bc3dc
7
- data.tar.gz: 21c716e53c0e391bfefa617e0a3bc68a23a14a04dce3d508ca82c127f993ea909a27799901d6ad3c3e0bb1625d749bae73882f2c8e2fcb8f0b400aca036df5ab
6
+ metadata.gz: 3b47b07aaa4528bfa49559ae27785f64da5de07e00305878b840cad7f00068e83c84951350494b37765e0a2499a59881d15979360a8c911702f81531613dd674
7
+ data.tar.gz: e103734e361736470524ea88f650fa0007a498273c2b54597a0d6fe3d0e768013f2a13f9edea755b72955ce57684614b7a824a745b81c41f0f2fe539b3d13b4d
data/.rubocop.yml CHANGED
@@ -120,6 +120,9 @@ Metrics/AbcSize:
120
120
  Metrics/ClassLength:
121
121
  Max: 200
122
122
 
123
+ Metrics/ModuleLength:
124
+ Max: 200
125
+
123
126
  Metrics/PerceivedComplexity:
124
127
  Enabled: false
125
128
 
data/CHANGELOG.md CHANGED
@@ -4,6 +4,32 @@ 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.37.0 - 2026-05-20]
8
+ ### Added
9
+ - routeros: support store mode `on_significant` (@infabo)
10
+ - model for Grandstream HT8xx (@mklopocki)
11
+ - Add --support option to gather system diagnostics (@robertcheramy)
12
+
13
+ ### Changed
14
+ - input/ssh: validate that cmd is a String. See #3700 (@robertcheramy)
15
+ - junos: changed "show system license" regex to reduce notification noise for PTX routers. See #3794 (@ctomkow)
16
+ - ios: keep motherboard information in show version. Closes #3798 (@robertcheramy)
17
+ - aoscx: use oxidized filtering instead of "show system | exclude...". (@robertcheramy)
18
+ - input/*: rewrite debug logging; remove unused logging; input/ssh: write a YAML simulation file (@robertcheramy)
19
+ - truenas: capture app, replication, cloudsync configurations without constant changes. See #3795 (@neilschelly)
20
+ - Set Rake::TestTask to `verbose = false` since the behavior changed with rake 13.4.2 (@robertcheramy)
21
+
22
+ ### Fixed
23
+ - VyOS: detect community string in SNMP traps. Fixes: #3793 (@nicolasberens)
24
+ - fortigate: show Part No. of SFPs. Fixes: #3800 (@robertcheramy)
25
+ - aoscx: Hide total power consumption (stacking). Fixes #3801 (@robertcheramy)
26
+ - linuxgeneric: fix prompt, telnet username and clean ANSI Escape Codes (@robertcheramy)
27
+ - cumulus: fix prompt (make : and space optional). Fixes #3812 (@robertcheramy)
28
+ - dlinknexgen: NULL byte handling. Fixes #3816 (@ziotibia81)
29
+ - nxos: hide snmpv3 priv key when remove_secret is true. Fixes: #3805 (@robertcheramy)
30
+ - tpink: use `\r\n` when sending commands and set `terminal length 0`. Fixes #3804 (@robertcheramy)
31
+
32
+
7
33
  ## [0.36.0 - 2026-03-31]
8
34
  ### Release Notes
9
35
  The fortios model has been split into fortigate and fortios. You need the new fortigate model for FortiGate firewalls. Be sure to check the [Fortinet model notes](docs/Model-Notes/Fortinet.md) before upgrading.
data/Rakefile CHANGED
@@ -30,7 +30,7 @@ task :test do
30
30
  t.ruby_opts = ['-W:deprecated']
31
31
  # Don't display ambiguity warning between regexp and division in models
32
32
  t.warning = false
33
- t.verbose = true
33
+ t.verbose = false
34
34
  end
35
35
  end
36
36
 
@@ -83,7 +83,6 @@ username: oxidized
83
83
  password: S3cr3tx
84
84
  model: junos
85
85
  interval: 3600 #interval in seconds, when 0 is configured no fetch config is done at initial start and after
86
- log: ~/.config/oxidized/log
87
86
  debug: false
88
87
  threads: 30 # maximum number of threads
89
88
  # use_max_threads:
@@ -143,6 +142,16 @@ model_map:
143
142
  cisco: ios
144
143
  juniper: junos
145
144
  !ruby/regexp /procurve/: procurve
145
+ logger:
146
+ # The default level is :info
147
+ # level: :info
148
+ appenders:
149
+ - type: syslog
150
+ level: :error
151
+ - type: stdout
152
+ level: :warn
153
+ - type: file
154
+ file: ~/.config/oxidized/info.log
146
155
  ```
147
156
 
148
157
  ## Advanced Group Configuration
@@ -189,7 +189,7 @@ The macro (with defaults) implements following code:
189
189
  if vars(:enable) == true
190
190
  cmd "enable"
191
191
  elsif vars(:enable)
192
- cmd "enable", /^[pP]assword:/
192
+ cmd "enable", /password/i
193
193
  cmd vars(:enable)
194
194
  end
195
195
  end
data/docs/Hooks.md CHANGED
@@ -109,50 +109,102 @@ hooks:
109
109
 
110
110
  ## Hook type: githubrepo
111
111
 
112
- Note: You must not use the same name as any local repo configured under output. Make sure your 'git' output has a unique name that does not match your remote_repo.
112
+ The `githubrepo` hook executes a `git push` to a configured `remote_repo` when
113
+ the specified event is triggered.
113
114
 
114
- The `githubrepo` hook executes a `git push` to a configured `remote_repo` when the specified event is triggered.
115
+ ### Configuration keys
115
116
 
116
- Several authentication methods are supported:
117
+ | Key | Description |
118
+ |---------------|-------------|
119
+ | `remote_repo` | The remote repository to push to. Use a URL string (no groups) or a group dictionary (see [Using groups](#using-groups)). |
120
+ | `username` | Username for authentication. Defaults to the user part of the `remote_repo` URI, falling back to `git`. |
121
+ | `password` | Password for username/password authentication. |
122
+ | `privatekey` | Path to the private key file. Must be in legacy PEM format (see note below). |
123
+ | `publickey` | Path to the public key file (optional — inferred from `privatekey` + `.pub` if omitted). |
117
124
 
118
- * Provide a `password` for username + password authentication
119
- * Provide both a `publickey` and a `privatekey` for ssh key-based authentication
120
- * Provide only a `privatekey` (public key filename is assumed to be `privatekey` + "`.pub`"
121
- * Don't provide any credentials for ssh-agent authentication
125
+ Notes:
126
+ - `remote_repo` must not match the name of any local `git` output repo configured under `output`. Use unique names for each.
127
+ - If using SSH key authentication with a passphrase-protected private key, provide the passphrase with the `OXIDIZED_SSH_PASSPHRASE` environment variable.
128
+ - The `privatekey` must be in the legacy PEM format (`BEGIN RSA PRIVATE KEY`), not the newer OpenSSH format (`BEGIN OPENSSH PRIVATE KEY`). See [#1877](https://github.com/ytti/oxidized/issues/1877) and [#2324](https://github.com/ytti/oxidized/issues/2324).
129
+ - To convert an existing key to PEM format, run:
130
+ ```shell
131
+ ssh-keygen -p -m PEM -f $MY_KEY_HERE
132
+ ```
122
133
 
123
- The username will be set to the relevant part of the `remote_repo` URI, with a fallback to `git`. It is also possible to provide one by setting the `username` configuration key.
134
+ ### Authentication methods
124
135
 
125
- For ssh key-based authentication, it is possible to set the environment variable `OXIDIZED_SSH_PASSPHRASE` to a passphrase if the private key requires it.
136
+ Choose one of the following methods:
126
137
 
127
- `githubrepo` hook recognizes the following configuration keys:
138
+ | Method | Required keys |
139
+ |-------------------------------|---------------|
140
+ | Username + password | `username` (optional), `password` |
141
+ | SSH key pair | `privatekey`, `publickey` (optional - assumed to be at `privatekey` + `.pub`) |
142
+ | SSH agent | no credentials needed |
128
143
 
129
- * `remote_repo`: the remote repository to be pushed to.
130
- * `username`: username for repository auth.
131
- * `password`: password for repository auth.
132
- * `publickey`: public key file path for repository auth. (optional)
133
- * `privatekey`: private key file path for repository auth.
134
- * NOTE: this key needs to be in the legacy PEM format, not the newer OpenSSL format [#1877](https://github.com/ytti/oxidized/issues/1877), [#2324](https://github.com/ytti/oxidized/issues/2324)
135
- * To convert a key beginning with `BEGIN OPENSSH PRIVATE KEY` to the legacy PEM format, run this command:
136
- `ssh-keygen -p -m PEM -f $MY_KEY_HERE`
144
+ ### Configuration examples
137
145
 
138
- When using groups, `remote_repo` must be a dictionary of groups that the hook should apply to. If a group is missing from the dictionary, no action will be taken.
146
+ **Username and password:**
139
147
 
140
- The dictionary entry can either be a url alone:
148
+ ```yaml
149
+ hooks:
150
+ push_to_remote:
151
+ type: githubrepo
152
+ events: [post_store]
153
+ remote_repo: git@git.intranet:oxidized/test.git
154
+ username: user
155
+ password: pass
156
+ ```
157
+
158
+ **SSH key pair:**
141
159
 
142
160
  ```yaml
143
161
  hooks:
144
162
  push_to_remote:
163
+ type: githubrepo
164
+ events: [post_store]
165
+ remote_repo: git@git.intranet:oxidized/test.git
166
+ publickey: /root/.ssh/id_rsa.pub
167
+ privatekey: /root/.ssh/id_rsa
168
+ ```
169
+
170
+
171
+ **SSH agent:**
172
+
173
+ ```yaml
174
+ hooks:
175
+ push_to_remote:
176
+ type: githubrepo
177
+ events: [post_store]
178
+ remote_repo: git@git.intranet:oxidized/test.git
179
+ ```
180
+
181
+ ### Using groups
182
+
183
+ When using groups and `single_repo` is set to `true` (default) in the
184
+ configuration section output/git, `remote_repo` must be a dictionary mapping
185
+ group names to remote repositories. Groups not listed in the dictionary are
186
+ silently skipped.
187
+
188
+ Each entry can be either a plain URL string:
189
+
190
+ ```yaml
191
+ hooks:
192
+ push_to_remote:
193
+ type: githubrepo
194
+ events: [post_store]
145
195
  remote_repo:
146
196
  routers: git@git.intranet:oxidized/routers.git
147
197
  switches: git@git.intranet:oxidized/switches.git
148
198
  firewalls: git@git.intranet:oxidized/firewalls.git
149
199
  ```
150
200
 
151
- ... or it can be a dictionary with `url` and `privatekey` specified:
201
+ ...or a dictionary with `url` and `privatekey` to use a per-group SSH key:
152
202
 
153
203
  ```yaml
154
204
  hooks:
155
205
  push_to_remote:
206
+ type: githubrepo
207
+ events: [post_store]
156
208
  remote_repo:
157
209
  routers:
158
210
  url: git@git.intranet:oxidized/routers.git
@@ -165,58 +217,31 @@ hooks:
165
217
  privatekey: /root/.ssh/id_rsa_firewalls
166
218
  ```
167
219
 
168
- Both forms can be mixed and matched.
220
+ Both forms can be mixed within the same configuration.
169
221
 
170
- ### githubrepo hook configuration example
222
+ ### Custom branch name
171
223
 
172
- Authenticate with a username and a password without groups in use:
224
+ The `githubrepo` hook uses the branch name from the
225
+ [git output](Outputs.md#output-git) as the remote branch name. When the
226
+ repository is first created, Oxidized uses the default branch name from
227
+ `git config --global init.defaultBranch`. The default is `master`.
173
228
 
174
- ```yaml
175
- hooks:
176
- push_to_remote:
177
- type: githubrepo
178
- events: [post_store]
179
- remote_repo: git@git.intranet:oxidized/test.git
180
- username: user
181
- password: pass
182
- ```
229
+ You can manually rename the branch after Oxidized has already created the
230
+ repository. Be aware that you may break things, so make backups.
183
231
 
184
- Authenticate with the username `git` and an ssh key:
232
+ To rename the branch after Oxidized has already created the repository:
185
233
 
186
- ```yaml
187
- hooks:
188
- push_to_remote:
189
- type: githubrepo
190
- events: [post_store]
191
- remote_repo: git@git.intranet:oxidized/test.git
192
- publickey: /root/.ssh/id_rsa.pub
193
- privatekey: /root/.ssh/id_rsa
194
- ```
234
+ 1. Stop oxidized.
235
+ 2. Back up your oxidized git repository.
236
+ 3. Change to your oxidized git repository directory.
237
+ 4. Inspect the current branches: `git branch -avv`
238
+ 5. Rename the local branch: `git branch -m <NewName>`
239
+ 6. Remove the stale remote-tracking reference: `git branch -r -d origin/<OldName>`
240
+ 7. Verify the result: `git branch -avv`
241
+ 8. Restart oxidized.
195
242
 
196
- ### Custom branch name
197
- Githubrepo will use the branch name used in the
198
- [git output](Outputs.md#output-git) as a remote branch name. When creating the
199
- git repository for the first time, Oxidized uses the default branch name
200
- configured in git with `git config --global init.defaultBranch <Name>`. The
201
- default is `master`.
202
-
203
- If you need to rename the branch name after Oxidized has created it, you may do
204
- it manually. Be aware that you may break things. Make backups and do not
205
- complain if something goes wrong!
206
-
207
- 1. Stop oxidized (no one should access the git repository while doing the
208
- following steps)
209
- 2. Make a backup of your oxidized data, especially the git repository
210
- 3. Change directory to your oxidized git repository (as configured in oxidized
211
- configuration file)
212
- 4. Inspect the current branches with `git branch -avv`
213
- 5. Rename the default branch with `git branch -m <NewName>`
214
- 6. Remove the reference to the old remote branch with
215
- `git branch -r -d origin/<OldName>`
216
- 6. Inspect the change with `git branch -avv`
217
- 7. Restart oxidized - you're done!
218
-
219
- Note that you will also have to clean your remote git repository.
243
+ Oxidized will push to a new remote branch. When everything is fine, you can
244
+ remove the old branch from the remote repository.
220
245
 
221
246
  ## Hook type: awssns
222
247
 
data/docs/Inputs.md CHANGED
@@ -208,25 +208,28 @@ input:
208
208
  ```
209
209
 
210
210
  ## Debugging
211
-
212
211
  In case a model plugin doesn't work correctly (ios, procurve, etc.), you can
213
- enable live debugging of SSH/Telnet sessions. Just add a `debug` option
214
- containing the value true to the `input` section. The log files will be created
215
- depending on the parent directory of the logfile option.
212
+ enable live debugging of SSH and Telnet sessions with the `debug` option of
213
+ the `input` section.
216
214
 
217
- The following example will log an active ssh/telnet session
218
- `/home/oxidized/.config/oxidized/log/<IP-Address>-<PROTOCOL>`. The file will be
219
- truncated on each consecutive ssh/telnet session, so you need to put a `tailf`
220
- or `tail -f` on that file!
215
+ Starting with version 0.37.0, `debug` can take different values:
216
+ - `text`: log input and output to a text file (ssh, telnet)
217
+ - `yaml`: produce a yaml simulation file (ssh, scp)
218
+ - `library`: activate debug logging of the underlying library
219
+ - a combination of the options above (`text, yaml`)
220
+ - `true`; activate all debugging options (Only option for versions prior 0.37.0)
221
221
 
222
- ```yaml
223
- log: /home/oxidized/.config/oxidized/log
222
+ The log files will be created in `~/.config/oxidized/logs/` (or `$OXIDIZED_LOGS/logs/`).
224
223
 
225
- # ...
224
+ The following example will log an active ssh/telnet session to
225
+ `~/.config/oxidized/logs/<IP-Address>-<PROTOCOL>-<timestamp>.txt` and for ssh
226
+ `~/.config/oxidized/logs/<IP-Address>-<PROTOCOL>-<timestamp>.yaml`. A new file
227
+ is created for each session.
226
228
 
229
+ ```yaml
227
230
  input:
228
231
  default: ssh, telnet
229
- debug: true
232
+ debug: yaml, text
230
233
  ssh:
231
234
  secure: false
232
235
  http:
@@ -0,0 +1,8 @@
1
+ # Grandstream HT8xx
2
+
3
+ You need to have enabled access to device by SSH.
4
+ Connection using user/password for retrieve the configuration containing XML file with all params stored in device memory.
5
+
6
+ Tested on hardware: v1 and software version: 1.0.61.2.
7
+
8
+ Back to [Model-Notes](README.md)
@@ -12,4 +12,17 @@ and attach the public key.
12
12
 
13
13
  Oxidized can now retrieve your configuration!
14
14
 
15
+ ## Save significant changes only
16
+
17
+ You can [store the configuration only on significant changes](/docs/Configuration.md#store-configuration-only-on-significant-changes)
18
+ by setting the [variable](/docs/Configuration.md#options-credentials-vars-etc-precedence)
19
+ `output_store_mode` to `on_significant`. On RouterOS, this prevents Oxidized from saving a
20
+ new configuration version when only the system history has changed without any actual
21
+ configuration change.
22
+
23
+ ```yaml
24
+ vars:
25
+ output_store_mode: on_significant
26
+ ```
27
+
15
28
  Back to [Model-Notes](README.md)
@@ -6,14 +6,18 @@ TrueNAS SCALE (Linux-based) devices.
6
6
  ## Authentication
7
7
 
8
8
  Ensure that the user configured for oxidized to login to your device has the
9
- permissions to read the configuration database. On older devices, this would
10
- just work.
9
+ permissions to read the configuration database. On older CORE instances, this
10
+ would just work without sudo. On newer devices, the `/data/freenas-v1.db` file
11
+ can only be read by the root user.
11
12
 
12
- On newer devices, the `/data/freenas-v1.db` file can only be read by the
13
- root user. You can make sure that the user that oxidized uses to login
14
- (`oxidized` in this example) can dump the configuration using `sudo` by
15
- adding something like this to your `/etc/sudoers` file:
13
+ On SCALE devices with Apps support, it's also necessary to add some privileges
14
+ to read the container configurations for any apps you have installed, which can
15
+ be found under `/mnt/.ix-apps`.
16
+
17
+ You can make sure that the user that oxidized uses to login (`oxidized` in this
18
+ example) can dump the configuration using `sudo` by adding something like this
19
+ to your `/etc/sudoers` file:
16
20
 
17
21
  ```
18
- oxidized ALL=(ALL) NOPASSWD: /usr/bin/sqlite3 file\:///data/freenas-v1.db?mode\=ro&immutable\=1 .dump
22
+ oxidized ALL=(ALL) NOPASSWD: /usr/bin/find /mnt/.ix-apps/app_configs *, /usr/bin/sqlite3 -readonly file\:/data/freenas-v1.db *
19
23
  ```
data/docs/Release.md CHANGED
@@ -71,9 +71,14 @@ git push origin 0.xx.yy
71
71
  ```
72
72
 
73
73
  Make a release from the tag in github.
74
- - Take the release notes frm CHANGELOG.md
74
+ - Name the release `0.xx.yy`
75
+ - Generate release notes
76
+ - Remove `## What's changed`
77
+ - Take the release notes from CHANGELOG.md
75
78
  - List new contributors (generated automatically)
76
79
  - Keep the Full Changelog (generated automatically)
80
+ - Preview
81
+ - Publish
77
82
 
78
83
  Close the corresponding milestone in github.
79
84
 
@@ -108,6 +108,7 @@
108
108
  |[Garderos](https://garderos.com/) |GRS (Garderos Router Software) |[garderos](/lib/oxidized/model/garderos.rb) | @robertcheramy |Routers for harsh environments
109
109
  |GCOM Technologies |Broadband Network Platform Software|[gcombnps](/lib/oxidized/model/gcombnps.rb)
110
110
  |Grandstream Networks|GSX |[grandstream](/lib/oxidized/model/grandstream.rb)
111
+ | |HT8xx |[grandstream](/lib/oxidized/model/grandstreamht8xx.rb) | @mklopocki | [Grandstream](Model-Notes/GrandstreamHT8xx.md)
111
112
  |Hatteras |Hatteras |[hatteras](/lib/oxidized/model/hatteras.rb)
112
113
  |Hillstone Networks |StoneOS |[stoneos](/lib/oxidized/model/stoneos.rb)
113
114
  |Hirschmann |Classic |[hirschmann](/lib/oxidized/model/hirschmann.rb)
@@ -70,7 +70,6 @@
70
70
  # resolve_dns: false
71
71
  # interval: 3600
72
72
  # rest: 0.0.0.0:8888
73
- # log: /home/oxidized/.config/oxidized/logs/oxidized.log
74
73
  # debug: true # optional – enables detailed logging from the hook
75
74
  #
76
75
  # source:
@@ -0,0 +1,152 @@
1
+ require 'time'
2
+
3
+ module Oxidized
4
+ class CLI
5
+ module Support
6
+ SENSITIVE_NAME_RE = /(password|passphrase|secret|token|enable|
7
+ (private|api|access)_?key|
8
+ community|credential|auth
9
+ )/ix
10
+ ROOT_GEMS = %w[oxidized oxidized-web].freeze
11
+ EXPLICIT_ENV_KEYS = %w[
12
+ OXIDIZED_HOME
13
+ OXIDIZED_LOGS
14
+ CONFIG_RELOAD_INTERVAL
15
+ UPDATE_CA_CERTIFICATES
16
+ ].freeze
17
+
18
+ private
19
+
20
+ def show_support_details
21
+ print_intro
22
+ print_environment
23
+ print_config_files
24
+ print_rugged_support
25
+ print_installed_gems
26
+ end
27
+
28
+ def print_intro
29
+ os_release = read_os_release
30
+ runit_path = '/etc/service/oxidized/run'
31
+
32
+ puts '> :warning:'
33
+ puts '> The --support option is intended for diagnostic purposes and may include sensitive information.'
34
+ puts '> Remove any sensitive data before sharing this output.'
35
+ puts
36
+ puts '## Oxidized Support Data'
37
+ puts "- Timestamp: #{Time.now.utc.iso8601}"
38
+ puts "- Oxidized version: #{Oxidized::VERSION_FULL}"
39
+ puts "- OS release: #{os_release}" if os_release
40
+ puts "- Container hint (#{runit_path} exists): #{File.exist?(runit_path)}"
41
+ puts "- Ruby engine: #{defined?(RUBY_ENGINE) ? RUBY_ENGINE : 'ruby'}"
42
+ puts "- Ruby version: #{RUBY_VERSION}p#{RUBY_PATCHLEVEL} (#{RUBY_PLATFORM})"
43
+ puts "- Working directory: #{Dir.pwd}"
44
+ puts "- Gem paths: #{Gem.path.join(', ')}"
45
+ puts
46
+ end
47
+
48
+ def print_environment
49
+ puts '### Environment Variables'
50
+ keys = (ENV.keys.grep(/^OXIDIZED_/) + EXPLICIT_ENV_KEYS).uniq.sort
51
+
52
+ keys.each do |key|
53
+ next unless ENV.has_key?(key)
54
+
55
+ value = ENV.fetch(key)
56
+ puts key.match?(SENSITIVE_NAME_RE) ? "#{key}=[REDACTED]" : "#{key}=#{value}"
57
+ end
58
+
59
+ puts
60
+ end
61
+
62
+ def print_config_files
63
+ puts '### Configuration Files'
64
+ config_paths.each do |path|
65
+ config_path = File.expand_path(path)
66
+ exists = File.exist?(config_path)
67
+ puts "- #{config_path} exists: #{exists ? 'yes' : 'no'}"
68
+ next unless exists
69
+
70
+ print_sanitized_config(config_path)
71
+ end
72
+ puts
73
+ end
74
+
75
+ def print_rugged_support
76
+ puts '### Rugged'
77
+ begin
78
+ require 'rugged'
79
+ puts "- Rugged version: #{Rugged::VERSION}"
80
+
81
+ ssh_supported = Rugged.respond_to?(:features) && Rugged.features.include?(:ssh)
82
+ puts "- Rugged SSH support: #{ssh_supported}"
83
+ rescue LoadError
84
+ puts '- Rugged: not available'
85
+ puts '- Rugged SSH support: false'
86
+ end
87
+ puts
88
+ end
89
+
90
+ def print_installed_gems
91
+ puts '### Relevant Installed Gems'
92
+ relevant_gem_names.each do |name|
93
+ versions = Gem::Specification.find_all_by_name(name).sort_by(&:version).map { |s| s.version.to_s }
94
+ puts "- #{name} (#{versions.join(', ')})" unless versions.empty?
95
+ end
96
+ end
97
+
98
+ def relevant_gem_names
99
+ names = ROOT_GEMS.select { |name| Gem::Specification.any? { |s| s.name == name } }
100
+
101
+ root_specs = names.flat_map { |name| Gem::Specification.find_all_by_name(name) }
102
+ runtime_deps = root_specs.flat_map { |spec| spec.dependencies }
103
+ names.concat(runtime_deps.map(&:name))
104
+ names.sort.uniq
105
+ end
106
+
107
+ def config_paths
108
+ user_default = File.join(Dir.home, '.config', 'oxidized', 'config')
109
+ home_from_env = File.join(File.expand_path(Oxidized::Config::ROOT), 'config')
110
+
111
+ [
112
+ '/etc/oxidized/config',
113
+ user_default,
114
+ home_from_env
115
+ ].uniq
116
+ end
117
+
118
+ def print_sanitized_config(path)
119
+ content = File.read(path)
120
+ puts '```yaml'
121
+ content.each_line(chomp: true) do |line|
122
+ key, separator, = line.partition(':')
123
+
124
+ if separator.empty? || key.empty?
125
+ puts line
126
+ next
127
+ end
128
+
129
+ if key.match?(SENSITIVE_NAME_RE)
130
+ puts "#{key}: [REDACTED]"
131
+ else
132
+ puts line
133
+ end
134
+ end
135
+ puts '```'
136
+ rescue StandardError => e
137
+ puts " <failed to read: #{e.class}: #{e.message}>"
138
+ end
139
+
140
+ def read_os_release
141
+ return nil unless File.exist?('/etc/os-release')
142
+
143
+ line = File.foreach('/etc/os-release').find { |entry| entry.start_with?('PRETTY_NAME=') }
144
+ return nil unless line
145
+
146
+ line.split('=', 2).last.to_s.strip.gsub(/^"|"$/, '')
147
+ rescue StandardError
148
+ nil
149
+ end
150
+ end
151
+ end
152
+ end
data/lib/oxidized/cli.rb CHANGED
@@ -1,8 +1,10 @@
1
1
  require 'semantic_logger'
2
+ require_relative 'cli/support'
2
3
 
3
4
  module Oxidized
4
5
  class CLI
5
6
  include SemanticLogger::Loggable
7
+ include Support
6
8
 
7
9
  require 'slop'
8
10
  require 'oxidized'
@@ -48,6 +50,7 @@ module Oxidized
48
50
  opts = Slop.parse do |opt|
49
51
  opt.on '-d', '--debug', 'turn on debugging'
50
52
  opt.on '--daemonize', 'Daemonize/fork the process'
53
+ opt.on '--support', 'show support diagnostics and exit'
51
54
  opt.string '--home-dir', 'Oxidized home dir', default: nil
52
55
  opt.string '--config-file', 'Oxidized config file', default: nil
53
56
  opt.on '-h', '--help', 'show usage' do
@@ -64,6 +67,12 @@ module Oxidized
64
67
  Kernel.exit
65
68
  end
66
69
  end
70
+
71
+ if opts[:support]
72
+ show_support_details
73
+ Kernel.exit
74
+ end
75
+
67
76
  [opts.arguments, opts]
68
77
  end
69
78
 
data/lib/oxidized/hook.rb CHANGED
@@ -6,6 +6,8 @@ module Oxidized
6
6
  def from_config(cfg)
7
7
  mgr = new
8
8
  cfg.hooks.each do |name, h_cfg|
9
+ raise("Please specify an hook type in the configuration") unless h_cfg.type?
10
+
9
11
  h_cfg.events.each do |event|
10
12
  mgr.register event.to_sym, name, h_cfg.type, h_cfg
11
13
  end