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.
Files changed (59) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +9 -0
  3. data/.rspec +4 -0
  4. data/.travis.yml +25 -0
  5. data/Gemfile +18 -0
  6. data/Makefile +56 -0
  7. data/README.md +77 -0
  8. data/Rakefile +67 -0
  9. data/bin/dolphin_server +98 -0
  10. data/config/db/cassandra_clear.txt +1 -0
  11. data/config/db/cassandra_schema.txt +14 -0
  12. data/config/db/sequel/migrations/0001_add_notification.rb +15 -0
  13. data/config/db/sequel/migrations/0002_add_event.rb +15 -0
  14. data/config/dolphin-mysql.conf.travis +26 -0
  15. data/config/dolphin.conf.example +26 -0
  16. data/lib/dolphin.rb +148 -0
  17. data/lib/dolphin/data_store.rb +55 -0
  18. data/lib/dolphin/data_stores/base_rdb.rb +57 -0
  19. data/lib/dolphin/data_stores/cassandra.rb +98 -0
  20. data/lib/dolphin/data_stores/mysql.rb +31 -0
  21. data/lib/dolphin/helpers/message/zabbix_helper.rb +16 -0
  22. data/lib/dolphin/helpers/request_helper.rb +72 -0
  23. data/lib/dolphin/mailer.rb +83 -0
  24. data/lib/dolphin/manager.rb +35 -0
  25. data/lib/dolphin/message_builder.rb +98 -0
  26. data/lib/dolphin/models/base.rb +8 -0
  27. data/lib/dolphin/models/cassandra/base.rb +11 -0
  28. data/lib/dolphin/models/cassandra/event.rb +42 -0
  29. data/lib/dolphin/models/cassandra/notification.rb +28 -0
  30. data/lib/dolphin/models/rdb/base.rb +12 -0
  31. data/lib/dolphin/models/rdb/event.rb +47 -0
  32. data/lib/dolphin/models/rdb/notification.rb +27 -0
  33. data/lib/dolphin/models/rdb/orm/base.rb +10 -0
  34. data/lib/dolphin/models/rdb/orm/event.rb +8 -0
  35. data/lib/dolphin/models/rdb/orm/notification.rb +8 -0
  36. data/lib/dolphin/query_processor.rb +50 -0
  37. data/lib/dolphin/request_handler.rb +150 -0
  38. data/lib/dolphin/sender.rb +47 -0
  39. data/lib/dolphin/util.rb +18 -0
  40. data/lib/dolphin/version.rb +3 -0
  41. data/lib/dolphin/worker.rb +149 -0
  42. data/script/console +13 -0
  43. data/spec/files/cassandra_models_spec.rb +127 -0
  44. data/spec/files/dolphin_spec.rb +110 -0
  45. data/spec/files/endpoint/event_spec.rb +123 -0
  46. data/spec/files/endpoint/notification_spec.rb +54 -0
  47. data/spec/files/message_builder_spec.rb +15 -0
  48. data/spec/helpers/test_helper.rb +21 -0
  49. data/spec/helpers/web_request_helper.rb +40 -0
  50. data/spec/spec_helper.rb +18 -0
  51. data/templates/email/alert_port.erb +24 -0
  52. data/templates/email/default.erb +3 -0
  53. data/tests/test_dolphin +10 -0
  54. data/tests/test_get_event +31 -0
  55. data/tests/test_get_notification +27 -0
  56. data/tests/test_post_event +37 -0
  57. data/tests/test_post_notification +43 -0
  58. data/wakame-dolphin.gemspec +40 -0
  59. 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
@@ -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,3 @@
1
+ module Dolphin
2
+ VERSION = '0.0.1'
3
+ 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
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- coding: utf-8 -*-
3
+
4
+ begin
5
+ require "rubygems"
6
+ require "bundler/setup"
7
+ rescue LoadError => e
8
+ end
9
+
10
+ require File.join(File.expand_path('../../', __FILE__), 'lib/dolphin')
11
+
12
+ require 'irb'
13
+ IRB.start
@@ -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