wakame-dolphin 0.0.2
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 +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
|