oxidized 0.28.0 → 0.29.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/workflows/publishdocker.yml +8 -1
- data/.github/workflows/ruby.yml +42 -0
- data/.rubocop.yml +30 -10
- data/.rubocop_todo.yml +95 -41
- data/CHANGELOG.md +139 -2
- data/Dockerfile +13 -9
- data/README.md +66 -32
- data/Rakefile +2 -0
- data/docs/Configuration.md +49 -7
- data/docs/Creating-Models.md +10 -4
- 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/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 +38 -0
- data/lib/oxidized/model/adtran.rb +5 -3
- data/lib/oxidized/model/adva.rb +66 -0
- data/lib/oxidized/model/airfiber.rb +1 -1
- data/lib/oxidized/model/aoscx.rb +96 -0
- data/lib/oxidized/model/aosw.rb +1 -1
- data/lib/oxidized/model/asa.rb +2 -0
- data/lib/oxidized/model/awplus.rb +1 -1
- data/lib/oxidized/model/bdcom.rb +49 -0
- data/lib/oxidized/model/cambiumepmp.rb +17 -0
- data/lib/oxidized/model/casa.rb +4 -1
- data/lib/oxidized/model/ciscoce.rb +12 -0
- data/lib/oxidized/model/ciscosmb.rb +2 -0
- data/lib/oxidized/model/comware.rb +16 -1
- data/lib/oxidized/model/cumulus.rb +58 -44
- data/lib/oxidized/model/dellx.rb +1 -3
- data/lib/oxidized/model/dlink.rb +2 -1
- data/lib/oxidized/model/edgecos.rb +22 -2
- data/lib/oxidized/model/edgeswitch.rb +4 -4
- data/lib/oxidized/model/eltex.rb +48 -0
- data/lib/oxidized/model/enterasys.rb +18 -3
- data/lib/oxidized/model/enterasys800.rb +29 -0
- data/lib/oxidized/model/eos.rb +2 -1
- data/lib/oxidized/model/fabricos.rb +1 -1
- data/lib/oxidized/model/fastiron.rb +3 -2
- data/lib/oxidized/model/fortios.rb +24 -11
- data/lib/oxidized/model/fortiwlc.rb +24 -0
- data/lib/oxidized/model/gaiaos.rb +40 -3
- data/lib/oxidized/model/h3c.rb +40 -0
- data/lib/oxidized/model/hatteras.rb +2 -2
- data/lib/oxidized/model/hios.rb +38 -0
- data/lib/oxidized/model/hpebladesystem.rb +1 -1
- data/lib/oxidized/model/ios.rb +13 -10
- data/lib/oxidized/model/iosxe.rb +1 -1
- data/lib/oxidized/model/ironware.rb +8 -4
- data/lib/oxidized/model/junos.rb +5 -1
- data/lib/oxidized/model/lancom.rb +23 -0
- data/lib/oxidized/model/lenovonos.rb +82 -0
- data/lib/oxidized/model/linksyssrw.rb +71 -0
- data/lib/oxidized/model/mlnxos.rb +2 -0
- data/lib/oxidized/model/model.rb +29 -3
- data/lib/oxidized/model/necix.rb +30 -0
- data/lib/oxidized/model/netgear.rb +5 -2
- data/lib/oxidized/model/netscaler.rb +38 -1
- data/lib/oxidized/model/nodegrid.rb +23 -0
- data/lib/oxidized/model/nxos.rb +3 -2
- data/lib/oxidized/model/openbsd.rb +9 -0
- data/lib/oxidized/model/opengear.rb +1 -1
- data/lib/oxidized/model/opnsense.rb +12 -4
- data/lib/oxidized/model/panos_api.rb +71 -0
- data/lib/oxidized/model/pfsense.rb +12 -7
- data/lib/oxidized/model/powerconnect.rb +1 -3
- data/lib/oxidized/model/procurve.rb +2 -2
- data/lib/oxidized/model/purityos.rb +8 -1
- data/lib/oxidized/model/quantaos.rb +1 -5
- data/lib/oxidized/model/routeros.rb +15 -2
- data/lib/oxidized/model/slxos.rb +1 -0
- data/lib/oxidized/model/smartcs.rb +40 -0
- data/lib/oxidized/model/sonicos.rb +9 -1
- data/lib/oxidized/model/srosmd.rb +97 -0
- data/lib/oxidized/model/stoneos.rb +6 -2
- data/lib/oxidized/model/supermicro.rb +1 -1
- data/lib/oxidized/model/swos.rb +9 -0
- data/lib/oxidized/model/timos.rb +1 -1
- data/lib/oxidized/model/tmos.rb +2 -1
- data/lib/oxidized/model/tplink.rb +2 -0
- data/lib/oxidized/model/trango.rb +11 -11
- data/lib/oxidized/model/truenas.rb +20 -0
- data/lib/oxidized/model/vrp.rb +1 -1
- data/lib/oxidized/model/xos.rb +4 -3
- data/lib/oxidized/model/yamaha.rb +57 -0
- data/lib/oxidized/model/zteolt.rb +52 -0
- data/lib/oxidized/model/zy1308.rb +11 -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 +4 -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/string.rb +9 -3
- data/lib/oxidized/version.rb +2 -2
- data/lib/oxidized/worker.rb +5 -5
- data/oxidized.gemspec +22 -16
- metadata +116 -29
- data/.travis.yml +0 -10
|
@@ -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,38 @@
|
|
|
1
|
+
class ACMEPACKET < Oxidized::Model
|
|
2
|
+
# Oracle ACME Packet 3k, 4k, 6k series
|
|
3
|
+
|
|
4
|
+
prompt /^\r*([\w.@()-\/]+[#>]\s?)$/
|
|
5
|
+
|
|
6
|
+
comment '! '
|
|
7
|
+
|
|
8
|
+
cmd :all do |cfg, cmdstring|
|
|
9
|
+
new_cfg = comment "COMMAND: #{cmdstring}\n"
|
|
10
|
+
new_cfg << cfg.cut_both
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
cmd 'show version' do |cfg|
|
|
14
|
+
comment cfg
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
cmd 'show running-config' do |cfg|
|
|
18
|
+
cfg
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
cfg :telnet do
|
|
22
|
+
password /^Password:/i
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
cfg :telnet, :ssh do
|
|
26
|
+
# preferred way to handle additional passwords
|
|
27
|
+
post_login do
|
|
28
|
+
if vars(:enable) == true
|
|
29
|
+
cmd "enable"
|
|
30
|
+
elsif vars(:enable)
|
|
31
|
+
cmd "enable", /^[pP]assword:/
|
|
32
|
+
cmd vars(:enable)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
pre_logout 'exit'
|
|
36
|
+
pre_logout 'exit'
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -15,9 +15,11 @@ class Adtran < Oxidized::Model
|
|
|
15
15
|
cmd 'show running-config'
|
|
16
16
|
|
|
17
17
|
cfg :ssh do
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
if vars :enable
|
|
19
|
+
post_login do
|
|
20
|
+
send "enable\n"
|
|
21
|
+
cmd vars(:enable)
|
|
22
|
+
end
|
|
21
23
|
end
|
|
22
24
|
post_login 'terminal length 0'
|
|
23
25
|
pre_logout 'exit'
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Oxidized model for ADVA devices
|
|
2
|
+
#
|
|
3
|
+
# IMPORTANT: To get this working, cli-paging must be disabled
|
|
4
|
+
# for the user that is used to fetch the configuration.
|
|
5
|
+
|
|
6
|
+
class ADVA < Oxidized::Model
|
|
7
|
+
prompt /\w+\-+[#>]\s?$/
|
|
8
|
+
comment '# '
|
|
9
|
+
|
|
10
|
+
cmd :secret do |cfg|
|
|
11
|
+
cfg.gsub! /community "[^"]+"/, 'community "<hidden>"'
|
|
12
|
+
cfg
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
cmd :all do |cfg|
|
|
16
|
+
cfg.cut_both
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
cmd 'show running-config current' do |cfg|
|
|
20
|
+
cfg.each_line.reject { |line| line.match /^Preparing configuration file.*/ }.join
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
cmd 'show system' do |cfg|
|
|
24
|
+
cfg = cfg.each_line.reject { |line| line.match /(up time|local time)/i }.join
|
|
25
|
+
|
|
26
|
+
cfg = "COMMAND: show system\n\n" + cfg
|
|
27
|
+
cfg = comment cfg
|
|
28
|
+
"\n\n" + cfg
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
cmd 'network-element ne-1'
|
|
32
|
+
|
|
33
|
+
cmd 'show shelf-info' do |cfg|
|
|
34
|
+
cfg = "COMMAND: show shelf-info\n\n" + cfg
|
|
35
|
+
cfg = comment cfg
|
|
36
|
+
"\n\n" + cfg
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
post do
|
|
40
|
+
ports = []
|
|
41
|
+
ports_output = ''
|
|
42
|
+
|
|
43
|
+
cmd 'show ports' do |cfg|
|
|
44
|
+
cfg.each_line do |line|
|
|
45
|
+
port = line.match(/\|((access|network)[^\|]+)\|/)
|
|
46
|
+
ports << port if port
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
ports.each do |port|
|
|
51
|
+
port_command = 'show ' + port[2] + '-port ' + port[1]
|
|
52
|
+
|
|
53
|
+
ports_output << cmd(port_command) do |cfg|
|
|
54
|
+
cfg = "COMMAND: " + port_command + "\n\n" + cfg
|
|
55
|
+
cfg = comment cfg
|
|
56
|
+
"\n\n" + cfg
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
ports_output
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
cfg :ssh do
|
|
64
|
+
pre_logout 'logout'
|
|
65
|
+
end
|
|
66
|
+
end
|