murakumo 0.4.4 → 0.4.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env ruby
2
+ $: << File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+
4
+ require 'optparse'
5
+
6
+ require 'util/murakumo_ec2_attach_interface'
7
+
8
+ access_key = nil
9
+ secret_key = nil
10
+ if_id = nil
11
+ dev_idx = nil
12
+ endpoint = nil
13
+ instance_id = nil
14
+
15
+ ARGV.options do |opt|
16
+ begin
17
+ opt.on('-k', '--access-key ACCESS_KEY') {|v| access_key = v }
18
+ opt.on('-s', '--secret-key SECRET_KEY') {|v| secret_key = v }
19
+ opt.on('-n', '--network-if-id IF_ID') {|v| if_id = v }
20
+ opt.on('-d', '--device-index INDEX') {|v| dev_idx = v }
21
+ opt.on('-r', '--region REGION') {|v| endpoint = v }
22
+ opt.on('-i', '--instance-id INSTANCE_ID') {|v| instance_id = v }
23
+ opt.parse!
24
+
25
+ access_key ||= (ENV['AMAZON_ACCESS_KEY_ID'] || ENV['AWS_ACCESS_KEY_ID'])
26
+ secret_key ||= (ENV['AMAZON_SECRET_ACCESS_KEY'] || ENV['AWS_SECRET_ACCESS_KEY'])
27
+
28
+ unless access_key and secret_key and if_id
29
+ puts opt.help
30
+ exit 1
31
+ end
32
+ rescue => e
33
+ $stderr.puts e
34
+ exit 1
35
+ end
36
+ end
37
+
38
+ Murakumo::Util::ec2_attach_interface(access_key, secret_key, if_id, dev_idx, endpoint, instance_id)
@@ -12,16 +12,21 @@ endpoint = nil
12
12
  instance_id = nil
13
13
 
14
14
  ARGV.options do |opt|
15
- opt.on('-k', '--access-key ACCESS_KEY') {|v| access_key = v }
16
- opt.on('-s', '--secret-key SECRET_KEY') {|v| secret_key = v }
17
- opt.on('-r', '--region REGION') {|v| endpoint = v }
18
- opt.parse!
19
-
20
- access_key ||= ENV['AMAZON_ACCESS_KEY_ID']
21
- secret_key ||= ENV['AMAZON_SECRET_ACCESS_KEY']
22
-
23
- unless access_key and secret_key
24
- puts opt.help
15
+ begin
16
+ opt.on('-k', '--access-key ACCESS_KEY') {|v| access_key = v }
17
+ opt.on('-s', '--secret-key SECRET_KEY') {|v| secret_key = v }
18
+ opt.on('-r', '--region REGION') {|v| endpoint = v }
19
+ opt.parse!
20
+
21
+ access_key ||= (ENV['AMAZON_ACCESS_KEY_ID'] || ENV['AWS_ACCESS_KEY_ID'])
22
+ secret_key ||= (ENV['AMAZON_SECRET_ACCESS_KEY'] || ENV['AWS_SECRET_ACCESS_KEY'])
23
+
24
+ unless access_key and secret_key
25
+ puts opt.help
26
+ exit 1
27
+ end
28
+ rescue => e
29
+ $stderr.puts e
25
30
  exit 1
26
31
  end
27
32
  end
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env ruby
2
+ $: << File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+
4
+ require 'optparse'
5
+ require 'yaml'
6
+
7
+ require 'util/murakumo_ec2_interfaces'
8
+
9
+ access_key = nil
10
+ secret_key = nil
11
+ endpoint = nil
12
+ instance_id = nil
13
+
14
+ ARGV.options do |opt|
15
+ begin
16
+ opt.on('-k', '--access-key ACCESS_KEY') {|v| access_key = v }
17
+ opt.on('-s', '--secret-key SECRET_KEY') {|v| secret_key = v }
18
+ opt.on('-r', '--region REGION') {|v| endpoint = v }
19
+ opt.parse!
20
+
21
+ access_key ||= (ENV['AMAZON_ACCESS_KEY_ID'] || ENV['AWS_ACCESS_KEY_ID'])
22
+ secret_key ||= (ENV['AMAZON_SECRET_ACCESS_KEY'] || ENV['AWS_SECRET_ACCESS_KEY'])
23
+
24
+ unless access_key and secret_key
25
+ puts opt.help
26
+ exit 1
27
+ end
28
+ rescue => e
29
+ $stderr.puts e
30
+ exit 1
31
+ end
32
+ end
33
+
34
+ instances = Murakumo::Util::ec2_interfaces(access_key, secret_key, endpoint)
35
+
36
+ puts YAML.dump(instances)
@@ -0,0 +1,37 @@
1
+ #!/usr/bin/env ruby
2
+ $: << File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+
4
+ require 'optparse'
5
+
6
+ require 'util/murakumo_ec2_private_ip_addresses'
7
+
8
+ access_key = nil
9
+ secret_key = nil
10
+ endpoint = nil
11
+ instance_id = nil
12
+
13
+ ARGV.options do |opt|
14
+ begin
15
+ opt.on('-k', '--access-key ACCESS_KEY') {|v| access_key = v }
16
+ opt.on('-s', '--secret-key SECRET_KEY') {|v| secret_key = v }
17
+ opt.on('-r', '--region REGION') {|v| endpoint = v }
18
+ opt.parse!
19
+
20
+ access_key ||= (ENV['AMAZON_ACCESS_KEY_ID'] || ENV['AWS_ACCESS_KEY_ID'])
21
+ secret_key ||= (ENV['AMAZON_SECRET_ACCESS_KEY'] || ENV['AWS_SECRET_ACCESS_KEY'])
22
+
23
+ unless access_key and secret_key
24
+ puts opt.help
25
+ exit 1
26
+ end
27
+ rescue => e
28
+ $stderr.puts e
29
+ exit 1
30
+ end
31
+ end
32
+
33
+ ip_addrs = Murakumo::Util::ec2_private_ip_addresses(access_key, secret_key, endpoint)
34
+
35
+ ip_addrs.each do |i|
36
+ puts i.join("\t")
37
+ end
@@ -11,17 +11,22 @@ endpoint = nil
11
11
  instance_id = nil
12
12
 
13
13
  ARGV.options do |opt|
