wakame-dolphin 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
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,26 @@
1
+ [server]
2
+ host = 127.0.0.1
3
+ port = 9004
4
+
5
+ [agent]
6
+ request_handler = 1
7
+ query_processor = 1
8
+ worker = 1
9
+ sender = 1
10
+
11
+ [database]
12
+ adapter = cassandra
13
+ hosts = 127.0.0.1
14
+ port = 9160
15
+ max_retry_count = 3
16
+ retry_interval = 3
17
+
18
+ [mail]
19
+ from = demo@example.com
20
+ # host = localhost
21
+ # port = 25
22
+ type = file
23
+
24
+ [logger]
25
+ format = human_readable
26
+ # format = ltsv
@@ -0,0 +1,148 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'parseconfig'
4
+ require 'ostruct'
5
+ require 'extlib/blank'
6
+
7
+ Signal.trap(:INT, "EXIT")
8
+
9
+ $LOAD_PATH.unshift File.expand_path('../', __FILE__)
10
+
11
+ module Dolphin
12
+ def self.settings(config='')
13
+
14
+ if @settings.nil?
15
+
16
+ # overwrite
17
+ if !ENV['CONFIG_FILE'].blank?
18
+ config = File.join(Dolphin.config_path, ENV['CONFIG_FILE'])
19
+ elsif config.blank?
20
+ config = File.join(Dolphin.config_path, 'dolphin.conf')
21
+ end
22
+
23
+ if !File.exists?(config)
24
+ puts "File not found #{config}"
25
+ exit!
26
+ end
27
+
28
+ # TODO:validation
29
+ @config = config
30
+ @settings = ParseConfig.new(config)
31
+ end
32
+ @settings
33
+ end
34
+
35
+ def self.config
36
+ @config
37
+ end
38
+
39
+ def self.root_path
40
+ File.expand_path('../../', __FILE__)
41
+ end
42
+
43
+ def self.templates_path
44
+ File.join(root_path, '/templates')
45
+ end
46
+
47
+ def self.config_path
48
+ File.join(root_path, '/config')
49
+ end
50
+
51
+ def self.db_path
52
+ File.join(config_path, '/db')
53
+ end
54
+
55
+ class EventObject < OpenStruct;end
56
+ class NotificationObject < OpenStruct; end
57
+ class ResponseObject
58
+ attr_accessor :message
59
+ def initialize
60
+ @success = nil
61
+ @message = ''
62
+ end
63
+
64
+ def success!
65
+ @success = true
66
+ end
67
+
68
+ def success?
69
+ warn 'Does not happened anything.' if @success.nil?
70
+ @success === true
71
+ end
72
+
73
+ def fail!
74
+ @success = false
75
+ end
76
+
77
+ def fail?
78
+ warn 'Does not happened anything.' if @success.nil?
79
+ @success === false
80
+ end
81
+ end
82
+
83
+ class FailureObject < ResponseObject
84
+ def initialize(message = '')
85
+ fail!
86
+ @message = message
87
+ freeze
88
+ end
89
+ end
90
+
91
+ class SuccessObject < ResponseObject
92
+ def initialize(message = '')
93
+ success!
94
+ @message = message
95
+ freeze
96
+ end
97
+ end
98
+
99
+ autoload :VERSION, 'dolphin/version'
100
+
101
+ autoload :Util, 'dolphin/util'
102
+ autoload :MessageBuilder, 'dolphin/message_builder'
103
+ autoload :TemplateBuilder, 'dolphin/message_builder'
104
+ autoload :Mailer, 'dolphin/mailer'
105
+ autoload :DataStore, 'dolphin/data_store'
106
+
107
+ module Models
108
+ autoload :Base, 'dolphin/models/base'
109
+ module Cassandra
110
+ autoload :Base, 'dolphin/models/cassandra/base'
111
+ autoload :Event, 'dolphin/models/cassandra/event'
112
+ autoload :Notification, 'dolphin/models/cassandra/notification'
113
+ end
114
+
115
+ module Rdb
116
+ autoload :Base, 'dolphin/models/rdb/base'
117
+ autoload :Event, 'dolphin/models/rdb/event'
118
+ autoload :Notification, 'dolphin/models/rdb/notification'
119
+ module Orm
120
+ autoload :Event, 'dolphin/models/rdb/orm/event'
121
+ autoload :Notification, 'dolphin/models/rdb/orm/notification'
122
+ end
123
+ end
124
+ end
125
+
126
+ module Helpers
127
+ autoload :RequestHelper, 'dolphin/helpers/request_helper'
128
+ module Message
129
+ autoload :ZabbixHelper, 'dolphin/helpers/message/zabbix_helper'
130
+ end
131
+ end
132
+
133
+ module DataStore
134
+ autoload :Cassandra, 'dolphin/data_stores/cassandra'
135
+ autoload :Mysql, 'dolphin/data_stores/mysql'
136
+ autoload :BaseRdb, 'dolphin/data_stores/base_rdb'
137
+ end
138
+
139
+ # Celluloid supervisor
140
+ autoload :Manager, 'dolphin/manager'
141
+
142
+ # Celluloid actors
143
+ autoload :RequestHandler, 'dolphin/request_handler'
144
+ autoload :Worker, 'dolphin/worker'
145
+ autoload :QueryProcessor, 'dolphin/query_processor'
146
+ autoload :Sender, 'dolphin/sender'
147
+
148
+ end
@@ -0,0 +1,55 @@
1
+ module Dolphin
2
+ module DataStore
3
+ include Dolphin::Util
4
+
5
+ DATABASE = 'dolphin'.freeze
6
+
7
+ def self.current_store
8
+ create(Dolphin.settings['database']['adapter'].to_sym)
9
+ end
10
+
11
+ def hosts
12
+ Dolphin.settings['database']['hosts']
13
+ end
14
+
15
+ def self.create(adapter)
16
+ config = {}
17
+ case adapter
18
+ when :cassandra
19
+ klass = Dolphin::DataStore::Cassandra
20
+ config.merge!({
21
+ :keyspace => DATABASE,
22
+ :hosts => Dolphin.settings['database']['hosts'],
23
+ :port => Dolphin.settings['database']['port'],
24
+ :max_retry_count => Dolphin.settings['database']['max_retry_count'].to_i,
25
+ :retry_interval => Dolphin.settings['database']['retry_interval'].to_i
26
+ })
27
+ when :mysql
28
+ klass = Dolphin::DataStore::Mysql
29
+ config.merge!({
30
+ :adapter => 'mysql2',
31
+ :database => DATABASE,
32
+ :host => Dolphin.settings['database']['host'],
33
+ :port => Dolphin.settings['database']['port'],
34
+ :user => Dolphin.settings['database']['user'],
35
+ :password => Dolphin.settings['database']['password'],
36
+ })
37
+ else
38
+ raise NotImplementedError
39
+ end
40
+ klass.new(config)
41
+ end
42
+
43
+ class ConncetionBase
44
+ include Dolphin::Util
45
+
46
+ def connect
47
+ raise NotImplementedError
48
+ end
49
+
50
+ def path
51
+ raise NotImplementedError
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,57 @@
1
+ module Dolphin
2
+ module DataStore
3
+ class BaseRdb
4
+
5
+ def initialize(config)
6
+ @adapter = config[:adapter]
7
+ @host = config[:host]
8
+ @user = config[:user]
9
+ @password = config[:password]
10
+ @database = config[:database]
11
+
12
+ # Set timezone to UTC
13
+ Sequel.default_timezone = :utc
14
+ end
15
+
16
+ def current_database
17
+ Sequel.connect(connect_path)
18
+ end
19
+
20
+ def closed?
21
+ @connection.nil?
22
+ end
23
+
24
+ ORM = Dolphin::Models::Rdb::Orm
25
+
26
+ def get_notification(id)
27
+ n = Dolphin::Models::Rdb::Notification.new(ORM::Notification)
28
+ n.get(id)
29
+ end
30
+
31
+ def put_event(event)
32
+ e = Dolphin::Models::Rdb::Event.new(ORM::Event)
33
+ e.put(event)
34
+ end
35
+
36
+ def get_event(params)
37
+ e = Dolphin::Models::Rdb::Event.new(ORM::Event)
38
+ e.get(params)
39
+ end
40
+
41
+ def put_notification(id, methods)
42
+ n = Dolphin::Models::Rdb::Notification.new(ORM::Notification)
43
+ n.put(id, methods)
44
+ end
45
+
46
+ def delete_notification(notification)
47
+ n = Dolphin::Models::Rdb::Notification.new(ORM::Notification)
48
+ n.delete(notification)
49
+ end
50
+
51
+ def connect_path
52
+ "#{@adapter}://#{@host}/#{@database}?user=#{@user}&password=#{@password}"
53
+ end
54
+
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,98 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'cassandra/1.1'
4
+
5
+ module Thrift
6
+ class FramedTransport < BaseTransport
7
+ def write(buf,sz=nil)
8
+ if !['US-ASCII', 'ASCII-8BIT'].include?(buf.encoding.to_s)
9
+ buf = buf.unpack("a*").first
10
+ end
11
+ return @transport.write(buf) unless @write
12
+
13
+ @wbuf << (sz ? buf[0...sz] : buf)
14
+ end
15
+ end
16
+ end
17
+
18
+ module Dolphin
19
+ module DataStore
20
+ class Cassandra
21
+ include Dolphin::Util
22
+
23
+ class UnAvailableNodeException < Exception; end
24
+
25
+ PATH_SEPARATOR = ':'.freeze
26
+
27
+ def initialize(config)
28
+ @keyspace = config[:keyspace]
29
+ raise "database hosts is blank" if config[:hosts].blank?
30
+ @hosts = config[:hosts].split(',')
31
+ @port = config[:port]
32
+ @max_retry_count = config[:max_retry_count] || 3
33
+ @retry_interval = config[:retry_interval] || 3
34
+ @retry_count = 0
35
+ end
36
+
37
+ def connect
38
+ begin
39
+ if @connection.nil?
40
+ @connection = ::Cassandra.new(@keyspace, seeds)
41
+
42
+ # test connecting..
43
+ @connection.ring
44
+ return @connection
45
+ end
46
+ rescue ThriftClient::NoServersAvailable => e
47
+ logger :error, e
48
+ @connection = nil
49
+ if @retry_count < @max_retry_count
50
+ @retry_count += 1
51
+ logger :error, "retry connection..#{@retry_count}"
52
+ sleep @retry_interval
53
+ retry
54
+ end
55
+ rescue UnAvailableNodeException => e
56
+ logger :error, e
57
+ rescue CassandraThrift::InvalidRequestException => e
58
+ logger :error, e
59
+ end
60
+ @connection
61
+ end
62
+
63
+ def closed?
64
+ @connection.nil?
65
+ end
66
+
67
+ def get_notification(id)
68
+ n = Dolphin::Models::Cassandra::Notification.new(@connection)
69
+ n.get(id)
70
+ end
71
+
72
+ def put_event(event)
73
+ e = Dolphin::Models::Cassandra::Event.new(@connection)
74
+ e.put(event)
75
+ end
76
+
77
+ def get_event(params)
78
+ e = Dolphin::Models::Cassandra::Event.new(@connection)
79
+ e.get(params)
80
+ end
81
+
82
+ def put_notification(id, methods)
83
+ n = Dolphin::Models::Cassandra::Notification.new(@connection)
84
+ n.put(id, methods)
85
+ end
86
+
87
+ def delete_notification(notification)
88
+ n = Dolphin::Models::Cassandra::Notification.new(@connection)
89
+ n.delete(notification)
90
+ end
91
+
92
+ private
93
+ def seeds
94
+ @hosts.collect{|host| "#{host}:#{@port}"}
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,31 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'sequel'
4
+
5
+ module Dolphin
6
+ module DataStore
7
+ class Mysql < BaseRdb
8
+ def connect
9
+ @connection = current_database
10
+ case @connection.adapter_scheme
11
+ when :mysql, :mysql2
12
+ Sequel::MySQL.default_charset = 'utf8'
13
+ Sequel::MySQL.default_collate = 'utf8_general_ci'
14
+ Sequel::MySQL.default_engine = ENV['MYSQL_DB_ENGINE'] || 'InnoDB'
15
+
16
+ # this is the mysql adapter specific constants. won't work with mysql2.
17
+ if @connection.adapter_scheme == :mysql
18
+ # Disable TEXT to Sequel::SQL::Blob translation.
19
+ # see the thread: MySQL text turning into blobs
20
+ # http://groups.google.com/group/sequel-talk/browse_thread/thread/d0f4c85abe9b3227/9ceaf291f90111e6
21
+ # lib/sequel/adapters/mysql.rb
22
+ [249, 250, 251, 252].each { |v|
23
+ Sequel::MySQL::MYSQL_TYPES.delete(v)
24
+ }
25
+ end
26
+ end
27
+ @connection
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,16 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module Dolphin::Helpers::Message
4
+ module ZabbixHelper
5
+ def trigger_value_text(trigger_value)
6
+ case trigger_value
7
+ when '0'
8
+ '正常'
9
+ when '1'
10
+ '異常'
11
+ else
12
+ '不明'
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,72 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'multi_json'
3
+ require 'extlib/blank'
4
+
5
+ module Dolphin
6
+ module Helpers
7
+ module RequestHelper
8
+
9
+ def attach_request_params(request)
10
+ raise "Unsuppoted Content-Type: #{request.env['Content-Type']}" unless request.env['Content-Type'] === 'application/json'
11
+ @params = {}
12
+ @notification_id = request.env['X-Notification-Id']
13
+ @message_type = request.env['X-Message-Type']
14
+ case request.method
15
+ when "POST"
16
+ v = request.input.to_a[0]
17
+ @params = MultiJson.load(v)
18
+ when "GET"
19
+ @params = parse_query_string(request.env["QUERY_STRING"])
20
+ end
21
+ @params
22
+ end
23
+
24
+ def run(request, &blk)
25
+ begin
26
+ attach_request_params(request)
27
+ logger :info, @params
28
+ blk.call
29
+ rescue LoadError => e
30
+ logger :error, e
31
+ [400, {}, MultiJson.dump({
32
+ :message => 'Request faild.'
33
+ })]
34
+ rescue => e
35
+ logger :error, e
36
+ [400, {}, MultiJson.dump({
37
+ :message => e.message
38
+ })]
39
+ end
40
+ end
41
+
42
+ def respond_with(data)
43
+ [200, {}, MultiJson.dump(data)]
44
+ end
45
+
46
+ def required(name)
47
+ case name
48
+ when 'notification_id'
49
+ raise 'Not found X-Notification-Id' if @notification_id.nil?
50
+ end
51
+ end
52
+
53
+ private
54
+ def parse_query_string(query_string)
55
+ params = {}
56
+ unless query_string.blank?
57
+ parts = query_string.split('&')
58
+ parts.collect do |part|
59
+ key, value = part.split('=')
60
+ params.store(key, value)
61
+ end
62
+ end
63
+ params
64
+ end
65
+
66
+ def parse_time(time)
67
+ return nil if time.blank? || !time.is_a?(String)
68
+ Time.parse(URI.decode(time)).to_time
69
+ end
70
+ end
71
+ end
72
+ end