murakumo 0.3.1 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
data/etc/murakumo.server CHANGED
@@ -72,8 +72,23 @@ max-ip-num: 8
72
72
  #domain: ap-northeast-1.compute.internal
73
73
  #enable-cache: true
74
74
 
75
+ #notification:
76
+ # host: my.smtp.server
77
+ # #port: 25
78
+ # sender: sender@mail.from
79
+ # recipients:
80
+ # - recipient1@mail.to
81
+ # - recipient2@mail.to
82
+ # #helo: my.domain
83
+ # #account: my_name
84
+ # #password: my_password
85
+ # #open_timeout: 30
86
+ # #read_timeout: 60
87
+
88
+ # Ip address, hostname, ttl
75
89
  host: $ip_addr, $hostname, 60
76
90
 
91
+ # alias hostname, ttl, master/secondary/backup
77
92
  #alias:
78
93
  # - foo,60,master
79
94
  # - bar,60,backup
@@ -84,6 +99,8 @@ host: $ip_addr, $hostname, 60
84
99
  # timeout: 5
85
100
  # healthy: 2
86
101
  # unhealthy: 2
102
+ # #on_activate: /foo/bar/zoo.sh # args: address name status
103
+ # #on_inactivate: /foo/bar/zoo.sh # args: address name status
87
104
  # script: |
88
105
  # tcp_check 80
89
106
  # bar:
@@ -12,10 +12,23 @@ max-ip-num: 8
12
12
  #domain: ap-northeast-1.compute.internal
13
13
  #enable-cache: true
14
14
 
15
+ #notification:
16
+ # host: my.smtp.server
17
+ # #port: 25
18
+ # sender: sender@mail.from
19
+ # recipients:
20
+ # - recipient1@mail.to
21
+ # - recipient2@mail.to
22
+ # #helo: my.domain
23
+ # #account: my_name
24
+ # #password: my_password
25
+ # #open_timeout: 30
26
+ # #read_timeout: 60
27
+
15
28
  # Ip address, hostname, ttl
16
29
  host: 10.11.12.13, my-host, 60
17
30
 
18
- # alias hostname, ttl, master/backup
31
+ # alias hostname, ttl, master/secondary/backup
19
32
  alias:
20
33
  - foo,60,master
21
34
  - bar,60,master
@@ -26,6 +39,8 @@ health-check:
26
39
  timeout: 5
27
40
  healthy: 2
28
41
  unhealthy: 2
42
+ #on_activate: /foo/bar/zoo.sh # args: address name status
43
+ #on_inactivate: /foo/bar/zoo.sh # args: address name status
29
44
  script: |
30
45
  tcp_check 80
31
46
  bar:
@@ -183,14 +183,64 @@ def murakumo_parse_args
183
183
  hostnames = [options[:host][0].downcase] + options[:aliases].map {|i| i[0].downcase }
184
184
 
185
185
  if hostnames.length != hostnames.uniq.length
186
- raise OptionParser::ParseError, 'same hostname was found'
186
+ parse_error('same hostname was found')
187
187
  end
188
188
 
189
189
  # health check
190
190
  if options.config_file and (health_check = options.config_file['health-check'])
191
- unless health_check.kind_of?(Hash) and health_check.all? {|k, v| v.has_key?('script') }
192
- raise OptionParser::ParseError, 'configuration of a health check is not right'
191
+ health_check.kind_of?(Hash) or parse_error('configuration of a health check is not right')
192
+
193
+ health_check.each do |name, conf|
194
+ if (conf['script'] || '').empty?
195
+ parse_error('configuration of a health check is not right', "#{name}/script")
196
+ end
197
+
198
+ %w(on_activate on_inactivate).each do |key|
199
+ next unless conf[key]
200
+ path = conf[key] = conf[key].strip
201
+
202
+ if FileTest.directory?(path) or not FileTest.executable?(path)
203
+ parse_error('configuration of a health check is not right', "#{name}/#{key}")
204
+ end
205
+ end
206
+ end
207
+ end
208
+
209
+ # notification
210
+ if options.config_file and (ntfc = options.config_file['notification'])
211
+ ntfc.kind_of?(Hash) or parse_error('configuration of a notification is not right')
212
+
213
+ if (ntfc['host'] || '').empty?
214
+ parse_error('configuration of a notification is not right', 'host')
215
+ end
216
+
217
+ unless ntfc['recipients']
218
+ parse_error('configuration of a notification is not right', 'recipients')
193
219
  end