14
- opt.on('-k', '--access-key ACCESS_KEY') {|v| access_key = v }
15
- opt.on('-s', '--secret-key SECRET_KEY') {|v| secret_key = v }
16
- opt.on('-r', '--region REGION') {|v| endpoint = v }
17
- opt.on('-i', '--instance-id INSTANCE_ID') {|v| instance_id = v }
18
- opt.parse!
19
-
20
- access_key ||= ENV['AMAZON_ACCESS_KEY_ID']
21
- secret_key ||= ENV['AMAZON_SECRET_ACCESS_KEY']
22
-
23
- unless access_key and secret_key
24
- puts opt.help
14
+ begin
15
+ opt.on('-k', '--access-key ACCESS_KEY') {|v| access_key = v }
16
+ opt.on('-s', '--secret-key SECRET_KEY') {|v| secret_key = v }
17
+ opt.on('-r', '--region REGION') {|v| endpoint = v }
18
+ opt.on('-i', '--instance-id INSTANCE_ID') {|v| instance_id = v }
19
+ opt.parse!
20
+
21
+ access_key ||= (ENV['AMAZON_ACCESS_KEY_ID'] || ENV['AWS_ACCESS_KEY_ID'])
22
+ secret_key ||= (ENV['AMAZON_SECRET_ACCESS_KEY'] || ENV['AWS_SECRET_ACCESS_KEY'])
23
+
24
+ unless access_key and secret_key
25
+ puts opt.help
26
+ exit 1
27
+ end
28
+ rescue => e
29
+ $stderr.puts e
25
30
  exit 1
26
31
  end
27
32
  end
@@ -0,0 +1,12 @@
1
+ #!/bin/sh
2
+ AWS_ACCESS_KEY_ID=...
3
+ AWS_SECRET_ACCESS_KEY=...
4
+ REGION=ap-northeast-1
5
+ IF_ID=eni-...
6
+
7
+ /usr/bin/murakumo-attach-ec2-attach-interface \
8
+ -k "$AWS_ACCESS_KEY_ID" -s "$AWS_SECRET_ACCESS_KEY" \
9
+ -r $REGION -n $IF_ID 2>&1 | logger
10
+
11
+ exit 0
12
+
@@ -1,19 +1,23 @@
1
- AMAZON_ACCESS_KEY_ID = '...'
2
- AMAZON_SECRET_ACCESS_KEY = '...'
1
+ AWS_ACCESS_KEY_ID = '...'
2
+ AWS_SECRET_ACCESS_KEY = '...'
3
+ REGION = 'ap-northeast-1'
3
4
 
4
5
  # get self ip address
5
6
  ip_addr = Murakumo::Util.self_ip_address
6
7
 
7
8
  # get hostname
8
- tags = Murakumo::Util.ec2_tags(AMAZON_ACCESS_KEY_ID, AMAZON_SECRET_ACCESS_KEY)
9
+ tags = Murakumo::Util.ec2_tags(AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, REGION)
9
10
  hostname = tags['Name'] || `curl -s http://169.254.169.254/latest/meta-data/local-hostname`
10
11
 
11
12
  # rewrite host option
12
13
  @options['host'] = "#{ip_addr}, #{hostname}"
13
14
 
14
15
  # get instances
15
- instances = Murakumo::Util.ec2_instances(AMAZON_ACCESS_KEY_ID, AMAZON_SECRET_ACCESS_KEY)
16
+ ip_addrs = Murakumo::Util::ec2_private_ip_addresses(AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, REGION)
16
17
 
17
18
  # rewrite initial-nodes
18
- nodes = instances.map {|i| i['privateIpAddress'] || '' }.select {|i| not i.empty? }
19
+ nodes = ip_addrs.select {|inst_id, ip_addr, status|
20
+ status == 'running'
21
+ }.map {|inst_id, ip_addr, status| ip_addr }
22
+
19
23
  @options['initial-nodes'] = nodes.join(',') unless nodes.empty?
@@ -134,6 +134,54 @@ host: $ip_addr, $hostname, 60
134
134
  # unhealthy: 2
135
135
  # script: |
136
136
  # http_get '/index.html'
137
+
138
+ # hook of server start
139
+ #on-start: /foo/bar/on-start.sh # args: address hostname
140
+
141
+ # hook of activation of backup/secondary
142
+ #activity-check:
143
+ # foo:
144
+ # start-delay: 60
145
+ # interval: 10
146
+ # #init-status: undefined # active/inactive/undefined (default: undefined)
147
+ # active: 2 # active threshold count
148
+ # inactive: 2 # inactive threshold count
149
+ # on-activate: /usr/sbin/attach_if.sh # args: address name status
150
+ # #on-inactivate: /foo/bar/zoo.sh # args: address name status
151
+ # bar:
152
+ # start-delay: 60
153
+ # interval: 10
154
+ # #init-status: undefined # active/inactive/undefined (default: undefined)
155
+ # active: 2 # active threshold count
156
+ # inactive: 2 # inactive threshold count
157
+ # on-activate: /usr/sbin/attach_if.sh # args: address name status
158
+ # #on-inactivate: /foo/bar/zoo.sh # args: address name status
159
+
160
+ ## about activity-check
161
+ ## ---
162
+ ## when BACKUP:
163
+ ## if BACKUP is started:
164
+ ## init-status: active -> on-inactivate
165
+ ## inactive -> nothing to do
166
+ ## if MASTER became unhealthy or down:
167
+ ## -> on-activate
168
+ ## if MASTER is restored:
169
+ ## -> on-inactivate
170
+ ##
171
+ ## when MASTER:
172
+ ## if MASTER is started:
173
+ ## init-status: active -> nothing to do
174
+ ## inactive -> on-activate
175
+ ## if BACKUP became unhealthy or down:
176
+ ## -> nothing to do
177
+ ## if MASTER became unhealthy:
178
+ ## -> on-inactivate
179
+ ## if MASTER became down:
180
+ ## -> cannot do anything
181
+ ## if MASTER is restored from down:
182
+ ## -> same as MASTER start
183
+ ## if MASTER is restored from unhealthy:
184
+ ## -> on-activate
137
185
  EOF
138
186
 
139
187
  chmod 600 $conf
@@ -57,20 +57,68 @@ alias:
57
57
  - foo,60,master,100
58
58
  - bar,60,master,100
59
59
 
