corona 0.0.1
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.
- data/.rspec +1 -0
- data/Gemfile +14 -0
- data/Gemfile.lock +32 -0
- data/README.md +17 -0
- data/Rakefile +34 -0
- data/TODO.md +6 -0
- data/bin/corona +5 -0
- data/corona.gemspec +18 -0
- data/lib/corona/config/bootstrap.rb +13 -0
- data/lib/corona/config/core.rb +26 -0
- data/lib/corona/core.rb +179 -0
- data/lib/corona/db.rb +50 -0
- data/lib/corona/log.rb +13 -0
- data/lib/corona/snmp.rb +82 -0
- data/lib/corona.rb +3 -0
- metadata +112 -0
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--colour
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
GEM
|
2
|
+
remote: https://rubygems.org/
|
3
|
+
specs:
|
4
|
+
coderay (1.0.9)
|
5
|
+
diff-lcs (1.2.3)
|
6
|
+
method_source (0.8.1)
|
7
|
+
pry (0.9.12)
|
8
|
+
coderay (~> 1.0.5)
|
9
|
+
method_source (~> 0.8)
|
10
|
+
slop (~> 3.4)
|
11
|
+
rspec (2.13.0)
|
12
|
+
rspec-core (~> 2.13.0)
|
13
|
+
rspec-expectations (~> 2.13.0)
|
14
|
+
rspec-mocks (~> 2.13.0)
|
15
|
+
rspec-core (2.13.1)
|
16
|
+
rspec-expectations (2.13.0)
|
17
|
+
diff-lcs (>= 1.1.3, < 2.0)
|
18
|
+
rspec-mocks (2.13.1)
|
19
|
+
sequel (3.46.0)
|
20
|
+
slop (3.4.4)
|
21
|
+
snmp (1.1.1)
|
22
|
+
sqlite3 (1.3.7)
|
23
|
+
|
24
|
+
PLATFORMS
|
25
|
+
ruby
|
26
|
+
|
27
|
+
DEPENDENCIES
|
28
|
+
pry
|
29
|
+
rspec
|
30
|
+
sequel
|
31
|
+
snmp
|
32
|
+
sqlite3
|
data/README.md
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# About
|
2
|
+
Corona sends SNMP queries to defined CIDR ranges and populates SQL database based on nodes found. Some particular problems it tries to deal with:
|
3
|
+
* Only discover one node once
|
4
|
+
* To that effect it has priority list of idDescr lo0.0, loopback0, vlan2 etc. Higher priority will always replace lower priority interface (say you have MGMT in loop0 but giga0/2.42 has valid MGMT address towards L2 metro)
|
5
|
+
* Tries to handle gracefully renumbering, renaming, etc
|
6
|
+
|
7
|
+
# Install
|
8
|
+
1. gem install corona
|
9
|
+
2. corona
|
10
|
+
3. ^C (break it)
|
11
|
+
4. edit ~/.config/corona/config
|
12
|
+
5. put corona in crontab as _corona|mail -E -s 'new nodes found' foo@example.com_
|
13
|
+
|
14
|
+
# Config
|
15
|
+
* You need to configure SNMP community
|
16
|
+
* You need to define CIDR to poll and CIDRs to ignore (subset of those you poll)
|
17
|
+
* CIDR in example config is list, but can be replaced with 'string' which points to file, where CIDRs are listed
|
data/Rakefile
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
begin
|
2
|
+
require 'bundler'
|
3
|
+
require 'rspec/core/rake_task'
|
4
|
+
Bundler.setup
|
5
|
+
rescue LoadError
|
6
|
+
warn 'missing dependencies'
|
7
|
+
exit 42
|
8
|
+
end
|
9
|
+
|
10
|
+
gemspec = eval(File.read(Dir['*.gemspec'].first))
|
11
|
+
|
12
|
+
desc 'Validate the gemspec'
|
13
|
+
task :gemspec do
|
14
|
+
gemspec.validate
|
15
|
+
end
|
16
|
+
|
17
|
+
RSpec::Core::RakeTask.new(:spec)
|
18
|
+
|
19
|
+
desc "Build gem locally"
|
20
|
+
task :build => [:spec, :gemspec] do
|
21
|
+
system "gem build #{gemspec.name}.gemspec"
|
22
|
+
FileUtils.mkdir_p "gems"
|
23
|
+
FileUtils.mv "#{gemspec.name}-#{gemspec.version}.gem", "gems"
|
24
|
+
end
|
25
|
+
|
26
|
+
desc "Install gem locally"
|
27
|
+
task :install => :build do
|
28
|
+
system "sudo sh -c \'umask 022; gem install gems/#{gemspec.name}-#{gemspec.version}\'"
|
29
|
+
end
|
30
|
+
|
31
|
+
desc "Clean automatically generated files"
|
32
|
+
task :clean do
|
33
|
+
FileUtils.rm_rf "gems"
|
34
|
+
end
|
data/TODO.md
ADDED
data/bin/corona
ADDED
data/corona.gemspec
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'corona'
|
3
|
+
s.version = '0.0.1'
|
4
|
+
s.platform = Gem::Platform::RUBY
|
5
|
+
s.authors = [ 'Saku Ytti' ]
|
6
|
+
s.email = %w( saku@ytti.fi )
|
7
|
+
s.homepage = 'http://github.com/ytti/corona'
|
8
|
+
s.summary = 'device discovery via snmp polls'
|
9
|
+
s.description = 'Threaded SNMP poll based network discovery. Devices are stored in SQL'
|
10
|
+
s.rubyforge_project = s.name
|
11
|
+
s.files = `git ls-files`.split("\n")
|
12
|
+
s.executables = %w( corona )
|
13
|
+
s.require_path = 'lib'
|
14
|
+
|
15
|
+
s.add_dependency 'sequel'
|
16
|
+
s.add_dependency 'sqlite3'
|
17
|
+
s.add_dependency 'snmp'
|
18
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Corona
|
2
|
+
require 'fileutils'
|
3
|
+
FileUtils.mkdir_p Config::Root
|
4
|
+
CFG.community = 'public'
|
5
|
+
CFG.db = File.join Config::Root, 'corona.db'
|
6
|
+
CFG.poll = %w( 10.10.10.0/24 10.10.20.0/24 )
|
7
|
+
CFG.ignore = %w( 10.10.10.42/32 10.10.20.42/32 )
|
8
|
+
CFG.mgmt = %w( lo0.0 loopback0 vlan2 )
|
9
|
+
CFG.threads = 50
|
10
|
+
CFG.log = File.join Config::Root, 'log'
|
11
|
+
CFG.debug = false
|
12
|
+
CFG.save
|
13
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Corona
|
2
|
+
require 'ostruct'
|
3
|
+
require 'yaml'
|
4
|
+
class Config < OpenStruct
|
5
|
+
Root = File.join ENV['HOME'], '.config', 'corona'
|
6
|
+
Crash = File.join Root, 'crash'
|
7
|
+
def initialize file=File.join(Config::Root, 'config')
|
8
|
+
super()
|
9
|
+
@file = file.to_s
|
10
|
+
end
|
11
|
+
def load
|
12
|
+
if File.exists? @file
|
13
|
+
marshal_load YAML.load_file @file
|
14
|
+
else
|
15
|
+
require 'corona/config/bootstrap'
|
16
|
+
end
|
17
|
+
end
|
18
|
+
def save
|
19
|
+
File.write @file, YAML.dump(marshal_dump)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
CFG = Config.new
|
23
|
+
CFG.load
|
24
|
+
Log.file = CFG.log if CFG.log
|
25
|
+
Log.level = Logger::INFO unless CFG.debug
|
26
|
+
end
|
data/lib/corona/core.rb
ADDED
@@ -0,0 +1,179 @@
|
|
1
|
+
require 'corona/log'
|
2
|
+
require 'corona/config/core'
|
3
|
+
require 'corona/snmp'
|
4
|
+
require 'corona/db'
|
5
|
+
require 'ipaddr'
|
6
|
+
require 'resolv'
|
7
|
+
|
8
|
+
module Corona
|
9
|
+
class << self
|
10
|
+
def new
|
11
|
+
Core.new
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class Core
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def initialize
|
20
|
+
poll, ignore = resolve_networks
|
21
|
+
@mutex = Mutex.new
|
22
|
+
@db = DB.new
|
23
|
+
threads = []
|
24
|
+
Thread.abort_on_exception = true
|
25
|
+
poll.each do |net|
|
26
|
+
net.to_range.each do |ip|
|
27
|
+
next if ignore.any? { |ignore| ignore.include? ip }
|
28
|
+
while threads.size >= CFG.threads
|
29
|
+
threads.delete_if { |thread| not thread.alive? }
|
30
|
+
sleep 0.01
|
31
|
+
end
|
32
|
+
threads << Thread.new { poll ip }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
threads.each { |thread| thread.join }
|
36
|
+
end
|
37
|
+
|
38
|
+
def poll ip
|
39
|
+
snmp = SNMP.new ip.to_s
|
40
|
+
oids = snmp.dbget
|
41
|
+
if oids
|
42
|
+
if index = snmp.ip2index(ip.to_s)
|
43
|
+
if int = snmp.ifdescr(index)
|
44
|
+
@mutex.synchronize { process :oids=>oids, :int=>int.downcase, :ip=>ip }
|
45
|
+
else
|
46
|
+
Log.warn "no ifDescr for #{index} at #{ip}"
|
47
|
+
end
|
48
|
+
else
|
49
|
+
Log.warn "no ifIndex for #{ip}"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def process opt
|
55
|
+
opt = normalize_opt opt
|
56
|
+
record = mkrecord opt
|
57
|
+
old_by_ip, old_by_sysname = @db.old record[:id], record[:oid_sysName]
|
58
|
+
|
59
|
+
# unique box having non-unique sysname
|
60
|
+
# old_by_sysname = false if record[:oid_sysDescr].match 'Application Control Engine'
|
61
|
+
|
62
|
+
if not old_by_sysname and not old_by_ip
|
63
|
+
# all new device
|
64
|
+
puts "ptr [%s] sysName [%s] ip [%s]" % [record[:ptr], record[:oid_sysName], record[:ip]]
|
65
|
+
Log.info "#{record[:ip]} added"
|
66
|
+
@db.add record
|
67
|
+
|
68
|
+
elsif not old_by_sysname and old_by_ip
|
69
|
+
# IP seen, name not, device got renamed?
|
70
|
+
Log.info "#{record[:ip]} got renamed"
|
71
|
+
@db.update record, [:ip, old_by_ip[:ip]]
|
72
|
+
|
73
|
+
elsif old_by_sysname and not old_by_ip
|
74
|
+
# name exists, but IP is new, figure out if we wan to use old or new IP
|
75
|
+
decide_old_new record, old_by_sysname
|
76
|
+
|
77
|
+
elsif old_by_sysname and old_by_ip
|
78
|
+
both_seen record, old_by_sysname, old_by_ip
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def both_seen record, old_by_sysname, old_by_ip
|
83
|
+
if old_by_sysname == old_by_ip
|
84
|
+
# no changes, updating same record
|
85
|
+
Log.debug "#{record[:ip]} refreshed, no channges"
|
86
|
+
@db.update record, [:oid_sysName, old_by_sysname[:oid_sysName]]
|
87
|
+
else
|
88
|
+
# same name seen and same IP seen, but records were not same (device got renumbered to existing node + existing node got delete?)
|
89
|
+
Log.warn "#{record[:ip]}, unique entries for IP and sysName in DB, updating by IP"
|
90
|
+
@db.update record, [:ip, old_by_ip[:ip]]
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def decide_old_new record, old_by_sysname
|
95
|
+
new_int_pref = (CFG.mgmt.index(record[:oid_ifDescr]) or 100)
|
96
|
+
old_int_pref = (CFG.mgmt.index(old_by_sysname[:oid_ifDescr]) or 99)
|
97
|
+
|
98
|
+
if new_int_pref < old_int_pref
|
99
|
+
# new int is more preferable than old
|
100
|
+
Log.info "#{record[:ip]} is replacing inferior #{old_by_sysname[:ip]}"
|
101
|
+
@db.update record, [:oid_sysName, old_by_sysname[:oid_sysName]]
|
102
|
+
|
103
|
+
elsif new_int_pref == 100 and old_int_pref == 99
|
104
|
+
# neither old or new interface is known good MGMT interface
|
105
|
+
if SNMP.new(old_by_sysname[:ip]).sysdescr
|
106
|
+
# if old IP works, don't update
|
107
|
+
Log.debug "#{record[:ip]} not updating, previously seen as #{old_by_sysname[:ip]}"
|
108
|
+
else
|
109
|
+
Log.info "#{record[:ip]} updating, old #{old_by_sysname[:ip]} is dead"
|
110
|
+
@db.update record, [:oid_sysName, old_by_sysname[:oid_sysName]]
|
111
|
+
end
|
112
|
+
|
113
|
+
elsif new_int_pref >= old_int_pref
|
114
|
+
# nothing to do, we have better entry
|
115
|
+
Log.debug "#{record[:ip]} already seen as superior via #{old_by_sysname[:ip]}"
|
116
|
+
|
117
|
+
else
|
118
|
+
Log.error "not updating, new: #{record[:ip]}, old: #{old_by_sysname[:ip]}"
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def mkrecord opt
|
123
|
+
{
|
124
|
+
:id => opt[:ip].to_i,
|
125
|
+
:ip => opt[:ip].to_s,
|
126
|
+
:ptr => ip2name(opt[:ip].to_s),
|
127
|
+
:model => model(opt),
|
128
|
+
:oid_ifDescr => opt[:int],
|
129
|
+
:oid_sysName => opt[:oids][:sysName],
|
130
|
+
:oid_sysLocation => opt[:oids][:sysLocation],
|
131
|
+
:oid_sysDescr => opt[:oids][:sysDescr],
|
132
|
+
}
|
133
|
+
end
|
134
|
+
|
135
|
+
def normalize_opt opt
|
136
|
+
opt[:oids][:sysName].sub! /-re[1-9]\./, '-re0.'
|
137
|
+
opt
|
138
|
+
end
|
139
|
+
|
140
|
+
def ip2name ip
|
141
|
+
Resolv.getname ip rescue ip
|
142
|
+
end
|
143
|
+
|
144
|
+
def model opt
|
145
|
+
case opt[:oids][:sysDescr]
|
146
|
+
when /Cisco Catalyst operating System/
|
147
|
+
'catos'
|
148
|
+
when /cisco/i, /Application Control Engine/i
|
149
|
+
'ios'
|
150
|
+
when /JUNOS/
|
151
|
+
'junos'
|
152
|
+
when /^NetScreen/, /^SSG-\d+/
|
153
|
+
'screenos'
|
154
|
+
when /IronWare/
|
155
|
+
'ironware'
|
156
|
+
when /^Summit/
|
157
|
+
'xos'
|
158
|
+
when /^\d+[A-Z]\sEthernet Switch$/
|
159
|
+
'powerconnect'
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
def resolve_networks
|
164
|
+
[CFG.poll, CFG.ignore].map do |nets|
|
165
|
+
if nets.respond_to? :each
|
166
|
+
nets.map { |net| IPAddr.new net }
|
167
|
+
else
|
168
|
+
out = []
|
169
|
+
File.read(nets).each_line do |net|
|
170
|
+
net = net.match /^([\d.\/]+)/
|
171
|
+
out.push IPAddr.new net[1] if net
|
172
|
+
end
|
173
|
+
out
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
end
|
179
|
+
end
|
data/lib/corona/db.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
module Corona
|
2
|
+
class DB
|
3
|
+
require 'sequel'
|
4
|
+
require 'sqlite3'
|
5
|
+
def initialize
|
6
|
+
@db = Sequel.sqlite(CFG.db, :max_connections => 1, :pool_timeout => 60)
|
7
|
+
|
8
|
+
@db.create_table :device do
|
9
|
+
primary_key :id
|
10
|
+
String :ip
|
11
|
+
String :ptr
|
12
|
+
String :model
|
13
|
+
String :oid_ifDescr
|
14
|
+
Boolean :active
|
15
|
+
Time :first_seen
|
16
|
+
Time :last_seen
|
17
|
+
String :oid_sysName
|
18
|
+
String :oid_sysLocation
|
19
|
+
String :oid_sysDescr
|
20
|
+
end unless @db.table_exists? :device
|
21
|
+
end
|
22
|
+
|
23
|
+
# http://sequel.rubyforge.org/rdoc/files/doc/cheat_sheet_rdoc.html
|
24
|
+
#
|
25
|
+
|
26
|
+
def add record
|
27
|
+
record[:first_seen] = record[:last_seen] = Time.now.utc
|
28
|
+
record[:active] = true
|
29
|
+
#Log.debug "adding: #{record}"
|
30
|
+
@db[:device].insert record
|
31
|
+
end
|
32
|
+
|
33
|
+
def update record, where
|
34
|
+
record[:last_seen] = Time.now.utc
|
35
|
+
record[:active] = true
|
36
|
+
#Log.debug "updating (where: #{where}): #{record}"
|
37
|
+
@db[:device].where('? == ?', where.first, where.last).update record
|
38
|
+
end
|
39
|
+
|
40
|
+
def [] primary_key
|
41
|
+
@db[:device].where('id == ?', primary_key).first
|
42
|
+
end
|
43
|
+
|
44
|
+
def old primary_key, oid_sysName
|
45
|
+
ip = self[primary_key]
|
46
|
+
sysName = @db[:device].where('oid_sysName == ?', oid_sysName).first
|
47
|
+
[ip, sysName]
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
data/lib/corona/log.rb
ADDED
data/lib/corona/snmp.rb
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
module Corona
|
2
|
+
class SNMP
|
3
|
+
DB_OID = {
|
4
|
+
:sysDescr => '1.3.6.1.2.1.1.1.0',
|
5
|
+
:sysLocation => '1.3.6.1.2.1.1.6.0',
|
6
|
+
:sysName => '1.3.6.1.2.1.1.5.0',
|
7
|
+
}
|
8
|
+
OID = {
|
9
|
+
:ipCidrRouteIfIndex => '1.3.6.1.2.1.4.24.4.1.5', # addr.255.255.255.255.0.0.0.0.0
|
10
|
+
:ipAdEntIfIndex => '1.3.6.1.2.1.4.20.1.2', # addr
|
11
|
+
:ipAddressIfIndex => '1.3.6.1.2.1.4.34.1.3', # 1,2 (uni,any) . 4,16 (size) . addr
|
12
|
+
:ifDescr => '1.3.6.1.2.1.2.2.1.2',
|
13
|
+
}
|
14
|
+
UNICAST = 1
|
15
|
+
IPV4 = 4
|
16
|
+
|
17
|
+
BULK_MAX = 30
|
18
|
+
require 'snmp'
|
19
|
+
def initialize host, community=CFG.community
|
20
|
+
@snmp = ::SNMP::Manager.new :Host => host, :Community => community,
|
21
|
+
:Timeout => 1, :Retries => 3, :MibModules => false
|
22
|
+
end
|
23
|
+
def get *oid
|
24
|
+
oid = [oid].flatten.join('.')
|
25
|
+
begin
|
26
|
+
@snmp.get(oid).each_varbind { |vb| return vb }
|
27
|
+
rescue ::SNMP::RequestTimeout
|
28
|
+
return false
|
29
|
+
end
|
30
|
+
end
|
31
|
+
def mget oids=DB_OID
|
32
|
+
result = {}
|
33
|
+
begin
|
34
|
+
@snmp.get(oids.map{|_,oid|oid}).each_varbind do |vb|
|
35
|
+
oids.each do |name,oid|
|
36
|
+
if vb.name.to_str == oid
|
37
|
+
result[name] = vb.value
|
38
|
+
next
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
rescue ::SNMP::RequestTimeout
|
43
|
+
return false
|
44
|
+
end
|
45
|
+
result
|
46
|
+
end
|
47
|
+
alias dbget mget
|
48
|
+
def bulkwalk root
|
49
|
+
last, oid, vbs = false, root, []
|
50
|
+
while not last
|
51
|
+
r = @snmp.get_bulk 0, BULK_MAX, oid
|
52
|
+
r.varbind_list.each do |vb|
|
53
|
+
oid = vb.name.to_str
|
54
|
+
(last = true; break) if not oid.match /^#{Regexp.quote root}/
|
55
|
+
vbs.push vb
|
56
|
+
end
|
57
|
+
end
|
58
|
+
vbs
|
59
|
+
end
|
60
|
+
|
61
|
+
def sysdescr
|
62
|
+
get DB_OID[:sysDescr]
|
63
|
+
end
|
64
|
+
|
65
|
+
def ip2index ip
|
66
|
+
oids = mget :route => [OID[:ipCidrRouteIfIndex], ip, '255.255.255.255.0.0.0.0.0'].join('.'),
|
67
|
+
:new => [OID[:ipAddressIfIndex], UNICAST, IPV4, ip].join('.'),
|
68
|
+
:old => [OID[:ipAdEntIfIndex], ip].join('.')
|
69
|
+
return false unless oids
|
70
|
+
index = oids[:route]
|
71
|
+
index = oids[:new] if not index.class == ::SNMP::Integer or index.to_s == '0'
|
72
|
+
index = oids[:old] if not index.class == ::SNMP::Integer or index.to_s == '0'
|
73
|
+
return false unless index.class == ::SNMP::Integer
|
74
|
+
index.to_s
|
75
|
+
end
|
76
|
+
def ifdescr index
|
77
|
+
descr = get OID[:ifDescr], index
|
78
|
+
return false unless descr and descr.value.class == ::SNMP::OctetString
|
79
|
+
descr.value.to_s
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
data/lib/corona.rb
ADDED
metadata
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: corona
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Saku Ytti
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-05-01 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: sequel
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: sqlite3
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: snmp
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
description: Threaded SNMP poll based network discovery. Devices are stored in SQL
|
63
|
+
email:
|
64
|
+
- saku@ytti.fi
|
65
|
+
executables:
|
66
|
+
- corona
|
67
|
+
extensions: []
|
68
|
+
extra_rdoc_files: []
|
69
|
+
files:
|
70
|
+
- .rspec
|
71
|
+
- Gemfile
|
72
|
+
- Gemfile.lock
|
73
|
+
- README.md
|
74
|
+
- Rakefile
|
75
|
+
- TODO.md
|
76
|
+
- bin/corona
|
77
|
+
- corona.gemspec
|
78
|
+
- lib/corona.rb
|
79
|
+
- lib/corona/config/bootstrap.rb
|
80
|
+
- lib/corona/config/core.rb
|
81
|
+
- lib/corona/core.rb
|
82
|
+
- lib/corona/db.rb
|
83
|
+
- lib/corona/log.rb
|
84
|
+
- lib/corona/snmp.rb
|
85
|
+
homepage: http://github.com/ytti/corona
|
86
|
+
licenses: []
|
87
|
+
post_install_message:
|
88
|
+
rdoc_options: []
|
89
|
+
require_paths:
|
90
|
+
- lib
|
91
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
92
|
+
none: false
|
93
|
+
requirements:
|
94
|
+
- - '>='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
segments:
|
98
|
+
- 0
|
99
|
+
hash: 1454207244225852473
|
100
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
101
|
+
none: false
|
102
|
+
requirements:
|
103
|
+
- - '>='
|
104
|
+
- !ruby/object:Gem::Version
|
105
|
+
version: '0'
|
106
|
+
requirements: []
|
107
|
+
rubyforge_project: corona
|
108
|
+
rubygems_version: 1.8.25
|
109
|
+
signing_key:
|
110
|
+
specification_version: 3
|
111
|
+
summary: device discovery via snmp polls
|
112
|
+
test_files: []
|