murakumo 0.3.1 → 0.3.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.
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.