60
- health-check:
61
- foo:
62
- interval: 5
63
- timeout: 5
64
- healthy: 2
65
- unhealthy: 2
66
- #on-activate: /foo/bar/zoo.sh # args: address name status
67
- #on-inactivate: /foo/bar/zoo.sh # args: address name status
68
- script: |
69
- tcp_check 80
70
- bar:
71
- interval: 5
72
- timeout: 5
73
- healthy: 2
74
- unhealthy: 2
75
- script: |
76
- http_get '/index.html'
60
+ #health-check:
61
+ # foo:
62
+ # interval: 5
63
+ # timeout: 5
64
+ # healthy: 2
65
+ # unhealthy: 2
66
+ # #on-activate: /foo/bar/zoo.sh # args: address name status
67
+ # #on-inactivate: /foo/bar/zoo.sh # args: address name status
68
+ # script: |
69
+ # tcp_check 80
70
+ # bar:
71
+ # interval: 5
72
+ # timeout: 5
73
+ # healthy: 2
74
+ # unhealthy: 2
75
+ # script: |
76
+ # http_get '/index.html'
77
+
78
+ # hook of server start
79
+ #on-start: /foo/bar/on-start.sh # args: address hostname
80
+
81
+ # hook of activation of backup/secondary
82
+ #activity-check:
83
+ # foo:
84
+ # start-delay: 60
85
+ # interval: 10
86
+ # #init-status: undefined # active/inactive/undefined (default: undefined)
87
+ # active: 2 # active threshold count
88
+ # inactive: 2 # inactive threshold count
89
+ # on-activate: /usr/sbin/attach_if.sh # args: address name status
90
+ # #on-inactivate: /foo/bar/zoo.sh # args: address name status
91
+ # bar:
92
+ # start-delay: 60
93
+ # interval: 10
94
+ # #init-status: undefined # active/inactive/undefined (default: undefined)
95
+ # active: 2 # active threshold count
96
+ # inactive: 2 # inactive threshold count
97
+ # on-activate: /usr/sbin/attach_if.sh # args: address name status
98
+ # #on-inactivate: /foo/bar/zoo.sh # args: address name status
99
+
100
+ ## about activity-check
101
+ ## ---
102
+ ## when BACKUP:
103
+ ## if BACKUP is started:
104
+ ## init-status: active -> on-inactivate
105
+ ## inactive -> nothing to do
106
+ ## if MASTER became unhealthy or down:
107
+ ## -> on-activate
108
+ ## if MASTER is restored:
109
+ ## -> on-inactivate
110
+ ##
111
+ ## when MASTER:
112
+ ## if MASTER is started:
113
+ ## init-status: active -> nothing to do
114
+ ## inactive -> on-activate
115
+ ## if BACKUP became unhealthy or down:
116
+ ## -> nothing to do
117
+ ## if MASTER became unhealthy:
118
+ ## -> on-inactivate
119
+ ## if MASTER became down:
120
+ ## -> cannot do anything
121
+ ## if MASTER is restored from down:
122
+ ## -> same as MASTER start
123
+ ## if MASTER is restored from unhealthy:
124
+ ## -> on-activate
@@ -2,6 +2,9 @@ require 'misc/murakumo_const'
2
2
  require 'util/murakumo_self_ip_address'
3
3
  require 'util/murakumo_ec2_tags'
4
4
  require 'util/murakumo_ec2_instances'
5
+ require 'util/murakumo_ec2_private_ip_addresses'
6
+ require 'util/murakumo_ec2_attach_interface'
7
+ require 'util/murakumo_ec2_interfaces'
5
8
 
6
9
  module Murakumo
7
10
 
@@ -220,9 +220,80 @@ def murakumo_parse_args
220
220
  parse_error('configuration of a health check is not right', "#{name}/#{key}")
221
221
  end
222
222
  end
223
+
224
+ # 各種変数の設定
225
+ {
226
+ 'interval' => [ 5, 1, 300],
227
+ 'timeout' => [ 5, 1, 300],
228
+ 'healthy' => [ 2, 1, 60],
229
+ 'unhealthy' => [ 2, 1, 60],
230
+ }.each {|key, vals|
231
+ defval, min, max = vals
232
+ value = (conf[key] || defval).to_i
233
+
234
+ if value < min
235
+ value = min
236
+ parse_error("health-check/#{name}/#{key} is smaller than #{min}.", "#{name}/#{key}")
237
+ elsif value > max
238
+ value = max
239
+ parse_error("health-check/#{name}/#{key} is larger than #{max}.", "#{name}/#{key}")
240
+ end
241
+
242
+ conf[key] = value
243
+ }
223
244
  end
224
245
  end # health check
225
246
 
247
+ # activity check
248
+ if (activity_check = options[:activity_check])
249
+ activity_check.kind_of?(Hash) or parse_error('configuration of a activity check is not right')
250
+
251
+ activity_check.each do |name, conf|
252
+ # 'on-activate'か'on-inactivate'のいずれかが必須
253
+ if (conf['on-activate'] || conf['on-inactivate'] || '').empty?
254
+ parse_error('configuration of a health check is not right', "on-activate or on-inactivate is not defined")
255
+ end
256
+
257
+ conf['init-status'] ||= 'undefined'
258
+
259
+ unless /\A(active|inactive|undefined)\Z/i =~ conf['init-status']
260
+ parse_error('configuration of a health check is not right', "#{name}/init-status")
261
+ end
262
+
263
+ conf['init-status'] = conf['init-status'].downcase.to_sym
264
+
265
+ %w(on-activate on-inactivate).each do |key|
266
+ next unless conf[key]
267
+ path = conf[key] = conf[key].strip
268
+
269
+ if FileTest.directory?(path) or not FileTest.executable?(path)
270
+ parse_error('configuration of a health check is not right', "#{name}/#{key}")
271
+ end
272
+ end
273
+
274
+ # 各種変数の設定
275
+ {
276
+ 'interval' => [ 10, 1, 300],
277
+ 'start-delay' => [ 60, 1, 300],
278
+ 'active' => [ 2, 1, 60],
279
+ 'inactive' => [ 2, 1, 60],
280
+ }.each {|key, vals|
281
+ defval, min, max = vals
282
+ value = (conf[key] || defval).to_i
283
+
284
+ if value < min
285
+ value = min
286
+ parse_error("activateation-check/#{name}/#{key} is smaller than #{min}.", "#{name}/#{key}")
287
+ elsif value > max
288
+ value = max
289
+ parse_error("activation-check/#{name}/#{key} is larger than #{max}.", "#{name}/#{key}")
290
+ end
291
+
292
+ conf[key] = value
293
+ }
294
+ end
295
+ end # activity check
296
+
226
297
  # notification