220
+
221
+ %w(port open_timeout read_timeout).each do |key|
222
+ if ntfc[key] and /\A\d+\Z/ !~ ntfc[key].to_s
223
+ parse_error('configuration of a notification is not right', key)
224
+ end
225
+ end
226
+
227
+ ntfc_args = [ntfc['host']]
228
+ ntfc_args << ntfc['port'].to_i if ntfc['port']
229
+ ntfc_args << ntfc['account'] if ntfc['account']
230
+ ntfc_args << ntfc['password'] if ntfc['password']
231
+
232
+ options[:notification] = ntfc_h = {:args => ntfc_args}
233
+
234
+ ntfc_h[:sender] = ntfc['sender'] || 'murakumo@localhost.localdomain'
235
+
236
+ if ntfc['recipients'].kind_of?(Array)
237
+ ntfc_h[:recipients] = ntfc['recipients']
238
+ else
239
+ ntfc_h[:recipients] = ntfc['recipients'].to_s.split(/\s*,\s*/).select {|i| not i.empty? }
240
+ end
241
+
242
+ ntfc_h[:open_timeout] = ntfc['open_timeout'].to_i if ntfc['open_timeout']
243
+ ntfc_h[:read_timeout] = ntfc['read_timeout'].to_i if ntfc['read_timeout']
194
244
  end
195
245
  end
196
246
 
@@ -1,5 +1,5 @@
1
1
  module Murakumo
2
- VERSION = '0.3.1'
2
+ VERSION = '0.3.2'
3
3
 
4
4
  # Priority
5
5
  MASTER = 1
@@ -77,8 +77,12 @@ module Murakumo
77
77
  health_check.each do |name, conf|
78
78
  name = name.downcase
79
79
 
80
+ if options[:notification]
81
+ conf = conf.merge(:notification => options[:notification])
82
+ end
83
+
80
84
  if datas.any? {|i| i[0] == name }
81
- checker = HealthChecker.new(name, self, @logger, conf)
85
+ checker = HealthChecker.new(@address, name, self, @logger, conf)
82
86
  @health_checkers[name] = checker
83
87
  # ヘルスチェックはまだ起動しない
84
88
  else
@@ -167,6 +171,10 @@ module Murakumo
167
171
  hash['health-check'] = @options.config_file['health-check']
168
172
  end
169
173
 
174
+ if @options.config_file and @options.config_file['notification']
175
+ hash['notification'] = @options.config_file['notification']
176
+ end
177
+
170
178
  return hash
171
179
  end
172
180
 
@@ -1,4 +1,5 @@
1
1
  require 'net/http'
2
+ require 'net/smtp'
2
3
  require 'socket'
3
4
 
4
5
  require 'misc/murakumo_const'
@@ -6,7 +7,7 @@ require 'misc/murakumo_const'
6
7
  module Murakumo
7
8
 
8
9
  # ヘルスチェックのコンテキスト
9
- class HealthCheckerContext
10
+ class HealthCheckContext
10
11
 
11
12
  def initialize(vars = {})
12
13
  vars.each do |name, val|
@@ -37,6 +38,14 @@ module Murakumo
37
38
  return false
38
39
  end
39
40
 
41
+ # SMTPチェッカー
42
+ def smtp_check(*args)
43
+ Net::SMTP.start(*args) {|smtp| true }
44
+ rescue => e
45
+ @logger.debug("#{@name}: #{e.message}")
46
+ return false
47
+ end
48
+
40
49
  # MySQLのドライバがあれば、MySQLチェッカーを定義
