wakame-dolphin 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.rspec +4 -0
- data/.travis.yml +25 -0
- data/Gemfile +18 -0
- data/Makefile +56 -0
- data/README.md +77 -0
- data/Rakefile +67 -0
- data/bin/dolphin_server +98 -0
- data/config/db/cassandra_clear.txt +1 -0
- data/config/db/cassandra_schema.txt +14 -0
- data/config/db/sequel/migrations/0001_add_notification.rb +15 -0
- data/config/db/sequel/migrations/0002_add_event.rb +15 -0
- data/config/dolphin-mysql.conf.travis +26 -0
- data/config/dolphin.conf.example +26 -0
- data/lib/dolphin.rb +148 -0
- data/lib/dolphin/data_store.rb +55 -0
- data/lib/dolphin/data_stores/base_rdb.rb +57 -0
- data/lib/dolphin/data_stores/cassandra.rb +98 -0
- data/lib/dolphin/data_stores/mysql.rb +31 -0
- data/lib/dolphin/helpers/message/zabbix_helper.rb +16 -0
- data/lib/dolphin/helpers/request_helper.rb +72 -0
- data/lib/dolphin/mailer.rb +83 -0
- data/lib/dolphin/manager.rb +35 -0
- data/lib/dolphin/message_builder.rb +98 -0
- data/lib/dolphin/models/base.rb +8 -0
- data/lib/dolphin/models/cassandra/base.rb +11 -0
- data/lib/dolphin/models/cassandra/event.rb +42 -0
- data/lib/dolphin/models/cassandra/notification.rb +28 -0
- data/lib/dolphin/models/rdb/base.rb +12 -0
- data/lib/dolphin/models/rdb/event.rb +47 -0
- data/lib/dolphin/models/rdb/notification.rb +27 -0
- data/lib/dolphin/models/rdb/orm/base.rb +10 -0
- data/lib/dolphin/models/rdb/orm/event.rb +8 -0
- data/lib/dolphin/models/rdb/orm/notification.rb +8 -0
- data/lib/dolphin/query_processor.rb +50 -0
- data/lib/dolphin/request_handler.rb +150 -0
- data/lib/dolphin/sender.rb +47 -0
- data/lib/dolphin/util.rb +18 -0
- data/lib/dolphin/version.rb +3 -0
- data/lib/dolphin/worker.rb +149 -0
- data/script/console +13 -0
- data/spec/files/cassandra_models_spec.rb +127 -0
- data/spec/files/dolphin_spec.rb +110 -0
- data/spec/files/endpoint/event_spec.rb +123 -0
- data/spec/files/endpoint/notification_spec.rb +54 -0
- data/spec/files/message_builder_spec.rb +15 -0
- data/spec/helpers/test_helper.rb +21 -0
- data/spec/helpers/web_request_helper.rb +40 -0
- data/spec/spec_helper.rb +18 -0
- data/templates/email/alert_port.erb +24 -0
- data/templates/email/default.erb +3 -0
- data/tests/test_dolphin +10 -0
- data/tests/test_get_event +31 -0
- data/tests/test_get_notification +27 -0
- data/tests/test_post_event +37 -0
- data/tests/test_post_notification +43 -0
- data/wakame-dolphin.gemspec +40 -0
- metadata +311 -0
@@ -0,0 +1,150 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'reel/app'
|
4
|
+
require 'extlib/blank'
|
5
|
+
|
6
|
+
module Dolphin
|
7
|
+
class RequestHandler
|
8
|
+
include Reel::App
|
9
|
+
include Dolphin::Util
|
10
|
+
include Dolphin::Helpers::RequestHelper
|
11
|
+
|
12
|
+
GET_EVENT_LIMIT = 30.freeze
|
13
|
+
|
14
|
+
def initialize(host, port)
|
15
|
+
|
16
|
+
# TODO: Fix Celluloid.logger loading order.
|
17
|
+
logger :info, "Load settings in #{Dolphin.config}"
|
18
|
+
|
19
|
+
@server = Reel::Server.supervise_as(:reques_handler, host, port) do |connection|
|
20
|
+
|
21
|
+
while request = connection.request
|
22
|
+
begin
|
23
|
+
logger :info, {
|
24
|
+
:host => request.headers["Host"],
|
25
|
+
:user_agent => request.headers["User-Agent"]
|
26
|
+
}
|
27
|
+
options = {
|
28
|
+
:method => request.method,
|
29
|
+
:input => request.body
|
30
|
+
}
|
31
|
+
options.merge!(request.headers)
|
32
|
+
status, headers_or_body, body = call Rack::MockRequest.env_for(request.url, options)
|
33
|
+
connection.respond status_symbol(status), headers_or_body, body.to_s
|
34
|
+
rescue => e
|
35
|
+
logger :error, e
|
36
|
+
break
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
logger :info, "Running on ruby #{RUBY_VERSION} with selected #{Celluloid::task_class}"
|
41
|
+
logger :info, "Listening on http://#{host}:#{port}"
|
42
|
+
@server
|
43
|
+
end
|
44
|
+
|
45
|
+
post '/events' do |request|
|
46
|
+
run(request) do
|
47
|
+
|
48
|
+
raise 'Nothing parameters.' if @params.blank?
|
49
|
+
|
50
|
+
event = {}
|
51
|
+
event[:notification_id] = @notification_id
|
52
|
+
event[:message_type] = @message_type
|
53
|
+
event[:messages] = @params
|
54
|
+
|
55
|
+
events = worker.future.put_event(event)
|
56
|
+
|
57
|
+
# always success because put_event is async action.
|
58
|
+
response_params = {
|
59
|
+
:message => 'OK'
|
60
|
+
}
|
61
|
+
respond_with response_params
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
get '/events' do |request|
|
66
|
+
run(request) do
|
67
|
+
|
68
|
+
limit = @params['limit'].blank? ? GET_EVENT_LIMIT : @params['limit'].to_i
|
69
|
+
raise "Requested over the limit. Limited to #{GET_EVENT_LIMIT}" if limit > GET_EVENT_LIMIT
|
70
|
+
|
71
|
+
params = {}
|
72
|
+
params[:count] = limit
|
73
|
+
params[:start_time] = parse_time(@params['start_time']) unless @params['start_time'].blank?
|
74
|
+
params[:start_id] = @params['start_id'] unless @params['start_id'].blank?
|
75
|
+
|
76
|
+
events = worker.get_event(params)
|
77
|
+
raise events.message if events.fail?
|
78
|
+
|
79
|
+
response_params = {
|
80
|
+
:results => events.message,
|
81
|
+
:message => 'OK'
|
82
|
+
}
|
83
|
+
response_params[:start_time] = @params['start_time'] unless @params['start_time'].blank?
|
84
|
+
respond_with response_params
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
get '/notifications' do |request|
|
89
|
+
run(request) do
|
90
|
+
required 'notification_id'
|
91
|
+
|
92
|
+
notification = {}
|
93
|
+
notification[:id] = @notification_id
|
94
|
+
|
95
|
+
result = worker.get_notification(notification)
|
96
|
+
raise result.message if result.fail?
|
97
|
+
raise "Not found notification id" if result.message.nil?
|
98
|
+
|
99
|
+
response_params = {
|
100
|
+
:results => result.message,
|
101
|
+
:message => 'OK'
|
102
|
+
}
|
103
|
+
respond_with response_params
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
post '/notifications' do |request|
|
108
|
+
run(request) do
|
109
|
+
required 'notification_id'
|
110
|
+
raise 'Nothing parameters.' if @params.blank?
|
111
|
+
|
112
|
+
unsupported_sender_types = @params.keys - Sender::TYPES
|
113
|
+
raise "Unsuppoted sender types: #{unsupported_sender_types.join(',')}" unless unsupported_sender_types.blank?
|
114
|
+
|
115
|
+
notification = {}
|
116
|
+
notification[:id] = @notification_id
|
117
|
+
notification[:methods] = @params
|
118
|
+
result = worker.put_notification(notification)
|
119
|
+
raise result.message if result.fail?
|
120
|
+
|
121
|
+
response_params = {
|
122
|
+
:message => 'OK'
|
123
|
+
}
|
124
|
+
respond_with response_params
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
delete '/notifications' do |request|
|
129
|
+
run(request) do
|
130
|
+
required 'notification_id'
|
131
|
+
|
132
|
+
notification = {}
|
133
|
+
notification[:id] = @notification_id
|
134
|
+
|
135
|
+
result = worker.delete_notification(notification)
|
136
|
+
raise result.message if result.fail?
|
137
|
+
|
138
|
+
response_params = {
|
139
|
+
:message => 'OK'
|
140
|
+
}
|
141
|
+
respond_with response_params
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
private
|
146
|
+
def worker
|
147
|
+
Celluloid::Actor[:workers]
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'celluloid'
|
4
|
+
require 'extlib/blank'
|
5
|
+
require 'time'
|
6
|
+
|
7
|
+
module Dolphin
|
8
|
+
module Sender
|
9
|
+
TYPES = ['email'].freeze
|
10
|
+
|
11
|
+
TYPE = [:mail_senders].freeze
|
12
|
+
|
13
|
+
class Mail
|
14
|
+
include Celluloid
|
15
|
+
include Dolphin::Util
|
16
|
+
|
17
|
+
def notify(notification_object)
|
18
|
+
time_now = DateTime.now.strftime('%a, %d %b %Y %H:%M:%S %z')
|
19
|
+
send_params = {
|
20
|
+
:from => notification_object.from,
|
21
|
+
:to => notification_object.to,
|
22
|
+
:subject => notification_object.subject,
|
23
|
+
:body => notification_object.body,
|
24
|
+
:date => time_now,
|
25
|
+
:event_id => notification_object.event_id
|
26
|
+
}
|
27
|
+
|
28
|
+
unless notification_object.to.blank?
|
29
|
+
send_params[:cc] = notification_object.cc
|
30
|
+
end
|
31
|
+
|
32
|
+
unless notification_object.bcc.blank?
|
33
|
+
send_params[:bcc] = notification_object.bcc
|
34
|
+
end
|
35
|
+
|
36
|
+
logger :info, send_params
|
37
|
+
begin
|
38
|
+
Mailer.notify(send_params)
|
39
|
+
logger :info, "Success Sent message"
|
40
|
+
rescue => e
|
41
|
+
logger :error, e.message
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/lib/dolphin/util.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'celluloid'
|
4
|
+
|
5
|
+
module Dolphin
|
6
|
+
module Util
|
7
|
+
include Celluloid::Logger
|
8
|
+
|
9
|
+
def logger(type, message)
|
10
|
+
message = {
|
11
|
+
:message => message,
|
12
|
+
:classname => self.class.name,
|
13
|
+
:thread_id => Thread.current.object_id
|
14
|
+
}
|
15
|
+
Celluloid.logger.__send__(type, message)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,149 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'extlib/blank'
|
4
|
+
|
5
|
+
module Dolphin
|
6
|
+
class Worker
|
7
|
+
include Celluloid
|
8
|
+
include Dolphin::Util
|
9
|
+
|
10
|
+
def put_event(event_object)
|
11
|
+
logger :info, "Worker put events #{event_object}"
|
12
|
+
|
13
|
+
notification_id = event_object[:notification_id]
|
14
|
+
message_template_id = event_object[:message_type]
|
15
|
+
|
16
|
+
future_event = query_processor.future.put_event(event_object)
|
17
|
+
|
18
|
+
# if notification_id not exists, doesn't send notification.
|
19
|
+
unless notification_id
|
20
|
+
return SuccessObject.new
|
21
|
+
end
|
22
|
+
|
23
|
+
future_notification = query_processor.future.get_notification(notification_id)
|
24
|
+
|
25
|
+
# synchronized
|
26
|
+
notifications = future_notification.value
|
27
|
+
event_id = future_event.value
|
28
|
+
if notifications.nil?
|
29
|
+
log_message = "Not found notification: #{event_object[:notification_id]}"
|
30
|
+
logger :error, log_message
|
31
|
+
return FailureObject.new(log_message)
|
32
|
+
end
|
33
|
+
|
34
|
+
if query_processor_failed?(notifications)
|
35
|
+
return FailureObject.new('Failed to get notifications')
|
36
|
+
end
|
37
|
+
|
38
|
+
notifications.each do |sender_type, values|
|
39
|
+
if values.blank?
|
40
|
+
logger :info, "Skip to notify message because notifications was blank."
|
41
|
+
next
|
42
|
+
end
|
43
|
+
|
44
|
+
unless Sender::TYPES.include? sender_type
|
45
|
+
log_message = "Not found sender #{sender_type}"
|
46
|
+
logger :error, log_message
|
47
|
+
# Does not do response to Request Handler.
|
48
|
+
next
|
49
|
+
end
|
50
|
+
|
51
|
+
build_params = {}
|
52
|
+
# TODO: Plugin
|
53
|
+
case sender_type
|
54
|
+
when 'email'
|
55
|
+
build_params["to"] = values['to']
|
56
|
+
build_params["cc"] = values['cc']
|
57
|
+
build_params["bcc"] = values['bcc']
|
58
|
+
build_params["messages"] = event_object[:messages]
|
59
|
+
end
|
60
|
+
|
61
|
+
message = build_message(sender_type, message_template_id, build_params)
|
62
|
+
message.event_id = event_id
|
63
|
+
|
64
|
+
if message.nil?
|
65
|
+
log_message = "Failed to build message: #{message}"
|
66
|
+
logger :error, log_message
|
67
|
+
# Does not do response to Request Handler.
|
68
|
+
next
|
69
|
+
end
|
70
|
+
|
71
|
+
logger :info, "Send notification from Worker #{message}"
|
72
|
+
|
73
|
+
begin
|
74
|
+
send_notification(sender_type, message)
|
75
|
+
rescue => e
|
76
|
+
logger :error, e
|
77
|
+
# Does not do response to Request Handler.
|
78
|
+
next
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
SuccessObject.new
|
83
|
+
end
|
84
|
+
|
85
|
+
def get_event(params)
|
86
|
+
event = query_processor.get_event(params)
|
87
|
+
if query_processor_failed?(event)
|
88
|
+
return FailureObject.new('Failed to get events')
|
89
|
+
end
|
90
|
+
SuccessObject.new(event)
|
91
|
+
end
|
92
|
+
|
93
|
+
def get_notification(notification)
|
94
|
+
notification_id = notification[:id]
|
95
|
+
notification = query_processor.get_notification(notification_id)
|
96
|
+
if query_processor_failed?(notification)
|
97
|
+
return FailureObject.new('Failed to get notification')
|
98
|
+
end
|
99
|
+
SuccessObject.new(notification)
|
100
|
+
end
|
101
|
+
|
102
|
+
def put_notification(notification)
|
103
|
+
notification = query_processor.put_notification(notification)
|
104
|
+
if query_processor_failed?(notification)
|
105
|
+
return FailureObject.new('Failed to put notification')
|
106
|
+
end
|
107
|
+
SuccessObject.new(notification)
|
108
|
+
end
|
109
|
+
|
110
|
+
def delete_notification(notification)
|
111
|
+
notification = query_processor.delete_notification(notification)
|
112
|
+
if query_processor_failed?(notification)
|
113
|
+
return FailureObject.new('Failed to delete notification')
|
114
|
+
end
|
115
|
+
SuccessObject.new(notification)
|
116
|
+
end
|
117
|
+
|
118
|
+
private
|
119
|
+
def query_processor_failed?(response_data)
|
120
|
+
response_data === FALSE
|
121
|
+
end
|
122
|
+
|
123
|
+
def query_processor
|
124
|
+
Celluloid::Actor[:query_processors]
|
125
|
+
end
|
126
|
+
|
127
|
+
def sender(type)
|
128
|
+
Celluloid::Actor[type]
|
129
|
+
end
|
130
|
+
|
131
|
+
def send_notification(type, log_message)
|
132
|
+
case type
|
133
|
+
when 'email'
|
134
|
+
sender(:mail_senders).notify(log_message)
|
135
|
+
else
|
136
|
+
raise "Unsuppoted sender type: #{type}"
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def build_message(type, template_id, params)
|
141
|
+
case type
|
142
|
+
when 'email'
|
143
|
+
MessageBuilder::Mail.new.build(template_id, params)
|
144
|
+
else
|
145
|
+
nil
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
data/script/console
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe 'Test Dolphin::Models for Cassandra' do
|
6
|
+
before(:all) do
|
7
|
+
@connection = Dolphin::DataStore::Cassandra.new(
|
8
|
+
:keyspace => 'dolphin_test',
|
9
|
+
:hosts => Dolphin.settings['database']['hosts'],
|
10
|
+
:port => Dolphin.settings['database']['port']
|
11
|
+
)
|
12
|
+
@connection.connect
|
13
|
+
end
|
14
|
+
|
15
|
+
describe Dolphin::Models::Cassandra::Event do
|
16
|
+
before(:all) do
|
17
|
+
if @connection.closed?
|
18
|
+
pending "Cassandra doens't exist"
|
19
|
+
else
|
20
|
+
@event_values = []
|
21
|
+
@event_values << {
|
22
|
+
'notification_id' => "system",
|
23
|
+
'message_type' => "alert_port",
|
24
|
+
'messages' => {
|
25
|
+
"message"=>"Alert!!!!"
|
26
|
+
}
|
27
|
+
}
|
28
|
+
|
29
|
+
@column_name = SimpleUUID::UUID.new(Time.now).to_guid
|
30
|
+
@connection.connect.insert(
|
31
|
+
Dolphin::Models::Cassandra::Event::COLUMN_FAMILY,
|
32
|
+
Dolphin::Models::Cassandra::Event::ROW_KEY,
|
33
|
+
{@column_name => MultiJson.dump(@event_values)}
|
34
|
+
)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe ".get" do
|
39
|
+
let(:message) {
|
40
|
+
res = @connection.get_event({:count=>1})
|
41
|
+
message = res[0]
|
42
|
+
}
|
43
|
+
|
44
|
+
it "expect to get message id" do
|
45
|
+
expect(message['id']).to eql SimpleUUID::UUID.new(message['id']).to_guid
|
46
|
+
end
|
47
|
+
|
48
|
+
it "expect to get message values" do
|
49
|
+
expect(message['event']).to eql @event_values
|
50
|
+
end
|
51
|
+
|
52
|
+
it "expect to get message created_at formated by ISO8601" do
|
53
|
+
expect(Time.iso8601(message['created_at'])).to be_instance_of Time
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe '.put' do
|
58
|
+
it "expect to put success" do
|
59
|
+
event_id = @connection.put_event(@event_values[0])
|
60
|
+
expect(SimpleUUID::UUID.new(event_id)).to be_a SimpleUUID::UUID
|
61
|
+
event_data = @connection.get_event({
|
62
|
+
:count => 1,
|
63
|
+
:start_id => SimpleUUID::UUID.new(event_id)
|
64
|
+
})[0]
|
65
|
+
expect(event_id).to eql event_data['id']
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
context Dolphin::Models::Cassandra::Notification do
|
71
|
+
|
72
|
+
before(:all) do
|
73
|
+
if @connection.closed?
|
74
|
+
pending "Cassandra doens't exist"
|
75
|
+
else
|
76
|
+
@notification_values = {
|
77
|
+
"email"=> {
|
78
|
+
"to" => "foo@example.com,bar@example.com",
|
79
|
+
"cc" => "foo@example.com,bar@example.com",
|
80
|
+
"bcc" =>"foofoo@example.com,barbar@example.com"
|
81
|
+
}
|
82
|
+
}
|
83
|
+
@row_key = 'system'
|
84
|
+
@connection.connect.insert('notifications', @row_key, {
|
85
|
+
'methods' => MultiJson.dump(@notification_values)
|
86
|
+
})
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
let(:notification_data) do
|
91
|
+
@connection.get_notification(@row_key)
|
92
|
+
end
|
93
|
+
|
94
|
+
describe '.get' do
|
95
|
+
it "expect to the same values before created" do
|
96
|
+
expect(notification_data).to eql @notification_values
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
describe '.put' do
|
101
|
+
let(:notification_new_data) do
|
102
|
+
@connection.put_notification(@row_key, @notification_values)
|
103
|
+
end
|
104
|
+
|
105
|
+
it "expect to put success" do
|
106
|
+
expect(notification_new_data).to be_nil
|
107
|
+
|
108
|
+
notification_data = @connection.get_notification(@row_key)
|
109
|
+
expect(notification_data).to eql @notification_values
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
describe '.delete' do
|
114
|
+
it "expect to delete success" do
|
115
|
+
@connection.put_notification(@row_key, @notification_values)
|
116
|
+
notification_new_data = @connection.get_notification(@row_key)
|
117
|
+
expect(notification_new_data).to eql @notification_values
|
118
|
+
|
119
|
+
deleted_notification = @connection.delete_notification(@row_key)
|
120
|
+
expect(deleted_notification).to be_nil
|
121
|
+
|
122
|
+
notification_data = @connection.get_notification(@row_key)
|
123
|
+
expect(notification_data).to be_nil
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|