227
298
  if (ntfc = options[:notification])
228
299
  ntfc.kind_of?(Hash) or parse_error('configuration of a notification is not right')
@@ -318,6 +389,13 @@ def murakumo_parse_args
318
389
  balancing_h[reg_dest] = attrs_h
319
390
  end
320
391
  end # balancing
392
+
393
+ # on start
394
+ if (on_start = options[:on_start])
395
+ unless File.exist?(on_start)
396
+ parse_error('on_start script is not found')
397
+ end
398
+ end # on start
321
399
  end # after
322
400
 
323
401
  error do |e|
@@ -1,5 +1,5 @@
1
1
  module Murakumo
2
- VERSION = '0.4.4'
2
+ VERSION = '0.4.5'
3
3
 
4
4
  # Priority
5
5
  MASTER = 1
@@ -0,0 +1,55 @@
1
+ require 'net/smtp'
2
+ require 'time'
3
+
4
+ module Murakumo
5
+
6
+ class ActivityCheckNotifier
7
+
8
+ def initialize(address, name, logger, options)
9
+ @address = address
10
+ @name = name
11
+ @logger = logger
12
+ @args = options[:args]
13
+ @sender = options[:sender]
14
+ @recipients = options[:recipients]
15
+ @open_timeout = options[:open_timeout]
16
+ @read_timeout = options[:read_timeout]
17
+ end
18
+
19
+ def notify_active
20
+ notify('active', "#{@name} became active.")
21
+ end
22
+
23
+ def notify_inactive
24
+ notify('inactive', "#{@name} became inactive. Zzz...")
25
+ end
26
+
27
+ private
28
+ def notify(status, body)
29
+ Net::SMTP.start(*@args) do |smtp|
30
+ smtp.open_timeout = @open_timeout if @open_timeout
31
+ smtp.read_timeout = @read_timeout if @read_timeout
32
+
33
+ smtp.send_mail(<<-EOS, @sender, *@recipients)
34
+ From: Murakumo Activity Check Notifier <#{@sender}>
35
+ To: #{@recipients.join(', ')}
36
+ Subject: [Activity] #{@name}/#{@address} => #{status}
37
+ Date: #{Time.now.rfc2822}
38
+
39
+ Address: #{@address}
40
+ Name: #{@name}
41
+ Status: #{status}
42
+
43
+ #{body.strip}
44
+ EOS
45
+ end
46
+
47
+ @logger.info("sent the notice: #{status}")
48
+ rescue Exception => e
49
+ message = (["#{e.class}: #{e.message}"] + (e.backtrace || [])).join("\n\tfrom ")
50
+ @logger.error("activity check failed: #{@name}: #{message}")
51
+ end
52
+
53
+ end # ActivityCheckNotifier
54
+
55
+ end # Murakumo
@@ -0,0 +1,198 @@
1
+ require 'open3'
2
+
3
+ require 'srv/murakumo_activity_check_notifier'
4
+ require 'misc/murakumo_const'
5
+
6
+ module Murakumo
7
+
8
+ class ActivityChecker
9
+
10
+ def initialize(address, name, cloud, logger, options)
11
+ @address = address
12
+ @name = name
13
+ @cloud = cloud
14
+ @logger = logger
15
+ @options = options
16
+
17
+ # 各種変数の設定
18
+ ['interval', 'start-delay', 'active', 'inactive', 'init-status'].each {|key|
19
+ value = options[key]
20
+ instance_variable_set("@#{key.gsub('-', '_')}", value)
21
+ }
22
+
23
+ # 通知オブジェクトの設定
24
+ if options[:notification]
25
+ @notifier = ActivityCheckNotifier.new(@address, @name, @logger, options[:notification])
26
+ end
27
+
28
+ # イベントハンドラの設定
29
+ @on_activate = options['on-activate']
30
+ @on_inactivate = options['on-inactivate']
31
+ end
32
+
33
+ def mark_active
34
+ if @activated.nil?
35
+ # 状態がなかったら、まず状態をセット
36
+ @logger.info("initial activity: #{@name}: active")
37
+ @activated = true
38
+ elsif @activated == true # わざとですよ…
39
+ @inactive_count = 0
40
+ elsif (@active_count += 1) >= @active
41
+ toggle_activity
42
+ end
43
+ end
44
+
45
+ def mark_inactive
46
+ if @activated.nil?
47
+ # 状態がなかったら、まず状態をセット
48
+ @logger.info("initial activity: #{@name}: inactive")
49
+ @activated = false
50
+ elsif @activated == false # わざとですよ…
51
+ @active_count = 0
52
+ elsif (@inactive_count += 1) >= @inactive
53
+ toggle_activity
54
+ end
55
+ end
56
+
57
+ def toggle_activity
58
+ @activated = !@activated
59
+ @active_count = 0
60
+ @inactive_count = 0
61
+
62
+ status = @activated ? 'active' : 'inactive'
63
+ @logger.info("activity condition changed: #{@name}: #{status}")
64
+
65
+ if @activated
66
+ @notifier.notify_active if @notifier
67
+ handle_event(@on_activate, 'active') if @on_activate
68
+ else
69
+ @notifier.notify_inactive if @notifier
70
+ handle_event(@on_inactivate, 'inactive') if @on_inactivate
71
+ end
72
+ end
73
+
74
+ def start
75
+ # 各種変数は初期状態にする
76
+ @alive = true
77
+ @active_count = 0
78
+ @inactive_count = 0
79
+
80
+ # アクティビティの初期状態を設定
81
+ case @init_status
82
+ when :active
83
+ @activated = true
84
+ @logger.info("initial activity: #{@name}: active")
85
+ when :inactive
86
+ @activated = false
87
+ @logger.info("initial activity: #{@name}: inactive")
88
+ else
89
+ @activated = nil
90
+ end
91
+
92
+ # 既存のスレッドは破棄
93
+ if @thread and @thread.alive?
94
+ begin
95
+ @thread.kill
96
+ rescue ThreadError
97
+ end
98
+ end
99
+
100
+ @thread = Thread.start {
101
+ begin
102
+ # 初回実行の遅延
103
+ if @start_delay
104
+ @logger.debug("activity check is delaying: #{@name}")
105
+ sleep @start_delay
106
+ @start_delay = nil
107
+ @logger.debug("activity check is starting: #{@name}")
108
+ end
109
+
110
+ while @alive
111
+ retval = nil
112
+
113
+ begin
114
+ retval = validate_activity
115
+ rescue => e
116
+ retval = false
117
+ message = (["#{e.class}: #{e.message}"] + (e.backtrace || [])).join("\n\tfrom ")
118
+ @logger.error("activity check failed: #{@name}: #{message}")
119
+ end
120
+
121
+ status = retval == true ? 'active' : retval == false ? 'inactive' : '-'
122
+ @logger.debug("result of a activity check: #{@name}: #{status}")
123
+
124
+ if retval == true
125
+ mark_active
126
+ elsif retval == false
127
+ mark_inactive
128
+ end
129
+
130
+ sleep @interval
131
+ end # while
132
+ rescue Exception => e
133
+ message = (["#{e.class}: #{e.message}"] + (e.backtrace || [])).join("\n\tfrom ")
134
+ @logger.error("#{@name}: #{message}")
135
+ end # begin
136
+ }
137
+ end
138
+
139
+ def stop
140
+ @alive = false
141
+ end
142
+
143
+ def alive?
144
+ @alive
145
+ end
146
+
147
+ private
148
+
149
+ def validate_activity
150
+ records = @cloud.db.execute(<<-EOS, @name, ACTIVE)
151
+ SELECT ip_address, priority FROM records
152
+ WHERE name = ? AND activity = ?
153
+ EOS
154
+
155
+ # レコードがなければ非アクティブ
156
+ return false if records.empty?
157
+
158
+ # マスタに自IPが含まれているならアクティブ
159
+ masters = records.select {|i| i['priority'] == MASTER }
160
+
161
+ if masters.any? {|i| i['ip_address'] == @address }
162
+ return true
163
+ end
164
+
165
+ # マスタがなくてセカンダリに自IPが含まれているならアクティブ
166
+ secondaries = records.select {|i| i['priority'] == SECONDARY }
167
+
168
+ if masters.empty? and secondaries.any? {|i| i['ip_address'] == @address }
169
+ return true
170
+ end
171
+
172
+ # マスタ・セカンダリがなくてバックアップに自IPが含まれているならアクティブ
173
+ backups = records.select {|i| i['priority'] == BACKUP }
174
+
175
+ if masters.empty? and secondaries.empty? and backups.any? {|i| i['ip_address'] == @address }
176
+ return true
177
+ end
178
+
179
+ # 上記以外は非アクティブ
180
+ return false
181
+ end
182
+
183
+ def handle_event(handler, status)
184
+ Open3.popen3("#{@on_activate} '#{@address}' '#{@name}' '#{status}'") do |stdin, stdout, stderr|
185
+ out = stdout.read.strip
186
+ @logger.info(out) unless out.empty?
187
+
188
+ err = stderr.read.strip
189
+ @logger.error(err) unless err.empty?
190
+ end
191
+ rescue Exception => e
192
+ message = (["#{e.class}: #{e.message}"] + (e.backtrace || [])).join("\n\tfrom ")
193
+ @logger.error("#{@name}: #{message}")
194
+ end
195
+
196
+ end # ActivityChecker
197
+
198
+ end # Murakumo
@@ -1,8 +1,10 @@
1
1
  require 'forwardable'
