murakumo 0.4.4 → 0.4.5

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.
@@ -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.