41
50
  mysql_class = nil
42
51
 
@@ -91,6 +100,6 @@ module Murakumo
91
100
  rescue LoadError
92
101
  end
93
102
 
94
- end # HealthCheckerContext
103
+ end # HealthCheckContext
95
104
 
96
105
  end # Murakumo
@@ -0,0 +1,56 @@
1
+ require 'net/smtp'
2
+ require 'resolv-replace'
3
+ require 'time'
4
+
5
+ module Murakumo
6
+
7
+ class HealthCheckNotifier
8
+
9
+ def initialize(address, name, logger, options)
10
+ @address = address
11
+ @name = name
12
+ @logger = logger
13
+ @args = options[:args]
14
+ @sender = options[:sender]
15
+ @recipients = options[:recipients]
16
+ @open_timeout = options[:open_timeout]
17
+ @read_timeout = options[:read_timeout]
18
+ end
19
+
20
+ def notify_active
21
+ notify('Active', "#{@name} changed into the activity status.")
22
+ end
23
+
24
+ def notify_inactive
25
+ notify('Inactive', "#{@name} changed into the inactivity status.")
26
+ end
27
+
28
+ private
29
+ def notify(status, body)
30
+ Net::SMTP.start(*@args) do |smtp|
31
+ smtp.open_timeout = @open_timeout if @open_timeout
32
+ smtp.read_timeout = @read_timeout if @read_timeout
33
+
34
+ smtp.send_mail(<<-EOS, @sender, *@recipients)
35
+ From: Murakumo Notifier <#{@sender}>
36
+ To: #{@recipients.join(', ')}
37
+ Subject: #{@name}/#{@address} => #{status}
38
+ Date: #{Time.now.rfc2822}
39
+
40
+ Address: #{@address}
41
+ Name: #{@name}
42
+ Status: #{status}
43
+
44
+ #{body.strip}
45
+ EOS
46
+ end
47
+
48
+ @logger.info("sent the notice: #{status}")
49
+ rescue Exception => e
50
+ message = (["#{e.class}: #{e.message}"] + (e.backtrace || [])).join("\n\tfrom ")
51
+ @logger.error("healthcheck failed: #{@name}: #{message}")
52
+ end
53
+
54
+ end # HealthCheckNotifier
55
+
56
+ end # Murakumo
@@ -1,14 +1,17 @@
1
1
  require 'timeout'
2
+ require 'open3'
2
3
  require 'resolv-replace'
3
4
 
4
- require 'srv/murakumo_health_checker_context'
5
+ require 'srv/murakumo_health_check_context'
6
+ require 'srv/murakumo_health_check_notifier'
5
7
  require 'misc/murakumo_const'
6
8
 
7
9
  module Murakumo
8
10
 
9
11
  class HealthChecker
10
12
 
11
- def initialize(name, cloud, logger, options)
13
+ def initialize(address, name, cloud, logger, options)
14
+ @address = address
12
15
  @name = name
13
16
  @cloud = cloud
14
17
  @logger = logger
@@ -32,6 +35,15 @@ module Murakumo
32
35
  @script = options['script']
33
36
  raise "health check script of #{@name} is not found" unless @script
34
37
  @script = File.read(script) if File.exists?(@script)
38
+
39
+ # 通知オブジェクトの設定
40
+ if options[:notification]
41
+ @notifier = HealthCheckNotifier.new(@address, @name, @logger, options[:notification])
42
+ end
43
+
44
+ # イベントハンドラの設定
45
+ @on_activate = options['on_activate']
46
+ @on_inactivate = options['on_inactivate']
35
47
  end
36
48
 
37
49
  def good
@@ -71,6 +83,15 @@ module Murakumo
71
83
 
72
84
  status = @normal_health ? 'healthy' : 'unhealthy'
73
85
  @logger.info("health condition changed: #{@name}: #{status}")
