eznemo 0.1.0 → 0.2.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/README.md +28 -7
- data/eznemo.gemspec +1 -0
- data/lib/eznemo/datastore.rb +13 -0
- data/lib/eznemo/monitor/ping.rb +56 -39
- data/lib/eznemo/monitor.rb +1 -8
- data/lib/eznemo/mysql.rb +52 -23
- data/lib/eznemo/version.rb +1 -1
- data/lib/eznemo.rb +1 -1
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4a63d6de019cde7d7b7f154e16534524759075ad
|
4
|
+
data.tar.gz: 930d98134aeb498f387fb8bcd69866948cb82dc0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e32c9ed5244114be6ea97713322558566fd1d4d2982b71046223700224d4092e4ede0f1b27d32529fc021f94eebed7be1ac02aca6537867a463763b15b721db9
|
7
|
+
data.tar.gz: 47945030a40c8e762568ec593e819309b42a93ee5347ec9ce25fd0f75604b9d45889bae290eac96ce3667b48d870dbcd3dc70a598fcc5ea643a77fa81bad2d5f
|
data/README.md
CHANGED
@@ -40,7 +40,8 @@ Config file.
|
|
40
40
|
:probe:
|
41
41
|
:name: Probe01
|
42
42
|
:datastore:
|
43
|
-
:type: :mysql
|
43
|
+
:type: :mysql # currently the only option
|
44
|
+
:queue_size: 20
|
44
45
|
:options:
|
45
46
|
:host: 127.0.0.1
|
46
47
|
:username: user
|
@@ -70,7 +71,6 @@ Config file.
|
|
70
71
|
interval: 60, # frequecy this check is run in seconds
|
71
72
|
type: 'ping', # or other monitor plugin name
|
72
73
|
state: true, # true means active
|
73
|
-
tags: '["tag1", "tag2"]',
|
74
74
|
options: '-S 192.168.0.11'
|
75
75
|
}
|
76
76
|
```
|
@@ -88,8 +88,20 @@ Config file.
|
|
88
88
|
}
|
89
89
|
```
|
90
90
|
|
91
|
+
### Tags
|
92
|
+
|
93
|
+
```ruby
|
94
|
+
{
|
95
|
+
check_id: 123, # from checks
|
96
|
+
text: 'prod' # tag text
|
97
|
+
}
|
98
|
+
```
|
99
|
+
|
100
|
+
|
91
101
|
### MySQL
|
92
102
|
|
103
|
+
Example using TokuDB.
|
104
|
+
|
93
105
|
```sql
|
94
106
|
CREATE TABLE `checks` (
|
95
107
|
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
@@ -98,10 +110,10 @@ CREATE TABLE `checks` (
|
|
98
110
|
`interval` int(11) NOT NULL,
|
99
111
|
`type` varchar(255) NOT NULL DEFAULT '',
|
100
112
|
`state` tinyint(1) NOT NULL,
|
101
|
-
`tags` text,
|
102
113
|
`options` text,
|
103
|
-
PRIMARY KEY (`id`)
|
104
|
-
|
114
|
+
PRIMARY KEY (`id`),
|
115
|
+
CLUSTERING KEY `state` (`state`)
|
116
|
+
) ENGINE=TokuDB DEFAULT CHARSET=utf8;
|
105
117
|
|
106
118
|
CREATE TABLE `results` (
|
107
119
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
@@ -112,9 +124,18 @@ CREATE TABLE `results` (
|
|
112
124
|
`response_ms` float NOT NULL DEFAULT '0',
|
113
125
|
`status_desc` varchar(255) DEFAULT NULL,
|
114
126
|
PRIMARY KEY (`id`),
|
115
|
-
KEY `check_id` (`check_id`),
|
127
|
+
CLUSTERING KEY `check_id` (`check_id`),
|
116
128
|
KEY `probe` (`probe`),
|
117
129
|
KEY `timestamp` (`timestamp`),
|
118
130
|
KEY `status` (`status`)
|
119
|
-
) ENGINE=
|
131
|
+
) ENGINE=TokuDB DEFAULT CHARSET=utf8;
|
132
|
+
|
133
|
+
CREATE TABLE `tags` (
|
134
|
+
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
135
|
+
`check_id` int(11) NOT NULL,
|
136
|
+
`text` varchar(63) NOT NULL DEFAULT '',
|
137
|
+
PRIMARY KEY (`id`),
|
138
|
+
KEY `check_id` (`check_id`),
|
139
|
+
CLUSTERING KEY `text` (`text`)
|
140
|
+
) ENGINE=TokuDB DEFAULT CHARSET=utf8;
|
120
141
|
```
|
data/eznemo.gemspec
CHANGED
data/lib/eznemo/datastore.rb
CHANGED
@@ -5,6 +5,19 @@ module EzNemo
|
|
5
5
|
@datastore ||= DataStore.new
|
6
6
|
end
|
7
7
|
|
8
|
+
# Sequel models
|
9
|
+
class Check < Sequel::Model
|
10
|
+
one_to_many :tags
|
11
|
+
end
|
12
|
+
|
13
|
+
class Tag < Sequel::Model
|
14
|
+
many_to_one :check
|
15
|
+
end
|
16
|
+
|
17
|
+
class Result < Sequel::Model
|
18
|
+
many_to_one :check
|
19
|
+
end
|
20
|
+
|
8
21
|
# Storage for checks and results
|
9
22
|
class DataStore
|
10
23
|
|
data/lib/eznemo/monitor/ping.rb
CHANGED
@@ -37,7 +37,7 @@ module EzNemo
|
|
37
37
|
end
|
38
38
|
|
39
39
|
# Add a check using this plugin
|
40
|
-
# @param check [
|
40
|
+
# @param check [EzNemo::Check]
|
41
41
|
def add_check(check)
|
42
42
|
min = config[:min_interval]
|
43
43
|
check[:interval] = min if check[:interval] < min
|
@@ -47,67 +47,84 @@ module EzNemo
|
|
47
47
|
end
|
48
48
|
|
49
49
|
def linux_ping(check)
|
50
|
-
result =
|
51
|
-
|
52
|
-
check_id: check[:id]
|
53
|
-
}
|
54
|
-
path = config[:path]
|
55
|
-
timeout = config[:timeout]
|
56
|
-
options = "#{config[:cmd_opts]} #{check[:options]}"
|
57
|
-
hostname = check[:hostname]
|
58
|
-
cmd = "#{path} -c 1 -nqW #{timeout} #{options} #{hostname}"
|
59
|
-
EM.system(cmd) do |output, status|
|
50
|
+
result = create_result_for_check(check)
|
51
|
+
EM.system(build_cmd(check)) do |output, status|
|
60
52
|
case status.exitstatus
|
61
53
|
when 0
|
62
54
|
expr = /=\s*([0-9\.]+)/
|
63
55
|
expr =~ output
|
64
|
-
result
|
65
|
-
result[:response_ms] = $1.to_f
|
66
|
-
result[:status_desc] = 'OK'
|
56
|
+
set_ok_result(result, $1.to_f)
|
67
57
|
when 1
|
68
|
-
result
|
69
|
-
result[:response_ms] = 0
|
70
|
-
result[:status_desc] = 'NG'
|
58
|
+
set_ng_result(result)
|
71
59
|
else
|
72
|
-
|
73
|
-
result[:status] = 0
|
74
|
-
result[:response_ms] = 0
|
75
|
-
result[:status_desc] = "ERROR: #{output}".chomp
|
60
|
+
set_error_result(result, output)
|
76
61
|
end
|
77
62
|
monitor.report(result)
|
78
63
|
end
|
79
64
|
end
|
80
65
|
|
81
66
|
def bsd_ping(check)
|
82
|
-
result =
|
83
|
-
|
84
|
-
|
85
|
-
}
|
86
|
-
timeout = config[:timeout] * 1000
|
87
|
-
options = "#{config[:cmd_opts]} #{check[:option]}"
|
88
|
-
hostname = check[:hostname]
|
89
|
-
cmd = "#{path} -c 1 -nqW #{timeout} #{options} #{hostname}"
|
90
|
-
EM.system(cmd) do |output, status|
|
67
|
+
result = create_result_for_check(check)
|
68
|
+
args = {timeout: config[:timeout] * 1000}
|
69
|
+
EM.system(build_cmd(check, args)) do |output, status|
|
91
70
|
case status.exitstatus
|
92
71
|
when 0
|
93
72
|
expr = /=\s*([0-9\.]+)/
|
94
73
|
expr =~ output
|
95
|
-
result
|
96
|
-
result[:response_ms] = $1.to_f
|
97
|
-
result[:status_desc] = 'OK'
|
74
|
+
set_ok_result(result, $1.to_f)
|
98
75
|
when 2
|
99
|
-
result
|
100
|
-
result[:response_ms] = 0
|
101
|
-
result[:status_desc] = 'NG'
|
76
|
+
set_ng_result(result)
|
102
77
|
else
|
103
|
-
result
|
104
|
-
result[:response_ms] = 0
|
105
|
-
result[:status_desc] = "ERROR: #{output}".chomp
|
78
|
+
set_error_result(result, output)
|
106
79
|
end
|
107
80
|
monitor.report(result)
|
108
81
|
end
|
109
82
|
end
|
110
83
|
|
84
|
+
private
|
85
|
+
|
86
|
+
# @param check [EzNemo::Check]
|
87
|
+
# @return [EzNemo::Result]
|
88
|
+
def create_result_for_check(check)
|
89
|
+
Result::new do |r|
|
90
|
+
r.timestamp = Time.now
|
91
|
+
r.check = check
|
92
|
+
r.probe = EzNemo.config[:probe][:name]
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# @param check [EzNemo::Check]
|
97
|
+
# @param args [Hash] overriding arguments
|
98
|
+
def build_cmd(check, args = {})
|
99
|
+
h = {
|
100
|
+
path: config[:path],
|
101
|
+
timeout: config[:timeout],
|
102
|
+
options: "#{config[:cmd_opts]} #{check[:options]}",
|
103
|
+
hostname: check[:hostname]
|
104
|
+
}
|
105
|
+
h.merge!(args)
|
106
|
+
"#{h[:path]} -c 1 -nqW #{h[:timeout]} #{h[:options]} #{h[:hostname]}"
|
107
|
+
end
|
108
|
+
|
109
|
+
def set_ok_result(result, ms)
|
110
|
+
result.status = true
|
111
|
+
result.response_ms = ms
|
112
|
+
result.status_desc = 'OK'
|
113
|
+
end
|
114
|
+
|
115
|
+
def set_ng_result(result)
|
116
|
+
result.status = false
|
117
|
+
result.response_ms = 0
|
118
|
+
result.status_desc = 'NG'
|
119
|
+
end
|
120
|
+
|
121
|
+
def set_err_result(result, msg)
|
122
|
+
msg = 'see log' if msg.nil? || msg.size == 0
|
123
|
+
result.status = false
|
124
|
+
result.response_ms = 0
|
125
|
+
result.status_desc = "ERROR: #{msg}".chomp
|
126
|
+
end
|
127
|
+
|
111
128
|
end
|
112
129
|
|
113
130
|
monitor.register(Ping.new)
|
data/lib/eznemo/monitor.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'json'
|
2
|
-
|
3
1
|
module EzNemo
|
4
2
|
|
5
3
|
# The shared Monitor instance
|
@@ -25,13 +23,8 @@ module EzNemo
|
|
25
23
|
# Starts check loops in the reactor
|
26
24
|
# @param checks [Array<Hash, ...>]
|
27
25
|
def start_checks(checks)
|
28
|
-
cfg_tags = EzNemo.config[:checks][:tags]
|
29
26
|
i = 0
|
30
27
|
checks.each do |c|
|
31
|
-
if cfg_tags
|
32
|
-
c[:tags] ? tags = JSON.parse(c[:tags]) : tags = []
|
33
|
-
next if (cfg_tags & tags).empty?
|
34
|
-
end
|
35
28
|
p = @plugins[c[:type].to_sym]
|
36
29
|
p.add_check(c)
|
37
30
|
i += 1
|
@@ -40,7 +33,7 @@ module EzNemo
|
|
40
33
|
end
|
41
34
|
|
42
35
|
# Report result; usually called by the plugin
|
43
|
-
# @param result [
|
36
|
+
# @param result [EzNemo::Result]
|
44
37
|
def report(result)
|
45
38
|
EzNemo.datastore.store_result(result)
|
46
39
|
end
|
data/lib/eznemo/mysql.rb
CHANGED
@@ -1,27 +1,27 @@
|
|
1
1
|
require 'mysql2/em'
|
2
|
+
require 'sequel'
|
3
|
+
require 'thread'
|
2
4
|
|
3
5
|
|
4
6
|
module EzNemo
|
5
7
|
|
8
|
+
# Sequel connection setup
|
9
|
+
Sequel::Model.db = Sequel.connect({adapter: 'mysql2'}.merge(config[:datastore][:options]))
|
10
|
+
|
6
11
|
# Defines DataStorage class for MySQL
|
7
12
|
module StorageAdapter
|
8
13
|
|
9
14
|
# Number of records it queues up before writing
|
10
|
-
|
15
|
+
DEFAULT_QUEUE_SIZE = 20
|
11
16
|
|
12
17
|
def initialize
|
13
18
|
@results = []
|
14
|
-
@
|
19
|
+
@queue_size = EzNemo.config[:datastore][:queue_size]
|
20
|
+
@queue_size ||= DEFAULT_QUEUE_SIZE
|
15
21
|
@opts = EzNemo.config[:datastore][:options]
|
16
22
|
@opts[:flags] = Mysql2::Client::MULTI_STATEMENTS
|
17
23
|
end
|
18
24
|
|
19
|
-
# Creates and returns new instance of {Mysql2::Client}
|
20
|
-
# @return [Mysql2::Client]
|
21
|
-
def database
|
22
|
-
Mysql2::Client.new(@opts)
|
23
|
-
end
|
24
|
-
|
25
25
|
# Creates and returns new instance of {Mysql2::EM::Client}
|
26
26
|
# @return [Mysql2::EM::Client]
|
27
27
|
def emdatabase
|
@@ -29,17 +29,36 @@ module EzNemo
|
|
29
29
|
end
|
30
30
|
|
31
31
|
# Returns all active checks
|
32
|
-
# @return [Array<
|
32
|
+
# @return [Array<EzNemo::Check, ...>]
|
33
33
|
def checks
|
34
|
-
|
35
|
-
|
34
|
+
checks_with_tags(EzNemo.config[:checks][:tags])
|
35
|
+
end
|
36
|
+
|
37
|
+
# Returns all active checks matching all tags
|
38
|
+
# @param tags [Array<String, ...>] list of tag text
|
39
|
+
# @return [Array<EzNemo::Checks, ...>]
|
40
|
+
def checks_with_tags(tags = nil)
|
41
|
+
cids = check_ids_with_tags(tags)
|
42
|
+
return Check.where(state: true).all if cids.nil?
|
43
|
+
Check.where(state: true, id: cids).all
|
44
|
+
end
|
45
|
+
|
46
|
+
# @param tags [Array<String, ...>] list of tag text
|
47
|
+
# @return [Array] check_id mathing all tags; nil when no tags supplied
|
48
|
+
def check_ids_with_tags(tags = nil)
|
49
|
+
return nil if tags.nil? || tags.empty?
|
50
|
+
candi_ids = []
|
51
|
+
tags.each { |t| candi_ids << Tag.where(text: t).map(:check_id) }
|
52
|
+
final_ids = candi_ids[0]
|
53
|
+
candi_ids.each { |ids| final_ids = final_ids & ids }
|
54
|
+
final_ids
|
36
55
|
end
|
37
56
|
|
38
57
|
# Stores a result; into queue first
|
39
58
|
# @param result [Hash] (see {EzNemo::Monitor#report})
|
40
59
|
def store_result(result)
|
41
60
|
@results << result
|
42
|
-
if @results.count >=
|
61
|
+
if @results.count >= @queue_size
|
43
62
|
write_results
|
44
63
|
end
|
45
64
|
end
|
@@ -49,19 +68,28 @@ module EzNemo
|
|
49
68
|
# @return [Object] Mysql2 client instance
|
50
69
|
def write_results(sync = false)
|
51
70
|
return nil if @results.empty?
|
52
|
-
sync ? db = database : db = emdatabase
|
53
|
-
stmt = ''
|
54
|
-
@results.each do |r|
|
55
|
-
r[:probe] = @probe
|
56
|
-
r[:status_desc] = db.escape(r[:status_desc])
|
57
|
-
cols = r.keys.join(',')
|
58
|
-
vals = r.values.join("','")
|
59
|
-
stmt << "INSERT INTO results (#{cols}) VALUES ('#{vals}');"
|
60
|
-
end
|
61
|
-
@results.clear
|
62
71
|
if sync
|
63
|
-
|
72
|
+
# Sequel won't run after trap; run in another thread
|
73
|
+
thr = Thread.new do
|
74
|
+
puts 'Flushing in another thread...'
|
75
|
+
Result.db.transaction do
|
76
|
+
@results.each { |r| r.save}
|
77
|
+
end
|
78
|
+
end
|
79
|
+
thr.join
|
80
|
+
return true
|
64
81
|
else
|
82
|
+
db = emdatabase
|
83
|
+
stmt = ''
|
84
|
+
@results.each do |r|
|
85
|
+
# r[:probe] = @probe
|
86
|
+
r[:status_desc] = db.escape(r[:status_desc])
|
87
|
+
cols = r.values.keys.join(',')
|
88
|
+
# find and convert boolean values to integer
|
89
|
+
vals = r.values.values.map { |v| !!v == v ? (v ? 1 : 0) : v }
|
90
|
+
vals = vals.join("','")
|
91
|
+
stmt << "INSERT INTO results (#{cols}) VALUES ('#{vals}');"
|
92
|
+
end
|
65
93
|
defer = db.query(stmt)
|
66
94
|
defer.callback do
|
67
95
|
end
|
@@ -70,6 +98,7 @@ module EzNemo
|
|
70
98
|
db.close if db.ping
|
71
99
|
end
|
72
100
|
end
|
101
|
+
@results.clear
|
73
102
|
db
|
74
103
|
end
|
75
104
|
|
data/lib/eznemo/version.rb
CHANGED
data/lib/eznemo.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: eznemo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ken J.
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-05-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: kajiki
|
@@ -38,6 +38,20 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '1.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: sequel
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '4.0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '4.0'
|
41
55
|
description: Simple network monitoring
|
42
56
|
email:
|
43
57
|
- kenjij@gmail.com
|