oxidized 0.28.0 → 0.29.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/dependabot.yml +31 -0
- data/.github/workflows/codeql.yml +76 -0
- data/.github/workflows/publishdocker.yml +11 -2
- data/.github/workflows/ruby.yml +42 -0
- data/.github/workflows/stale.yml +16 -0
- data/.rubocop.yml +30 -10
- data/.rubocop_todo.yml +97 -43
- data/CHANGELOG.md +149 -2
- data/Dockerfile +15 -9
- data/README.md +63 -32
- data/Rakefile +2 -0
- data/docs/Configuration.md +49 -7
- data/docs/Creating-Models.md +24 -19
- data/docs/Hooks.md +35 -6
- data/docs/Model-Notes/ADVA.md +12 -0
- data/docs/Model-Notes/Cumulus.md +7 -1
- data/docs/Model-Notes/IOS.md +36 -0
- data/docs/Model-Notes/JunOS.md +3 -3
- data/docs/Model-Notes/LenovoNOS.md +29 -0
- data/docs/Model-Notes/LinksysSRW.md +15 -0
- data/docs/Model-Notes/Nokia.md +3 -0
- data/docs/Model-Notes/OS10.md +33 -0
- data/docs/Model-Notes/PanOS_API.md +28 -0
- data/docs/Model-Notes/README.md +2 -0
- data/docs/Ruby-API.md +12 -8
- data/docs/Sources.md +18 -0
- data/docs/Supported-OS-Types.md +51 -6
- data/docs/Troubleshooting.md +1 -1
- data/extra/gitdiff-msteams.sh +91 -0
- data/extra/nagios_check_failing_nodes.rb +6 -9
- data/extra/oxidized-report-git-commits +71 -14
- data/extra/oxidized.init +2 -5
- data/extra/oxidized.logrotate +1 -0
- data/extra/oxidized.runit +4 -1
- data/extra/oxidized.service +5 -8
- data/extra/rest_client.rb +1 -1
- data/extra/syslog.rb +2 -2
- data/lib/oxidized/cli.rb +1 -1
- data/lib/oxidized/config/vars.rb +5 -2
- data/lib/oxidized/config.rb +6 -3
- data/lib/oxidized/core.rb +1 -1
- data/lib/oxidized/hook/exec.rb +6 -6
- data/lib/oxidized/hook/githubrepo.rb +42 -11
- data/lib/oxidized/hook/slackdiff.rb +2 -2
- data/lib/oxidized/hook/xmppdiff.rb +45 -25
- data/lib/oxidized/hook.rb +4 -8
- data/lib/oxidized/input/exec.rb +1 -1
- data/lib/oxidized/input/input.rb +1 -0
- data/lib/oxidized/input/ssh.rb +23 -20
- data/lib/oxidized/input/telnet.rb +52 -44
- data/lib/oxidized/job.rb +1 -0
- data/lib/oxidized/jobs.rb +11 -6
- data/lib/oxidized/manager.rb +1 -0
- data/lib/oxidized/model/acmepacket.rb +40 -0
- data/lib/oxidized/model/acos.rb +3 -1
- data/lib/oxidized/model/acsw.rb +2 -0
- data/lib/oxidized/model/adtran.rb +7 -3
- data/lib/oxidized/model/adva.rb +68 -0
- data/lib/oxidized/model/aen.rb +2 -0
- data/lib/oxidized/model/aireos.rb +2 -0
- data/lib/oxidized/model/airfiber.rb +3 -1
- data/lib/oxidized/model/airos.rb +2 -0
- data/lib/oxidized/model/alteonos.rb +2 -0
- data/lib/oxidized/model/alvarion.rb +2 -0
- data/lib/oxidized/model/aos.rb +2 -0
- data/lib/oxidized/model/aos7.rb +2 -0
- data/lib/oxidized/model/aoscx.rb +98 -0
- data/lib/oxidized/model/aosw.rb +4 -2
- data/lib/oxidized/model/apc_aos.rb +2 -0
- data/lib/oxidized/model/arbos.rb +2 -0
- data/lib/oxidized/model/aricentiss.rb +2 -0
- data/lib/oxidized/model/asa.rb +4 -0
- data/lib/oxidized/model/asyncos.rb +2 -0
- data/lib/oxidized/model/audiocodes.rb +2 -0
- data/lib/oxidized/model/audiocodesmp.rb +2 -0
- data/lib/oxidized/model/awplus.rb +3 -1
- data/lib/oxidized/model/axos.rb +2 -0
- data/lib/oxidized/model/bdcom.rb +51 -0
- data/lib/oxidized/model/boss.rb +3 -1
- data/lib/oxidized/model/br6910.rb +2 -0
- data/lib/oxidized/model/c4cmts.rb +2 -0
- data/lib/oxidized/model/cambium.rb +2 -0
- data/lib/oxidized/model/cambiumepmp.rb +19 -0
- data/lib/oxidized/model/casa.rb +6 -1
- data/lib/oxidized/model/catos.rb +2 -0
- data/lib/oxidized/model/ciscoce.rb +14 -0
- data/lib/oxidized/model/cisconga.rb +2 -0
- data/lib/oxidized/model/ciscosma.rb +2 -0
- data/lib/oxidized/model/ciscosmb.rb +4 -0
- data/lib/oxidized/model/ciscovpn3k.rb +2 -0
- data/lib/oxidized/model/cnos.rb +2 -0
- data/lib/oxidized/model/comnetms.rb +2 -0
- data/lib/oxidized/model/comtrol.rb +2 -0
- data/lib/oxidized/model/comware.rb +17 -1
- data/lib/oxidized/model/coriant8600.rb +2 -0
- data/lib/oxidized/model/coriantgroove.rb +2 -0
- data/lib/oxidized/model/corianttmos.rb +2 -0
- data/lib/oxidized/model/cumulus.rb +60 -44
- data/lib/oxidized/model/datacom.rb +2 -0
- data/lib/oxidized/model/dcnos.rb +2 -0
- data/lib/oxidized/model/dellx.rb +3 -3
- data/lib/oxidized/model/dlink.rb +4 -1
- data/lib/oxidized/model/dnos.rb +2 -0
- data/lib/oxidized/model/eciapollo.rb +2 -0
- data/lib/oxidized/model/edgecos.rb +24 -2
- data/lib/oxidized/model/edgeos.rb +2 -0
- data/lib/oxidized/model/edgeswitch.rb +6 -4
- data/lib/oxidized/model/eltex.rb +50 -0
- data/lib/oxidized/model/enterasys.rb +20 -3
- data/lib/oxidized/model/enterasys800.rb +31 -0
- data/lib/oxidized/model/eos.rb +4 -1
- data/lib/oxidized/model/fabricos.rb +3 -1
- data/lib/oxidized/model/fastiron.rb +5 -2
- data/lib/oxidized/model/fiberdriver.rb +2 -0
- data/lib/oxidized/model/firebrick.rb +2 -0
- data/lib/oxidized/model/firelinuxos.rb +2 -0
- data/lib/oxidized/model/firewareos.rb +2 -0
- data/lib/oxidized/model/fortios.rb +26 -11
- data/lib/oxidized/model/fortiwlc.rb +26 -0
- data/lib/oxidized/model/ftos.rb +2 -0
- data/lib/oxidized/model/fujitsupy.rb +2 -0
- data/lib/oxidized/model/gaiaos.rb +42 -3
- data/lib/oxidized/model/gcombnps.rb +2 -0
- data/lib/oxidized/model/grandstream.rb +2 -0
- data/lib/oxidized/model/h3c.rb +42 -0
- data/lib/oxidized/model/hatteras.rb +4 -2
- data/lib/oxidized/model/hios.rb +40 -0
- data/lib/oxidized/model/hirschmann.rb +2 -0
- data/lib/oxidized/model/hpebladesystem.rb +3 -1
- data/lib/oxidized/model/hpemsa.rb +2 -0
- data/lib/oxidized/model/hpmsm.rb +2 -0
- data/lib/oxidized/model/ibos.rb +2 -0
- data/lib/oxidized/model/icotera.rb +2 -0
- data/lib/oxidized/model/ios.rb +15 -10
- data/lib/oxidized/model/iosxe.rb +1 -1
- data/lib/oxidized/model/iosxr.rb +2 -0
- data/lib/oxidized/model/ipos.rb +2 -0
- data/lib/oxidized/model/ironware.rb +10 -4
- data/lib/oxidized/model/isam.rb +2 -0
- data/lib/oxidized/model/junos.rb +7 -1
- data/lib/oxidized/model/lancom.rb +25 -0
- data/lib/oxidized/model/lenovonos.rb +84 -0
- data/lib/oxidized/model/linksyssrw.rb +73 -0
- data/lib/oxidized/model/linuxgeneric.rb +2 -0
- data/lib/oxidized/model/masteros.rb +2 -0
- data/lib/oxidized/model/mlnxos.rb +4 -0
- data/lib/oxidized/model/model.rb +35 -8
- data/lib/oxidized/model/mtrlrfs.rb +2 -0
- data/lib/oxidized/model/ndms.rb +3 -1
- data/lib/oxidized/model/necix.rb +32 -0
- data/lib/oxidized/model/netgear.rb +7 -2
- data/lib/oxidized/model/netonix.rb +2 -0
- data/lib/oxidized/model/netscaler.rb +40 -1
- data/lib/oxidized/model/nodegrid.rb +25 -0
- data/lib/oxidized/model/nos.rb +2 -0
- data/lib/oxidized/model/nsxconfig.rb +2 -0
- data/lib/oxidized/model/nsxfirewall.rb +2 -0
- data/lib/oxidized/model/nxos.rb +5 -2
- data/lib/oxidized/model/oneos.rb +2 -0
- data/lib/oxidized/model/openbsd.rb +11 -0
- data/lib/oxidized/model/opengear.rb +3 -1
- data/lib/oxidized/model/openwrt.rb +2 -0
- data/lib/oxidized/model/opnsense.rb +14 -4
- data/lib/oxidized/model/os10.rb +2 -0
- data/lib/oxidized/model/outputs.rb +2 -0
- data/lib/oxidized/model/panos.rb +2 -0
- data/lib/oxidized/model/panos_api.rb +73 -0
- data/lib/oxidized/model/pfsense.rb +14 -7
- data/lib/oxidized/model/planet.rb +2 -0
- data/lib/oxidized/model/powerconnect.rb +3 -3
- data/lib/oxidized/model/procurve.rb +4 -2
- data/lib/oxidized/model/purityos.rb +10 -1
- data/lib/oxidized/model/qtech.rb +2 -0
- data/lib/oxidized/model/quantaos.rb +3 -5
- data/lib/oxidized/model/raisecom.rb +2 -0
- data/lib/oxidized/model/routeros.rb +17 -2
- data/lib/oxidized/model/saos.rb +2 -0
- data/lib/oxidized/model/screenos.rb +2 -0
- data/lib/oxidized/model/sgos.rb +2 -0
- data/lib/oxidized/model/siklu.rb +2 -0
- data/lib/oxidized/model/slxos.rb +3 -0
- data/lib/oxidized/model/smartax.rb +2 -0
- data/lib/oxidized/model/smartcs.rb +42 -0
- data/lib/oxidized/model/sonicos.rb +11 -1
- data/lib/oxidized/model/speedtouch.rb +2 -0
- data/lib/oxidized/model/sros.rb +3 -1
- data/lib/oxidized/model/srosmd.rb +99 -0
- data/lib/oxidized/model/stoneos.rb +8 -2
- data/lib/oxidized/model/supermicro.rb +1 -1
- data/lib/oxidized/model/swos.rb +11 -0
- data/lib/oxidized/model/tdre.rb +2 -0
- data/lib/oxidized/model/telco.rb +2 -0
- data/lib/oxidized/model/timos.rb +1 -1
- data/lib/oxidized/model/tmos.rb +5 -2
- data/lib/oxidized/model/tplink.rb +4 -0
- data/lib/oxidized/model/trango.rb +13 -11
- data/lib/oxidized/model/truenas.rb +22 -0
- data/lib/oxidized/model/ucs.rb +2 -0
- data/lib/oxidized/model/viptela.rb +2 -0
- data/lib/oxidized/model/voltaire.rb +2 -0
- data/lib/oxidized/model/voss.rb +2 -0
- data/lib/oxidized/model/vrp.rb +3 -1
- data/lib/oxidized/model/vyatta.rb +2 -0
- data/lib/oxidized/model/weos.rb +2 -0
- data/lib/oxidized/model/xos.rb +6 -3
- data/lib/oxidized/model/yamaha.rb +59 -0
- data/lib/oxidized/model/zhoneolt.rb +2 -0
- data/lib/oxidized/model/zteolt.rb +54 -0
- data/lib/oxidized/model/zy1308.rb +13 -0
- data/lib/oxidized/model/zynos.rb +2 -0
- data/lib/oxidized/model/zynoscli.rb +2 -0
- data/lib/oxidized/model/zynosgs.rb +2 -0
- data/lib/oxidized/node/stats.rb +1 -0
- data/lib/oxidized/node.rb +16 -11
- data/lib/oxidized/nodes.rb +7 -6
- data/lib/oxidized/output/file.rb +2 -1
- data/lib/oxidized/output/git.rb +5 -3
- data/lib/oxidized/output/gitcrypt.rb +5 -8
- data/lib/oxidized/output/http.rb +2 -0
- data/lib/oxidized/source/csv.rb +1 -0
- data/lib/oxidized/source/http.rb +4 -0
- data/lib/oxidized/source/source.rb +7 -2
- data/lib/oxidized/source/sql.rb +15 -5
- data/lib/oxidized/version.rb +2 -2
- data/lib/oxidized/worker.rb +5 -5
- data/lib/oxidized.rb +1 -1
- data/lib/refinements.rb +43 -0
- data/oxidized.gemspec +22 -16
- metadata +120 -31
- data/.github/no-response.yml +0 -13
- data/.travis.yml +0 -10
- data/lib/oxidized/string.rb +0 -36
data/lib/oxidized/config/vars.rb
CHANGED
@@ -1,12 +1,15 @@
|
|
1
1
|
module Oxidized::Config::Vars
|
2
2
|
# convenience method for accessing node, group or global level user variables
|
3
3
|
def vars(name)
|
4
|
+
model_name = @node.model.class.name.to_s.downcase
|
4
5
|
if @node.vars&.has_key?(name)
|
5
6
|
@node.vars[name]
|
7
|
+
elsif Oxidized.config.groups.has_key?(@node.group) && Oxidized.config.groups[@node.group].models.has_key(model_name) && Oxidized.config.groups[@node.group].models[model_name].vars.has_key?(name.to_s)
|
8
|
+
Oxidized.config.groups[@node.group].models[model_name].vars[name.to_s]
|
6
9
|
elsif Oxidized.config.groups.has_key?(@node.group) && Oxidized.config.groups[@node.group].vars.has_key?(name.to_s)
|
7
10
|
Oxidized.config.groups[@node.group].vars[name.to_s]
|
8
|
-
elsif Oxidized.config.models.has_key(
|
9
|
-
Oxidized.config.models[
|
11
|
+
elsif Oxidized.config.models.has_key(model_name) && Oxidized.config.models[model_name].vars.has_key?(name.to_s)
|
12
|
+
Oxidized.config.models[model_name].vars[name.to_s]
|
10
13
|
elsif Oxidized.config.vars.has_key?(name.to_s)
|
11
14
|
Oxidized.config.vars[name.to_s]
|
12
15
|
end
|
data/lib/oxidized/config.rb
CHANGED
@@ -2,8 +2,9 @@ module Oxidized
|
|
2
2
|
require 'asetus'
|
3
3
|
class NoConfig < OxidizedError; end
|
4
4
|
class InvalidConfig < OxidizedError; end
|
5
|
+
|
5
6
|
class Config
|
6
|
-
Root = ENV['OXIDIZED_HOME'] || File.join(
|
7
|
+
Root = ENV['OXIDIZED_HOME'] || File.join(Dir.home, '.config', 'oxidized')
|
7
8
|
Crash = File.join(ENV['OXIDIZED_LOGS'] || Root, 'crash')
|
8
9
|
Log = File.join(ENV['OXIDIZED_LOGS'] || Root, 'logs')
|
9
10
|
InputDir = File.join Directory, %w[lib oxidized input]
|
@@ -14,7 +15,7 @@ module Oxidized
|
|
14
15
|
Sleep = 1
|
15
16
|
|
16
17
|
def self.load(cmd_opts = {})
|
17
|
-
asetus = Asetus.new(name: 'oxidized', load: false, key_to_s: true)
|
18
|
+
asetus = Asetus.new(name: 'oxidized', load: false, key_to_s: true, usrdir: Oxidized::Config::Root)
|
18
19
|
Oxidized.asetus = asetus
|
19
20
|
|
20
21
|
asetus.default.username = 'username'
|
@@ -25,6 +26,7 @@ module Oxidized
|
|
25
26
|
asetus.default.use_syslog = false
|
26
27
|
asetus.default.debug = false
|
27
28
|
asetus.default.threads = 30
|
29
|
+
asetus.default.use_max_threads = false
|
28
30
|
asetus.default.timeout = 20
|
29
31
|
asetus.default.retries = 3
|
30
32
|
asetus.default.prompt = /^([\w.@-]+[#>]\s?)$/
|
@@ -32,6 +34,7 @@ module Oxidized
|
|
32
34
|
asetus.default.next_adds_job = false # if true, /next adds job, so device is fetched immmeiately
|
33
35
|
asetus.default.vars = {} # could be 'enable'=>'enablePW'
|
34
36
|
asetus.default.groups = {} # group level configuration
|
37
|
+
asetus.default.group_map = {} # map aliases of groups to names
|
35
38
|
asetus.default.models = {} # model level configuration
|
36
39
|
asetus.default.pid = File.join(Oxidized::Config::Root, 'pid')
|
37
40
|
|
@@ -69,6 +72,6 @@ module Oxidized
|
|
69
72
|
end
|
70
73
|
|
71
74
|
class << self
|
72
|
-
attr_accessor :mgr, :
|
75
|
+
attr_accessor :mgr, :hooks
|
73
76
|
end
|
74
77
|
end
|
data/lib/oxidized/core.rb
CHANGED
@@ -10,7 +10,7 @@ module Oxidized
|
|
10
10
|
|
11
11
|
def initialize(_args)
|
12
12
|
Oxidized.mgr = Manager.new
|
13
|
-
Oxidized.
|
13
|
+
Oxidized.hooks = HookManager.from_config(Oxidized.config)
|
14
14
|
nodes = Nodes.new
|
15
15
|
raise NoNodesFound, 'source returns no usable nodes' if nodes.size.zero?
|
16
16
|
|
data/lib/oxidized/hook/exec.rb
CHANGED
@@ -30,11 +30,9 @@ class Exec < Oxidized::Hook
|
|
30
30
|
env = make_env ctx
|
31
31
|
log "Execute: #{@cmd.inspect}", :debug
|
32
32
|
th = Thread.new do
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
raise e unless @async
|
37
|
-
end
|
33
|
+
run_cmd! env
|
34
|
+
rescue StandardError => e
|
35
|
+
raise e unless @async
|
38
36
|
end
|
39
37
|
th.join unless @async
|
40
38
|
end
|
@@ -70,7 +68,9 @@ class Exec < Oxidized::Hook
|
|
70
68
|
"OX_NODE_GROUP" => ctx.node.group.to_s,
|
71
69
|
"OX_NODE_MODEL" => ctx.node.model.class.name,
|
72
70
|
"OX_REPO_COMMITREF" => ctx.commitref.to_s,
|
73
|
-
"OX_REPO_NAME" => ctx.node.repo.to_s
|
71
|
+
"OX_REPO_NAME" => ctx.node.repo.to_s,
|
72
|
+
"OX_ERR_TYPE" => ctx.node.err_type.to_s,
|
73
|
+
"OX_ERR_REASON" => ctx.node.err_reason.to_s
|
74
74
|
)
|
75
75
|
end
|
76
76
|
if ctx.job
|
@@ -4,18 +4,32 @@ class GithubRepo < Oxidized::Hook
|
|
4
4
|
end
|
5
5
|
|
6
6
|
def run_hook(ctx)
|
7
|
-
repo
|
7
|
+
repo = Rugged::Repository.new(ctx.node.repo)
|
8
|
+
creds = credentials(ctx.node)
|
9
|
+
url = remote_repo(ctx.node)
|
10
|
+
|
11
|
+
if url.nil? || url.empty?
|
12
|
+
log "No repository defined for #{ctx.node.group}/#{ctx.node.name}", :debug
|
13
|
+
return
|
14
|
+
end
|
15
|
+
|
8
16
|
log "Pushing local repository(#{repo.path})..."
|
9
|
-
|
10
|
-
log "to remote: #{remote.url}"
|
17
|
+
log "to remote: #{url}"
|
11
18
|
|
12
|
-
|
19
|
+
if repo.remotes['origin'].nil?
|
20
|
+
repo.remotes.create('origin', url)
|
21
|
+
elsif repo.remotes['origin'].url != url
|
22
|
+
repo.remotes.set_url('origin', url)
|
23
|
+
end
|
24
|
+
remote = repo.remotes['origin']
|
25
|
+
|
26
|
+
fetch_and_merge_remote(repo, creds)
|
13
27
|
|
14
|
-
remote.push([repo.head.name], credentials:
|
28
|
+
remote.push([repo.head.name], credentials: creds)
|
15
29
|
end
|
16
30
|
|
17
|
-
def fetch_and_merge_remote(repo)
|
18
|
-
result = repo.fetch('origin', [repo.head.name], credentials:
|
31
|
+
def fetch_and_merge_remote(repo, creds)
|
32
|
+
result = repo.fetch('origin', [repo.head.name], credentials: creds)
|
19
33
|
log result.inspect, :debug
|
20
34
|
|
21
35
|
unless result[:total_deltas].positive?
|
@@ -43,15 +57,20 @@ class GithubRepo < Oxidized::Hook
|
|
43
57
|
|
44
58
|
private
|
45
59
|
|
46
|
-
def credentials
|
60
|
+
def credentials(node)
|
47
61
|
Proc.new do |_url, username_from_url, _allowed_types| # rubocop:disable Style/Proc
|
48
62
|
git_user = cfg.has_key?('username') ? cfg.username : (username_from_url || 'git')
|
49
63
|
if cfg.has_key?('password')
|
50
64
|
log "Authenticating using username and password as '#{git_user}'", :debug
|
51
65
|
Rugged::Credentials::UserPassword.new(username: git_user, password: cfg.password)
|
52
|
-
elsif cfg.has_key?('
|
66
|
+
elsif cfg.has_key?('privatekey')
|
67
|
+
pubkey = cfg.has_key?('publickey') ? cfg.publickey : nil
|
53
68
|
log "Authenticating using ssh keys as '#{git_user}'", :debug
|
54
|
-
|
69
|
+
rugged_sshkey(git_user: git_user, privkey: cfg.privatekey, pubkey: pubkey)
|
70
|
+
elsif cfg.has_key?('remote_repo') && cfg.remote_repo.has_key?(node.group) && cfg.remote_repo[node.group].has_key?('privatekey')
|
71
|
+
pubkey = cfg.remote_repo[node.group].has_key?('publickey') ? cfg.remote_repo[node.group].publickey : nil
|
72
|
+
log "Authenticating using ssh keys as '#{git_user}' for '#{node.group}/#{node.name}'", :debug
|
73
|
+
rugged_sshkey(git_user: git_user, privkey: cfg.remote_repo[node.group].privatekey, pubkey: pubkey)
|
55
74
|
else
|
56
75
|
log "Authenticating using ssh agent as '#{git_user}'", :debug
|
57
76
|
Rugged::Credentials::SshKeyFromAgent.new(username: git_user)
|
@@ -59,11 +78,23 @@ class GithubRepo < Oxidized::Hook
|
|
59
78
|
end
|
60
79
|
end
|
61
80
|
|
81
|
+
def rugged_sshkey(args = {})
|
82
|
+
git_user = args[:git_user]
|
83
|
+
privkey = args[:privkey]
|
84
|
+
pubkey = args[:pubkey] || (privkey + '.pub')
|
85
|
+
Rugged::Credentials::SshKey.new(username: git_user,
|
86
|
+
publickey: File.expand_path(pubkey),
|
87
|
+
privatekey: File.expand_path(privkey),
|
88
|
+
passphrase: ENV.fetch("OXIDIZED_SSH_PASSPHRASE", nil))
|
89
|
+
end
|
90
|
+
|
62
91
|
def remote_repo(node)
|
63
92
|
if node.group.nil? || cfg.remote_repo.is_a?(String)
|
64
93
|
cfg.remote_repo
|
65
|
-
|
94
|
+
elsif cfg.remote_repo[node.group].is_a?(String)
|
66
95
|
cfg.remote_repo[node.group]
|
96
|
+
elsif cfg.remote_repo[node.group].url.is_a?(String)
|
97
|
+
cfg.remote_repo[node.group].url
|
67
98
|
end
|
68
99
|
end
|
69
100
|
end
|
@@ -14,11 +14,11 @@ class SlackDiff < Oxidized::Hook
|
|
14
14
|
return unless ctx.event.to_s == "post_store"
|
15
15
|
|
16
16
|
log "Connecting to slack"
|
17
|
-
Slack.configure do |config|
|
17
|
+
Slack::Web::Client.configure do |config|
|
18
18
|
config.token = cfg.token
|
19
19
|
config.proxy = cfg.proxy if cfg.has_key?('proxy')
|
20
20
|
end
|
21
|
-
client = Slack::Client.new
|
21
|
+
client = Slack::Web::Client.new
|
22
22
|
client.auth_test
|
23
23
|
log "Connected"
|
24
24
|
if cfg.has_key?("diff") ? cfg.diff : true
|
@@ -2,6 +2,44 @@ require 'xmpp4r'
|
|
2
2
|
require 'xmpp4r/muc/helper/simplemucclient'
|
3
3
|
|
4
4
|
class XMPPDiff < Oxidized::Hook
|
5
|
+
def connect
|
6
|
+
@client = Jabber::Client.new(Jabber::JID.new(cfg.jid))
|
7
|
+
|
8
|
+
log "Connecting to XMPP"
|
9
|
+
begin
|
10
|
+
Timeout.timeout(15) do
|
11
|
+
begin
|
12
|
+
@client.connect
|
13
|
+
rescue StandardError => e
|
14
|
+
log "Failed to connect to XMPP: #{e}"
|
15
|
+
end
|
16
|
+
sleep 1
|
17
|
+
|
18
|
+
log "Authenticating to XMPP"
|
19
|
+
@client.auth(cfg.password)
|
20
|
+
sleep 1
|
21
|
+
|
22
|
+
log "Connected to XMPP"
|
23
|
+
|
24
|
+
@muc = Jabber::MUC::SimpleMUCClient.new(@client)
|
25
|
+
@muc.join(cfg.channel + "/" + cfg.nick)
|
26
|
+
|
27
|
+
log "Joined #{cfg.channel}"
|
28
|
+
end
|
29
|
+
rescue Timeout::Error
|
30
|
+
log "timed out"
|
31
|
+
@client = nil
|
32
|
+
@muc = nil
|
33
|
+
end
|
34
|
+
|
35
|
+
@client.on_exception do
|
36
|
+
log "XMPP connection aborted, reconnecting"
|
37
|
+
@client = nil
|
38
|
+
@muc = nil
|
39
|
+
connect
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
5
43
|
def validate_cfg!
|
6
44
|
raise KeyError, 'hook.jid is required' unless cfg.has_key?('jid')
|
7
45
|
raise KeyError, 'hook.password is required' unless cfg.has_key?('password')
|
@@ -21,35 +59,17 @@ class XMPPDiff < Oxidized::Hook
|
|
21
59
|
interesting = diff[:patch].lines.to_a[4..-1].any? do |line|
|
22
60
|
["+", "-"].include?(line[0]) && (not ["#", "!"].include?(line[1]))
|
23
61
|
end
|
24
|
-
interesting &&= diff[:patch].lines.to_a[5..-1].any? { |line| line[0] == '-' }
|
25
|
-
interesting &&= diff[:patch].lines.to_a[5..-1].any? { |line| line[0] == '+' }
|
26
62
|
|
27
63
|
if interesting
|
28
|
-
|
29
|
-
client = Jabber::Client.new(Jabber::JID.new(cfg.jid))
|
30
|
-
client.connect
|
31
|
-
sleep 1
|
32
|
-
client.auth(cfg.password)
|
33
|
-
sleep 1
|
34
|
-
|
35
|
-
log "Connected"
|
36
|
-
|
37
|
-
m = Jabber::MUC::SimpleMUCClient.new(client)
|
38
|
-
m.join(cfg.channel + "/" + cfg.nick)
|
39
|
-
|
40
|
-
log "Joined"
|
41
|
-
|
42
|
-
title = "#{ctx.node.name} #{ctx.node.group} #{ctx.node.model.class.name.to_s.downcase}"
|
43
|
-
log "Posting diff as snippet to #{cfg.channel}"
|
44
|
-
|
45
|
-
m.say(title + "\n\n" + diff[:patch].lines.to_a[4..-1].join)
|
46
|
-
|
47
|
-
sleep 1
|
48
|
-
|
49
|
-
client.close
|
64
|
+
connect if @muc.nil?
|
50
65
|
|
51
|
-
|
66
|
+
# Maybe connecting failed, so only proceed if we actually joined the MUC
|
67
|
+
unless @muc.nil?
|
68
|
+
title = "#{ctx.node.name} #{ctx.node.group} #{ctx.node.model.class.name.to_s.downcase}"
|
69
|
+
log "Posting diff as snippet to #{cfg.channel}"
|
52
70
|
|
71
|
+
@muc.say(title + "\n\n" + diff[:patch].lines.to_a[4..-1].join)
|
72
|
+
end
|
53
73
|
end
|
54
74
|
end
|
55
75
|
rescue Timeout::Error
|
data/lib/oxidized/hook.rb
CHANGED
@@ -55,12 +55,10 @@ module Oxidized
|
|
55
55
|
ctx.event = event
|
56
56
|
|
57
57
|
@registered_hooks[event].each do |r_hook|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
"(#{e.inspect}) for event #{event.inspect}"
|
63
|
-
end
|
58
|
+
r_hook.hook.run_hook ctx
|
59
|
+
rescue StandardError => e
|
60
|
+
Oxidized.logger.error "Hook #{r_hook.name} (#{r_hook.hook}) failed " \
|
61
|
+
"(#{e.inspect}) for event #{event.inspect}"
|
64
62
|
end
|
65
63
|
end
|
66
64
|
end
|
@@ -69,8 +67,6 @@ module Oxidized
|
|
69
67
|
class Hook
|
70
68
|
attr_reader :cfg
|
71
69
|
|
72
|
-
def initialize; end
|
73
|
-
|
74
70
|
def cfg=(cfg)
|
75
71
|
@cfg = cfg
|
76
72
|
validate_cfg! if respond_to? :validate_cfg!
|
data/lib/oxidized/input/exec.rb
CHANGED
@@ -6,8 +6,8 @@ module Oxidized
|
|
6
6
|
|
7
7
|
def connect(node)
|
8
8
|
@node = node
|
9
|
-
@node.model.cfg["exec"].each { |cb| instance_exec(&cb) }
|
10
9
|
@log = File.open(Oxidized::Config::Log + "/#{@node.ip}-exec", "w") if Oxidized.config.input.debug?
|
10
|
+
@node.model.cfg["exec"].each { |cb| instance_exec(&cb) }
|
11
11
|
end
|
12
12
|
|
13
13
|
def cmd(cmd_str)
|
data/lib/oxidized/input/input.rb
CHANGED
data/lib/oxidized/input/ssh.rb
CHANGED
@@ -122,34 +122,27 @@ module Oxidized
|
|
122
122
|
def make_ssh_opts
|
123
123
|
secure = Oxidized.config.input.ssh.secure?
|
124
124
|
ssh_opts = {
|
125
|
-
number_of_password_prompts:
|
126
|
-
keepalive:
|
127
|
-
verify_host_key:
|
128
|
-
|
129
|
-
|
130
|
-
|
125
|
+
number_of_password_prompts: 0,
|
126
|
+
keepalive: vars(:ssh_no_keepalive) ? false : true,
|
127
|
+
verify_host_key: secure ? :always : :never,
|
128
|
+
append_all_supported_algorithms: true,
|
129
|
+
password: @node.auth[:password],
|
130
|
+
timeout: Oxidized.config.timeout,
|
131
|
+
port: (vars(:ssh_port) || 22).to_i,
|
132
|
+
forward_agent: false
|
131
133
|
}
|
132
134
|
|
133
135
|
auth_methods = vars(:auth_methods) || %w[none publickey password]
|
134
136
|
ssh_opts[:auth_methods] = auth_methods
|
135
137
|
Oxidized.logger.debug "AUTH METHODS::#{auth_methods}"
|
136
138
|
|
137
|
-
|
138
|
-
proxy_command = "ssh "
|
139
|
-
proxy_command += "-o StrictHostKeyChecking=no " unless secure
|
140
|
-
if (proxy_port = vars(:ssh_proxy_port))
|
141
|
-
proxy_command += "-p #{proxy_port} "
|
142
|
-
end
|
143
|
-
proxy_command += "#{proxy_host} -W %h:%p"
|
144
|
-
proxy = Net::SSH::Proxy::Command.new(proxy_command)
|
145
|
-
ssh_opts[:proxy] = proxy
|
146
|
-
end
|
139
|
+
ssh_opts[:proxy] = make_ssh_proxy_command(vars(:ssh_proxy), vars(:ssh_proxy_port), secure) if vars(:ssh_proxy)
|
147
140
|
|
148
|
-
ssh_opts[:keys] = [vars(:ssh_keys)].flatten
|
149
|
-
ssh_opts[:kex] = vars(:ssh_kex).split(/,\s*/)
|
141
|
+
ssh_opts[:keys] = [vars(:ssh_keys)].flatten if vars(:ssh_keys)
|
142
|
+
ssh_opts[:kex] = vars(:ssh_kex).split(/,\s*/) if vars(:ssh_kex)
|
150
143
|
ssh_opts[:encryption] = vars(:ssh_encryption).split(/,\s*/) if vars(:ssh_encryption)
|
151
|
-
ssh_opts[:host_key] = vars(:ssh_host_key).split(/,\s*/)
|
152
|
-
ssh_opts[:hmac] = vars(:ssh_hmac).split(/,\s*/)
|
144
|
+
ssh_opts[:host_key] = vars(:ssh_host_key).split(/,\s*/) if vars(:ssh_host_key)
|
145
|
+
ssh_opts[:hmac] = vars(:ssh_hmac).split(/,\s*/) if vars(:ssh_hmac)
|
153
146
|
|
154
147
|
if Oxidized.config.input.debug?
|
155
148
|
ssh_opts[:logger] = Oxidized.logger
|
@@ -158,5 +151,15 @@ module Oxidized
|
|
158
151
|
|
159
152
|
ssh_opts
|
160
153
|
end
|
154
|
+
|
155
|
+
def make_ssh_proxy_command(proxy_host, proxy_port, secure)
|
156
|
+
return nil unless !proxy_host.nil? && !proxy_host.empty?
|
157
|
+
|
158
|
+
proxy_command = "ssh "
|
159
|
+
proxy_command += "-o StrictHostKeyChecking=no " unless secure
|
160
|
+
proxy_command += "-p #{proxy_port} " if proxy_port
|
161
|
+
proxy_command += "#{proxy_host} -W [%h]:%p"
|
162
|
+
Net::SSH::Proxy::Command.new(proxy_command)
|
163
|
+
end
|
161
164
|
end
|
162
165
|
end
|
@@ -35,13 +35,15 @@ module Oxidized
|
|
35
35
|
end
|
36
36
|
|
37
37
|
def cmd(cmd_str, expect = @node.prompt)
|
38
|
+
Oxidized.logger.debug "Telnet: #{cmd_str} @#{@node.name}"
|
38
39
|
return send(cmd_str + "\r\n") unless expect
|
39
40
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
@telnet.
|
41
|
+
# create a string to be passed to oxidized_expect and modified _there_
|
42
|
+
# default to a single space so it shouldn't be coerced to nil by any models.
|
43
|
+
out = String(' ')
|
44
|
+
@telnet.puts(cmd_str)
|
45
|
+
@telnet.oxidized_expect(timeout: @timeout, expect: expect, out: out)
|
46
|
+
out
|
45
47
|
end
|
46
48
|
|
47
49
|
def send(data)
|
@@ -69,46 +71,52 @@ module Oxidized
|
|
69
71
|
end
|
70
72
|
end
|
71
73
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
74
|
+
module Net
|
75
|
+
class Telnet
|
76
|
+
## how to do this, without redefining the whole damn thing
|
77
|
+
## FIXME: we also need output (not sure I'm going to support this)
|
78
|
+
attr_reader :output
|
79
|
+
|
80
|
+
def oxidized_expect(options) ## rubocop:disable Metrics/PerceivedComplexity
|
81
|
+
model = @options["Model"]
|
82
|
+
@log = @options["Log"]
|
83
|
+
|
84
|
+
expects = [options[:expect]].flatten
|
85
|
+
time_out = options[:timeout] || @options["Timeout"] || Oxidized.config.timeout?
|
86
|
+
|
87
|
+
Timeout.timeout(time_out) do
|
88
|
+
line = ""
|
89
|
+
rest = ""
|
90
|
+
buf = ""
|
91
|
+
loop do
|
92
|
+
c = @sock.readpartial(1024 * 1024)
|
93
|
+
@output = c
|
94
|
+
c = rest + c
|
95
|
+
|
96
|
+
if Integer(c.rindex(/#{IAC}#{SE}/no) || 0) <
|
97
|
+
Integer(c.rindex(/#{IAC}#{SB}/no) || 0)
|
98
|
+
buf = preprocess(c[0...c.rindex(/#{IAC}#{SB}/no)])
|
99
|
+
rest = c[c.rindex(/#{IAC}#{SB}/no)..-1]
|
100
|
+
elsif (pt = c.rindex(/#{IAC}[^#{IAC}#{AO}#{AYT}#{DM}#{IP}#{NOP}]?\z/no) ||
|
101
|
+
c.rindex(/\r\z/no))
|
102
|
+
buf = preprocess(c[0...pt])
|
103
|
+
rest = c[pt..-1]
|
104
|
+
else
|
105
|
+
buf = preprocess(c)
|
106
|
+
rest = ''
|
107
|
+
end
|
108
|
+
if Oxidized.config.input.debug?
|
109
|
+
@log.print buf
|
110
|
+
@log.flush
|
111
|
+
end
|
112
|
+
line += buf
|
113
|
+
line = model.expects line
|
114
|
+
# match is a regexp object. we need to return that for logins to work.
|
115
|
+
match = expects.find { |re| line.match re }
|
116
|
+
# stomp on the out string object if we have one. (thus we were called by cmd?)
|
117
|
+
options[:out]&.replace(line)
|
118
|
+
return match if match
|
107
119
|
end
|
108
|
-
line += buf
|
109
|
-
line = model.expects line
|
110
|
-
match = expects.find { |re| line.match re }
|
111
|
-
return match if match
|
112
120
|
end
|
113
121
|
end
|
114
122
|
end
|
data/lib/oxidized/job.rb
CHANGED
data/lib/oxidized/jobs.rb
CHANGED
@@ -4,13 +4,14 @@ module Oxidized
|
|
4
4
|
MAX_INTER_JOB_GAP = 300 # add job if more than X from last job started
|
5
5
|
attr_accessor :interval, :max, :want
|
6
6
|
|
7
|
-
def initialize(max, interval, nodes)
|
8
|
-
@max
|
7
|
+
def initialize(max, use_max_threads, interval, nodes)
|
8
|
+
@max = max
|
9
|
+
@use_max_threads = use_max_threads
|
9
10
|
# Set interval to 1 if interval is 0 (=disabled) so we don't break
|
10
11
|
# the 'ceil' function
|
11
|
-
@interval
|
12
|
-
@nodes
|
13
|
-
@last
|
12
|
+
@interval = interval.zero? ? 1 : interval
|
13
|
+
@nodes = nodes
|
14
|
+
@last = Time.now.utc
|
14
15
|
@durations = Array.new @nodes.size, AVERAGE_DURATION
|
15
16
|
duration AVERAGE_DURATION
|
16
17
|
super()
|
@@ -33,7 +34,11 @@ module Oxidized
|
|
33
34
|
end
|
34
35
|
|
35
36
|
def new_count
|
36
|
-
@want =
|
37
|
+
@want = if @use_max_threads
|
38
|
+
@max
|
39
|
+
else
|
40
|
+
((@nodes.size * @duration) / @interval).ceil
|
41
|
+
end
|
37
42
|
@want = 1 if @want < 1
|
38
43
|
@want = @nodes.size if @want > @nodes.size
|
39
44
|
@want = @max if @want > @max
|
data/lib/oxidized/manager.rb
CHANGED
@@ -0,0 +1,40 @@
|
|
1
|
+
class ACMEPACKET < Oxidized::Model
|
2
|
+
using Refinements
|
3
|
+
|
4
|
+
# Oracle ACME Packet 3k, 4k, 6k series
|
5
|
+
|
6
|
+
prompt /^\r*([\w.@()-\/]+[#>]\s?)$/
|
7
|
+
|
8
|
+
comment '! '
|
9
|
+
|
10
|
+
cmd :all do |cfg, cmdstring|
|
11
|
+
new_cfg = comment "COMMAND: #{cmdstring}\n"
|
12
|
+
new_cfg << cfg.cut_both
|
13
|
+
end
|
14
|
+
|
15
|
+
cmd 'show version' do |cfg|
|
16
|
+
comment cfg
|
17
|
+
end
|
18
|
+
|
19
|
+
cmd 'show running-config' do |cfg|
|
20
|
+
cfg
|
21
|
+
end
|
22
|
+
|
23
|
+
cfg :telnet do
|
24
|
+
password /^Password:/i
|
25
|
+
end
|
26
|
+
|
27
|
+
cfg :telnet, :ssh do
|
28
|
+
# preferred way to handle additional passwords
|
29
|
+
post_login do
|
30
|
+
if vars(:enable) == true
|
31
|
+
cmd "enable"
|
32
|
+
elsif vars(:enable)
|
33
|
+
cmd "enable", /^[pP]assword:/
|
34
|
+
cmd vars(:enable)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
pre_logout 'exit'
|
38
|
+
pre_logout 'exit'
|
39
|
+
end
|
40
|
+
end
|
data/lib/oxidized/model/acos.rb
CHANGED
data/lib/oxidized/model/acsw.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
class Adtran < Oxidized::Model
|
2
|
+
using Refinements
|
3
|
+
|
2
4
|
# Adtran
|
3
5
|
|
4
6
|
prompt /([\w.@-]+[#>]\s?)$/
|
@@ -15,9 +17,11 @@ class Adtran < Oxidized::Model
|
|
15
17
|
cmd 'show running-config'
|
16
18
|
|
17
19
|
cfg :ssh do
|
18
|
-
|
19
|
-
|
20
|
-
|
20
|
+
if vars :enable
|
21
|
+
post_login do
|
22
|
+
send "enable\n"
|
23
|
+
cmd vars(:enable)
|
24
|
+
end
|
21
25
|
end
|
22
26
|
post_login 'terminal length 0'
|
23
27
|
pre_logout 'exit'
|