inquisitor 0.1.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/LICENSE +21 -0
- data/README.md +54 -0
- data/bin/monitor +5 -0
- data/bin/monitor_web +6 -0
- data/lib/inquisitor.rb +35 -0
- data/lib/inquisitor/cli.rb +22 -0
- data/lib/inquisitor/contact.rb +7 -0
- data/lib/inquisitor/extensions.rb +54 -0
- data/lib/inquisitor/node.rb +61 -0
- data/lib/inquisitor/server/public/down.png +0 -0
- data/lib/inquisitor/server/public/loading.gif +0 -0
- data/lib/inquisitor/server/public/script.js +31 -0
- data/lib/inquisitor/server/public/style.css +38 -0
- data/lib/inquisitor/server/public/up.png +0 -0
- data/lib/inquisitor/server/views/index.haml +40 -0
- data/lib/inquisitor/server/views/layout.haml +15 -0
- data/lib/inquisitor/settings.rb +24 -0
- data/lib/inquisitor/version.rb +6 -0
- data/lib/inquisitor/web.rb +55 -0
- data/spec/inquisitor/contact_spec.rb +14 -0
- data/spec/inquisitor/node_spec.rb +80 -0
- data/spec/inquisitor/outpost_factory_spec.rb +26 -0
- data/spec/inquisitor/settings_spec.rb +41 -0
- data/spec/inquisitor/web_spec.rb +118 -0
- data/spec/spec_helper.rb +32 -0
- data/spec/spec_integration_helper.rb +15 -0
- data/spec/support/blueprints.rb +11 -0
- metadata +224 -0
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
Copyright (C) 2011, brain-geek
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
4
|
+
this software and associated documentation files (the "Software"), to deal in
|
5
|
+
the Software without restriction, including without limitation the rights to
|
6
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
7
|
+
of the Software, and to permit persons to whom the Software is furnished to do
|
8
|
+
so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in all
|
11
|
+
copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
19
|
+
SOFTWARE.
|
20
|
+
|
21
|
+
Images by @genn_org
|
data/README.md
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
Inquisitor
|
2
|
+
===============
|
3
|
+
|
4
|
+
[](http://travis-ci.org/brain-geek/inquisitor)
|
5
|
+
[](https://gemnasium.com/brain-geek/inquisitor)
|
6
|
+
|
7
|
+
This project is aimed on creation ruby-powered monitoring solution with simple web interface.
|
8
|
+
|
9
|
+
Usage
|
10
|
+
-----
|
11
|
+
###Standalone install:
|
12
|
+
#####Running check:
|
13
|
+
|
14
|
+
monitor -d sqlite3://`pwd`/sqlite_database.db
|
15
|
+
|
16
|
+
#####Running web server:
|
17
|
+
|
18
|
+
monitor_web -d sqlite3://`pwd`/sqlite_database.db
|
19
|
+
|
20
|
+
###Mounting to rails app:
|
21
|
+
#####Add to gemfile:
|
22
|
+
|
23
|
+
gem 'data_mapper'
|
24
|
+
gem 'dm-redis-adapter'
|
25
|
+
gem 'inquisitor', :git => 'git://github.com/brain-geek/inquisitor.git'
|
26
|
+
|
27
|
+
#####Create initializer:
|
28
|
+
|
29
|
+
require 'inquisitor/web'
|
30
|
+
Inquisitor.settings.set :db_path => {:adapter => "redis"}
|
31
|
+
|
32
|
+
#####Add to routes:
|
33
|
+
|
34
|
+
mount Inquisitor::Web.new, :at => "/inquisitor"
|
35
|
+
|
36
|
+
###Development web server
|
37
|
+
shotgun config.dev.ru
|
38
|
+
|
39
|
+
Features
|
40
|
+
-----
|
41
|
+
#####Databases supported
|
42
|
+
It should work with all databases supported by datamapper. Tested with postgresql, mysql, redis and sqlite. Format for db_path can be found [in datamapper doc](http://datamapper.org/getting-started.html) - "Specify your database connection".
|
43
|
+
|
44
|
+
#####Cli options:
|
45
|
+
You can read availible options from lib/inquisitor/cli.rb . Same options are supported by standalone install
|
46
|
+
|
47
|
+
#####Supported types of monitoring:
|
48
|
+
[outpost gem](https://github.com/vinibaggio/outpost) is used as backend for monitoring. For now, http:// and ping:// checks are supported.
|
49
|
+
|
50
|
+
Copyright
|
51
|
+
---------
|
52
|
+
|
53
|
+
Copyright (c) 2011 @brain-geek. See LICENSE for details.
|
54
|
+
|
data/bin/monitor
ADDED
data/bin/monitor_web
ADDED
data/lib/inquisitor.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'outpost'
|
2
|
+
require 'outpost/scouts'
|
3
|
+
require 'outpost/notifiers/email'
|
4
|
+
|
5
|
+
require 'data_mapper'
|
6
|
+
require File.join(File.dirname(__FILE__), 'inquisitor', 'extensions.rb')
|
7
|
+
require File.join(File.dirname(__FILE__), 'inquisitor', 'node.rb')
|
8
|
+
require File.join(File.dirname(__FILE__), 'inquisitor', 'contact.rb')
|
9
|
+
require File.join(File.dirname(__FILE__), 'inquisitor', 'settings.rb')
|
10
|
+
DataMapper.finalize
|
11
|
+
|
12
|
+
module Inquisitor
|
13
|
+
class << self
|
14
|
+
def create_outpost(name = '')
|
15
|
+
outpost = Outpost::Application.new
|
16
|
+
outpost.name = name
|
17
|
+
|
18
|
+
Inquisitor::Contact.all.each do |contact|
|
19
|
+
outpost.add_notifier Outpost::Notifiers::Email, {
|
20
|
+
:from => Inquisitor.settings.mail_from,
|
21
|
+
:to => contact.email,
|
22
|
+
:subject => Inquisitor.settings.mail_subject
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
26
|
+
outpost
|
27
|
+
end
|
28
|
+
|
29
|
+
def settings
|
30
|
+
@settings ||= Settings.new
|
31
|
+
end
|
32
|
+
|
33
|
+
delegate :check_all, :to => Node
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
begin
|
2
|
+
require 'slop'
|
3
|
+
rescue LoadError
|
4
|
+
require 'rubygems'
|
5
|
+
require 'slop'
|
6
|
+
end
|
7
|
+
|
8
|
+
require File.join(File.dirname(__FILE__), '..', 'inquisitor')
|
9
|
+
require File.join(File.dirname(__FILE__), 'web')
|
10
|
+
|
11
|
+
opts = Slop.parse do
|
12
|
+
on :d, :db_path, 'DB path', :optional => false
|
13
|
+
on :mail_from, 'Send mail from email', :optional => true
|
14
|
+
on :mail_subject, 'Mail subject', :optional => true
|
15
|
+
on :check_period, :as => :integer, :optional => true
|
16
|
+
end
|
17
|
+
|
18
|
+
opts = opts.to_hash.delete_if{|key, value| value.nil? }
|
19
|
+
|
20
|
+
raise 'DB connection is not set' unless opts.has_key?(:db_path)
|
21
|
+
|
22
|
+
Inquisitor.settings.set opts
|
@@ -0,0 +1,54 @@
|
|
1
|
+
#Module.delegate by active_support
|
2
|
+
class Module
|
3
|
+
# File activesupport/lib/active_support/core_ext/module/delegation.rb, line 106
|
4
|
+
def delegate(*methods)
|
5
|
+
options = methods.pop
|
6
|
+
unless options.is_a?(Hash) && to = options[:to]
|
7
|
+
raise ArgumentError, "Delegation needs a target. Supply an options hash with a :to key as the last argument (e.g. delegate :hello, :to => :greeter)."
|
8
|
+
end
|
9
|
+
|
10
|
+
if options[:prefix] == true && options[:to].to_s =~ /^[^a-z_]/
|
11
|
+
raise ArgumentError, "Can only automatically set the delegation prefix when delegating to a method."
|
12
|
+
end
|
13
|
+
|
14
|
+
prefix = options[:prefix] && "#{options[:prefix] == true ? to : options[:prefix]}_" || ''
|
15
|
+
|
16
|
+
file, line = caller.first.split(':', 2)
|
17
|
+
line = line.to_i
|
18
|
+
|
19
|
+
methods.each do |method|
|
20
|
+
on_nil =
|
21
|
+
if options[:allow_nil]
|
22
|
+
'return'
|
23
|
+
else
|
24
|
+
%Q(raise "#{self}##{prefix}#{method} delegated to #{to}.#{method}, but #{to} is nil: \#{self.inspect}")
|
25
|
+
end
|
26
|
+
|
27
|
+
module_eval(" def #{prefix}#{method}(*args, &block) # def customer_name(*args, &block)
|
28
|
+
#{to}.__send__(#{method.inspect}, *args, &block) # client.__send__(:name, *args, &block)
|
29
|
+
rescue NoMethodError # rescue NoMethodError
|
30
|
+
if #{to}.nil? # if client.nil?
|
31
|
+
#{on_nil} # return # depends on :allow_nil
|
32
|
+
else # else
|
33
|
+
raise # raise
|
34
|
+
end # end
|
35
|
+
end # end
|
36
|
+
", file, line - 1)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
module ActiveSupport
|
42
|
+
module Delegation #:nodoc:
|
43
|
+
def self.perform(object, target, method, method_name, allow_nil, to, args, block)
|
44
|
+
target.__send__(method, *args, &block)
|
45
|
+
rescue NoMethodError
|
46
|
+
if target.nil?
|
47
|
+
return nil if allow_nil
|
48
|
+
raise "#{object.class}##{method_name} delegated to #{to}.#{method}, but #{to} is nil: #{object.inspect}"
|
49
|
+
else
|
50
|
+
raise
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'uri'
|
2
|
+
|
3
|
+
module Inquisitor
|
4
|
+
class Node
|
5
|
+
include DataMapper::Resource
|
6
|
+
property :id, Serial
|
7
|
+
property :url, String, :index => :unique
|
8
|
+
property :name, String, :index => true
|
9
|
+
|
10
|
+
validates_presence_of :url
|
11
|
+
validates_with_method :url, :method => :check_protocol
|
12
|
+
|
13
|
+
delegate :run, :notify, :to => :outpost
|
14
|
+
alias :check :run
|
15
|
+
|
16
|
+
def check_and_notify
|
17
|
+
notify unless run == :up
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.check_all
|
21
|
+
all.each &:check_and_notify
|
22
|
+
end
|
23
|
+
|
24
|
+
def last_log
|
25
|
+
outpost.messages.join('<br />')
|
26
|
+
end
|
27
|
+
|
28
|
+
def check_protocol
|
29
|
+
outpost
|
30
|
+
true
|
31
|
+
rescue URI::InvalidURIError
|
32
|
+
false
|
33
|
+
end
|
34
|
+
|
35
|
+
protected
|
36
|
+
def outpost
|
37
|
+
@outpost ||= begin
|
38
|
+
outpost = Inquisitor.create_outpost(self.name)
|
39
|
+
uri = URI.parse(url)
|
40
|
+
|
41
|
+
case uri.scheme
|
42
|
+
when 'http'
|
43
|
+
outpost.add_scout Outpost::Scouts::Http => '' do
|
44
|
+
options :host => uri.host, :port => uri.port, :path => uri.path.empty? ? '/' : uri.path
|
45
|
+
report :up, :response_code => 200...400
|
46
|
+
report :down, :response_code => 400..600
|
47
|
+
end
|
48
|
+
when 'ping'
|
49
|
+
outpost.add_scout Outpost::Scouts::Ping => '' do
|
50
|
+
options :host => uri.host
|
51
|
+
report :up, :response_time => {:less_than => 1000}
|
52
|
+
end
|
53
|
+
else
|
54
|
+
raise URI::InvalidURIError
|
55
|
+
end
|
56
|
+
|
57
|
+
outpost
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
Binary file
|
Binary file
|
@@ -0,0 +1,31 @@
|
|
1
|
+
$(window).load(function(){
|
2
|
+
// status loading
|
3
|
+
$('td.status-load').each(function(index, element){
|
4
|
+
$.get($(this).attr('rel'), '', function(req)
|
5
|
+
{
|
6
|
+
$('.element-' + req['id'] + ' .status-load img').attr('src', $('body').attr('root_path') + req.status + '.png')
|
7
|
+
$('.element-' + req['id'] + ' .status-load').attr('detailed', req.log)
|
8
|
+
});
|
9
|
+
});
|
10
|
+
|
11
|
+
// submit on enter
|
12
|
+
$('form.form-stacked input').keypress(function(e)
|
13
|
+
{
|
14
|
+
if(e.which == 13)
|
15
|
+
{
|
16
|
+
$(this).closest('form').submit();
|
17
|
+
e.preventDefault();
|
18
|
+
return false;
|
19
|
+
}
|
20
|
+
});
|
21
|
+
|
22
|
+
|
23
|
+
// magic with show-hide
|
24
|
+
$('.show_detailed').click(function(){
|
25
|
+
$(this).closest('form').find('.hidden').toggle();
|
26
|
+
return false;
|
27
|
+
});
|
28
|
+
|
29
|
+
|
30
|
+
|
31
|
+
});
|
@@ -0,0 +1,38 @@
|
|
1
|
+
html, body
|
2
|
+
{
|
3
|
+
background-color: #EEE;
|
4
|
+
}
|
5
|
+
|
6
|
+
.content
|
7
|
+
{
|
8
|
+
background-color: white;
|
9
|
+
padding: 20px;
|
10
|
+
margin: 0 -20px;
|
11
|
+
}
|
12
|
+
|
13
|
+
td.status-load
|
14
|
+
{
|
15
|
+
width: 40px;
|
16
|
+
}
|
17
|
+
|
18
|
+
#nodes table
|
19
|
+
{
|
20
|
+
margin-bottom: 0px;
|
21
|
+
}
|
22
|
+
|
23
|
+
#nodes fieldset .hidden
|
24
|
+
{
|
25
|
+
display:none;
|
26
|
+
}
|
27
|
+
|
28
|
+
#nodes fieldset button
|
29
|
+
{
|
30
|
+
margin-top: 10px;
|
31
|
+
}
|
32
|
+
|
33
|
+
a.show_detailed {
|
34
|
+
border-bottom: 1px dotted #00438A;
|
35
|
+
margin-bottom: 10px;
|
36
|
+
text-decoration: none;
|
37
|
+
font-size: 10px;
|
38
|
+
}
|
Binary file
|
@@ -0,0 +1,40 @@
|
|
1
|
+
%h2 Check nodes
|
2
|
+
#nodes
|
3
|
+
%table
|
4
|
+
- @nodes.each do |node|
|
5
|
+
%tr{ :class => "element-#{node.id}"}
|
6
|
+
%td.status-load{:rel => url_for("node/status/#{node.id}")}
|
7
|
+
%img{:src => url_for('loading.gif'), :height => 36, :width => 32}
|
8
|
+
%td= node.url
|
9
|
+
%td{:width => '100%'}= node.name
|
10
|
+
%td
|
11
|
+
%a.btn.danger{:href => url_for("/node/delete/#{node.id}")} Delete
|
12
|
+
|
13
|
+
%form.form-stacked.actions{:action => url_for("/node/new"), :method => "post", :id => 'add_node'}
|
14
|
+
%fieldset
|
15
|
+
.clearfix
|
16
|
+
%label{:for => "node[name]"}Url
|
17
|
+
%input{:type => "text", :name => "node[url]", :id => "add-url-field"}
|
18
|
+
.clearfix
|
19
|
+
%a.show_detailed{:href => '#'} Options
|
20
|
+
.clearfix.hidden
|
21
|
+
%label{:for => "node[name]"}Title
|
22
|
+
%input{:type => "text", :name => "node[name]", :id => "add-name-field"}
|
23
|
+
.clearfix
|
24
|
+
%input.btn.primary{:type => "submit", :value => "Add node"}
|
25
|
+
|
26
|
+
%h2 Notify me by
|
27
|
+
#contacts
|
28
|
+
.list
|
29
|
+
%table
|
30
|
+
- @contacts.each do |contact|
|
31
|
+
%tr{ :class => "element-#{contact.id}"}
|
32
|
+
%td= contact.email
|
33
|
+
|
34
|
+
%form.form-stacked.actions{:action => url_for("/contact/new"), :method => "post", :id => 'add_contact'}
|
35
|
+
%fieldset
|
36
|
+
.clearfix
|
37
|
+
%label{:for => "contact[email]"}Email
|
38
|
+
%input{:type => "text", :name => "contact[email]", :id => "add-email-field"}
|
39
|
+
.clearfix
|
40
|
+
%input.btn{:type => "submit", :value => "Add contact"}
|
@@ -0,0 +1,15 @@
|
|
1
|
+
!!! 5
|
2
|
+
%html
|
3
|
+
%head
|
4
|
+
%title Index page
|
5
|
+
%meta{:content => "text/html;charset=utf-8", "http-equiv" => "Content-Type"}
|
6
|
+
= stylesheet 'http://twitter.github.com/bootstrap/1.4.0/bootstrap.min.css', url_for('/style.css')
|
7
|
+
%script{:src => 'http://code.jquery.com/jquery-1.7.1.min.js'}
|
8
|
+
%script{:src => url_for('/script.js')}
|
9
|
+
:javascript
|
10
|
+
$(function(){$('body').attr('root_path', '#{url_for("/")}')});
|
11
|
+
|
12
|
+
%body
|
13
|
+
.container
|
14
|
+
.content
|
15
|
+
= yield
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Inquisitor
|
2
|
+
class Settings
|
3
|
+
attr_accessor :mail_from, :mail_subject, :check_period
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
self.mail_from = 'changeme.in@Inquisitor.settings'
|
7
|
+
self.mail_subject = 'Subject for Inquisitor notify letter'
|
8
|
+
self.check_period = 30
|
9
|
+
end
|
10
|
+
|
11
|
+
def db_path=(path)
|
12
|
+
DataMapper.setup(:default, path)
|
13
|
+
DataMapper.auto_upgrade!
|
14
|
+
end
|
15
|
+
|
16
|
+
def set(params)
|
17
|
+
params.each do |key, value|
|
18
|
+
if respond_to?("#{key}=")
|
19
|
+
send("#{key}=", value)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'sinatra/base'
|
2
|
+
require 'sinatra/link_header'
|
3
|
+
require 'sinatra/json'
|
4
|
+
require 'sinatra/url_for'
|
5
|
+
require 'haml'
|
6
|
+
|
7
|
+
module Inquisitor
|
8
|
+
class Web < Sinatra::Base
|
9
|
+
helpers Sinatra::LinkHeader
|
10
|
+
helpers Sinatra::JSON
|
11
|
+
helpers Sinatra::UrlForHelper
|
12
|
+
|
13
|
+
dir = File.dirname(File.expand_path(__FILE__))
|
14
|
+
|
15
|
+
set :views, "#{dir}/server/views"
|
16
|
+
|
17
|
+
if respond_to? :public_folder
|
18
|
+
set :public_folder, "#{dir}/server/public"
|
19
|
+
else
|
20
|
+
set :public, "#{dir}/server/public"
|
21
|
+
end
|
22
|
+
|
23
|
+
set :static, true
|
24
|
+
set :run, false
|
25
|
+
|
26
|
+
get '/' do
|
27
|
+
@nodes = Inquisitor::Node.all
|
28
|
+
@contacts = Inquisitor::Contact.all
|
29
|
+
haml :index, :format => :html5
|
30
|
+
end
|
31
|
+
|
32
|
+
get '/node/status/:id' do
|
33
|
+
n = Inquisitor::Node.get(params[:id].to_i)
|
34
|
+
json :status => n.check, :log => n.last_log, :id => n.id
|
35
|
+
end
|
36
|
+
|
37
|
+
get '/node/delete/:id' do
|
38
|
+
n = Inquisitor::Node.get(params[:id].to_i)
|
39
|
+
n.destroy unless n.nil?
|
40
|
+
redirect url_for('/')
|
41
|
+
end
|
42
|
+
|
43
|
+
post '/node/new' do
|
44
|
+
Inquisitor::Node.create params["node"]
|
45
|
+
|
46
|
+
redirect url_for('/')
|
47
|
+
end
|
48
|
+
|
49
|
+
post '/contact/new' do
|
50
|
+
Inquisitor::Contact.create params["contact"]
|
51
|
+
|
52
|
+
redirect url_for('/')
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'spec_helper.rb')
|
2
|
+
|
3
|
+
describe Inquisitor::Contact do
|
4
|
+
describe "validation" do
|
5
|
+
it "saves with valid email" do
|
6
|
+
c = Inquisitor::Contact.make_unsaved :email => "valid#{Time.now.to_i}@gmail.com"
|
7
|
+
c.save.should be_true
|
8
|
+
end
|
9
|
+
it "does not save with invalid email" do
|
10
|
+
c = Inquisitor::Contact.make_unsaved :email => '#{Time.now.to_i}invalidfghdfhdgdgmail.com'
|
11
|
+
c.save.should be_false
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'spec_helper.rb')
|
2
|
+
|
3
|
+
describe Inquisitor::Node do
|
4
|
+
describe 'http checking' do
|
5
|
+
it "should check if it tells that http site is ok" do
|
6
|
+
n = Inquisitor::Node.make :url => 'http://ya.ru'
|
7
|
+
|
8
|
+
n.check.should == :up
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should tell that page with redirect is ok, not down" do
|
12
|
+
n = Inquisitor::Node.make :url => 'http://google.com/'
|
13
|
+
|
14
|
+
n.check.should == :up
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should fail if hostname not found" do
|
18
|
+
n = Inquisitor::Node.make :url => 'http://akjfsjjgsdf.google.com'
|
19
|
+
|
20
|
+
n.check.should == :down
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should fail if page not found" do
|
24
|
+
n = Inquisitor::Node.make :url => 'http://www.google.com/404.html'
|
25
|
+
|
26
|
+
n.check.should == :down
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe 'ping checking' do
|
31
|
+
it "should pass if host is reachable" do
|
32
|
+
n = Inquisitor::Node.make :url => 'ping://127.0.0.1'
|
33
|
+
n.check.should == :up
|
34
|
+
end
|
35
|
+
it "should not pass if host is not reachable" do
|
36
|
+
n = Inquisitor::Node.make :url => 'ping://sdfsadfasdfasdf.asdfasdfasdf.asdfasdf'
|
37
|
+
n.check.should == :down
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe 'validation' do
|
42
|
+
it "should fail if unknown protocol of url is passed" do
|
43
|
+
n = Inquisitor::Node.make_unsaved :url => 'https://github.com'
|
44
|
+
n.save.should be_false
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe "work with outpost" do
|
49
|
+
it "should return logs from outpost" do
|
50
|
+
n = Inquisitor::Node.make
|
51
|
+
o = Object.new
|
52
|
+
o.should_receive(:messages).and_return([])
|
53
|
+
n.should_receive(:outpost).and_return(o)
|
54
|
+
|
55
|
+
n.last_log
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should run all checks at once" do
|
60
|
+
nodes = []
|
61
|
+
|
62
|
+
5.times do
|
63
|
+
node = Inquisitor::Node.make
|
64
|
+
node.should_receive(:run).and_return(:down)
|
65
|
+
node.should_receive(:notify)
|
66
|
+
nodes.push node
|
67
|
+
end
|
68
|
+
|
69
|
+
5.times do
|
70
|
+
node = Inquisitor::Node.make
|
71
|
+
node.should_receive(:run).and_return(:up)
|
72
|
+
node.should_not_receive(:notify)
|
73
|
+
nodes.push node
|
74
|
+
end
|
75
|
+
|
76
|
+
Inquisitor::Node.should_receive(:all).and_return(nodes)
|
77
|
+
|
78
|
+
Inquisitor.check_all
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'spec_integration_helper.rb')
|
2
|
+
|
3
|
+
describe 'Outpost factory' do
|
4
|
+
before do
|
5
|
+
@contact = Inquisitor::Contact.make
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should add email notifiers" do
|
9
|
+
outpost = Inquisitor.create_outpost 'title'
|
10
|
+
|
11
|
+
outpost.name.should == 'title'
|
12
|
+
|
13
|
+
outpost.notifiers.first[0].should == Outpost::Notifiers::Email
|
14
|
+
outpost.notifiers.first[1][:to].should == @contact.email
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should send emails" do
|
18
|
+
Mail.defaults do
|
19
|
+
delivery_method :test
|
20
|
+
end
|
21
|
+
|
22
|
+
Mail::TestMailer.deliveries.should == []
|
23
|
+
Inquisitor::Node.make(:url => 'ping://non-existant.domain').check_and_notify
|
24
|
+
Mail::TestMailer.deliveries.count.should == 1
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'spec_helper.rb')
|
2
|
+
|
3
|
+
describe 'App settings' do
|
4
|
+
before :each do
|
5
|
+
Inquisitor.instance_variable_set '@settings', nil
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should have default values" do
|
9
|
+
Inquisitor.settings.mail_from.should == 'changeme.in@Inquisitor.settings'
|
10
|
+
Inquisitor.settings.mail_subject.should == 'Subject for Inquisitor notify letter'
|
11
|
+
|
12
|
+
Inquisitor.settings.check_period.should == 30
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should send email from emails we set and with defined title" do
|
16
|
+
Inquisitor::Contact.make
|
17
|
+
|
18
|
+
subj = 'Notify set in test env'
|
19
|
+
mail = 'test-receiver@gmail.com'
|
20
|
+
|
21
|
+
Inquisitor.settings.mail_from = mail
|
22
|
+
Inquisitor.settings.mail_subject = subj
|
23
|
+
outpost = Inquisitor.create_outpost
|
24
|
+
|
25
|
+
outpost.notifiers.first[1][:from].should == mail
|
26
|
+
outpost.notifiers.first[1][:subject].should == subj
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should set db settings" do
|
30
|
+
DataMapper.should_receive(:setup).with :default, :path
|
31
|
+
DataMapper.should_receive(:auto_upgrade!)
|
32
|
+
|
33
|
+
Inquisitor.settings.db_path = :path
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should do mass asignments" do
|
37
|
+
Inquisitor.settings.set :mail_from => 'me@gmail.com', :check_period => 900
|
38
|
+
Inquisitor.settings.mail_from.should == 'me@gmail.com'
|
39
|
+
Inquisitor.settings.check_period.should == 900
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'spec_integration_helper.rb')
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
describe "Basic frontend test" do
|
5
|
+
def app
|
6
|
+
@app ||= Inquisitor::Web
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should respond to / and list all" do
|
10
|
+
nodes = []
|
11
|
+
5.times { nodes.push Inquisitor::Node.make }
|
12
|
+
Inquisitor::Node.should_receive(:all).and_return(nodes)
|
13
|
+
|
14
|
+
contacts = []
|
15
|
+
3.times { contacts.push Inquisitor::Contact.make }
|
16
|
+
Inquisitor::Contact.should_receive(:all).and_return(contacts)
|
17
|
+
|
18
|
+
get '/'
|
19
|
+
|
20
|
+
last_response.should be_ok
|
21
|
+
|
22
|
+
nodes.each do |n|
|
23
|
+
within "#nodes .element-#{n.id}" do |scope|
|
24
|
+
scope.should contain n.name
|
25
|
+
scope.should contain n.url
|
26
|
+
scope.should have_selector("td[rel='node/status/#{n.id}']")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
contacts.each do |n|
|
31
|
+
within "#contacts .element-#{n.id}" do |scope|
|
32
|
+
scope.should contain n.email
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should delete node from interface" do
|
38
|
+
5.times { Inquisitor::Node.make }
|
39
|
+
node = Inquisitor::Node.make
|
40
|
+
5.times { Inquisitor::Node.make }
|
41
|
+
|
42
|
+
get '/'
|
43
|
+
|
44
|
+
Inquisitor::Node.first(node.attributes).should_not be_nil
|
45
|
+
|
46
|
+
within "#nodes .element-#{node.id}" do |scope|
|
47
|
+
scope.click_link "Delete"
|
48
|
+
end
|
49
|
+
|
50
|
+
Inquisitor::Node.first(node.attributes).should be_nil
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should respond with service status" do
|
54
|
+
n = Inquisitor::Node.make
|
55
|
+
n.should_receive(:check).and_return(:up)
|
56
|
+
n.should_receive(:last_log).and_return('best log in the world')
|
57
|
+
|
58
|
+
Inquisitor::Node.should_receive(:get).with(n.id).and_return(n)
|
59
|
+
|
60
|
+
get "/node/status/#{n.id}"
|
61
|
+
|
62
|
+
resp = JSON.parse(response.body)
|
63
|
+
resp['status'].should == 'up'
|
64
|
+
resp['log'].should == 'best log in the world'
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should create node" do
|
68
|
+
node = Inquisitor::Node.make_unsaved.attributes
|
69
|
+
visit '/'
|
70
|
+
Inquisitor::Node.first(node).should be_nil
|
71
|
+
|
72
|
+
fill_in "add-name-field", :with => node[:name]
|
73
|
+
fill_in "add-url-field", :with => node[:url]
|
74
|
+
click_button "Add node"
|
75
|
+
|
76
|
+
Inquisitor::Node.first(node).should_not be_nil
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should create new contact" do
|
80
|
+
contact = Inquisitor::Contact.make_unsaved.attributes
|
81
|
+
visit '/'
|
82
|
+
Inquisitor::Contact.first(contact).should be_nil
|
83
|
+
|
84
|
+
fill_in "add-email-field", :with => contact[:email]
|
85
|
+
click_button "Add contact"
|
86
|
+
|
87
|
+
Inquisitor::Contact.first(contact).should_not be_nil
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should delete node" do
|
91
|
+
test_delete(Inquisitor::Node)
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should create node" do
|
95
|
+
test_new(Inquisitor::Node)
|
96
|
+
end
|
97
|
+
|
98
|
+
it "should create contact" do
|
99
|
+
test_new(Inquisitor::Contact)
|
100
|
+
end
|
101
|
+
|
102
|
+
private
|
103
|
+
def test_new(cls)
|
104
|
+
attrs = cls.make_unsaved.attributes
|
105
|
+
name = cls.to_s.split('::').last.downcase
|
106
|
+
cls.first(attrs).should be_nil
|
107
|
+
post "/#{name}/new", name => attrs
|
108
|
+
cls.first(attrs).should_not be_nil
|
109
|
+
end
|
110
|
+
|
111
|
+
def test_delete(cls)
|
112
|
+
attrs = cls.make.attributes
|
113
|
+
cls.first(attrs).should_not be_nil
|
114
|
+
name = cls.to_s.split('::').last.downcase
|
115
|
+
get "/#{name}/delete/#{attrs[:id]}"
|
116
|
+
cls.first(attrs).should be_nil
|
117
|
+
end
|
118
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rack/test'
|
3
|
+
require 'rspec'
|
4
|
+
require 'webrat'
|
5
|
+
require 'ffaker'
|
6
|
+
require File.join(File.dirname(__FILE__), '..', 'lib', 'inquisitor.rb')
|
7
|
+
|
8
|
+
RSpec.configure do |config|
|
9
|
+
config.before(:all) { Sham.reset(:before_all) }
|
10
|
+
config.before(:each) { Sham.reset(:before_each) }
|
11
|
+
end
|
12
|
+
|
13
|
+
if ENV['DB'] == 'sqlite'
|
14
|
+
Inquisitor.settings.db_path = "sqlite3://#{Dir.pwd}/test.db"
|
15
|
+
puts "Using sqlite"
|
16
|
+
elsif ENV['DB'] == 'redis'
|
17
|
+
Inquisitor.settings.db_path ={:adapter => "redis"}
|
18
|
+
puts "Using redis"
|
19
|
+
elsif ENV['DB'] == 'mysql'
|
20
|
+
`mysql -e 'create database test;'`
|
21
|
+
Inquisitor.settings.db_path ="mysql://@localhost/test"
|
22
|
+
puts "Using mysql"
|
23
|
+
elsif ENV['DB'] == 'pg'
|
24
|
+
`psql -c 'create database test;' -U postgres`
|
25
|
+
Inquisitor.settings.db_path ="postgres://postgres@localhost/test"
|
26
|
+
puts "Using pg"
|
27
|
+
else
|
28
|
+
Inquisitor.settings.db_path = 'sqlite3::memory:'
|
29
|
+
puts 'Using sqlite(by default)'
|
30
|
+
end
|
31
|
+
|
32
|
+
require File.join(File.dirname(__FILE__), 'support/blueprints.rb')
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper.rb')
|
2
|
+
require File.join(File.dirname(__FILE__), '..', 'lib', 'inquisitor', 'web.rb')
|
3
|
+
|
4
|
+
RSpec.configure do |config|
|
5
|
+
config.include Rack::Test::Methods
|
6
|
+
config.include Webrat::Methods
|
7
|
+
config.include Webrat::Matchers
|
8
|
+
config.before{ Inquisitor::Node.all.destroy }
|
9
|
+
end
|
10
|
+
|
11
|
+
Webrat.configure do |config|
|
12
|
+
config.mode= :rack
|
13
|
+
end
|
14
|
+
|
15
|
+
Inquisitor::Web.set :environment, :test
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'machinist/data_mapper'
|
2
|
+
require 'sham'
|
3
|
+
|
4
|
+
Inquisitor::Node.blueprint do
|
5
|
+
url { 'http://' + Faker::Lorem.words(2).join('-').downcase + '.com' }
|
6
|
+
name { Faker::Name.name }
|
7
|
+
end
|
8
|
+
|
9
|
+
Inquisitor::Contact.blueprint do
|
10
|
+
email { Faker::Internet.email }
|
11
|
+
end
|
metadata
ADDED
@@ -0,0 +1,224 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: inquisitor
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 25
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 1
|
10
|
+
version: 0.1.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Rozumiy Alexander
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2012-01-12 00:00:00 Z
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
version_requirements: &id001 !ruby/object:Gem::Requirement
|
22
|
+
none: false
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
hash: 3
|
27
|
+
segments:
|
28
|
+
- 0
|
29
|
+
version: "0"
|
30
|
+
requirement: *id001
|
31
|
+
prerelease: false
|
32
|
+
type: :runtime
|
33
|
+
name: data_mapper
|
34
|
+
- !ruby/object:Gem::Dependency
|
35
|
+
version_requirements: &id002 !ruby/object:Gem::Requirement
|
36
|
+
none: false
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
hash: 3
|
41
|
+
segments:
|
42
|
+
- 0
|
43
|
+
version: "0"
|
44
|
+
requirement: *id002
|
45
|
+
prerelease: false
|
46
|
+
type: :runtime
|
47
|
+
name: outpost
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
version_requirements: &id003 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
hash: 3
|
55
|
+
segments:
|
56
|
+
- 0
|
57
|
+
version: "0"
|
58
|
+
requirement: *id003
|
59
|
+
prerelease: false
|
60
|
+
type: :runtime
|
61
|
+
name: net-ping
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
version_requirements: &id004 !ruby/object:Gem::Requirement
|
64
|
+
none: false
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
hash: 3
|
69
|
+
segments:
|
70
|
+
- 0
|
71
|
+
version: "0"
|
72
|
+
requirement: *id004
|
73
|
+
prerelease: false
|
74
|
+
type: :runtime
|
75
|
+
name: mail
|
76
|
+
- !ruby/object:Gem::Dependency
|
77
|
+
version_requirements: &id005 !ruby/object:Gem::Requirement
|
78
|
+
none: false
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
hash: 3
|
83
|
+
segments:
|
84
|
+
- 0
|
85
|
+
version: "0"
|
86
|
+
requirement: *id005
|
87
|
+
prerelease: false
|
88
|
+
type: :runtime
|
89
|
+
name: sinatra
|
90
|
+
- !ruby/object:Gem::Dependency
|
91
|
+
version_requirements: &id006 !ruby/object:Gem::Requirement
|
92
|
+
none: false
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
hash: 3
|
97
|
+
segments:
|
98
|
+
- 0
|
99
|
+
version: "0"
|
100
|
+
requirement: *id006
|
101
|
+
prerelease: false
|
102
|
+
type: :runtime
|
103
|
+
name: sinatra-contrib
|
104
|
+
- !ruby/object:Gem::Dependency
|
105
|
+
version_requirements: &id007 !ruby/object:Gem::Requirement
|
106
|
+
none: false
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
hash: 3
|
111
|
+
segments:
|
112
|
+
- 0
|
113
|
+
version: "0"
|
114
|
+
requirement: *id007
|
115
|
+
prerelease: false
|
116
|
+
type: :runtime
|
117
|
+
name: haml
|
118
|
+
- !ruby/object:Gem::Dependency
|
119
|
+
version_requirements: &id008 !ruby/object:Gem::Requirement
|
120
|
+
none: false
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
hash: 3
|
125
|
+
segments:
|
126
|
+
- 0
|
127
|
+
version: "0"
|
128
|
+
requirement: *id008
|
129
|
+
prerelease: false
|
130
|
+
type: :runtime
|
131
|
+
name: emk-sinatra-url-for
|
132
|
+
- !ruby/object:Gem::Dependency
|
133
|
+
version_requirements: &id009 !ruby/object:Gem::Requirement
|
134
|
+
none: false
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
hash: 3
|
139
|
+
segments:
|
140
|
+
- 0
|
141
|
+
version: "0"
|
142
|
+
requirement: *id009
|
143
|
+
prerelease: false
|
144
|
+
type: :runtime
|
145
|
+
name: slop
|
146
|
+
description: Monitoring daemon with simple web UI.
|
147
|
+
email: brain-geek@yandex.ua
|
148
|
+
executables:
|
149
|
+
- monitor
|
150
|
+
- monitor_web
|
151
|
+
extensions: []
|
152
|
+
|
153
|
+
extra_rdoc_files: []
|
154
|
+
|
155
|
+
files:
|
156
|
+
- lib/inquisitor/extensions.rb
|
157
|
+
- lib/inquisitor/cli.rb
|
158
|
+
- lib/inquisitor/contact.rb
|
159
|
+
- lib/inquisitor/node.rb
|
160
|
+
- lib/inquisitor/settings.rb
|
161
|
+
- lib/inquisitor/web.rb
|
162
|
+
- lib/inquisitor/version.rb
|
163
|
+
- lib/inquisitor/server/public/down.png
|
164
|
+
- lib/inquisitor/server/public/loading.gif
|
165
|
+
- lib/inquisitor/server/public/script.js
|
166
|
+
- lib/inquisitor/server/public/style.css
|
167
|
+
- lib/inquisitor/server/public/up.png
|
168
|
+
- lib/inquisitor/server/views/layout.haml
|
169
|
+
- lib/inquisitor/server/views/index.haml
|
170
|
+
- lib/inquisitor.rb
|
171
|
+
- bin/monitor
|
172
|
+
- bin/monitor_web
|
173
|
+
- README.md
|
174
|
+
- LICENSE
|
175
|
+
- spec/inquisitor/node_spec.rb
|
176
|
+
- spec/inquisitor/web_spec.rb
|
177
|
+
- spec/inquisitor/contact_spec.rb
|
178
|
+
- spec/inquisitor/outpost_factory_spec.rb
|
179
|
+
- spec/inquisitor/settings_spec.rb
|
180
|
+
- spec/support/blueprints.rb
|
181
|
+
- spec/spec_helper.rb
|
182
|
+
- spec/spec_integration_helper.rb
|
183
|
+
homepage: https://github.com/brain-geek/inquisitor
|
184
|
+
licenses: []
|
185
|
+
|
186
|
+
post_install_message:
|
187
|
+
rdoc_options: []
|
188
|
+
|
189
|
+
require_paths:
|
190
|
+
- lib
|
191
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
192
|
+
none: false
|
193
|
+
requirements:
|
194
|
+
- - ">="
|
195
|
+
- !ruby/object:Gem::Version
|
196
|
+
hash: 3
|
197
|
+
segments:
|
198
|
+
- 0
|
199
|
+
version: "0"
|
200
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
201
|
+
none: false
|
202
|
+
requirements:
|
203
|
+
- - ">="
|
204
|
+
- !ruby/object:Gem::Version
|
205
|
+
hash: 3
|
206
|
+
segments:
|
207
|
+
- 0
|
208
|
+
version: "0"
|
209
|
+
requirements: []
|
210
|
+
|
211
|
+
rubyforge_project:
|
212
|
+
rubygems_version: 1.8.11
|
213
|
+
signing_key:
|
214
|
+
specification_version: 3
|
215
|
+
summary: Monitoring daemon with simple web UI.
|
216
|
+
test_files:
|
217
|
+
- spec/inquisitor/node_spec.rb
|
218
|
+
- spec/inquisitor/web_spec.rb
|
219
|
+
- spec/inquisitor/contact_spec.rb
|
220
|
+
- spec/inquisitor/outpost_factory_spec.rb
|
221
|
+
- spec/inquisitor/settings_spec.rb
|
222
|
+
- spec/support/blueprints.rb
|
223
|
+
- spec/spec_helper.rb
|
224
|
+
- spec/spec_integration_helper.rb
|