snowman-io 0.0.4 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +3 -0
- data/README.md +4 -6
- data/bin/snowman +1 -1
- data/lib/config/mongoid.yml +5 -0
- data/lib/snowman-io.rb +62 -30
- data/lib/snowman-io/aggregate.rb +97 -0
- data/lib/snowman-io/api.rb +33 -65
- data/lib/snowman-io/api/agent.rb +27 -0
- data/lib/snowman-io/api/apps.rb +45 -0
- data/lib/snowman-io/api/auth_helpers.rb +76 -0
- data/lib/snowman-io/api/checks.rb +59 -0
- data/lib/snowman-io/api/extra/meteor.rb +45 -0
- data/lib/snowman-io/api/fridge.rb +14 -0
- data/lib/snowman-io/api/info.rb +30 -0
- data/lib/snowman-io/api/metrics.rb +115 -0
- data/lib/snowman-io/api/users.rb +231 -0
- data/lib/snowman-io/cli.rb +69 -0
- data/lib/snowman-io/launcher.rb +12 -11
- data/lib/snowman-io/loop/check_processor.rb +29 -0
- data/lib/snowman-io/loop/checks.rb +59 -0
- data/lib/snowman-io/loop/main.rb +43 -0
- data/lib/snowman-io/loop/ping.rb +25 -0
- data/lib/snowman-io/migration.rb +79 -0
- data/lib/snowman-io/models/aggregation.rb +15 -0
- data/lib/snowman-io/models/app.rb +61 -0
- data/lib/snowman-io/models/check.rb +48 -0
- data/lib/snowman-io/models/concerns/tokenable.rb +15 -0
- data/lib/snowman-io/models/data_point.rb +9 -0
- data/lib/snowman-io/models/deleted.rb +9 -0
- data/lib/snowman-io/models/following.rb +8 -0
- data/lib/snowman-io/models/metric.rb +36 -0
- data/lib/snowman-io/models/setting.rb +24 -0
- data/lib/snowman-io/models/user.rb +73 -0
- data/lib/snowman-io/options.rb +11 -3
- data/lib/snowman-io/report_mailer.rb +88 -0
- data/lib/snowman-io/reports.rb +16 -0
- data/lib/snowman-io/ui/AUTO_GENERATED_FOLDER +2 -0
- data/lib/snowman-io/ui/assets/ui-0e39dafcb798020fb855e325931c8451.css +1 -0
- data/lib/snowman-io/ui/assets/ui-d30809d0ae0a003d841fa95a352d624b.js +9 -0
- data/lib/snowman-io/ui/assets/vendor-7edfd1432c1bbd806306d5583c75b1fc.css +5 -0
- data/lib/snowman-io/ui/assets/vendor-c22e2ccc87c9bc7609b95939c308bc7f.js +24 -0
- data/lib/snowman-io/{api/public/bootstrap → ui/bootstrap-3.3.1}/css/bootstrap-theme.css +0 -0
- data/lib/snowman-io/{api/public/bootstrap → ui/bootstrap-3.3.1}/css/bootstrap-theme.css.map +0 -0
- data/lib/snowman-io/{api/public/bootstrap → ui/bootstrap-3.3.1}/css/bootstrap-theme.min.css +0 -0
- data/lib/snowman-io/{api/public/bootstrap → ui/bootstrap-3.3.1}/css/bootstrap.css +0 -0
- data/lib/snowman-io/{api/public/bootstrap → ui/bootstrap-3.3.1}/css/bootstrap.css.map +0 -0
- data/lib/snowman-io/{api/public/bootstrap → ui/bootstrap-3.3.1}/css/bootstrap.min.css +0 -0
- data/lib/snowman-io/{api/public/bootstrap → ui/bootstrap-3.3.1}/fonts/glyphicons-halflings-regular.eot +0 -0
- data/lib/snowman-io/{api/public/bootstrap → ui/bootstrap-3.3.1}/fonts/glyphicons-halflings-regular.svg +0 -0
- data/lib/snowman-io/{api/public/bootstrap → ui/bootstrap-3.3.1}/fonts/glyphicons-halflings-regular.ttf +0 -0
- data/lib/snowman-io/{api/public/bootstrap → ui/bootstrap-3.3.1}/fonts/glyphicons-halflings-regular.woff +0 -0
- data/lib/snowman-io/{api/public/bootstrap → ui/bootstrap-3.3.1}/js/bootstrap.js +0 -0
- data/lib/snowman-io/{api/public/bootstrap → ui/bootstrap-3.3.1}/js/bootstrap.min.js +0 -0
- data/lib/snowman-io/{api/public/bootstrap → ui/bootstrap-3.3.1}/js/npm.js +0 -0
- data/lib/snowman-io/ui/crossdomain.xml +15 -0
- data/lib/snowman-io/ui/fonts/glyphicons-halflings-regular.eot +0 -0
- data/lib/snowman-io/ui/fonts/glyphicons-halflings-regular.svg +229 -0
- data/lib/snowman-io/ui/fonts/glyphicons-halflings-regular.ttf +0 -0
- data/lib/snowman-io/ui/fonts/glyphicons-halflings-regular.woff +0 -0
- data/lib/snowman-io/ui/index.html +175 -0
- data/lib/snowman-io/ui/robots.txt +2 -0
- data/lib/snowman-io/utils.rb +66 -0
- data/lib/snowman-io/version.rb +1 -1
- data/lib/snowman-io/views/layouts/custom.css +42 -0
- data/lib/snowman-io/views/layouts/main.html.erb +38 -0
- data/lib/snowman-io/views/layouts/styles.css +264 -0
- data/lib/snowman-io/views/layouts/transactional-email-templates-LICENSE +21 -0
- data/lib/snowman-io/views/report_mailer/check_triggered.html.erb +16 -0
- data/lib/snowman-io/views/report_mailer/checks/_human_last_value_limit.html.erb +2 -0
- data/lib/snowman-io/views/report_mailer/checks/_human_prev_day_datapoints_limit.html.erb +2 -0
- data/lib/snowman-io/views/report_mailer/daily_report.html.erb +40 -0
- data/lib/snowman-io/views/report_mailer/restore_password.html.erb +28 -0
- data/lib/snowman-io/views/report_mailer/send_invite.html.erb +32 -0
- data/lib/snowman-io/web.rb +28 -0
- data/lib/snowman-io/web_server.rb +107 -0
- data/snowman-io.gemspec +15 -5
- metadata +220 -49
- data/lib/snowman-io/api/public/README.md +0 -36
- data/lib/snowman-io/api/public/css/normalize.css +0 -406
- data/lib/snowman-io/api/public/css/style.css +0 -4
- data/lib/snowman-io/api/public/js/app.js +0 -13
- data/lib/snowman-io/api/public/js/libs/ember-1.8.1.js +0 -49740
- data/lib/snowman-io/api/public/js/libs/handlebars-v1.3.0.js +0 -2746
- data/lib/snowman-io/api/public/js/libs/jquery-1.10.2.js +0 -9789
- data/lib/snowman-io/api/public/tests/runner.css +0 -14
- data/lib/snowman-io/api/public/tests/runner.js +0 -13
- data/lib/snowman-io/api/public/tests/tests.js +0 -30
- data/lib/snowman-io/api/public/tests/vendor/qunit-1.12.0.css +0 -244
- data/lib/snowman-io/api/public/tests/vendor/qunit-1.12.0.js +0 -2212
- data/lib/snowman-io/api/views/index.erb +0 -26
- data/lib/snowman-io/api/views/layout.erb +0 -24
- data/lib/snowman-io/api/views/login.erb +0 -21
- data/lib/snowman-io/api/views/unpacking.erb +0 -21
- data/lib/snowman-io/check.rb +0 -49
- data/lib/snowman-io/check_result.rb +0 -15
- data/lib/snowman-io/checks/hosted_graphite.rb +0 -23
- data/lib/snowman-io/handler.rb +0 -27
- data/lib/snowman-io/notifiers/slack.rb +0 -76
- data/lib/snowman-io/processor.rb +0 -32
- data/lib/snowman-io/scheduler.rb +0 -42
@@ -1,26 +0,0 @@
|
|
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>
|
@@ -1,24 +0,0 @@
|
|
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>
|
@@ -1,21 +0,0 @@
|
|
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>
|
@@ -1,21 +0,0 @@
|
|
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/check.rb
DELETED
@@ -1,49 +0,0 @@
|
|
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
|
@@ -1,23 +0,0 @@
|
|
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
|
data/lib/snowman-io/handler.rb
DELETED
@@ -1,27 +0,0 @@
|
|
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
|
@@ -1,76 +0,0 @@
|
|
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/processor.rb
DELETED
@@ -1,32 +0,0 @@
|
|
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
|
data/lib/snowman-io/scheduler.rb
DELETED
@@ -1,42 +0,0 @@
|
|
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
|