2
2
  require 'rgossip2'
3
3
  require 'sqlite3'
4
+ require 'open3'
4
5
 
5
6
  require 'srv/murakumo_health_checker'
7
+ require 'srv/murakumo_activity_checker'
6
8
  require 'srv/murakumo_balancer'
7
9
  require 'misc/murakumo_const'
8
10
 
@@ -96,6 +98,34 @@ module Murakumo
96
98
  end
97
99
  end
98
100
 
101
+ # アクティビティチェック
102
+ @activity_checkers = {}
103
+
104
+ if options[:activity_check]
105
+ activity_check = options[:activity_check]
106
+
107
+ if activity_check.kind_of?(Hash)
108
+ activity_check.each do |name, conf|
109
+ name = name.downcase
110
+
111
+ if options[:notification]
112
+ conf = conf.merge(:notification => options[:notification])
113
+ end
114
+
115
+ if datas.any? {|i| i[0] == name }
116
+ checker = ActivityChecker.new(@address, name, self, @logger, conf)
117
+ @activity_checkers[name] = checker
118
+ # アクティビティチェックはまだ起動しない
119
+ else
120
+ # ホスト名になかったら警告
121
+ @logger.warn("host for a activity check is not found: #{name}")
122
+ end
123
+ end
124
+ else
125
+ @logger.warn('configuration of a activity check is not right')
126
+ end
127
+ end
128
+
99
129
  # キャッシュ
100
130
  @cache = {} if options[:enable_cache]
101
131
 
@@ -113,9 +143,34 @@ module Murakumo
113
143
  checker.start
114
144
  end
115
145
 
146
+ # アクティビティチェックを起動
147
+ @activity_checkers.each do |name, checker|
148
+ checker.start
149
+ end
150
+
151
+ # 起動時フックスクリプトの実行
152
+ if @options[:on_start]
153
+ exec_start_script(@options[:on_start])
154
+ end
155
+
116
156
  @gossip.start
117
157
  end
118
158
 
159
+ def exec_start_script(script)
160
+ @logger.info("starting script is performed: #{script}")
161
+
162
+ Open3.popen3("#{script} '#{@address}' '#{@hostname}'") do |stdin, stdout, stderr|
163
+ out = stdout.read.strip
164
+ @logger.info(out) unless out.empty?
165
+
166
+ err = stderr.read.strip
167
+ @logger.error(err) unless err.empty?
168
+ end
169
+ rescue Exception => e
170
+ message = (["#{e.class}: #{e.message}"] + (e.backtrace || [])).join("\n\tfrom ")
171
+ @logger.error("#{@name}: #{message}")
172
+ end
173
+
119
174
  def to_hash
