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.
- data/bin/murakumo-attach-ec2-attach-interface +38 -0
- data/bin/murakumo-show-ec2-instances +15 -10
- data/bin/murakumo-show-ec2-interfaces +36 -0
- data/bin/murakumo-show-ec2-private-ip-addresses +37 -0
- data/bin/murakumo-show-ec2-tags +16 -11
- data/etc/attach_if.sh.example +12 -0
- data/etc/murakumo-init.rb.for-ec2 +9 -5
- data/etc/murakumo.server +48 -0
- data/etc/murakumo.yml.example +65 -17
- data/lib/cli/murakumo_initializer_context.rb +3 -0
- data/lib/cli/murakumo_options.rb +78 -0
- data/lib/misc/murakumo_const.rb +1 -1
- data/lib/srv/murakumo_activity_check_notifier.rb +55 -0
- data/lib/srv/murakumo_activity_checker.rb +198 -0
- data/lib/srv/murakumo_cloud.rb +64 -1
- data/lib/srv/murakumo_health_check_notifier.rb +5 -5
- data/lib/srv/murakumo_health_checker.rb +5 -16
- data/lib/util/murakumo_ec2_attach_interface.rb +108 -0
- data/lib/util/murakumo_ec2_client.rb +5 -5
- data/lib/util/murakumo_ec2_interfaces.rb +59 -0
- data/lib/util/murakumo_ec2_private_ip_addresses.rb +42 -0
- metadata +36 -26
@@ -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
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
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
|
data/bin/murakumo-show-ec2-tags
CHANGED
@@ -11,17 +11,22 @@ endpoint = nil
|
|
11
11
|
instance_id = nil
|
12
12
|
|
13
13
|
ARGV.options do |opt|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
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
|
-
|
2
|
-
|
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(
|
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
|
-
|
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 =
|
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?
|
data/etc/murakumo.server
CHANGED
@@ -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
|
data/etc/murakumo.yml.example
CHANGED
@@ -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
|
|
data/lib/cli/murakumo_options.rb
CHANGED
@@ -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|
|
data/lib/misc/murakumo_const.rb
CHANGED
@@ -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
|
data/lib/srv/murakumo_cloud.rb
CHANGED
@@ -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('
|
21
|
+
notify('healthy', "#{@name} became healthy :-)")
|
22
22
|
end
|
23
23
|
|
24
24
|
def notify_inactive
|
25
|
-
notify('
|
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("
|
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
|
-
|
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, '
|
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, '
|
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("
|
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-
|
14
|
+
API_VERSION = '2011-12-15'
|
15
15
|
SIGNATURE_VERSION = 2
|
16
|
+
SIGNATURE_ALGORITHM = :SHA256
|
16
17
|
|
17
|
-
def initialize(accessKeyId, secretAccessKey, endpoint = nil
|
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#{
|
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(
|
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:
|
4
|
+
hash: 5
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 4
|
9
|
-
-
|
10
|
-
version: 0.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-
|
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:
|
44
|
+
hash: 17
|
46
45
|
segments:
|
47
46
|
- 0
|
48
|
-
-
|
49
|
-
-
|
50
|
-
version: 0.
|
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/
|
128
|
-
|
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.
|
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.
|