snowman-io 0.0.3 → 0.0.4
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/CHANGELOG.md +5 -1
- data/README.md +3 -17
- data/bin/snowman +1 -0
- data/lib/snowman-io/api/public/README.md +36 -0
- data/lib/snowman-io/api/public/bootstrap/css/bootstrap-theme.css +470 -0
- data/lib/snowman-io/api/public/bootstrap/css/bootstrap-theme.css.map +1 -0
- data/lib/snowman-io/api/public/bootstrap/css/bootstrap-theme.min.css +5 -0
- data/lib/snowman-io/api/public/bootstrap/css/bootstrap.css +6332 -0
- data/lib/snowman-io/api/public/bootstrap/css/bootstrap.css.map +1 -0
- data/lib/snowman-io/api/public/bootstrap/css/bootstrap.min.css +5 -0
- data/lib/snowman-io/api/public/bootstrap/fonts/glyphicons-halflings-regular.eot +0 -0
- data/lib/snowman-io/api/public/bootstrap/fonts/glyphicons-halflings-regular.svg +229 -0
- data/lib/snowman-io/api/public/bootstrap/fonts/glyphicons-halflings-regular.ttf +0 -0
- data/lib/snowman-io/api/public/bootstrap/fonts/glyphicons-halflings-regular.woff +0 -0
- data/lib/snowman-io/api/public/bootstrap/js/bootstrap.js +2320 -0
- data/lib/snowman-io/api/public/bootstrap/js/bootstrap.min.js +7 -0
- data/lib/snowman-io/api/public/bootstrap/js/npm.js +13 -0
- data/lib/snowman-io/api/public/css/normalize.css +406 -0
- data/lib/snowman-io/api/public/css/style.css +4 -0
- data/lib/snowman-io/api/public/js/app.js +13 -0
- data/lib/snowman-io/api/public/js/libs/ember-1.8.1.js +49740 -0
- data/lib/snowman-io/api/public/js/libs/handlebars-v1.3.0.js +2746 -0
- data/lib/snowman-io/api/public/js/libs/jquery-1.10.2.js +9789 -0
- data/lib/snowman-io/api/public/tests/runner.css +14 -0
- data/lib/snowman-io/api/public/tests/runner.js +13 -0
- data/lib/snowman-io/api/public/tests/tests.js +30 -0
- data/lib/snowman-io/api/public/tests/vendor/qunit-1.12.0.css +244 -0
- data/lib/snowman-io/api/public/tests/vendor/qunit-1.12.0.js +2212 -0
- data/lib/snowman-io/api/views/index.erb +26 -0
- data/lib/snowman-io/api/views/layout.erb +24 -0
- data/lib/snowman-io/api/views/login.erb +21 -0
- data/lib/snowman-io/api/views/unpacking.erb +21 -0
- data/lib/snowman-io/api.rb +61 -1
- data/lib/snowman-io/check.rb +49 -0
- data/lib/snowman-io/check_result.rb +15 -0
- data/lib/snowman-io/checks/hosted_graphite.rb +23 -0
- data/lib/snowman-io/handler.rb +27 -0
- data/lib/snowman-io/launcher.rb +24 -0
- data/lib/snowman-io/notifiers/slack.rb +76 -0
- data/lib/snowman-io/options.rb +3 -14
- data/lib/snowman-io/processor.rb +32 -0
- data/lib/snowman-io/scheduler.rb +42 -0
- data/lib/snowman-io/version.rb +1 -1
- data/lib/snowman-io.rb +34 -5
- data/snowman-io.gemspec +9 -2
- metadata +131 -10
@@ -0,0 +1,26 @@
|
|
1
|
+
<% content_for :head do %>
|
2
|
+
<meta content="<%= SnowmanIO::VERSION %>" name="snowman-io-version" />
|
3
|
+
<link rel="stylesheet" href="/css/style.css">
|
4
|
+
<% end %>
|
5
|
+
|
6
|
+
<script type="text/x-handlebars">
|
7
|
+
<div class="container">
|
8
|
+
<h2>
|
9
|
+
Welcome to SnowmanIO
|
10
|
+
<small><a href="/logout">logout</a></small>
|
11
|
+
</h2>
|
12
|
+
|
13
|
+
{{outlet}}
|
14
|
+
</div>
|
15
|
+
</script>
|
16
|
+
|
17
|
+
<script type="text/x-handlebars" id="index">
|
18
|
+
<p>Version: {{model.version}}</p>
|
19
|
+
</script>
|
20
|
+
|
21
|
+
<script src="/js/libs/jquery-1.10.2.js"></script>
|
22
|
+
<script src="/js/libs/handlebars-v1.3.0.js"></script>
|
23
|
+
<script src="/js/libs/ember-1.8.1.js"></script>
|
24
|
+
<script src="/js/app.js"></script>
|
25
|
+
<!-- to activate the test runner, add the "?test" query string parameter -->
|
26
|
+
<script src="/tests/runner.js"></script>
|
@@ -0,0 +1,24 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html lang="en">
|
3
|
+
<head>
|
4
|
+
<meta charset="utf-8">
|
5
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
7
|
+
<title>SnowmanIO: be a little snowy</title>
|
8
|
+
|
9
|
+
<!-- Bootstrap -->
|
10
|
+
<link href="/bootstrap/css/bootstrap.min.css" rel="stylesheet">
|
11
|
+
|
12
|
+
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
|
13
|
+
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
|
14
|
+
<!--[if lt IE 9]>
|
15
|
+
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
|
16
|
+
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
|
17
|
+
<![endif]-->
|
18
|
+
|
19
|
+
<%= yield_content :head %>
|
20
|
+
</head>
|
21
|
+
<body>
|
22
|
+
<%= yield %>
|
23
|
+
</body>
|
24
|
+
</html>
|
@@ -0,0 +1,21 @@
|
|
1
|
+
<div class="container">
|
2
|
+
<div class="page-header">
|
3
|
+
<h1>SnowmanIO</h1>
|
4
|
+
</div>
|
5
|
+
|
6
|
+
<% if @wrong_password_warning %>
|
7
|
+
<div class="alert alert-danger">
|
8
|
+
Wrong password.
|
9
|
+
</div>
|
10
|
+
<% end %>
|
11
|
+
|
12
|
+
<div class="col-sm-6">
|
13
|
+
<form action="/login" method="POST" role="form">
|
14
|
+
<div class="form-group">
|
15
|
+
<label for=password>Password</label>
|
16
|
+
<input type=password name=password class="form-control">
|
17
|
+
</div>
|
18
|
+
<input type=submit value="Login" class="btn btn-default">
|
19
|
+
</form>
|
20
|
+
</div>
|
21
|
+
</div>
|
@@ -0,0 +1,21 @@
|
|
1
|
+
<div class="container">
|
2
|
+
<div class="page-header">
|
3
|
+
<h1>SnowmanIO: Installation</h1>
|
4
|
+
</div>
|
5
|
+
|
6
|
+
<% if @empty_password_warning %>
|
7
|
+
<div class="alert alert-danger">
|
8
|
+
Empty password is not allowed.
|
9
|
+
</div>
|
10
|
+
<% end %>
|
11
|
+
|
12
|
+
<div class="col-sm-6">
|
13
|
+
<form action="/unpacking" method="POST" role="form">
|
14
|
+
<div class="form-group">
|
15
|
+
<label for=password>Admin password</label>
|
16
|
+
<input type=text name=password class="form-control">
|
17
|
+
</div>
|
18
|
+
<input type=submit value="Set Admin Password" class="btn btn-primary">
|
19
|
+
</form>
|
20
|
+
</div>
|
21
|
+
</div>
|
data/lib/snowman-io/api.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'sinatra'
|
2
|
+
require 'sinatra/content_for'
|
2
3
|
|
3
4
|
module SnowmanIO
|
4
5
|
class API < Sinatra::Base
|
@@ -8,8 +9,67 @@ module SnowmanIO
|
|
8
9
|
run!(sinatra_options)
|
9
10
|
end
|
10
11
|
|
12
|
+
enable :sessions
|
13
|
+
helpers Sinatra::ContentFor
|
14
|
+
set :public_folder, File.dirname(__FILE__) + "/api/public"
|
15
|
+
set :views, File.dirname(__FILE__) + "/api/views"
|
16
|
+
# TODO: fix it
|
17
|
+
set :session_secret, 'super secret'
|
18
|
+
|
19
|
+
ADMIN_PASSWORD_KEY = "admin_password_hash"
|
20
|
+
|
21
|
+
def admin_exists?
|
22
|
+
!!SnowmanIO.redis.get(ADMIN_PASSWORD_KEY)
|
23
|
+
end
|
24
|
+
|
25
|
+
def admin_authenticated?
|
26
|
+
admin_exists? && !!session[:user]
|
27
|
+
end
|
28
|
+
|
29
|
+
before do
|
30
|
+
if !admin_exists?
|
31
|
+
redirect to('/unpacking') if request.path_info != '/unpacking'
|
32
|
+
elsif !admin_authenticated?
|
33
|
+
redirect to('/login') if request.path_info != '/login'
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
11
37
|
get "/" do
|
12
|
-
|
38
|
+
erb :index
|
39
|
+
end
|
40
|
+
|
41
|
+
get "/login" do
|
42
|
+
erb :login
|
43
|
+
end
|
44
|
+
|
45
|
+
post "/login" do
|
46
|
+
if BCrypt::Password.new(SnowmanIO.redis.get(ADMIN_PASSWORD_KEY)) == params["password"]
|
47
|
+
session[:user] = "admin"
|
48
|
+
redirect to('/')
|
49
|
+
else
|
50
|
+
@wrong_password_warning = true
|
51
|
+
erb :login
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
get "/logout" do
|
56
|
+
session[:user] = nil
|
57
|
+
redirect to("/login")
|
58
|
+
end
|
59
|
+
|
60
|
+
get "/unpacking" do
|
61
|
+
erb :unpacking
|
62
|
+
end
|
63
|
+
|
64
|
+
post "/unpacking" do
|
65
|
+
if params["password"].empty?
|
66
|
+
@empty_password_warning = true
|
67
|
+
erb :unpacking
|
68
|
+
else
|
69
|
+
session[:user] = "admin"
|
70
|
+
SnowmanIO.redis.set(ADMIN_PASSWORD_KEY, BCrypt::Password.create(params["password"]))
|
71
|
+
redirect to('/')
|
72
|
+
end
|
13
73
|
end
|
14
74
|
end
|
15
75
|
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'open-uri'
|
3
|
+
require "active_support/time"
|
4
|
+
|
5
|
+
require 'snowman-io/notifiers/slack'
|
6
|
+
|
7
|
+
module SnowmanIO
|
8
|
+
class Check
|
9
|
+
include Checks::HostedGraphite
|
10
|
+
|
11
|
+
DEFAULT_INTERVAL = 1.minute
|
12
|
+
class << self
|
13
|
+
def interval(value = nil)
|
14
|
+
if value
|
15
|
+
@interval = value
|
16
|
+
else
|
17
|
+
@interval || DEFAULT_INTERVAL
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def human(value = nil)
|
22
|
+
if value
|
23
|
+
@human = value
|
24
|
+
else
|
25
|
+
self.name + ": #{@human}"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def notifiers
|
30
|
+
@notifiers ||= [Notifiers::Slack].select { |notifier| notifier.configured? }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def perform
|
35
|
+
if ok?
|
36
|
+
status = "success"
|
37
|
+
message = self.class.human + " - OK"
|
38
|
+
else
|
39
|
+
status = "failed"
|
40
|
+
message = self.class.human + " - FAIL"
|
41
|
+
end
|
42
|
+
CheckResult.new(self.class, status, message)
|
43
|
+
end
|
44
|
+
|
45
|
+
def ok?
|
46
|
+
raise "Implement ok? in check class"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module SnowmanIO
|
2
|
+
module Checks
|
3
|
+
# Gets last value from Hosted Graphite metric (https://www.hostedgraphite.com/)
|
4
|
+
module HostedGraphite
|
5
|
+
protected
|
6
|
+
|
7
|
+
def get_hg_value(metric, options = {})
|
8
|
+
access_key = ENV["HG_KEY"]
|
9
|
+
return nil unless access_key
|
10
|
+
base_url = "https://www.hostedgraphite.com#{access_key}/graphite/render"
|
11
|
+
from = options[:from] || "-10mins"
|
12
|
+
url = base_url + "?format=json&target=#{URI.escape metric}&from=#{from}"
|
13
|
+
handle = open(url)
|
14
|
+
raw_data = JSON.parse(handle.gets)
|
15
|
+
raw = raw_data.first
|
16
|
+
datapoints = raw['datapoints'].delete_if { |v| v.first.nil? }
|
17
|
+
if datapoints.last
|
18
|
+
datapoints.last.first
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module SnowmanIO
|
2
|
+
# Handler process result from checks, saves them
|
3
|
+
# to redis and fires notifications if needed.
|
4
|
+
class Handler
|
5
|
+
include Celluloid
|
6
|
+
|
7
|
+
def handle(result)
|
8
|
+
history_key = "history:#{result.check_name.underscore}"
|
9
|
+
SnowmanIO.redis.rpush(history_key, result.serialize)
|
10
|
+
history = SnowmanIO.redis.lrange(history_key, -4, -1).map { |result| JSON.load(result) }
|
11
|
+
previous_status_failed = if history.size < 4
|
12
|
+
false
|
13
|
+
else
|
14
|
+
["failed", "exception"].include?(history.shift["status"])
|
15
|
+
end
|
16
|
+
if !previous_status_failed && history.size >= 3 && history.all? { |result| result["status"] == "failed" || result["status"] == "exception" }
|
17
|
+
notify_fail(result)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def notify_fail(result)
|
24
|
+
result.check.notifiers.each { |notifier| notifier.pool.async.notify(result) }
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'snowman-io/scheduler'
|
2
|
+
require 'snowman-io/handler'
|
3
|
+
|
4
|
+
module SnowmanIO
|
5
|
+
class Launcher
|
6
|
+
include Celluloid
|
7
|
+
|
8
|
+
attr_reader :scheduler, :handler
|
9
|
+
|
10
|
+
def initialize(checks)
|
11
|
+
@handler = Handler.new_link
|
12
|
+
@scheduler = Scheduler.new_link(checks)
|
13
|
+
@scheduler.handler = handler
|
14
|
+
end
|
15
|
+
|
16
|
+
def start
|
17
|
+
scheduler.async.start
|
18
|
+
end
|
19
|
+
|
20
|
+
def stop
|
21
|
+
#TODO
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module SnowmanIO
|
2
|
+
module Notifiers
|
3
|
+
class Slack
|
4
|
+
include Celluloid
|
5
|
+
class << self
|
6
|
+
def webhook_url
|
7
|
+
ENV["SLACK_WEBHOOK_URL"]
|
8
|
+
end
|
9
|
+
|
10
|
+
def channel
|
11
|
+
ENV["SLACK_CHANNEL"]
|
12
|
+
end
|
13
|
+
|
14
|
+
def bot_name
|
15
|
+
ENV["SLACK_BOT_NAME"]
|
16
|
+
end
|
17
|
+
|
18
|
+
def configured?
|
19
|
+
webhook_url.present?
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def notify(result)
|
24
|
+
return unless self.class.configured?
|
25
|
+
post_data(result.message)
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def configuration
|
31
|
+
{
|
32
|
+
:webhook_url => self.class.webhook_url,
|
33
|
+
:bot_name => self.class.bot_name || "snowman-io",
|
34
|
+
:channel => self.class.channel
|
35
|
+
}
|
36
|
+
end
|
37
|
+
|
38
|
+
def post_data(message)
|
39
|
+
uri = URI(configuration[:webhook_url])
|
40
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
41
|
+
http.use_ssl = true
|
42
|
+
|
43
|
+
req = Net::HTTP::Post.new("#{uri.path}?#{uri.query}")
|
44
|
+
req.body = payload(message).to_json
|
45
|
+
|
46
|
+
response = http.request(req)
|
47
|
+
verify_response(response)
|
48
|
+
end
|
49
|
+
|
50
|
+
def slack_uri(token)
|
51
|
+
url = "https://#{team_name}.slack.com/services/hooks/incoming-webhook?token=#{token}"
|
52
|
+
URI(url)
|
53
|
+
end
|
54
|
+
|
55
|
+
def verify_response(response)
|
56
|
+
case response
|
57
|
+
when Net::HTTPSuccess
|
58
|
+
true
|
59
|
+
else
|
60
|
+
raise response.error!
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# TODO: include :icon_url
|
65
|
+
def payload(text)
|
66
|
+
{
|
67
|
+
:username => configuration[:bot_name],
|
68
|
+
:attachments => [{
|
69
|
+
:text => text,
|
70
|
+
:color => "#FF0000"
|
71
|
+
}]
|
72
|
+
}.tap { |payload| payload[:channel] = channel if configuration[:channel] }
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
data/lib/snowman-io/options.rb
CHANGED
@@ -9,26 +9,15 @@ module SnowmanIO
|
|
9
9
|
options = default_options
|
10
10
|
|
11
11
|
opt_parser = OptionParser.new do |opts|
|
12
|
-
opts.banner = "Usage: snowman
|
12
|
+
opts.banner = "Usage: snowman [options]"
|
13
13
|
|
14
14
|
opts.separator ""
|
15
|
-
opts.separator "
|
16
|
-
opts.separator " server Run SnowManIO server"
|
17
|
-
|
18
|
-
opts.separator ""
|
19
|
-
opts.separator "Server options:"
|
15
|
+
opts.separator "Options:"
|
20
16
|
opts.on("-p", "--port PORT", "use PORT (default: 4567)") do |port|
|
21
17
|
options[:port] = port.to_i
|
22
18
|
end
|
23
19
|
|
24
|
-
|
25
|
-
puts opts
|
26
|
-
exit
|
27
|
-
end
|
28
|
-
|
29
|
-
options[:command] = args.shift
|
30
|
-
unless AVAILABLE_COMMANDS.include?(options[:command])
|
31
|
-
puts "Error: Command '#{options[:command]}' not recognized"
|
20
|
+
opts.on("-h", "--help", "show this message") do
|
32
21
|
puts opts
|
33
22
|
exit
|
34
23
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module SnowmanIO
|
2
|
+
# Processor initiated by Scheduler, executes check and notifies
|
3
|
+
# Scheduler about the result of the check.
|
4
|
+
class Processor
|
5
|
+
include Celluloid
|
6
|
+
|
7
|
+
def initialize(scheduler)
|
8
|
+
@scheduler = scheduler
|
9
|
+
end
|
10
|
+
|
11
|
+
# TODO: logging can be extracted in some kind of middleware
|
12
|
+
def process(check)
|
13
|
+
begin
|
14
|
+
SnowmanIO.logger.info("Processing check #{check.human}, started at #{Time.now}")
|
15
|
+
result = check.new.perform
|
16
|
+
rescue Exception => e
|
17
|
+
result = result_from_exception(check, e)
|
18
|
+
raise
|
19
|
+
ensure
|
20
|
+
SnowmanIO.logger.info("Processing check #{check.human}, finished at #{Time.now}")
|
21
|
+
@scheduler.processor_done(current_actor, result)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def result_from_exception(check, e)
|
28
|
+
message = "Check #{check.human} was interruppted by exception: #{e.class}: #{e.message}"
|
29
|
+
CheckResult.new(check, "exception", message)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require "snowman-io/processor"
|
2
|
+
|
3
|
+
module SnowmanIO
|
4
|
+
# Scheduler schedules execution of checks.
|
5
|
+
class Scheduler
|
6
|
+
include Celluloid
|
7
|
+
trap_exit :processor_died
|
8
|
+
|
9
|
+
attr_accessor :handler
|
10
|
+
|
11
|
+
def initialize(checks)
|
12
|
+
@time = {}
|
13
|
+
checks.each do |check|
|
14
|
+
@time[check] = Time.now + check.interval
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def start
|
19
|
+
every(1) { schedule_checks }
|
20
|
+
end
|
21
|
+
|
22
|
+
def processor_done(processor, result)
|
23
|
+
@handler.async.handle(result)
|
24
|
+
processor.terminate
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def schedule_checks
|
30
|
+
@time.each do |check, time|
|
31
|
+
if time <= Time.now
|
32
|
+
Processor.new_link(current_actor).async.process(check)
|
33
|
+
@time[check] = Time.now + check.interval
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def processor_died(_actor, _reason)
|
39
|
+
# TODO
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/lib/snowman-io/version.rb
CHANGED
data/lib/snowman-io.rb
CHANGED
@@ -1,17 +1,46 @@
|
|
1
|
+
require 'logger'
|
2
|
+
require 'redis'
|
3
|
+
require 'bcrypt'
|
4
|
+
require 'celluloid/autostart'
|
5
|
+
|
1
6
|
require "snowman-io/version"
|
2
7
|
require "snowman-io/api"
|
3
8
|
require "snowman-io/options"
|
9
|
+
require "snowman-io/checks/hosted_graphite"
|
10
|
+
require "snowman-io/check"
|
11
|
+
require "snowman-io/check_result"
|
12
|
+
|
13
|
+
require "snowman-io/launcher"
|
4
14
|
|
5
15
|
module SnowmanIO
|
6
16
|
def self.start
|
7
17
|
# parse options
|
8
18
|
options = Options.new.parse!(ARGV)
|
9
19
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
20
|
+
Celluloid.logger = (options[:verbose] ? SnowmanIO.logger : nil)
|
21
|
+
|
22
|
+
launcher = Launcher.new(load_checks)
|
23
|
+
launcher.start
|
24
|
+
|
25
|
+
# start web server on main thread
|
26
|
+
API.start(options)
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.load_checks
|
30
|
+
checks = []
|
31
|
+
Dir[Dir.pwd + "/**/*_check.rb"].each do |path|
|
32
|
+
require path
|
33
|
+
klass = path.sub(Dir.pwd + "/checks" + "/", "").sub(/\.rb$/, '').camelize
|
34
|
+
checks.push Kernel.const_get(klass)
|
15
35
|
end
|
36
|
+
checks
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.redis
|
40
|
+
@redis ||= Redis.new(url: ENV["REDIS_URL"])
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.logger
|
44
|
+
@logger ||= Logger.new(STDERR)
|
16
45
|
end
|
17
46
|
end
|
data/snowman-io.gemspec
CHANGED
@@ -19,8 +19,15 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
20
20
|
spec.require_paths = ["lib"]
|
21
21
|
|
22
|
-
spec.add_dependency "sinatra"
|
22
|
+
spec.add_dependency "sinatra", "~> 1.4"
|
23
|
+
spec.add_dependency "sinatra-contrib", "~> 1.4"
|
24
|
+
spec.add_dependency "celluloid", "~> 0.16.0"
|
25
|
+
spec.add_dependency "redis", "~> 3.1.0"
|
26
|
+
spec.add_dependency "activesupport", "~> 4.1.8"
|
27
|
+
spec.add_dependency "bcrypt", "~> 3.1"
|
28
|
+
|
23
29
|
spec.add_development_dependency "bundler", "~> 1.7"
|
24
30
|
spec.add_development_dependency "rake", "~> 10.0"
|
25
|
-
spec.add_development_dependency "rspec"
|
31
|
+
spec.add_development_dependency "rspec", "~> 3.1"
|
32
|
+
spec.add_development_dependency "capybara", "~> 2.4"
|
26
33
|
end
|