86
+
87
+ case activity
88
+ when ACTIVE
89
+ @notifier.notify_active if @notifier
90
+ handle_event(@on_activate, 'Active') if @on_activate
91
+ when INACTIVE
92
+ @notifier.notify_inactive if @notifier
93
+ handle_event(@on_inactivate, 'Inactive') if @on_inactivate
94
+ end
74
95
  end
75
96
 
76
97
  def start
@@ -98,7 +119,7 @@ module Murakumo
98
119
 
99
120
  begin
100
121
  retval = timeout(@timeout) {
101
- HealthCheckerContext.new(:name => @name, :logger => @logger, :options => @options).instance_eval(@script)
122
+ HealthCheckContext.new(:name => @name, :logger => @logger, :options => @options).instance_eval(@script)
102
123
  }
103
124
  rescue Timeout::Error
104
125
  retval = false
@@ -133,6 +154,22 @@ module Murakumo
133
154
  def alive?
134
155
  @alive
135
156
  end
157
+
158
+ private
159
+
160
+ def handle_event(handler, status)
161
+ Open3.popen3("#{@on_activate} '#{@address}' '#{@name}' '#{status}'") do |stdin, stdout, stderr|
162
+ out = stdout.read.strip
163
+ @logger.info(out) unless out.empty?
164
+
165
+ err = stderr.read.strip
166
+ @logger.error(err) unless err.empty?
167
+ end
168
+ rescue Exception => e
169
+ message = (["#{e.class}: #{e.message}"] + (e.backtrace || [])).join("\n\tfrom ")
170
+ @logger.error("#{@name}: #{message}")
171
+ end
172
+
136
173
  end # HealthChecker
137
174
 
138
175
  end # Murakumo
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: murakumo
3
3
  version: !ruby/object:Gem::Version
4
- hash: 17
4
+ hash: 23
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 3
9
- - 1
10
- version: 0.3.1
9
+ - 2
10
+ version: 0.3.2
11
11
  platform: ruby
12
12
  authors:
13
13
  - winebarrel
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-11-23 00:00:00 Z
18
+ date: 2011-11-26 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: rubydns
@@ -93,23 +93,24 @@ extra_rdoc_files: []
93
93
 
94
94
  files:
95
95
  - README
96
- - bin/murakumo
97
96
  - bin/murakumo-install-init-script
98
97
  - bin/mrkmctl
99
- - lib/cli/mrkmctl.rb
100
- - lib/cli/murakumo.rb
98
+ - bin/murakumo
101
99
  - lib/cli/murakumo_options.rb
100
+ - lib/cli/mrkmctl.rb
102
101
  - lib/cli/mrkmctl_options.rb
103
- - lib/misc/murakumo_const.rb
102
+ - lib/cli/murakumo.rb
103
+ - lib/srv/murakumo_health_check_notifier.rb
104
104
  - lib/srv/murakumo_server.rb
105
- - lib/srv/murakumo_health_checker_context.rb
106
105
  - lib/srv/murakumo_health_checker.rb
107
106
  - lib/srv/murakumo_cloud.rb
108
- - etc/murakumo.server
109
- - etc/murakumo.yml.example
110
- - etc/gai.conf.example
107
+ - lib/srv/murakumo_health_check_context.rb
108
+ - lib/misc/murakumo_const.rb
111
109
  - etc/murakumo-update-config-for-ec2
110
+ - etc/gai.conf.example
111
+ - etc/murakumo.yml.example
112
112
  - etc/dhclient-script.patch
113
+ - etc/murakumo.server
113
114
  homepage: https://bitbucket.org/winebarrel/murakumo
114
115
  licenses: []
115
116
 
@@ -139,7 +140,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
139
140
  requirements: []
140
141
 
141
142
  rubyforge_project:
142
- rubygems_version: 1.8.11
143
+ rubygems_version: 1.8.1
143
144
  signing_key:
144
145
  specification_version: 3
145
146
  summary: Murakumo is the internal DNS server which manages name information using a gossip protocol.