120
175
  keys = {
121
176
  :auth_key => 'auth-key',
@@ -166,7 +221,7 @@ module Murakumo
166
221
  hash['host'] = records.find {|r| r[3] == ORIGIN }[0..2].join(',')
167
222
 
168
223
  aliases = records.select {|r| r[3] != ORIGIN }.map do |r|
169
- [r[1], r[2], (r[3] == MASTER ? 'master' : 'backup'), r[4]].join(',')
224
+ [r[1], r[2], (r[3] == MASTER ? 'master' : r[3] == SECONDARY ? 'secondary' : 'backup'), r[4]].join(',')
170
225
  end
171
226
 
172
227
  hash['alias'] = aliases unless aliases.empty?
@@ -177,6 +232,10 @@ module Murakumo
177
232
  hash['health-check'] = @options.config_file['health-check']
178
233
  end
179
234
 
235
+ if @options.config_file['activity-check']
236
+ hash['activity-check'] = @options.config_file['activity-check']
237
+ end
238
+
180
239
  if @options.config_file['notification']
181
240
  hash['notification'] = @options.config_file['notification']
182
241
  end
@@ -190,6 +249,10 @@ module Murakumo
190
249
  if @options.config_file['balancing']
191
250
  hash['balancing'] = @options.config_file['balancing']
192
251
  end
252
+
253
+ if @options.config_file['on-start']
254
+ hash['on-start'] = @options.config_file['on-start']
255
+ end
193
256
  end # 設定ファイルのみの項目
194
257
 
195
258
  return hash
@@ -18,11 +18,11 @@ module Murakumo
18
18
  end
19
19
 
20
20
  def notify_active
21
- notify('Active', "#{@name} changed into the activity status.")
21
+ notify('healthy', "#{@name} became healthy :-)")
22
22
  end
23
23
 
24
24
  def notify_inactive
25
- notify('Inactive', "#{@name} changed into the inactivity status.")
25
+ notify('unhealthy', "#{@name} became unhealthy :-(")
26
26
  end
27
27
 
28
28
  private
@@ -32,9 +32,9 @@ module Murakumo
32
32
  smtp.read_timeout = @read_timeout if @read_timeout
33
33
 
34
34
  smtp.send_mail(<<-EOS, @sender, *@recipients)
35
- From: Murakumo Notifier <#{@sender}>
35
+ From: Murakumo Health Check Notifier <#{@sender}>
36
36
  To: #{@recipients.join(', ')}
37
- Subject: #{@name}/#{@address} => #{status}
37
+ Subject: [Health] #{@name}/#{@address} => #{status}
38
38
  Date: #{Time.now.rfc2822}
39
39
 
40
40
  Address: #{@address}
@@ -48,7 +48,7 @@ Status: #{status}
48
48
  @logger.info("sent the notice: #{status}")
49
49
  rescue Exception => e
50
50
  message = (["#{e.class}: #{e.message}"] + (e.backtrace || [])).join("\n\tfrom ")
51
- @logger.error("healthcheck failed: #{@name}: #{message}")
51
+ @logger.error("health check failed: #{@name}: #{message}")
52
52
  end
53
53
 
54
54
  end # HealthCheckNotifier
@@ -18,16 +18,8 @@ module Murakumo
18
18
  @options = options
19
19
 
20
20
  # 各種変数の設定
21
- {
22
- 'interval' => [30, 1, 300],
23
- 'timeout' => [ 5, 1, 300],
24
- 'healthy' => [10, 2, 10],
25
- 'unhealthy' => [ 2, 2, 10],
26
- }.each {|key, vals|
27
- defval, min, max = vals
28
- value = (options[key] || defval).to_i
29
- value = min if value < min
30
- value = max if value > max
21
+ ['interval', 'timeout', 'healthy', 'unhealthy'].each {|key|
22
+ value = options[key]
31
23
  instance_variable_set("@#{key}", value)
32
24
  }
33
25
 
@@ -87,10 +79,10 @@ module Murakumo
87
79
  case activity
88
80
  when ACTIVE
89
81
  @notifier.notify_active if @notifier
90
- handle_event(@on_activate, 'Active') if @on_activate
82
+ handle_event(@on_activate, 'healthy') if @on_activate
91
83
  when INACTIVE
92
84
  @notifier.notify_inactive if @notifier
93
- handle_event(@on_inactivate, 'Inactive') if @on_inactivate
85
+ handle_event(@on_inactivate, 'unhealthy') if @on_inactivate
94
86
  end
95
87
  end
96
88
 
@@ -110,9 +102,6 @@ module Murakumo
110
102
  end
111
103
 
112
104
  @thread = Thread.start {
113
- healthy = 0
114
- unhealthy = 0
115
-
116
105
  begin
117
106
  while @alive
118
107
  retval = nil
@@ -126,7 +115,7 @@ module Murakumo
126
115
  rescue => e
127
116
  retval = false
128
117
  message = (["#{e.class}: #{e.message}"] + (e.backtrace || [])).join("\n\tfrom ")
129
- @logger.error("healthcheck failed: #{@name}: #{message}")
118
+ @logger.error("health check failed: #{@name}: #{message}")
130
119
  end
131
120
 
132
121
  status = retval == true ? 'good' : retval == false ? 'bad' : '-'
@@ -0,0 +1,108 @@
1
+ require 'net/http'
2
+ require 'rexml/document'
3
+
4
+ require 'util/murakumo_ec2_client'
5
+ require 'util/murakumo_ec2_interfaces'
6
+
7
+ module Murakumo
8
+
9
+ class Util
10
+ WAIT_LIMIT = 99
11
+ WAIT_INTERVAL = 0.3
12
+
13
+ def self.ec2_attach_interface(access_key, secret_key, if_id, dev_idx = 1, endpoint = nil, instance_id = nil)
14
+ dev_idx = 1 unless dev_idx
15
+
16
+ unless instance_id
17
+ instance_id = Net::HTTP.get('169.254.169.254', '/latest/meta-data/instance-id')
18
+ end
19
+
20
+ check_own_attached(access_key, secret_key, endpoint, if_id, instance_id)
21
+
22
+ ec2_detach_interface(access_key, secret_key, if_id, endpoint, :force) rescue nil
23
+
24
+ wait_detach(access_key, secret_key, endpoint, if_id)
25
+
26
+ ec2cli = Murakumo::Util::EC2Client.new(access_key, secret_key, endpoint)
27
+ source = ec2cli.query('AttachNetworkInterface',
28
+ 'NetworkInterfaceId' => if_id, 'InstanceId' => instance_id, 'DeviceIndex' => dev_idx)
29
+
30
+ errors = []
31
+
32
+ REXML::Document.new(source).each_element('//Errors/Error') do |element|
33
+ code = element.text('Code')
34
+ message = element.text('Message')
35
+ errors << "#{code}:#{message}"
36
+ end
37
+
38
+ raise errors.join(', ') unless errors.empty?
39
+ end
40
+
41
+ def self.ec2_detach_interface(access_key, secret_key, if_id, endpoint = nil, force = false)
42
+ interfaces = ec2_interfaces(access_key, secret_key, endpoint, if_id)
43
+
44
+ if not interfaces or interfaces.empty?
45
+ raise 'interface was not found'
46
+ end
47
+
48
+ interface = interfaces.first
49
+ attachment_id = (interface['attachment'] || {})['attachmentId'] || ''
50
+
51
+ if attachment_id.empty?
52
+ raise 'attachmentId was not found'
53
+ end
54
+
55
+ ec2cli = Murakumo::Util::EC2Client.new(access_key, secret_key, endpoint)
56
+
57
+ params = {'AttachmentId' => attachment_id}
58
+ params['Force'] = true if force
59
+ source = ec2cli.query('DetachNetworkInterface', params)
60
+
61
+ errors = []
62
+
63
+ REXML::Document.new(source).each_element('//Errors/Error') do |element|
64
+ code = element.text('Code')
65
+ message = element.text('Message')
66
+ errors << "#{code}:#{message}"
67
+ end
68
+
69
+ raise errors.join(', ') unless errors.empty?
70
+ end
71
+
72
+ def self.check_own_attached(access_key, secret_key, endpoint, if_id, instance_id)
73
+ interfaces = ec2_interfaces(access_key, secret_key, endpoint, if_id)
74
+
75
+ if not interfaces or interfaces.empty?
76
+ raise 'interface was not found'
77
+ end
78
+
79
+ interface = interfaces.first
80
+
81
+ if (interface['attachment'] || {})['instanceId'] == instance_id
82
+ raise 'interface is already attached'
83
+ end
84
+ end
85
+ private_class_method :check_own_attached
86
+
87
+ def self.wait_detach(access_key, secret_key, endpoint, if_id)
88
+ WAIT_LIMIT.times do
89
+ interfaces = ec2_interfaces(access_key, secret_key, endpoint, if_id)
90
+
91
+ if not interfaces or interfaces.empty?
92
+ raise 'interface was not found'
93
+ end
94
+
95
+ interface = interfaces.first
96
+
97
+ return if interface['status'] == 'available'
98
+
99
+ sleep WAIT_INTERVAL
100
+ end
101
+
102
+ raise 'cannot detach interface'
103
+ end
104
+ private_class_method :wait_detach
105
+
106
+ end # Util
107
+
108
+ end # Murakumo
@@ -11,10 +11,11 @@ module Murakumo
11
11
 
12
12
  class EC2Client
13
13
 
14
- API_VERSION = '2011-12-01'
14
+ API_VERSION = '2011-12-15'
15
15
  SIGNATURE_VERSION = 2
16
+ SIGNATURE_ALGORITHM = :SHA256
16
17
 
17
- def initialize(accessKeyId, secretAccessKey, endpoint = nil, algorithm = :SHA256)
18
+ def initialize(accessKeyId, secretAccessKey, endpoint = nil)
18
19
  unless endpoint
19
20
  local_hostname = Net::HTTP.get('169.254.169.254', '/latest/meta-data/local-hostname')
20
21
 
@@ -28,7 +29,6 @@ module Murakumo
28
29
  @accessKeyId = accessKeyId
29
30
  @secretAccessKey = secretAccessKey
30
31
  @endpoint = endpoint
31
- @algorithm = algorithm
32
32
 
33
33
  if /\A[^.]+\Z/ =~ @endpoint
34
34
  @endpoint = "ec2.#{@endpoint}.amazonaws.com"
@@ -41,7 +41,7 @@ module Murakumo
41
41
  :Version => API_VERSION,
42
42
  :Timestamp => Time.now.getutc.strftime('%Y-%m-%dT%H:%M:%SZ'),
43
43
  :SignatureVersion => SIGNATURE_VERSION,
44
- :SignatureMethod => "Hmac#{@algorithm}",
44
+ :SignatureMethod => "Hmac#{SIGNATURE_ALGORITHM}",
45
45
  :AWSAccessKeyId => @accessKeyId,
46
46
  }.merge(params)
47
47
 
@@ -69,7 +69,7 @@ module Murakumo
69
69
  def aws_sign(params)
70
70
  params = params.sort_by {|a, b| a.to_s }.map {|k, v| "#{CGI.escape(k.to_s)}=#{CGI.escape(v.to_s)}" }.join('&')
71
71
  string_to_sign = "POST\n#{@endpoint}\n/\n#{params}"
72
- digest = OpenSSL::HMAC.digest(OpenSSL::Digest.const_get(@algorithm).new, @secretAccessKey, string_to_sign)
72
+ digest = OpenSSL::HMAC.digest(OpenSSL::Digest.const_get(SIGNATURE_ALGORITHM).new, @secretAccessKey, string_to_sign)
73
73
  Base64.encode64(digest).gsub("\n", '')
74
74
  end
75
75
  end
@@ -0,0 +1,59 @@
1
+ require 'net/http'
2
+ require 'rexml/document'
3
+
4
+ require 'util/murakumo_ec2_client'
5
+
6
+ module Murakumo
7
+
8
+ class Util
9
+
10
+ def self.ec2_interfaces(access_key, secret_key, endpoint = nil, if_id = nil)
11
+ dev_idx = 1 unless dev_idx
12
+ params = {}
13
+
14
+ if if_id
15
+ params.update('Filter.1.Name' => 'network-interface-id', 'Filter.1.Value' => if_id)
16
+ end
17
+
18
+ ec2cli = Murakumo::Util::EC2Client.new(access_key, secret_key, endpoint)
19
+
20
+ source = ec2cli.query('DescribeNetworkInterfaces', params)
21
+ interfaces = []
22
+
23
+ items = REXML::Document.new(source).get_elements('//networkInterfaceSet/item')
24
+ walk_item_list(items, interfaces)
25
+
26
+ return interfaces
27
+ end
28
+
29
+ def self.walk_item_list(list, ary)
30
+ list.each do |item|
31
+ hash = {}
32
+ walk_item(item, hash)
33
+ ary << hash
34
+ end
35
+ end
36
+ private_class_method :walk_item_list
37
+
38
+ def self.walk_item(item, hash)
39
+ return unless item.has_elements?
40
+
41
+ item.elements.each do |child|
42
+ if child.has_elements?
43
+ if child.elements.all? {|i| i.name =~ /\Aitem\Z/i }
44
+ hash[child.name] = nested = []
45
+ walk_item_list(child.elements, nested)
46
+ else
47
+ hash[child.name] = nested = {}
48
+ walk_item(child, nested)
49
+ end
50
+ else
51
+ hash[child.name] = child.text
52
+ end
53
+ end
54
+ end
55
+ private_class_method :walk_item
56
+
57
+ end # Util
58
+
59
+ end # Murakumo
@@ -0,0 +1,42 @@
1
+ require 'net/http'
2
+ require 'rexml/parsers/pullparser'
3
+
4
+ require 'util/murakumo_ec2_client'
5
+
6
+ module Murakumo
7
+
8
+ class Util
9
+
10
+ def self.ec2_private_ip_addresses(access_key, secret_key, endpoint = nil)
11
+ ec2cli = Murakumo::Util::EC2Client.new(access_key, secret_key, endpoint)
12
+ source = ec2cli.query('DescribeInstances')
13
+
14
+ parser = REXML::Parsers::PullParser.new(source)
15
+ ip_addrs = []
16
+ instance_id = nil
17
+ status = nil
18
+
19
+ while parser.has_next?
20
+ event = parser.pull
21
+ next if event.event_type != :start_element
22
+
23
+ case event[0]
24
+ when 'instanceId'
25
+ instance_id = parser.pull[0]
26
+ when 'instanceState'
27
+ until event.event_type == :start_element and event[0] == 'name'
28
+ event = parser.pull
29
+ end
30
+
31
+ status = parser.pull[0]
32
+ when 'privateIpAddress'
33
+ ip_addrs << [instance_id, parser.pull[0], status]
34
+ end
35
+ end
36
+
37
+ return ip_addrs
38
+ end
39
+
40
+ end # Util
41
+
42
+ 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: 7
4
+ hash: 5
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 4
9
- - 4
10
- version: 0.4.4
9
+ - 5
10
+ version: 0.4.5
11
11
  platform: ruby
12
12
  authors:
13
13
  - winebarrel
@@ -15,8 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2012-01-12 00:00:00 +09:00
19
- default_executable:
18
+ date: 2012-01-22 00:00:00 Z
20
19
  dependencies:
21
20
  - !ruby/object:Gem::Dependency
22
21
  name: rubydns
@@ -42,12 +41,12 @@ dependencies:
42
41
  requirements:
43
42
  - - ">="
44
43
  - !ruby/object:Gem::Version
45
- hash: 11
44
+ hash: 17
46
45
  segments:
47
46
  - 0
48
- - 1
49
- - 8
50
- version: 0.1.8
47
+ - 2
48
+ - 3
49
+ version: 0.2.3
51
50
  type: :runtime
52
51
  version_requirements: *id002
53
52
  - !ruby/object:Gem::Dependency
@@ -91,41 +90,52 @@ executables:
91
90
  - murakumo-show-ip-address
92
91
  - murakumo-show-ec2-tags
93
92
  - murakumo-show-ec2-instances
93
+ - murakumo-show-ec2-private-ip-addresses
94
+ - murakumo-attach-ec2-attach-interface
95
+ - murakumo-show-ec2-interfaces
94
96
  extensions: []
95
97
 
96
98
  extra_rdoc_files: []
97
99
 
98
100
  files:
99
101
  - README
100
- - bin/murakumo-show-ec2-tags
101
- - bin/murakumo-install-init-script
102
102
  - bin/murakumo-show-ec2-instances
103
+ - bin/murakumo-show-ec2-private-ip-addresses
104
+ - bin/murakumo-attach-ec2-attach-interface
103
105
  - bin/murakumo
106
+ - bin/murakumo-show-ec2-tags
104
107
  - bin/murakumo-show-ip-address
108
+ - bin/murakumo-show-ec2-interfaces
109
+ - bin/murakumo-install-init-script
105
110
  - bin/mrkmctl
106
- - lib/misc/murakumo_const.rb
107
- - lib/srv/murakumo_health_check_context.rb
108
- - lib/srv/murakumo_balancer.rb
109
- - lib/srv/murakumo_cloud.rb
110
- - lib/srv/murakumo_health_check_notifier.rb
111
- - lib/srv/murakumo_health_checker.rb
112
- - lib/srv/murakumo_server.rb
113
- - lib/cli/mrkmctl_options.rb
114
- - lib/cli/murakumo_initializer_context.rb
115
111
  - lib/cli/mrkmctl.rb
116
112
  - lib/cli/murakumo.rb
117
113
  - lib/cli/murakumo_options.rb
114
+ - lib/cli/murakumo_initializer_context.rb
115
+ - lib/cli/mrkmctl_options.rb
116
+ - lib/misc/murakumo_const.rb
117
+ - lib/util/murakumo_ec2_private_ip_addresses.rb
118
118
  - lib/util/murakumo_ec2_instances.rb
119
- - lib/util/murakumo_self_ip_address.rb
120
119
  - lib/util/murakumo_ec2_tags.rb
120
+ - lib/util/murakumo_ec2_interfaces.rb
121
+ - lib/util/murakumo_self_ip_address.rb
122
+ - lib/util/murakumo_ec2_attach_interface.rb
121
123
  - lib/util/murakumo_ec2_client.rb
124
+ - lib/srv/murakumo_health_check_context.rb
125
+ - lib/srv/murakumo_server.rb
126
+ - lib/srv/murakumo_health_check_notifier.rb
127
+ - lib/srv/murakumo_activity_check_notifier.rb
128
+ - lib/srv/murakumo_activity_checker.rb
129
+ - lib/srv/murakumo_health_checker.rb
130
+ - lib/srv/murakumo_balancer.rb
131
+ - lib/srv/murakumo_cloud.rb
132
+ - etc/murakumo.server
122
133
  - etc/murakumo-init.rb.for-ec2
134
+ - etc/murakumo.yml.example
123
135
  - etc/gai.conf.example
124
- - etc/murakumo.server
125
- - etc/dhclient-script.patch
126
136
  - etc/murakumo-update-config-for-ec2
127
- - etc/murakumo.yml.example
128
- has_rdoc: true
137
+ - etc/attach_if.sh.example
138
+ - etc/dhclient-script.patch
129
139
  homepage: https://github.com/cookpad/murakumo/wiki
130
140
  licenses: []
131
141
 
@@ -155,7 +165,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
155
165
  requirements: []
156
166
 
157
167
  rubyforge_project:
158
- rubygems_version: 1.5.3
168
+ rubygems_version: 1.8.15
159
169
  signing_key:
160
170
  specification_version: 3
161
171
  summary: Murakumo is the internal DNS server which manages name information using a gossip protocol.