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,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