oxidized 0.32.1 → 0.34.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/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/publishdocker.yml +35 -16
- data/.github/workflows/ruby.yml +4 -2
- data/.gitignore +2 -0
- data/.rubocop.yml +29 -8
- data/.rubocop_todo.yml +1 -60
- data/CHANGELOG.md +103 -2
- data/CONTRIBUTING.md +20 -10
- data/Dockerfile +37 -64
- data/README.md +47 -141
- data/Rakefile +9 -11
- data/docs/Configuration.md +236 -27
- data/docs/DeviceSimulation.md +19 -7
- data/docs/Docker.md +245 -0
- data/docs/Issues.md +27 -1
- data/docs/Model-Notes/EatonNetwork.md +18 -0
- data/docs/Model-Notes/HPEAruba.md +3 -2
- data/docs/ModelUnitTests.md +35 -25
- data/docs/Outputs.md +83 -2
- data/docs/Release.md +34 -24
- data/docs/Supported-OS-Types.md +7 -0
- data/docs/Troubleshooting.md +4 -13
- data/extra/device2yaml.rb +24 -9
- data/extra/rest_client.rb +3 -2
- data/extra/syslog.rb +8 -3
- data/lib/oxidized/cli.rb +7 -3
- data/lib/oxidized/config/vars.rb +22 -14
- data/lib/oxidized/config.rb +3 -2
- data/lib/oxidized/core.rb +30 -8
- data/lib/oxidized/hook/ciscosparkdiff.rb +11 -9
- data/lib/oxidized/hook/exec.rb +5 -4
- data/lib/oxidized/hook/githubrepo.rb +23 -17
- data/lib/oxidized/hook/noophook.rb +2 -2
- data/lib/oxidized/hook/slackdiff.rb +9 -8
- data/lib/oxidized/hook/xmppdiff.rb +9 -9
- data/lib/oxidized/hook.rb +10 -8
- data/lib/oxidized/input/cli.rb +8 -3
- data/lib/oxidized/input/exec.rb +1 -1
- data/lib/oxidized/input/ftp.rb +2 -2
- data/lib/oxidized/input/http.rb +6 -6
- data/lib/oxidized/input/input.rb +1 -0
- data/lib/oxidized/input/scp.rb +2 -2
- data/lib/oxidized/input/ssh.rb +21 -14
- data/lib/oxidized/input/telnet.rb +3 -3
- data/lib/oxidized/input/tftp.rb +1 -1
- data/lib/oxidized/job.rb +7 -4
- data/lib/oxidized/logger.rb +51 -0
- data/lib/oxidized/model/acos.rb +1 -0
- data/lib/oxidized/model/aos7.rb +9 -0
- data/lib/oxidized/model/aoscx.rb +2 -0
- data/lib/oxidized/model/aosw.rb +22 -17
- data/lib/oxidized/model/aricentiss.rb +2 -2
- data/lib/oxidized/model/asa.rb +3 -3
- data/lib/oxidized/model/awplus.rb +13 -10
- data/lib/oxidized/model/eatonnetwork.rb +65 -0
- data/lib/oxidized/model/edgecos.rb +2 -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 +1 -1
- data/lib/oxidized/model/fabricos.rb +1 -1
- data/lib/oxidized/model/fastiron.rb +3 -1
- data/lib/oxidized/model/firelinuxos.rb +12 -3
- data/lib/oxidized/model/fortios.rb +5 -4
- data/lib/oxidized/model/gaiaos.rb +4 -4
- data/lib/oxidized/model/ingate.rb +47 -0
- data/lib/oxidized/model/ios.rb +16 -5
- data/lib/oxidized/model/ironware.rb +1 -1
- data/lib/oxidized/model/junos.rb +4 -0
- data/lib/oxidized/model/linksyssrw.rb +3 -3
- data/lib/oxidized/model/mlnxos.rb +14 -7
- data/lib/oxidized/model/model.rb +4 -3
- data/lib/oxidized/model/netgear.rb +8 -0
- data/lib/oxidized/model/nsxdfw.rb +2 -1
- data/lib/oxidized/model/nsxfirewall.rb +2 -1
- data/lib/oxidized/model/nxos.rb +2 -2
- data/lib/oxidized/model/openwrt.rb +6 -6
- data/lib/oxidized/model/powerconnect.rb +31 -10
- data/lib/oxidized/model/procurve.rb +3 -1
- data/lib/oxidized/model/qtech.rb +3 -1
- data/lib/oxidized/model/quantaos.rb +8 -6
- data/lib/oxidized/model/routeros.rb +3 -2
- data/lib/oxidized/model/saos10.rb +38 -0
- data/lib/oxidized/model/sixwind.rb +28 -0
- data/lib/oxidized/model/sonicos.rb +1 -1
- data/lib/oxidized/model/srosmd.rb +1 -1
- data/lib/oxidized/model/supermicro.rb +1 -1
- data/lib/oxidized/model/timos.rb +1 -1
- data/lib/oxidized/model/tmos.rb +1 -0
- data/lib/oxidized/model/tnsr.rb +53 -0
- data/lib/oxidized/model/trango.rb +3 -1
- data/lib/oxidized/model/unifiap.rb +144 -0
- data/lib/oxidized/model/vrp.rb +3 -1
- data/lib/oxidized/model/xos.rb +3 -1
- data/lib/oxidized/model/zhoneolt.rb +3 -1
- data/lib/oxidized/model/zynos.rb +3 -3
- data/lib/oxidized/node.rb +44 -27
- data/lib/oxidized/nodes.rb +8 -4
- data/lib/oxidized/output/file.rb +28 -0
- data/lib/oxidized/output/git.rb +148 -41
- data/lib/oxidized/output/gitcrypt.rb +18 -13
- data/lib/oxidized/output/http.rb +5 -4
- data/lib/oxidized/output/output.rb +14 -0
- data/lib/oxidized/source/http.rb +4 -2
- data/lib/oxidized/version.rb +6 -4
- data/lib/oxidized/worker.rb +13 -13
- data/lib/oxidized.rb +3 -24
- data/lib/refinements.rb +2 -0
- data/oxidized.gemspec +10 -8
- metadata +74 -41
- data/examples/podman-compose/Makefile +0 -103
- data/examples/podman-compose/README.md +0 -94
- data/examples/podman-compose/docker-compose.yml +0 -30
- data/examples/podman-compose/gitserver/.gitignore +0 -1
- data/examples/podman-compose/gitserver/Dockerfile +0 -14
- data/examples/podman-compose/model-simulation/Dockerfile-model +0 -13
- data/examples/podman-compose/model-simulation/asternos.sh +0 -36
- data/examples/podman-compose/oxidized-config/.gitignore +0 -10
- data/examples/podman-compose/oxidized-config/config +0 -46
- data/examples/podman-compose/oxidized-config/config_csv-file +0 -46
- data/examples/podman-compose/oxidized-config/config_csv-gitserver +0 -56
- data/examples/podman-compose/oxidized-config/router.db +0 -1
- data/examples/podman-compose/oxidized-ssh/.gitignore +0 -1
- data/examples/podman-compose/oxidized-ssh/README.md +0 -14
data/docs/Supported-OS-Types.md
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
|Vendor |OS model |oxidized model |model maintainers|comment / model notes|
|
4
4
|
|--------------------|------------------------------|-------------------------------------------------|-----------------|---------------------|
|
5
|
+
|6WIND |VSR |[sixwind](/lib/oxidized/model/sixwind.rb) |@hcaldicott |
|
5
6
|
|A10 Networks |ACOS |[acos](/lib/oxidized/model/acos.rb) | |
|
6
7
|
|Accedian Performance Elements (NIDs)|AEN |[aen](/lib/oxidized/model/aen.rb)
|
7
8
|
|Acme Packet |ACMEPACKET |[acmepacket](/lib/oxidized/model/acmepacket.rb)
|
@@ -30,6 +31,7 @@
|
|
30
31
|
| |BOSS (Baystack Operating System Software)|[boss](/lib/oxidized/model/boss.rb)
|
31
32
|
|BDCOM |S2200PB, S2200-B, S2500-B, S2500-C, S2500PB, S2500-P, S2900 series|[bdcom](/lib/oxidized/model/bdcom.rb)
|
32
33
|
|Brocade |FabricOS |[fabricos](/lib/oxidized/model/fabricos.rb)
|
34
|
+
| |Enhanced Fabric OS |[efos](/lib/oxidized/model/efos.rb)
|
33
35
|
| |FastIron |[fastiron](/lib/oxidized/model/fastiron.rb)
|
34
36
|
| |IronWare |[ironware](/lib/oxidized/model/ironware.rb)
|
35
37
|
| |NOS (Network Operating System)|[nos](/lib/oxidized/model/nos.rb)
|
@@ -43,6 +45,7 @@
|
|
43
45
|
|Centec Networks |CNOS |[cnos](/lib/oxidized/model/cnos.rb)
|
44
46
|
|Check Point |GaiaOS |[gaiaos](/lib/oxidized/model/gaiaos.rb)
|
45
47
|
|Ciena |SAOS |[saos](/lib/oxidized/model/saos.rb)
|
48
|
+
| |SAOS10 |[saos10](/lib/oxidized/model/saos10.rb)
|
46
49
|
|Cisco |ACSW |[acsw](/lib/oxidized/model/acsw.rb)
|
47
50
|
| |AireOS |[aireos](/lib/oxidized/model/aireos.rb) | |[AireOS](Model-Notes/AireOS.md)
|
48
51
|
| |ASA |[asa](/lib/oxidized/model/asa.rb) |@robertcheramy
|
@@ -75,6 +78,7 @@
|
|
75
78
|
| |Dell EMC Networking OS10 |[os10](/lib/oxidized/model/os10.rb) | |[Dell EMC Networking OS10](Model-Notes/OS10.md)
|
76
79
|
|D-Link |D-Link |[dlink](/lib/oxidized/model/dlink.rb)
|
77
80
|
| |D-Link cisco like CLI |[dlinknextgen](/lib/oxidized/model/dlinknextgen.rb)
|
81
|
+
|Eaton |Gigabit Network Card |[eatonnetwork](/lib/oxidized/model/eatonnetwork.rb) |@thanegill
|
78
82
|
|ECI Telecom |ECIapollo |[eciapollo](/lib/oxidized/model/eciapollo.rb)
|
79
83
|
|EdgeCore |ECS3510, ES3526XA-V2, ES3528M |[edgecos](/lib/oxidized/model/edgecos.rb)
|
80
84
|
|Eltex |Eltex |[eltex](/lib/oxidized/model/eltex.rb)
|
@@ -113,6 +117,7 @@
|
|
113
117
|
|Huawei |VRP |[vrp](/lib/oxidized/model/vrp.rb) | |[VRP-Huawei](Model-Notes/VRP-Huawei.md)
|
114
118
|
| |SmartAX series |[smartax](/lib/oxidized/model/smartax.rb) | |[SmartAX-Huawei](Model-Notes/SmartAX-Huawei.md)
|
115
119
|
|Icotera |6400 series |[icotera](/lib/oxidized/model/icotera.rb)
|
120
|
+
|Ingate |SIParator/Firewalls |[ingate](/lib/oxidized/model/ingate.rb) |@thanegill
|
116
121
|
|IP Infusion |OcNOS |[ocnos](/lib/oxidized/model/ocnos.rb)
|
117
122
|
|Juniper |JunOS |[junos](/lib/oxidized/model/junos.rb) | |[MX/QFX/EX/SRX/J Series](Model-Notes/JunOS.md)
|
118
123
|
| |ScreenOS (Netscreen) |[screenos](/lib/oxidized/model/screenos.rb)
|
@@ -129,6 +134,7 @@
|
|
129
134
|
|MRV |MasterOS |[masteros](/lib/oxidized/model/masteros.rb)
|
130
135
|
| |FiberDriver |[fiberdriver](/lib/oxidized/model/fiberdriver.rb)
|
131
136
|
|NEC |NEC IX |[necix](/lib/oxidized/model/necix.rb)
|
137
|
+
|Netgate |TNSR |[tnsr](/lib/oxidized/model/tnsr.rb) |@Vantomas
|
132
138
|
|Netgear |Netgear switches |[netgear](/lib/oxidized/model/netgear.rb) | |[Netgear](Model-Notes/Netgear.md)
|
133
139
|
|Netonix |WISP Switch (As Netonix) |[netonix](/lib/oxidized/model/netonix.rb)
|
134
140
|
|Nokia (formerly TiMetra, Alcatel, Alcatel-Lucent)|SR OS (TiMOS)|[sros](/lib/oxidized/model/sros.rb) | |[Nokia ISAM](Model-Notes/Nokia.md)
|
@@ -169,6 +175,7 @@
|
|
169
175
|
| |Edgeos |[edgeos](/lib/oxidized/model/edgeos.rb)
|
170
176
|
| |EdgeSwitch |[edgeswitch](/lib/oxidized/model/edgeswitch.rb)
|
171
177
|
| |AirFiber |[airfiber](/lib/oxidized/model/airfiber.rb)
|
178
|
+
| |UnifiAP |[unifiap](/lib/oxidized/model/unifiap.rb) |@clifcox |Also suports AirOS, and some Unifi switches
|
172
179
|
|Uplink |EP4440-DP |[EP4440](/lib/oxidized/model/uplinkolt.rb) | |Might support all EP4440 series
|
173
180
|
|VMWare |NSX Edge (configuration) |[nsxconfig](/lib/oxidized/model/nsxconfig.rb)
|
174
181
|
| |NSX Edge (firewall rules) |[nsxfirewall](/lib/oxidized/model/nsxfirewall.rb)
|
data/docs/Troubleshooting.md
CHANGED
@@ -27,7 +27,10 @@ Welcome to the advanced nuclear launchinator 5A-X20. Proceed with caution.
|
|
27
27
|
SEKRET-5A-X20#
|
28
28
|
```
|
29
29
|
|
30
|
-
Review the relevant device model file and identify the defined prompt. You can
|
30
|
+
Review the relevant device model file and identify the defined prompt. You can
|
31
|
+
find the device models in the `lib/oxidized/model` subdirectory of the
|
32
|
+
repository. For example, the Cisco IOS model, `ios.rb` may use the following
|
33
|
+
prompt:
|
31
34
|
|
32
35
|
```text
|
33
36
|
prompt /^([\w.@()-]+[#>]\s?)$/
|
@@ -85,18 +88,6 @@ If you are running oxidized in a container, you need to map /home/oxidized/.ssh
|
|
85
88
|
container to a local repository and save the known_hosts in the local repository. You can
|
86
89
|
find an example how to do this under [examples/podman-compose](/examples/podman-compose/)
|
87
90
|
|
88
|
-
## Git performance issues with large device counts
|
89
|
-
When you use git to store your configurations, the size of your repository will
|
90
|
-
grow over time. This growth can lead to performance issues. To resolve these issues, you should perform a Git garbage collection on your repository.
|
91
|
-
|
92
|
-
Follow these steps to do so:
|
93
|
-
|
94
|
-
1. Stop oxidized (no one should access the git repository while running garbage collection)
|
95
|
-
2. Make a backup of your oxidized data, especially the Git repository
|
96
|
-
3. Change directory your oxidized git repository (as configured in oxidized configuration file)
|
97
|
-
4. Execute the command `git gc` to run the garbage collection
|
98
|
-
5. Restart oxidized - you're done!
|
99
|
-
|
100
91
|
## Oxidized ignores the changes I made to its git repository
|
101
92
|
First of all: you shouldn't manipulate the git repository of oxidized. Don't
|
102
93
|
create it, don't modify it, leave it alone. You can break things. You have
|
data/extra/device2yaml.rb
CHANGED
@@ -6,24 +6,21 @@ require 'optparse'
|
|
6
6
|
require 'etc'
|
7
7
|
require 'timeout'
|
8
8
|
|
9
|
-
# This
|
9
|
+
# This script logs in a network device and outputs a YAML file that can be
|
10
10
|
# used for model unit tests in spec/model/
|
11
11
|
# For more information, see docs/DeviceSimulation.md
|
12
12
|
|
13
|
-
# This script is quick & dirty - it grew with the time an could be a project
|
14
|
-
# for its own. It works, and that should be enough ;-)
|
15
|
-
|
16
13
|
################# Methods
|
17
14
|
# Runs cmd in the ssh session, either im exec mode or with a tty
|
18
15
|
# saves the output to @output
|
19
16
|
def ssh_exec(cmd)
|
20
|
-
puts "\n### Sending #{cmd}..."
|
21
|
-
@output&.puts " #{cmd}: |-"
|
17
|
+
puts "\n### Sending #{cmd.dump}..."
|
18
|
+
@output&.puts " #{@sequence_prepend_command}#{cmd.dump}: |-"
|
22
19
|
|
23
20
|
if @exec_mode
|
24
|
-
@ssh_output = @ssh.exec! cmd
|
21
|
+
@ssh_output = @ssh.exec! cmd
|
25
22
|
else
|
26
|
-
@ses.send_data cmd
|
23
|
+
@ses.send_data cmd
|
27
24
|
shell_wait
|
28
25
|
end
|
29
26
|
yaml_output(' ')
|
@@ -68,7 +65,14 @@ def shell_wait
|
|
68
65
|
puts "\n### ESC pressed, skipping idle timeout"
|
69
66
|
return false
|
70
67
|
else
|
71
|
-
# if not, send the char through ssh
|
68
|
+
# if not, record the char and send the char through ssh
|
69
|
+
puts "\n### #{char.dump} pressed"
|
70
|
+
yaml_output(' ')
|
71
|
+
@output&.puts " #{@sequence_prepend_command}#{char.dump}: |-"
|
72
|
+
@ssh_output = ''
|
73
|
+
start_time = Time.now
|
74
|
+
@ssh_output_length = @ssh_output.length
|
75
|
+
|
72
76
|
@ses.send_data char
|
73
77
|
end
|
74
78
|
end
|
@@ -85,6 +89,8 @@ def yaml_output(prepend = '')
|
|
85
89
|
# Now print the collected output to @output
|
86
90
|
firstline = true
|
87
91
|
|
92
|
+
prepend = @sequence_prepend_output + prepend
|
93
|
+
|
88
94
|
# as we want to prepend 'prepend' to each line, we need each_line and chomp
|
89
95
|
# chomp removes the trainling \n
|
90
96
|
@ssh_output.each_line(chomp: true) do |line|
|
@@ -113,6 +119,9 @@ end
|
|
113
119
|
|
114
120
|
# Define options
|
115
121
|
options = {}
|
122
|
+
@sequence_prepend_command = '- '
|
123
|
+
@sequence_prepend_output = ' '
|
124
|
+
|
116
125
|
optparse = OptionParser.new do |opts|
|
117
126
|
opts.banner = <<~HEREDOC
|
118
127
|
Usages:
|
@@ -140,6 +149,10 @@ optparse = OptionParser.new do |opts|
|
|
140
149
|
options[:timeout] = timeout
|
141
150
|
end
|
142
151
|
opts.on('-e', '--exec-mode', 'Run ssh in exec mode (without tty)') { @exec_mode = true }
|
152
|
+
opts.on('-u', '--unordered', 'The YAML simulation should not enforce an order of the commands') do
|
153
|
+
@sequence_prepend_command = ''
|
154
|
+
@sequence_prepend_output = ''
|
155
|
+
end
|
143
156
|
opts.on '-h', '--help', 'Print this help' do
|
144
157
|
puts opts
|
145
158
|
exit
|
@@ -182,6 +195,8 @@ elsif options[:input]
|
|
182
195
|
end
|
183
196
|
|
184
197
|
puts "Running #{ssh_commands} on #{ssh_user}@#{ssh_host}"
|
198
|
+
# Add \n to each command
|
199
|
+
ssh_commands.map! { |s| s + "\n" }
|
185
200
|
|
186
201
|
# Defaut idle timeout: 5 seconds, as tests showed that 2 seconds is too short
|
187
202
|
@idle_timeout = options[:timeout] || 5
|
data/extra/rest_client.rb
CHANGED
@@ -6,7 +6,7 @@ module Oxidized
|
|
6
6
|
require 'asetus'
|
7
7
|
|
8
8
|
class Config
|
9
|
-
|
9
|
+
ROOT = ENV['OXIDIZED_HOME'] || File.join(Dir.home, '.config', 'oxidized')
|
10
10
|
end
|
11
11
|
|
12
12
|
CFGS = Asetus.new name: 'oxidized', load: false, key_to_s: true
|
@@ -38,7 +38,8 @@ module Oxidized
|
|
38
38
|
|
39
39
|
def next(opt)
|
40
40
|
data = JSON.dump opt
|
41
|
-
|
41
|
+
headers = { 'content-type': 'application/json' }
|
42
|
+
@web.put PATH + '/node/next/' + opt[:name].to_s, data, headers
|
42
43
|
end
|
43
44
|
end
|
44
45
|
end
|
data/extra/syslog.rb
CHANGED
@@ -8,8 +8,10 @@
|
|
8
8
|
# set system syslog host SERVER interactive-commands notice
|
9
9
|
# set system syslog host SERVER match "^mgd\[[0-9]+\]: UI_COMMIT: .*"
|
10
10
|
|
11
|
-
# Ports < 1024 need extra privileges, use a port higher than this by setting the
|
12
|
-
#
|
11
|
+
# Ports < 1024 need extra privileges, use a port higher than this by setting the
|
12
|
+
# port option in your oxidized config file.
|
13
|
+
# To use the default port for syslog (514) you shouldn't pass an argument, but
|
14
|
+
# you will need to allow this with:
|
13
15
|
# sudo setcap 'cap_net_bind_service=+ep' /usr/bin/ruby
|
14
16
|
|
15
17
|
# Config options are:
|
@@ -52,6 +54,7 @@ module Oxidized
|
|
52
54
|
class SyslogMonitor
|
53
55
|
MSG = {
|
54
56
|
ios: /%SYS-(SW[0-9]+-)?5-CONFIG_I:/,
|
57
|
+
iosxr: /%MGBL-SYS-5-CONFIG_I/,
|
55
58
|
junos: 'UI_COMMIT:',
|
56
59
|
eos: /%SYS-5-CONFIG_I:/,
|
57
60
|
nxos: /%VSHD-5-VSHD_SYSLOG_CONFIG_I:/,
|
@@ -89,6 +92,7 @@ module Oxidized
|
|
89
92
|
opts[:from] = log[-1][1..-2]
|
90
93
|
opts
|
91
94
|
end
|
95
|
+
alias iosxr ios
|
92
96
|
alias nxos ios
|
93
97
|
alias eos ios
|
94
98
|
|
@@ -116,7 +120,8 @@ module Oxidized
|
|
116
120
|
def run(io)
|
117
121
|
loop do
|
118
122
|
log = select [io]
|
119
|
-
log
|
123
|
+
log = log.first.first
|
124
|
+
ip = nil
|
120
125
|
if @mode == :udp
|
121
126
|
log, ip = log.recvfrom_nonblock 2000
|
122
127
|
ip = ip.last
|
data/lib/oxidized/cli.rb
CHANGED
@@ -1,5 +1,9 @@
|
|
1
|
+
require 'semantic_logger'
|
2
|
+
|
1
3
|
module Oxidized
|
2
4
|
class CLI
|
5
|
+
include SemanticLogger::Loggable
|
6
|
+
|
3
7
|
require 'slop'
|
4
8
|
require 'oxidized'
|
5
9
|
require 'English'
|
@@ -9,7 +13,7 @@ module Oxidized
|
|
9
13
|
Process.daemon if @opts[:daemonize]
|
10
14
|
write_pid
|
11
15
|
begin
|
12
|
-
|
16
|
+
logger.info "Oxidized starting, running as pid #{$PROCESS_ID}"
|
13
17
|
Oxidized.new
|
14
18
|
rescue StandardError => e
|
15
19
|
crash e
|
@@ -23,13 +27,13 @@ module Oxidized
|
|
23
27
|
_args, @opts = parse_opts
|
24
28
|
|
25
29
|
Config.load(@opts)
|
26
|
-
Oxidized.
|
30
|
+
Oxidized::Logger.setup
|
27
31
|
|
28
32
|
@pidfile = File.expand_path(Oxidized.config.pid)
|
29
33
|
end
|
30
34
|
|
31
35
|
def crash(error)
|
32
|
-
|
36
|
+
logger.fatal "Oxidized crashed, crashfile written in #{Config::CRASH}"
|
33
37
|
File.open Config::CRASH, 'w' do |file|
|
34
38
|
file.puts '-' * 50
|
35
39
|
file.puts Time.now.utc
|
data/lib/oxidized/config/vars.rb
CHANGED
@@ -1,17 +1,25 @@
|
|
1
|
-
module Oxidized
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
1
|
+
module Oxidized
|
2
|
+
class Config
|
3
|
+
module Vars
|
4
|
+
# convenience method for accessing node, group or global level user variables
|
5
|
+
def vars(name)
|
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]
|
21
|
+
end
|
22
|
+
end
|
15
23
|
end
|
16
24
|
end
|
17
25
|
end
|
data/lib/oxidized/config.rb
CHANGED
@@ -27,7 +27,6 @@ module Oxidized
|
|
27
27
|
asetus.default.model = 'junos'
|
28
28
|
asetus.default.resolve_dns = true # if false, don't resolve DNS to IP
|
29
29
|
asetus.default.interval = 3600
|
30
|
-
asetus.default.use_syslog = false
|
31
30
|
asetus.default.debug = false
|
32
31
|
asetus.default.run_once = false
|
33
32
|
asetus.default.threads = 30
|
@@ -35,7 +34,6 @@ module Oxidized
|
|
35
34
|
asetus.default.timeout = 20
|
36
35
|
asetus.default.retries = 3
|
37
36
|
asetus.default.prompt = /^([\w.@-]+[#>]\s?)$/
|
38
|
-
asetus.default.rest = '127.0.0.1:8888' # or false to disable
|
39
37
|
asetus.default.next_adds_job = false # if true, /next adds job, so device is fetched immmeiately
|
40
38
|
asetus.default.vars = {} # could be 'enable'=>'enablePW'
|
41
39
|
asetus.default.groups = {} # group level configuration
|
@@ -43,6 +41,9 @@ module Oxidized
|
|
43
41
|
asetus.default.models = {} # model level configuration
|
44
42
|
asetus.default.pid = File.join(Oxidized::Config::ROOT, 'pid')
|
45
43
|
|
44
|
+
# Extentions
|
45
|
+
asetus.default.extensions['oxidized-web'].load = false
|
46
|
+
|
46
47
|
asetus.default.crash.directory = File.join(Oxidized::Config::ROOT, 'crashes')
|
47
48
|
asetus.default.crash.hostnames = false
|
48
49
|
|
data/lib/oxidized/core.rb
CHANGED
@@ -6,6 +6,8 @@ module Oxidized
|
|
6
6
|
end
|
7
7
|
|
8
8
|
class Core
|
9
|
+
include SemanticLogger::Loggable
|
10
|
+
|
9
11
|
class NoNodesFound < OxidizedError; end
|
10
12
|
|
11
13
|
def initialize(_args)
|
@@ -23,15 +25,36 @@ module Oxidized
|
|
23
25
|
end
|
24
26
|
Signals.register_signal('HUP', reload_proc)
|
25
27
|
|
26
|
-
#
|
27
|
-
|
28
|
+
# Load extensions, currently only oxidized-web
|
29
|
+
# We have different namespaces for oxidized-web, which needs to be
|
30
|
+
# adressed if we need a generic way to load extensions:
|
31
|
+
# - gem: oxidized-web
|
32
|
+
# - module: Oxidized::API
|
33
|
+
# - path: oxidized/web
|
34
|
+
# - entrypoint: Oxidized::API::Web.new(nodes, configuration)
|
35
|
+
|
36
|
+
# Initialize oxidized-web if requested
|
37
|
+
if Oxidized.config.has_key? 'rest'
|
38
|
+
logger.warn(
|
39
|
+
'configuration: "rest" is deprecated. Migrate to ' \
|
40
|
+
'"extensions.oxidized-web" and remove "rest" from the configuration'
|
41
|
+
)
|
42
|
+
configuration = Oxidized.config.rest
|
43
|
+
elsif Oxidized.config.extensions['oxidized-web'].load?
|
44
|
+
# This comment stops rubocop complaining about Style/IfUnlessModifier
|
45
|
+
configuration = Oxidized.config.extensions['oxidized-web']
|
46
|
+
end
|
47
|
+
|
48
|
+
if configuration
|
28
49
|
begin
|
29
50
|
require 'oxidized/web'
|
30
51
|
rescue LoadError
|
31
|
-
raise OxidizedError,
|
32
|
-
|
52
|
+
raise OxidizedError,
|
53
|
+
'oxidized-web not found: install it or disable it by ' \
|
54
|
+
'removing "rest" and "extensions.oxidized-web" from your ' \
|
55
|
+
'configuration'
|
33
56
|
end
|
34
|
-
@rest = API::Web.new nodes,
|
57
|
+
@rest = API::Web.new nodes, configuration
|
35
58
|
@rest.run
|
36
59
|
end
|
37
60
|
run
|
@@ -40,14 +63,13 @@ module Oxidized
|
|
40
63
|
private
|
41
64
|
|
42
65
|
def reload
|
43
|
-
|
66
|
+
logger.info("Reloading node list")
|
44
67
|
@worker.reload
|
45
|
-
Oxidized.logger.reopen
|
46
68
|
@need_reload = false
|
47
69
|
end
|
48
70
|
|
49
71
|
def run
|
50
|
-
|
72
|
+
logger.debug "Starting the worker..."
|
51
73
|
loop do
|
52
74
|
reload if @need_reload
|
53
75
|
@worker.work
|
@@ -14,30 +14,32 @@ class CiscoSparkDiff < Oxidized::Hook
|
|
14
14
|
return unless ctx.node
|
15
15
|
return unless ctx.event.to_s == "post_store"
|
16
16
|
|
17
|
-
|
17
|
+
logger.info "Connecting to Cisco Spark"
|
18
18
|
CiscoSpark.configure do |config|
|
19
19
|
config.api_key = cfg.accesskey
|
20
20
|
config.proxy = cfg.proxy if cfg.has_key?('proxy')
|
21
21
|
end
|
22
22
|
room = CiscoSpark::Room.new(id: cfg.space)
|
23
|
-
|
23
|
+
logger.info "Connected"
|
24
24
|
|
25
25
|
if cfg.has_key?("diff") ? cfg.diff : true
|
26
26
|
gitoutput = ctx.node.output.new
|
27
27
|
diff = gitoutput.get_diff ctx.node, ctx.node.group, ctx.commitref, nil
|
28
28
|
title = ctx.node.name.to_s
|
29
|
-
|
30
|
-
room.send_message CiscoSpark::Message.new(text:
|
29
|
+
logger.info "Posting diff as snippet to #{cfg.space}"
|
30
|
+
room.send_message CiscoSpark::Message.new(text: "Device #{title} modified:\n" +
|
31
|
+
diff[:patch].lines.to_a[4..-1].join)
|
31
32
|
end
|
32
33
|
|
33
34
|
if cfg.message?
|
34
|
-
|
35
|
-
msg = cfg.message % { node: ctx.node.name.to_s, group: ctx.node.group.to_s, commitref: ctx.commitref,
|
36
|
-
|
37
|
-
|
35
|
+
logger.info cfg.message
|
36
|
+
msg = cfg.message % { node: ctx.node.name.to_s, group: ctx.node.group.to_s, commitref: ctx.commitref,
|
37
|
+
model: ctx.node.model.class.name.to_s.downcase }
|
38
|
+
logger.info msg
|
39
|
+
logger.info "Posting message to #{cfg.space}"
|
38
40
|
room.send_message CiscoSpark::Message.new(text: msg)
|
39
41
|
end
|
40
42
|
|
41
|
-
|
43
|
+
logger.info "Finished"
|
42
44
|
end
|
43
45
|
end
|
data/lib/oxidized/hook/exec.rb
CHANGED
@@ -28,7 +28,7 @@ class Exec < Oxidized::Hook
|
|
28
28
|
|
29
29
|
def run_hook(ctx)
|
30
30
|
env = make_env ctx
|
31
|
-
|
31
|
+
logger.debug "Execute: #{@cmd.inspect}"
|
32
32
|
th = Thread.new do
|
33
33
|
run_cmd! env
|
34
34
|
rescue StandardError => e
|
@@ -38,20 +38,21 @@ class Exec < Oxidized::Hook
|
|
38
38
|
end
|
39
39
|
|
40
40
|
def run_cmd!(env)
|
41
|
-
pid
|
41
|
+
pid = nil
|
42
|
+
status = nil
|
42
43
|
Timeout.timeout(@timeout) do
|
43
44
|
pid = spawn env, @cmd, unsetenv_others: true
|
44
45
|
pid, status = wait2 pid
|
45
46
|
unless status.exitstatus.zero?
|
46
47
|
msg = "#{@cmd.inspect} failed with exit value #{status.exitstatus}"
|
47
|
-
|
48
|
+
logger.error msg
|
48
49
|
raise msg
|
49
50
|
end
|
50
51
|
end
|
51
52
|
rescue Timeout::Error
|
52
53
|
kill "TERM", pid
|
53
54
|
msg = "#{@cmd} timed out"
|
54
|
-
|
55
|
+
logger.error msg
|
55
56
|
raise Timeout::Error, msg
|
56
57
|
end
|
57
58
|
|
@@ -6,8 +6,13 @@ class GithubRepo < Oxidized::Hook
|
|
6
6
|
end
|
7
7
|
|
8
8
|
def run_hook(ctx)
|
9
|
+
unless ctx.node
|
10
|
+
logger.error 'GithubRepo.run_hook: no node provided'
|
11
|
+
return
|
12
|
+
end
|
13
|
+
|
9
14
|
unless ctx.node.repo
|
10
|
-
|
15
|
+
logger.error "Oxidized output is not git, can't push to remote"
|
11
16
|
return
|
12
17
|
end
|
13
18
|
repo = Rugged::Repository.new(ctx.node.repo)
|
@@ -15,12 +20,11 @@ class GithubRepo < Oxidized::Hook
|
|
15
20
|
url = remote_repo(ctx.node)
|
16
21
|
|
17
22
|
if url.nil? || url.empty?
|
18
|
-
|
23
|
+
logger.error "No repository defined for #{ctx.node.group}/#{ctx.node.name}"
|
19
24
|
return
|
20
25
|
end
|
21
26
|
|
22
|
-
|
23
|
-
log "to remote: #{url}"
|
27
|
+
logger.info "Pushing local repository(#{repo.path}) to remote: #{url}"
|
24
28
|
|
25
29
|
if repo.remotes['origin'].nil?
|
26
30
|
repo.remotes.create('origin', url)
|
@@ -34,10 +38,10 @@ class GithubRepo < Oxidized::Hook
|
|
34
38
|
remote.push([repo.head.name], credentials: creds)
|
35
39
|
rescue Rugged::NetworkError => e
|
36
40
|
if e.message == 'unsupported URL protocol'
|
37
|
-
|
41
|
+
logger.warn "Rugged does not support the git URL '#{url}'."
|
38
42
|
unless Rugged.features.include?(:ssh)
|
39
|
-
|
40
|
-
|
43
|
+
logger.warn "Note: Rugged isn't installed with ssh support. You may need " \
|
44
|
+
'"gem install rugged -- --with-ssh"'
|
41
45
|
end
|
42
46
|
end
|
43
47
|
# re-raise exception for the calling method
|
@@ -47,28 +51,28 @@ class GithubRepo < Oxidized::Hook
|
|
47
51
|
|
48
52
|
def fetch_and_merge_remote(repo, creds)
|
49
53
|
result = repo.fetch('origin', [repo.head.name], credentials: creds)
|
50
|
-
|
54
|
+
logger.debug result.inspect
|
51
55
|
|
52
56
|
their_branch = remote_branch(repo)
|
53
57
|
|
54
58
|
unless their_branch
|
55
|
-
|
59
|
+
logger.debug 'remote branch does not exist yet, nothing to merge'
|
56
60
|
return
|
57
61
|
end
|
58
62
|
|
59
63
|
result = repo.merge_analysis(their_branch.target_id)
|
60
64
|
|
61
65
|
if result.include? :up_to_date
|
62
|
-
|
66
|
+
logger.debug 'nothing to merge'
|
63
67
|
return
|
64
68
|
end
|
65
69
|
|
66
|
-
|
70
|
+
logger.debug "merging fetched branch #{their_branch.name}"
|
67
71
|
|
68
72
|
merge_index = repo.merge_commits(repo.head.target_id, their_branch.target_id)
|
69
73
|
|
70
74
|
if merge_index.conflicts?
|
71
|
-
|
75
|
+
logger.warn "Conflicts detected, skipping Rugged::Commit.create"
|
72
76
|
return
|
73
77
|
end
|
74
78
|
|
@@ -85,18 +89,20 @@ class GithubRepo < Oxidized::Hook
|
|
85
89
|
Proc.new do |_url, username_from_url, _allowed_types| # rubocop:disable Style/Proc
|
86
90
|
git_user = cfg.has_key?('username') ? cfg.username : (username_from_url || 'git')
|
87
91
|
if cfg.has_key?('password')
|
88
|
-
|
92
|
+
logger.debug "Authenticating using username and password as '#{git_user}'"
|
89
93
|
Rugged::Credentials::UserPassword.new(username: git_user, password: cfg.password)
|
90
94
|
elsif cfg.has_key?('privatekey')
|
91
95
|
pubkey = cfg.has_key?('publickey') ? cfg.publickey : nil
|
92
|
-
|
96
|
+
logger.debug "Authenticating using ssh keys as '#{git_user}'"
|
93
97
|
rugged_sshkey(git_user: git_user, privkey: cfg.privatekey, pubkey: pubkey)
|
94
|
-
elsif cfg.has_key?('remote_repo') &&
|
98
|
+
elsif cfg.has_key?('remote_repo') &&
|
99
|
+
cfg.remote_repo.has_key?(node.group) &&
|
100
|
+
cfg.remote_repo[node.group].has_key?('privatekey')
|
95
101
|
pubkey = cfg.remote_repo[node.group].has_key?('publickey') ? cfg.remote_repo[node.group].publickey : nil
|
96
|
-
|
102
|
+
logger.debug "Authenticating using ssh keys as '#{git_user}' for '#{node.group}/#{node.name}'"
|
97
103
|
rugged_sshkey(git_user: git_user, privkey: cfg.remote_repo[node.group].privatekey, pubkey: pubkey)
|
98
104
|
else
|
99
|
-
|
105
|
+
logger.debug "Authenticating using ssh agent as '#{git_user}'"
|
100
106
|
Rugged::Credentials::SshKeyFromAgent.new(username: git_user)
|
101
107
|
end
|
102
108
|
end
|
@@ -12,7 +12,7 @@ class SlackDiff < Oxidized::Hook
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def slack_upload(client, title, content, channel)
|
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")
|
@@ -39,14 +39,14 @@ class SlackDiff < Oxidized::Hook
|
|
39
39
|
return unless ctx.node
|
40
40
|
return unless ctx.event.to_s == "post_store"
|
41
41
|
|
42
|
-
|
42
|
+
logger.info "Connecting to slack"
|
43
43
|
Slack::Web::Client.configure do |config|
|
44
44
|
config.token = cfg.token
|
45
45
|
config.proxy = cfg.proxy if cfg.has_key?('proxy')
|
46
46
|
end
|
47
47
|
client = Slack::Web::Client.new
|
48
48
|
client.auth_test
|
49
|
-
|
49
|
+
logger.info "Connected"
|
50
50
|
if cfg.has_key?("diff") ? cfg.diff : true
|
51
51
|
gitoutput = ctx.node.output.new
|
52
52
|
diff = gitoutput.get_diff ctx.node, ctx.node.group, ctx.commitref, nil
|
@@ -58,12 +58,13 @@ class SlackDiff < Oxidized::Hook
|
|
58
58
|
end
|
59
59
|
# message custom formatted - optional
|
60
60
|
if cfg.message?
|
61
|
-
|
62
|
-
msg = cfg.message % { node: ctx.node.name.to_s, group: ctx.node.group.to_s, commitref: ctx.commitref,
|
63
|
-
|
64
|
-
|
61
|
+
logger.info cfg.message
|
62
|
+
msg = cfg.message % { node: ctx.node.name.to_s, group: ctx.node.group.to_s, commitref: ctx.commitref,
|
63
|
+
model: ctx.node.model.class.name.to_s.downcase }
|
64
|
+
logger.info msg
|
65
|
+
logger.info "Posting message to #{cfg.channel}"
|
65
66
|
client.chat_postMessage(channel: cfg.channel, text: msg, as_user: true)
|
66
67
|
end
|
67
|
-
|
68
|
+
logger.info "Finished"
|
68
69
|
end
|
69
70
|
end
|