inquisitor 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![Build Status](https://secure.travis-ci.org/brain-geek/inquisitor.png)](http://travis-ci.org/brain-geek/inquisitor)
|
5
|
+
[![Dependencies Status](https://gemnasium.com/brain-geek/inquisitor.png)](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
|