oxidized 0.29.1 → 0.37.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.coderabbit.yaml +21 -0
- data/.github/ISSUE_TEMPLATE/bug_report.md +45 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +22 -0
- data/.github/ISSUE_TEMPLATE/support-request.md +39 -0
- data/.github/workflows/codeql.yml +4 -4
- data/.github/workflows/publishdocker.yml +108 -13
- data/.github/workflows/ruby.yml +3 -12
- data/.github/workflows/stale.yml +6 -1
- data/.gitignore +2 -0
- data/.rubocop.yml +69 -13
- data/.rubocop_todo.yml +13 -143
- data/CHANGELOG.md +431 -4
- data/CONTRIBUTING.md +189 -0
- data/Dockerfile +89 -34
- data/README.md +59 -188
- data/Rakefile +58 -12
- data/bin/oxidized +2 -5
- data/docs/Configuration.md +382 -149
- data/docs/Creating-Models.md +262 -10
- data/docs/DeviceSimulation.md +196 -0
- data/docs/Docker.md +246 -0
- data/docs/Hooks.md +146 -51
- data/docs/Inputs.md +237 -0
- data/docs/Issues.md +123 -0
- data/docs/Model-Notes/APC.md +72 -0
- data/docs/Model-Notes/Cumulus.md +5 -0
- data/docs/Model-Notes/EatonNetwork.md +18 -0
- data/docs/Model-Notes/ExaLink.md +43 -0
- data/docs/Model-Notes/FSOS.md +17 -0
- data/docs/Model-Notes/Fortinet.md +75 -0
- data/docs/Model-Notes/GrandstreamHT8xx.md +8 -0
- data/docs/Model-Notes/HPEAruba.md +32 -0
- data/docs/Model-Notes/IvantiConnectSecure.md +59 -0
- data/docs/Model-Notes/OS6.md +10 -0
- data/docs/Model-Notes/README.md +1 -20
- data/docs/Model-Notes/RouterOS.md +28 -0
- data/docs/Model-Notes/SikluMHTG.md +7 -0
- data/docs/Model-Notes/TrueNAS.md +23 -0
- data/docs/Model-Notes/XGS4600-Zyxel.md +5 -0
- data/docs/ModelUnitTests.md +219 -0
- data/docs/Outputs.md +102 -5
- data/docs/Release.md +102 -0
- data/docs/Ruby-API.md +135 -2
- data/docs/Sources.md +34 -0
- data/docs/Supported-OS-Types.md +207 -270
- data/docs/Troubleshooting.md +43 -1
- data/extra/device2yaml.rb +259 -0
- data/extra/gitdiff-msteams.sh +32 -5
- data/extra/hooks/modelrules.rb +55 -0
- data/extra/hooks/modelrulesadvanced.rb +167 -0
- data/extra/hooks/srcipmap.rb +54 -0
- data/extra/nagios_check_failing_nodes.rb +1 -1
- data/extra/oxidized.runit +1 -1
- data/extra/rest_client.rb +5 -4
- data/extra/syslog.rb +11 -6
- data/lib/oxidized/cli/support.rb +152 -0
- data/lib/oxidized/cli.rb +21 -6
- data/lib/oxidized/config/vars.rb +33 -14
- data/lib/oxidized/config.rb +28 -17
- data/lib/oxidized/core.rb +50 -8
- data/lib/oxidized/hook/ciscosparkdiff.rb +11 -9
- data/lib/oxidized/hook/exec.rb +5 -4
- data/lib/oxidized/hook/githubrepo.rb +55 -18
- data/lib/oxidized/hook/noophook.rb +2 -2
- data/lib/oxidized/hook/slackdiff.rb +50 -14
- data/lib/oxidized/hook/xmppdiff.rb +9 -9
- data/lib/oxidized/hook.rb +68 -16
- data/lib/oxidized/input/cli.rb +8 -3
- data/lib/oxidized/input/debugtext.rb +40 -0
- data/lib/oxidized/input/debugyaml.rb +82 -0
- data/lib/oxidized/input/exec.rb +2 -11
- data/lib/oxidized/input/ftp.rb +2 -19
- data/lib/oxidized/input/http.rb +67 -17
- data/lib/oxidized/input/input.rb +35 -14
- data/lib/oxidized/input/scp.rb +27 -0
- data/lib/oxidized/input/ssh.rb +59 -83
- data/lib/oxidized/input/sshbase.rb +102 -0
- data/lib/oxidized/input/telnet.rb +20 -19
- data/lib/oxidized/input/tftp.rb +8 -8
- data/lib/oxidized/job.rb +18 -7
- data/lib/oxidized/jobs.rb +11 -1
- data/lib/oxidized/logger.rb +51 -0
- data/lib/oxidized/manager.rb +18 -17
- data/lib/oxidized/model/acos.rb +2 -1
- data/lib/oxidized/model/addpack.rb +26 -0
- data/lib/oxidized/model/adtran.rb +5 -1
- data/lib/oxidized/model/adva.rb +3 -3
- data/lib/oxidized/model/airfiber.rb +1 -1
- data/lib/oxidized/model/aos7.rb +11 -0
- data/lib/oxidized/model/aoscx.rb +37 -29
- data/lib/oxidized/model/aosw.rb +39 -29
- data/lib/oxidized/model/apc_aos.rb +7 -2
- data/lib/oxidized/model/apcaos.rb +39 -0
- data/lib/oxidized/model/aricentiss.rb +9 -2
- data/lib/oxidized/model/arubainstant.rb +93 -0
- data/lib/oxidized/model/asa.rb +11 -10
- data/lib/oxidized/model/asternos.rb +22 -0
- data/lib/oxidized/model/asyncos.rb +3 -3
- data/lib/oxidized/model/audiocodes.rb +2 -2
- data/lib/oxidized/model/awplus.rb +15 -12
- data/lib/oxidized/model/axos.rb +1 -1
- data/lib/oxidized/model/bdcom.rb +1 -0
- data/lib/oxidized/model/c4cmts.rb +1 -2
- data/lib/oxidized/model/ciscosma.rb +1 -1
- data/lib/oxidized/model/ciscosmb.rb +6 -1
- data/lib/oxidized/model/cnos.rb +13 -10
- data/lib/oxidized/model/comtrol.rb +1 -1
- data/lib/oxidized/model/comware.rb +5 -3
- data/lib/oxidized/model/cumulus.rb +14 -2
- data/lib/oxidized/model/defacto.rb +26 -0
- data/lib/oxidized/model/dellx.rb +1 -1
- data/lib/oxidized/model/dlink.rb +5 -2
- data/lib/oxidized/model/dlinknextgen.rb +55 -0
- data/lib/oxidized/model/dnos.rb +3 -0
- data/lib/oxidized/model/dslcommands.rb +93 -0
- data/lib/oxidized/model/dslsetup.rb +102 -0
- data/lib/oxidized/model/eatonnetwork.rb +70 -0
- data/lib/oxidized/model/edgecos.rb +3 -1
- data/lib/oxidized/model/edgeos.rb +7 -6
- data/lib/oxidized/model/edgeswitch.rb +3 -1
- data/lib/oxidized/model/efos.rb +41 -0
- data/lib/oxidized/model/eltex.rb +4 -2
- data/lib/oxidized/model/enterasys800.rb +2 -2
- data/lib/oxidized/model/enterprise_sonic.rb +46 -0
- data/lib/oxidized/model/eos.rb +3 -1
- data/lib/oxidized/model/exalink.rb +36 -0
- data/lib/oxidized/model/f5os.rb +17 -0
- data/lib/oxidized/model/fabricos.rb +2 -2
- data/lib/oxidized/model/fastiron.rb +5 -3
- data/lib/oxidized/model/firebrick.rb +2 -2
- data/lib/oxidized/model/firelinuxos.rb +13 -6
- data/lib/oxidized/model/firewareos.rb +10 -1
- data/lib/oxidized/model/fortigate.rb +160 -0
- data/lib/oxidized/model/fortios.rb +38 -48
- data/lib/oxidized/model/fsos.rb +46 -0
- data/lib/oxidized/model/gaiaos.rb +4 -4
- data/lib/oxidized/model/garderos.rb +38 -0
- data/lib/oxidized/model/grandstreamht8xx.rb +19 -0
- data/lib/oxidized/model/h3c.rb +1 -1
- data/lib/oxidized/model/ibos.rb +1 -0
- data/lib/oxidized/model/ingate.rb +47 -0
- data/lib/oxidized/model/ios.rb +57 -30
- data/lib/oxidized/model/iosxr.rb +2 -2
- data/lib/oxidized/model/ironware.rb +7 -5
- data/lib/oxidized/model/ivanti.rb +54 -0
- data/lib/oxidized/model/junos.rb +12 -5
- data/lib/oxidized/model/kornfeldos.rb +33 -0
- data/lib/oxidized/model/lenovonos.rb +2 -0
- data/lib/oxidized/model/linksyssrw.rb +3 -3
- data/lib/oxidized/model/linuxgeneric.rb +4 -2
- data/lib/oxidized/model/macros.rb +60 -0
- data/lib/oxidized/model/mimosab11.rb +34 -0
- data/lib/oxidized/model/ml66.rb +33 -0
- data/lib/oxidized/model/mlnxos.rb +18 -14
- data/lib/oxidized/model/model.rb +98 -103
- data/lib/oxidized/model/mtrlrfs.rb +1 -0
- data/lib/oxidized/model/ndms.rb +6 -0
- data/lib/oxidized/model/netgear.rb +14 -3
- data/lib/oxidized/model/netonix.rb +1 -1
- data/lib/oxidized/model/netscaler.rb +1 -1
- data/lib/oxidized/model/nodegrid.rb +1 -1
- data/lib/oxidized/model/nsxdfw.rb +31 -0
- data/lib/oxidized/model/nsxfirewall.rb +2 -1
- data/lib/oxidized/model/nxos.rb +20 -15
- data/lib/oxidized/model/ocnos.rb +42 -0
- data/lib/oxidized/model/onefinity.rb +18 -0
- data/lib/oxidized/model/openbsd.rb +1 -1
- data/lib/oxidized/model/opengear.rb +36 -1
- data/lib/oxidized/model/openwrt.rb +6 -6
- data/lib/oxidized/model/opnsense.rb +9 -1
- data/lib/oxidized/model/os6.rb +48 -0
- data/lib/oxidized/model/outputs.rb +5 -0
- data/lib/oxidized/model/panos.rb +2 -0
- data/lib/oxidized/model/perle.rb +41 -0
- data/lib/oxidized/model/pfsense.rb +9 -0
- data/lib/oxidized/model/powerconnect.rb +32 -11
- data/lib/oxidized/model/procurve.rb +6 -2
- data/lib/oxidized/model/qtech.rb +3 -1
- data/lib/oxidized/model/quantaos.rb +8 -6
- data/lib/oxidized/model/rgos.rb +33 -0
- data/lib/oxidized/model/riverbed.rb +104 -0
- data/lib/oxidized/model/routeros.rb +18 -11
- data/lib/oxidized/model/saos.rb +18 -1
- data/lib/oxidized/model/saos10.rb +38 -0
- data/lib/oxidized/model/siklu.rb +1 -1
- data/lib/oxidized/model/siklumhtg.rb +22 -0
- data/lib/oxidized/model/sixwind.rb +28 -0
- data/lib/oxidized/model/slxos.rb +3 -3
- data/lib/oxidized/model/smartbyte.rb +48 -0
- data/lib/oxidized/model/sonicos.rb +27 -20
- data/lib/oxidized/model/speedtouch.rb +1 -1
- data/lib/oxidized/model/sros.rb +3 -3
- data/lib/oxidized/model/srosmd.rb +1 -1
- data/lib/oxidized/model/supermicro.rb +1 -1
- data/lib/oxidized/model/telco.rb +1 -1
- data/lib/oxidized/model/tmos.rb +1 -0
- data/lib/oxidized/model/tnsr.rb +57 -0
- data/lib/oxidized/model/tplink.rb +5 -5
- data/lib/oxidized/model/trango.rb +4 -2
- data/lib/oxidized/model/truenas.rb +64 -3
- data/lib/oxidized/model/ucs.rb +1 -1
- data/lib/oxidized/model/unifiap.rb +144 -0
- data/lib/oxidized/model/uplinkolt.rb +46 -0
- data/lib/oxidized/model/voltaire.rb +1 -1
- data/lib/oxidized/model/voss.rb +3 -0
- data/lib/oxidized/model/vrp.rb +5 -1
- data/lib/oxidized/model/vyatta.rb +9 -3
- data/lib/oxidized/model/vyos.rb +37 -0
- data/lib/oxidized/model/xos.rb +10 -1
- data/lib/oxidized/model/zhoneolt.rb +4 -2
- data/lib/oxidized/model/zynos.rb +67 -3
- data/lib/oxidized/model/zynosadsl.rb +14 -0
- data/lib/oxidized/model/zynoscli.rb +1 -1
- data/lib/oxidized/model/zynosgs.rb +2 -0
- data/lib/oxidized/model/zynosmgs.rb +32 -0
- data/lib/oxidized/node.rb +99 -64
- data/lib/oxidized/nodes.rb +40 -19
- data/lib/oxidized/output/file.rb +80 -43
- data/lib/oxidized/output/git.rb +295 -151
- data/lib/oxidized/output/gitcrypt.rb +193 -185
- data/lib/oxidized/output/http.rb +63 -51
- data/lib/oxidized/output/output.rb +20 -4
- data/lib/oxidized/signals.rb +44 -0
- data/lib/oxidized/source/csv.rb +49 -49
- data/lib/oxidized/source/http.rb +76 -63
- data/lib/oxidized/source/jsonfile.rb +68 -0
- data/lib/oxidized/source/source.rb +73 -18
- data/lib/oxidized/source/sql.rb +71 -59
- data/lib/oxidized/version.rb +6 -4
- data/lib/oxidized/worker.rb +57 -29
- data/lib/oxidized.rb +4 -24
- data/lib/refinements.rb +21 -1
- data/oxidized.gemspec +45 -21
- metadata +248 -41
- data/lib/oxidized/model/timos.rb +0 -10
data/lib/oxidized/source/csv.rb
CHANGED
|
@@ -1,60 +1,60 @@
|
|
|
1
1
|
module Oxidized
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
def setup
|
|
9
|
-
if @cfg.empty?
|
|
10
|
-
Oxidized.asetus.user.source.csv.file = File.join(Config::Root, 'router.db')
|
|
11
|
-
Oxidized.asetus.user.source.csv.delimiter = /:/
|
|
12
|
-
Oxidized.asetus.user.source.csv.map.name = 0
|
|
13
|
-
Oxidized.asetus.user.source.csv.map.model = 1
|
|
14
|
-
Oxidized.asetus.user.source.csv.gpg = false
|
|
15
|
-
Oxidized.asetus.save :user
|
|
16
|
-
raise NoConfig, 'no source csv config, edit ~/.config/oxidized/config'
|
|
2
|
+
module Source
|
|
3
|
+
class CSV < Source
|
|
4
|
+
def initialize
|
|
5
|
+
@cfg = Oxidized.config.source.csv
|
|
6
|
+
super
|
|
17
7
|
end
|
|
18
|
-
require 'gpgme' if @cfg.gpg?
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def load(_node_want = nil)
|
|
22
|
-
nodes = []
|
|
23
|
-
open_file.each_line do |line|
|
|
24
|
-
next if line =~ /^\s*#/
|
|
25
|
-
|
|
26
|
-
data = line.chomp.split(@cfg.delimiter, -1)
|
|
27
|
-
next if data.empty?
|
|
28
8
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
9
|
+
def setup
|
|
10
|
+
if @cfg.empty?
|
|
11
|
+
Oxidized.asetus.user.source.csv.file = File.join(Config::ROOT, 'router.db')
|
|
12
|
+
Oxidized.asetus.user.source.csv.delimiter = /:/
|
|
13
|
+
Oxidized.asetus.user.source.csv.map.name = 0
|
|
14
|
+
Oxidized.asetus.user.source.csv.map.model = 1
|
|
15
|
+
Oxidized.asetus.user.source.csv.gpg = false
|
|
16
|
+
Oxidized.asetus.save :user
|
|
17
|
+
raise NoConfig, "no source csv config, edit #{Oxidized::Config.configfile}"
|
|
33
18
|
end
|
|
34
|
-
|
|
35
|
-
keys[:group] = map_group keys[:group] if keys.has_key? :group
|
|
19
|
+
require 'gpgme' if @cfg.gpg?
|
|
36
20
|
|
|
37
|
-
# map
|
|
38
|
-
|
|
39
|
-
@cfg.vars_map.each do |key, position|
|
|
40
|
-
vars[key.to_sym] = node_var_interpolate data[position]
|
|
41
|
-
end
|
|
42
|
-
keys[:vars] = vars unless vars.empty?
|
|
21
|
+
# map.name is mandatory
|
|
22
|
+
return if @cfg.map.has_key?('name')
|
|
43
23
|
|
|
44
|
-
|
|
24
|
+
raise InvalidConfig, "map/name is a mandatory source attribute, edit #{Oxidized::Config.configfile}"
|
|
45
25
|
end
|
|
46
|
-
nodes
|
|
47
|
-
end
|
|
48
26
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
27
|
+
def load(_node_want = nil)
|
|
28
|
+
nodes = []
|
|
29
|
+
open_file.each_line do |line|
|
|
30
|
+
next if line =~ /^\s*#/
|
|
31
|
+
|
|
32
|
+
data = line.chomp.split(@cfg.delimiter, -1)
|
|
33
|
+
next if data.empty?
|
|
34
|
+
|
|
35
|
+
# map node parameters
|
|
36
|
+
keys = {}
|
|
37
|
+
@cfg.map.each do |key, position|
|
|
38
|
+
keys[key.to_sym] = node_var_interpolate data[position]
|
|
39
|
+
end
|
|
40
|
+
keys[:model] = map_model keys[:model] if keys.has_key? :model
|
|
41
|
+
keys[:group] = map_group keys[:group] if keys.has_key? :group
|
|
42
|
+
|
|
43
|
+
# map node specific vars
|
|
44
|
+
vars = {}
|
|
45
|
+
@cfg.vars_map.each do |key, position|
|
|
46
|
+
vars[key.to_s] = node_var_interpolate data[position]
|
|
47
|
+
end
|
|
48
|
+
keys[:vars] = vars unless vars.empty?
|
|
49
|
+
|
|
50
|
+
keys = Oxidized.hooks.source_node_transform(node: keys,
|
|
51
|
+
node_raw: data,
|
|
52
|
+
context: self)
|
|
53
|
+
next if keys.nil?
|
|
54
|
+
|
|
55
|
+
nodes << keys
|
|
56
|
+
end
|
|
57
|
+
nodes
|
|
58
58
|
end
|
|
59
59
|
end
|
|
60
60
|
end
|
data/lib/oxidized/source/http.rb
CHANGED
|
@@ -1,81 +1,94 @@
|
|
|
1
1
|
module Oxidized
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
module Source
|
|
3
|
+
require "oxidized/source/jsonfile"
|
|
4
|
+
class HTTP < JSONFile
|
|
5
|
+
def initialize
|
|
6
|
+
super
|
|
7
|
+
@cfg = Oxidized.config.source.http
|
|
8
|
+
end
|
|
7
9
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
+
def setup
|
|
11
|
+
if @cfg.empty?
|
|
12
|
+
Oxidized.asetus.user.source.http.url = 'https://url/api'
|
|
13
|
+
Oxidized.asetus.user.source.http.map.name = 'name'
|
|
14
|
+
Oxidized.asetus.user.source.http.map.model = 'model'
|
|
15
|
+
Oxidized.asetus.save :user
|
|
10
16
|
|
|
11
|
-
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
require "net/http"
|
|
15
|
-
require "net/https"
|
|
16
|
-
require "uri"
|
|
17
|
-
require "json"
|
|
18
|
-
|
|
19
|
-
def load(node_want = nil)
|
|
20
|
-
nodes = []
|
|
21
|
-
data = JSON.parse(read_http(node_want))
|
|
22
|
-
data = string_navigate(data, @cfg.hosts_location) if @cfg.hosts_location?
|
|
23
|
-
data.each do |node|
|
|
24
|
-
next if node.empty?
|
|
25
|
-
|
|
26
|
-
# map node parameters
|
|
27
|
-
keys = {}
|
|
28
|
-
@cfg.map.each do |key, want_position|
|
|
29
|
-
keys[key.to_sym] = node_var_interpolate string_navigate(node, want_position)
|
|
17
|
+
raise NoConfig, "No source http config, edit #{Oxidized::Config.configfile}"
|
|
30
18
|
end
|
|
31
|
-
keys[:model] = map_model keys[:model] if keys.has_key? :model
|
|
32
|
-
keys[:group] = map_group keys[:group] if keys.has_key? :group
|
|
33
19
|
|
|
34
|
-
#
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
20
|
+
# check for mandatory attributes
|
|
21
|
+
if !@cfg.has_key?('url')
|
|
22
|
+
raise InvalidConfig, "url is a mandatory http source attribute, edit #{Oxidized::Config.configfile}"
|
|
23
|
+
elsif !@cfg.map.has_key?('name')
|
|
24
|
+
raise InvalidConfig, "map/name is a mandatory source attribute, edit #{Oxidized::Config.configfile}"
|
|
38
25
|
end
|
|
39
|
-
keys[:vars] = vars unless vars.empty?
|
|
40
|
-
|
|
41
|
-
nodes << keys
|
|
42
26
|
end
|
|
43
|
-
nodes
|
|
44
|
-
end
|
|
45
27
|
|
|
46
|
-
|
|
28
|
+
require "net/http"
|
|
29
|
+
require "net/https"
|
|
30
|
+
require "uri"
|
|
31
|
+
require "json"
|
|
47
32
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
33
|
+
def load(node_want = nil)
|
|
34
|
+
uri = URI.parse(@cfg.url)
|
|
35
|
+
data = JSON.parse(read_http(uri, node_want))
|
|
36
|
+
node_data = data
|
|
37
|
+
node_data = string_navigate_object(data, @cfg.hosts_location) if @cfg.hosts_location?
|
|
38
|
+
node_data = pagination(data, node_want) if @cfg.pagination?
|
|
39
|
+
|
|
40
|
+
transform_json(node_data)
|
|
55
41
|
end
|
|
56
|
-
object
|
|
57
|
-
end
|
|
58
42
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
43
|
+
private
|
|
44
|
+
|
|
45
|
+
def pagination(data, node_want)
|
|
46
|
+
node_data = []
|
|
47
|
+
unless @cfg.pagination_key_name?
|
|
48
|
+
raise Oxidized::OxidizedError,
|
|
49
|
+
"if using pagination, 'pagination_key_name' setting must be set"
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
next_key = @cfg.pagination_key_name
|
|
53
|
+
# Process the initial batch first
|
|
54
|
+
node_data += string_navigate_object(data, @cfg.hosts_location) if @cfg.hosts_location?
|
|
55
|
+
|
|
56
|
+
# Now loop only for subsequent pages
|
|
57
|
+
loop do
|
|
58
|
+
# Check for the next URL *before* trying to fetch/add
|
|
59
|
+
break if data[next_key].nil?
|
|
64
60
|
|
|
65
|
-
|
|
66
|
-
|
|
61
|
+
# Fetch the next page
|
|
62
|
+
new_uri = URI.parse(data[next_key]) # Safe to parse now
|
|
63
|
+
data = JSON.parse(read_http(new_uri, node_want))
|
|
64
|
+
|
|
65
|
+
# Add nodes from the *newly fetched* batch
|
|
66
|
+
node_data += string_navigate_object(data, @cfg.hosts_location) if @cfg.hosts_location?
|
|
67
|
+
end
|
|
67
68
|
|
|
68
|
-
|
|
69
|
-
headers = {}
|
|
70
|
-
@cfg.headers.each do |header, value|
|
|
71
|
-
headers[header] = value
|
|
69
|
+
node_data
|
|
72
70
|
end
|
|
73
71
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
72
|
+
def read_http(uri, node_want)
|
|
73
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
|
74
|
+
http.use_ssl = true if uri.scheme == 'https'
|
|
75
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE unless @cfg.secure
|
|
76
|
+
|
|
77
|
+
# Add read_timeout to handle case of big list of nodes (default value is 60 seconds)
|
|
78
|
+
http.read_timeout = Integer(@cfg.read_timeout) if @cfg.has_key? "read_timeout"
|
|
79
|
+
|
|
80
|
+
# map headers
|
|
81
|
+
headers = {}
|
|
82
|
+
@cfg.headers.each do |header, value|
|
|
83
|
+
headers[header] = value
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
req_uri = uri.request_uri
|
|
87
|
+
req_uri = "#{req_uri}/#{node_want}" if node_want
|
|
88
|
+
request = Net::HTTP::Get.new(req_uri, headers)
|
|
89
|
+
request.basic_auth(@cfg.user, @cfg.pass) if @cfg.user? && @cfg.pass?
|
|
90
|
+
http.request(request).body
|
|
91
|
+
end
|
|
79
92
|
end
|
|
80
93
|
end
|
|
81
94
|
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
module Oxidized
|
|
2
|
+
module Source
|
|
3
|
+
class JSONFile < Source
|
|
4
|
+
require "json"
|
|
5
|
+
def initialize
|
|
6
|
+
@cfg = Oxidized.config.source.jsonfile
|
|
7
|
+
super
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def setup
|
|
11
|
+
if @cfg.empty?
|
|
12
|
+
Oxidized.asetus.user.source.jsonfile.file = File.join(Oxidized::Config::ROOT,
|
|
13
|
+
'router.json')
|
|
14
|
+
Oxidized.asetus.user.source.jsonfile.map.name = "name"
|
|
15
|
+
Oxidized.asetus.user.source.jsonfile.map.model = "model"
|
|
16
|
+
Oxidized.asetus.user.source.jsonfile.gpg = false
|
|
17
|
+
Oxidized.asetus.save :user
|
|
18
|
+
raise NoConfig, "No source json config, edit #{Oxidized::Config.configfile}"
|
|
19
|
+
end
|
|
20
|
+
require 'gpgme' if @cfg.gpg?
|
|
21
|
+
|
|
22
|
+
# map.name is mandatory
|
|
23
|
+
return if @cfg.map.has_key?('name')
|
|
24
|
+
|
|
25
|
+
raise InvalidConfig, "map/name is a mandatory source attribute, edit #{Oxidized::Config.configfile}"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def load(*)
|
|
29
|
+
data = JSON.parse(open_file.read)
|
|
30
|
+
data = string_navigate_object(data, @cfg.hosts_location) if @cfg.hosts_location?
|
|
31
|
+
|
|
32
|
+
transform_json(data)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
def transform_json(data)
|
|
38
|
+
nodes = []
|
|
39
|
+
data.each do |node|
|
|
40
|
+
next if node.empty?
|
|
41
|
+
|
|
42
|
+
# map node parameters
|
|
43
|
+
keys = {}
|
|
44
|
+
@cfg.map.each do |key, want_position|
|
|
45
|
+
keys[key.to_sym] = node_var_interpolate string_navigate_object(node, want_position)
|
|
46
|
+
end
|
|
47
|
+
keys[:model] = map_model keys[:model] if keys.has_key? :model
|
|
48
|
+
keys[:group] = map_group keys[:group] if keys.has_key? :group
|
|
49
|
+
|
|
50
|
+
# map node specific vars
|
|
51
|
+
vars = {}
|
|
52
|
+
@cfg.vars_map.each do |key, want_position|
|
|
53
|
+
vars[key.to_s] = node_var_interpolate string_navigate_object(node, want_position)
|
|
54
|
+
end
|
|
55
|
+
keys[:vars] = vars unless vars.empty?
|
|
56
|
+
|
|
57
|
+
keys = Oxidized.hooks.source_node_transform(node: keys,
|
|
58
|
+
node_raw: node,
|
|
59
|
+
context: self)
|
|
60
|
+
next if keys.nil?
|
|
61
|
+
|
|
62
|
+
nodes << keys
|
|
63
|
+
end
|
|
64
|
+
nodes
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -1,26 +1,81 @@
|
|
|
1
1
|
module Oxidized
|
|
2
|
-
|
|
3
|
-
class
|
|
2
|
+
module Source
|
|
3
|
+
class Source
|
|
4
|
+
class NoConfig < OxidizedError; end
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
def initialize
|
|
7
|
+
@model_map = Oxidized.config.model_map || {}
|
|
8
|
+
@group_map = Oxidized.config.group_map || {}
|
|
9
|
+
end
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
# common code of #map_model and #map_group
|
|
12
|
+
def map_value(map_hash, original_value)
|
|
13
|
+
map_hash.each do |key, new_value|
|
|
14
|
+
mthd = key.instance_of?(Regexp) ? :match : :eql?
|
|
15
|
+
return new_value if original_value.send(mthd, key)
|
|
16
|
+
end
|
|
17
|
+
original_value
|
|
18
|
+
end
|
|
13
19
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
20
|
+
# search a match for model in the configuration and returns it.
|
|
21
|
+
# If no match is found, return model
|
|
22
|
+
#
|
|
23
|
+
# model can be matched against a string or a regexp:
|
|
24
|
+
#
|
|
25
|
+
# model_map:
|
|
26
|
+
# cisco: ios
|
|
27
|
+
# juniper: junos
|
|
28
|
+
# !ruby/regexp /procurve/: procurve
|
|
29
|
+
def map_model(model)
|
|
30
|
+
map_value(@model_map, model)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# search a match for group in the configuration and returns it.
|
|
34
|
+
# If no match is found, return group
|
|
35
|
+
#
|
|
36
|
+
# group can be matched against a string or a regexp:
|
|
37
|
+
#
|
|
38
|
+
# group_map:
|
|
39
|
+
# alias1: groupA
|
|
40
|
+
# alias2: groupA
|
|
41
|
+
# alias3: groupB
|
|
42
|
+
# alias4: groupB
|
|
43
|
+
# !ruby/regexp /specialgroup/: groupS
|
|
44
|
+
# aliasN: groupZ
|
|
45
|
+
def map_group(group)
|
|
46
|
+
map_value(@group_map, group)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def node_var_interpolate(var)
|
|
50
|
+
case var
|
|
51
|
+
when "nil" then nil
|
|
52
|
+
when "false" then false
|
|
53
|
+
when "true" then true
|
|
54
|
+
else var
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
private
|
|
59
|
+
|
|
60
|
+
def open_file
|
|
61
|
+
file = File.expand_path(@cfg.file)
|
|
62
|
+
if @cfg.gpg?
|
|
63
|
+
crypto = GPGME::Crypto.new password: @cfg.gpg_password
|
|
64
|
+
crypto.decrypt(File.open(file)).to_s
|
|
65
|
+
else
|
|
66
|
+
File.open(file)
|
|
67
|
+
end
|
|
68
|
+
end
|
|
17
69
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
70
|
+
def string_navigate_object(object, wants)
|
|
71
|
+
wants = wants.split(".").map do |want|
|
|
72
|
+
head, match, _tail = want.partition(/\[\d+\]/)
|
|
73
|
+
match.empty? ? head : [head, match[1..-2].to_i]
|
|
74
|
+
end
|
|
75
|
+
wants.flatten.each do |want|
|
|
76
|
+
object = object[want] if object.respond_to? :each
|
|
77
|
+
end
|
|
78
|
+
object
|
|
24
79
|
end
|
|
25
80
|
end
|
|
26
81
|
end
|
data/lib/oxidized/source/sql.rb
CHANGED
|
@@ -1,75 +1,87 @@
|
|
|
1
1
|
module Oxidized
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
2
|
+
module Source
|
|
3
|
+
class SQL < Source
|
|
4
|
+
begin
|
|
5
|
+
require 'sequel'
|
|
6
|
+
rescue LoadError
|
|
7
|
+
raise OxidizedError, 'sequel not found: sudo gem install sequel'
|
|
8
|
+
end
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
def setup
|
|
11
|
+
if @cfg.empty?
|
|
12
|
+
Oxidized.asetus.user.source.sql.adapter = 'sqlite'
|
|
13
|
+
Oxidized.asetus.user.source.sql.database = File.join(Config::ROOT, 'sqlite.db')
|
|
14
|
+
Oxidized.asetus.user.source.sql.table = 'devices'
|
|
15
|
+
Oxidized.asetus.user.source.sql.map.name = 'name'
|
|
16
|
+
Oxidized.asetus.user.source.sql.map.model = 'rancid'
|
|
17
|
+
Oxidized.asetus.save :user
|
|
18
|
+
raise NoConfig, "No source sql config, edit #{Oxidized::Config.configfile}"
|
|
19
|
+
end
|
|
11
20
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
Oxidized.asetus.user.source.sql.table = 'devices'
|
|
15
|
-
Oxidized.asetus.user.source.sql.map.name = 'name'
|
|
16
|
-
Oxidized.asetus.user.source.sql.map.model = 'rancid'
|
|
17
|
-
Oxidized.asetus.save :user
|
|
18
|
-
raise NoConfig, 'no source sql config, edit ~/.config/oxidized/config'
|
|
19
|
-
end
|
|
21
|
+
# map.name is mandatory
|
|
22
|
+
return if @cfg.map.has_key?('name')
|
|
20
23
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
db = connect
|
|
24
|
-
query = db[@cfg.table.to_sym]
|
|
25
|
-
query = query.with_sql(@cfg.query) if @cfg.query?
|
|
24
|
+
raise InvalidConfig, "map/name is a mandatory source attribute, edit #{Oxidized::Config.configfile}"
|
|
25
|
+
end
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
def load(node_want = nil)
|
|
28
|
+
nodes = []
|
|
29
|
+
db = connect
|
|
30
|
+
query = db[@cfg.table.to_sym]
|
|
31
|
+
query = query.with_sql(@cfg.query) if @cfg.query?
|
|
28
32
|
|
|
29
|
-
|
|
30
|
-
# map node parameters
|
|
31
|
-
keys = {}
|
|
32
|
-
@cfg.map.each { |key, sql_column| keys[key.to_sym] = node_var_interpolate node[sql_column.to_sym] }
|
|
33
|
-
keys[:model] = map_model keys[:model] if keys.has_key? :model
|
|
34
|
-
keys[:group] = map_group keys[:group] if keys.has_key? :group
|
|
33
|
+
query = query.where(@cfg.map.name.to_sym => node_want) if node_want
|
|
35
34
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
35
|
+
query.each do |node|
|
|
36
|
+
# map node parameters
|
|
37
|
+
keys = {}
|
|
38
|
+
@cfg.map.each { |key, sql_column| keys[key.to_sym] = node_var_interpolate node[sql_column.to_sym] }
|
|
39
|
+
keys[:model] = map_model keys[:model] if keys.has_key? :model
|
|
40
|
+
keys[:group] = map_group keys[:group] if keys.has_key? :group
|
|
41
|
+
|
|
42
|
+
# map node specific vars
|
|
43
|
+
vars = {}
|
|
44
|
+
@cfg.vars_map.each do |key, sql_column|
|
|
45
|
+
vars[key.to_s] = node_var_interpolate node[sql_column.to_sym]
|
|
46
|
+
end
|
|
47
|
+
keys[:vars] = vars unless vars.empty?
|
|
42
48
|
|
|
43
|
-
|
|
49
|
+
keys = Oxidized.hooks.source_node_transform(node: keys,
|
|
50
|
+
node_raw: node.to_hash,
|
|
51
|
+
context: self)
|
|
52
|
+
next if keys.nil?
|
|
53
|
+
|
|
54
|
+
nodes << keys
|
|
55
|
+
end
|
|
56
|
+
db.disconnect
|
|
57
|
+
nodes
|
|
44
58
|
end
|
|
45
|
-
db.disconnect
|
|
46
|
-
nodes
|
|
47
|
-
end
|
|
48
59
|
|
|
49
|
-
|
|
60
|
+
private
|
|
50
61
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
62
|
+
def initialize
|
|
63
|
+
super
|
|
64
|
+
@cfg = Oxidized.config.source.sql
|
|
65
|
+
end
|
|
55
66
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
67
|
+
def connect
|
|
68
|
+
options = {
|
|
69
|
+
adapter: @cfg.adapter,
|
|
70
|
+
host: @cfg.host?,
|
|
71
|
+
user: @cfg.user?,
|
|
72
|
+
password: @cfg.password?,
|
|
73
|
+
database: @cfg.database,
|
|
74
|
+
ssl_mode: @cfg.ssl_mode?
|
|
75
|
+
}
|
|
76
|
+
if @cfg.with_ssl?
|
|
77
|
+
options.merge!(sslca: @cfg.ssl_ca?,
|
|
78
|
+
sslcert: @cfg.ssl_cert?,
|
|
79
|
+
sslkey: @cfg.ssl_key?)
|
|
80
|
+
end
|
|
81
|
+
Sequel.connect(options)
|
|
82
|
+
rescue Sequel::AdapterNotFound => e
|
|
83
|
+
raise OxidizedError, "SQL adapter gem not installed: " + e.message
|
|
69
84
|
end
|
|
70
|
-
Sequel.connect(options)
|
|
71
|
-
rescue Sequel::AdapterNotFound => error
|
|
72
|
-
raise OxidizedError, "SQL adapter gem not installed: " + error.message
|
|
73
85
|
end
|
|
74
86
|
end
|
|
75
87
|
end
|
data/lib/oxidized/version.rb
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Oxidized
|
|
2
|
-
VERSION = '0.
|
|
3
|
-
VERSION_FULL = '0.
|
|
4
|
+
VERSION = '0.37.0'
|
|
5
|
+
VERSION_FULL = '0.37.0'
|
|
4
6
|
def self.version_set
|
|
5
7
|
version_full = %x(git describe --tags).chop rescue ""
|
|
6
8
|
version = %x(git describe --tags --abbrev=0).chop rescue ""
|
|
@@ -12,8 +14,8 @@ module Oxidized
|
|
|
12
14
|
const_set(:VERSION, version)
|
|
13
15
|
const_set(:VERSION_FULL, version_full)
|
|
14
16
|
file = File.readlines(__FILE__)
|
|
15
|
-
file[
|
|
16
|
-
file[
|
|
17
|
+
file[3] = " VERSION = '%s'\n" % VERSION
|
|
18
|
+
file[4] = " VERSION_FULL = '%s'\n" % VERSION_FULL
|
|
17
19
|
File.write(__FILE__, file.join)
|
|
18
20
|
end
|
|
19
21
|
end
|