ey_cloud_server 1.0.1 → 1.1.1.pre5
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/ey-flex/version.rb +1 -1
- data/lib/ey-flex.rb +0 -5
- metadata +52 -42
- data/bin/ey-monitor +0 -5
- data/lib/ey-flex/ey-api.rb +0 -21
- data/lib/ey-flex/stonith.rb +0 -190
data/lib/ey-flex/version.rb
CHANGED
data/lib/ey-flex.rb
CHANGED
@@ -4,12 +4,9 @@ require 'date'
|
|
4
4
|
require 'digest'
|
5
5
|
require 'net/http'
|
6
6
|
require 'fileutils'
|
7
|
-
require 'eventmachine'
|
8
|
-
require 'em-http'
|
9
7
|
require 'json/ext'
|
10
8
|
require 'right_aws'
|
11
9
|
require 'open-uri'
|
12
|
-
require 'rest_client'
|
13
10
|
require 'dbi'
|
14
11
|
require 'zlib'
|
15
12
|
require 'stringio'
|
@@ -29,9 +26,7 @@ end
|
|
29
26
|
require lib_dir + '/big-brother'
|
30
27
|
require lib_dir + '/backups'
|
31
28
|
require lib_dir + '/bucket_minder'
|
32
|
-
require lib_dir + '/ey-api'
|
33
29
|
require lib_dir + '/mysql_database'
|
34
30
|
require lib_dir + '/postgresql_database'
|
35
31
|
require lib_dir + '/snapshot_minder'
|
36
|
-
require lib_dir + '/stonith'
|
37
32
|
require lib_dir + '/version'
|
metadata
CHANGED
@@ -1,7 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ey_cloud_server
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
prerelease: true
|
5
|
+
segments:
|
6
|
+
- 1
|
7
|
+
- 1
|
8
|
+
- 1
|
9
|
+
- pre5
|
10
|
+
version: 1.1.1.pre5
|
5
11
|
platform: ruby
|
6
12
|
authors:
|
7
13
|
- Ezra Zygmuntowicz
|
@@ -9,75 +15,77 @@ autorequire:
|
|
9
15
|
bindir: bin
|
10
16
|
cert_chain: []
|
11
17
|
|
12
|
-
date: 2010-
|
18
|
+
date: 2010-04-14 00:00:00 -07:00
|
13
19
|
default_executable:
|
14
20
|
dependencies:
|
15
21
|
- !ruby/object:Gem::Dependency
|
16
|
-
name: json
|
17
22
|
type: :runtime
|
18
|
-
|
19
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
version_requirements: &id001 !ruby/object:Gem::Requirement
|
20
24
|
requirements:
|
21
25
|
- - ">="
|
22
26
|
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 0
|
23
29
|
version: "0"
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
type: :runtime
|
28
|
-
version_requirement:
|
29
|
-
version_requirements: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - ">="
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: "0"
|
34
|
-
version:
|
30
|
+
requirement: *id001
|
31
|
+
name: json
|
32
|
+
prerelease: false
|
35
33
|
- !ruby/object:Gem::Dependency
|
36
|
-
name: open4
|
37
34
|
type: :runtime
|
38
|
-
|
39
|
-
version_requirements: !ruby/object:Gem::Requirement
|
35
|
+
version_requirements: &id002 !ruby/object:Gem::Requirement
|
40
36
|
requirements:
|
41
37
|
- - ">="
|
42
38
|
- !ruby/object:Gem::Version
|
39
|
+
segments:
|
40
|
+
- 0
|
43
41
|
version: "0"
|
44
|
-
|
42
|
+
requirement: *id002
|
43
|
+
name: right_aws
|
44
|
+
prerelease: false
|
45
45
|
- !ruby/object:Gem::Dependency
|
46
|
-
name: aws-s3
|
47
46
|
type: :runtime
|
48
|
-
|
49
|
-
version_requirements: !ruby/object:Gem::Requirement
|
47
|
+
version_requirements: &id003 !ruby/object:Gem::Requirement
|
50
48
|
requirements:
|
51
49
|
- - ">="
|
52
50
|
- !ruby/object:Gem::Version
|
51
|
+
segments:
|
52
|
+
- 0
|
53
53
|
version: "0"
|
54
|
-
|
54
|
+
requirement: *id003
|
55
|
+
name: open4
|
56
|
+
prerelease: false
|
55
57
|
- !ruby/object:Gem::Dependency
|
56
|
-
name: igrigorik-em-http-request
|
57
58
|
type: :runtime
|
58
|
-
|
59
|
-
version_requirements: !ruby/object:Gem::Requirement
|
59
|
+
version_requirements: &id004 !ruby/object:Gem::Requirement
|
60
60
|
requirements:
|
61
61
|
- - ">="
|
62
62
|
- !ruby/object:Gem::Version
|
63
|
+
segments:
|
64
|
+
- 0
|
63
65
|
version: "0"
|
64
|
-
|
66
|
+
requirement: *id004
|
67
|
+
name: aws-s3
|
68
|
+
prerelease: false
|
65
69
|
- !ruby/object:Gem::Dependency
|
66
|
-
name: rest-client
|
67
70
|
type: :runtime
|
68
|
-
|
69
|
-
version_requirements: !ruby/object:Gem::Requirement
|
71
|
+
version_requirements: &id005 !ruby/object:Gem::Requirement
|
70
72
|
requirements:
|
71
|
-
- - "
|
73
|
+
- - "="
|
72
74
|
- !ruby/object:Gem::Version
|
73
|
-
|
74
|
-
|
75
|
+
segments:
|
76
|
+
- 0
|
77
|
+
- 1
|
78
|
+
- 5
|
79
|
+
- pre
|
80
|
+
version: 0.1.5.pre
|
81
|
+
requirement: *id005
|
82
|
+
name: ey_stonith
|
83
|
+
prerelease: false
|
75
84
|
description: Server side components for Engine Yard's cloud
|
76
85
|
email: awsmdev@engineyard.com
|
77
86
|
executables:
|
78
87
|
- eybackup
|
79
88
|
- ey-snapshots
|
80
|
-
- ey-monitor
|
81
89
|
- ey-agent
|
82
90
|
extensions: []
|
83
91
|
|
@@ -90,11 +98,9 @@ files:
|
|
90
98
|
- lib/ey-flex/backups.rb
|
91
99
|
- lib/ey-flex/big-brother.rb
|
92
100
|
- lib/ey-flex/bucket_minder.rb
|
93
|
-
- lib/ey-flex/ey-api.rb
|
94
101
|
- lib/ey-flex/mysql_database.rb
|
95
102
|
- lib/ey-flex/postgresql_database.rb
|
96
103
|
- lib/ey-flex/snapshot_minder.rb
|
97
|
-
- lib/ey-flex/stonith.rb
|
98
104
|
- lib/ey-flex/version.rb
|
99
105
|
- lib/ey-flex.rb
|
100
106
|
has_rdoc: true
|
@@ -110,18 +116,22 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
110
116
|
requirements:
|
111
117
|
- - ">="
|
112
118
|
- !ruby/object:Gem::Version
|
119
|
+
segments:
|
120
|
+
- 0
|
113
121
|
version: "0"
|
114
|
-
version:
|
115
122
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
116
123
|
requirements:
|
117
|
-
- - "
|
124
|
+
- - ">"
|
118
125
|
- !ruby/object:Gem::Version
|
119
|
-
|
120
|
-
|
126
|
+
segments:
|
127
|
+
- 1
|
128
|
+
- 3
|
129
|
+
- 1
|
130
|
+
version: 1.3.1
|
121
131
|
requirements: []
|
122
132
|
|
123
133
|
rubyforge_project:
|
124
|
-
rubygems_version: 1.3.
|
134
|
+
rubygems_version: 1.3.6
|
125
135
|
signing_key:
|
126
136
|
specification_version: 3
|
127
137
|
summary: Server side components for Engine Yard's cloud
|
data/bin/ey-monitor
DELETED
data/lib/ey-flex/ey-api.rb
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
module EyApi
|
2
|
-
def call_api(path, opts={})
|
3
|
-
JSON.parse(@rest["/api/#{path}"].post(@keys.merge(opts), {"Accept" => "application/json"}))
|
4
|
-
rescue RestClient::RequestFailed => e
|
5
|
-
case e.http_code
|
6
|
-
when 503
|
7
|
-
sleep 10 # Nanite, save us...
|
8
|
-
retry
|
9
|
-
else
|
10
|
-
raise "API call to Engine Yard failed with status #{e.http_code}."
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
def get_envs
|
15
|
-
@_envs ||= call_api("environments")
|
16
|
-
end
|
17
|
-
|
18
|
-
def get_json(instance_id)
|
19
|
-
call_api("json_for_instance", :instance_id => instance_id)
|
20
|
-
end
|
21
|
-
end
|
data/lib/ey-flex/stonith.rb
DELETED
@@ -1,190 +0,0 @@
|
|
1
|
-
module EY
|
2
|
-
class Log
|
3
|
-
def self.write(str)
|
4
|
-
puts str
|
5
|
-
File.open("/root/ey-monitor2.log", "a") do |f|
|
6
|
-
f.write("#{str}\n")
|
7
|
-
end
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
|
-
class Stonith
|
12
|
-
include EyApi
|
13
|
-
|
14
|
-
def self.run
|
15
|
-
opts = YAML::load(File.read("/etc/.mysql.backups.yml"))
|
16
|
-
opts.merge!(YAML::load(File.read("/etc/.ey-cloud.yml")))
|
17
|
-
EventMachine.run {
|
18
|
-
EY::Stonith.new(opts.merge(:heartbeat => 10))
|
19
|
-
}
|
20
|
-
end
|
21
|
-
|
22
|
-
def initialize(opts={})
|
23
|
-
Log.write "Starting up"
|
24
|
-
@opts = opts
|
25
|
-
@rest = RestClient::Resource.new(opts[:api])
|
26
|
-
@keys = {:aws_secret_id => @opts[:aws_secret_id], :aws_secret_key => @opts[:aws_secret_key]}
|
27
|
-
@bad_checks = 0
|
28
|
-
@seen_good_check = false
|
29
|
-
@ec2 = RightAws::Ec2.new(@opts[:aws_secret_id], @opts[:aws_secret_key])
|
30
|
-
@taking_over = false
|
31
|
-
get_local_json
|
32
|
-
get_master_from_json
|
33
|
-
setup_traps
|
34
|
-
start
|
35
|
-
am_i_master?
|
36
|
-
end
|
37
|
-
|
38
|
-
def setup_traps
|
39
|
-
trap("HUP") { cancel_master_check_timer; Log.write "timer canceled, not monitoring until you wake me up again"}
|
40
|
-
trap("USR1") { EM.add_timer(600) { setup_master_check_timer unless am_i_master? }; Log.write "woke up, starting monitoring again in 10 minutes"}
|
41
|
-
end
|
42
|
-
|
43
|
-
def get_mysql_handle
|
44
|
-
DBI.connect("DBI:Mysql:engineyard:#{@json['db_host']}", 'root', @opts[:dbpass])
|
45
|
-
end
|
46
|
-
|
47
|
-
def try_lock(nodename)
|
48
|
-
Log.write("Trying to grab the lock for: #{nodename}")
|
49
|
-
db = get_mysql_handle
|
50
|
-
db.execute("begin")
|
51
|
-
res = db.execute("select master_lock from locks for update")
|
52
|
-
master = res.fetch[0]
|
53
|
-
res.finish
|
54
|
-
got_lock = false
|
55
|
-
if master == @master
|
56
|
-
got_lock = true
|
57
|
-
@master = "http://#{private_dns_name}/haproxy/monitor"
|
58
|
-
db.do("update locks set master_lock = '#{@master}'")
|
59
|
-
else
|
60
|
-
# new master, don't start monitoring till it comes up
|
61
|
-
@seen_good_check = false
|
62
|
-
@taking_over = false
|
63
|
-
@master = master
|
64
|
-
Log.write("Failed to grab lock, relenting: #{nodename}\nmaster is: #{@master}")
|
65
|
-
EM.add_timer(600) { Log.write "restarting monitoring"; setup_master_check_timer }
|
66
|
-
end
|
67
|
-
db.do("commit")
|
68
|
-
db.disconnect
|
69
|
-
got_lock
|
70
|
-
end
|
71
|
-
|
72
|
-
def start
|
73
|
-
setup_master_check_timer
|
74
|
-
EM.add_periodic_timer(300) { get_local_json }
|
75
|
-
end
|
76
|
-
|
77
|
-
def setup_master_check_timer
|
78
|
-
cancel_master_check_timer
|
79
|
-
unless self_monitor_url == @master
|
80
|
-
@check_master_timer = EventMachine::PeriodicTimer.new(@opts[:heartbeat]) { check_master }
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
def cancel_master_check_timer
|
85
|
-
@check_master_timer && @check_master_timer.cancel
|
86
|
-
end
|
87
|
-
|
88
|
-
def check_master
|
89
|
-
http = EventMachine::HttpRequest.new(@master).get :timeout => 10
|
90
|
-
|
91
|
-
http.callback {
|
92
|
-
unless http.response_header.status == 200
|
93
|
-
take_over_as_master
|
94
|
-
else
|
95
|
-
@seen_good_check = true
|
96
|
-
@bad_checks = 0
|
97
|
-
end
|
98
|
-
http.response_header.status
|
99
|
-
}
|
100
|
-
http.errback { |msg, err|
|
101
|
-
take_over_as_master
|
102
|
-
}
|
103
|
-
end
|
104
|
-
|
105
|
-
def take_over_as_master
|
106
|
-
Log.write("Got a bad check: seen good check is #{@seen_good_check.inspect}")
|
107
|
-
@bad_checks += 1
|
108
|
-
if @bad_checks > 5 && @seen_good_check && !@taking_over
|
109
|
-
Log.write "I'm trying to take over!"
|
110
|
-
@taking_over = true
|
111
|
-
cancel_master_check_timer
|
112
|
-
if try_lock(private_dns_name)
|
113
|
-
Log.write("I got the lock!")
|
114
|
-
steal_ip
|
115
|
-
unless notify_awsm
|
116
|
-
timer = EventMachine::PeriodicTimer.new(5) { timer.cancel if notify_awsm }
|
117
|
-
end
|
118
|
-
end
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
def am_i_master?
|
123
|
-
res = false
|
124
|
-
@ec2.describe_addresses.each do |desc|
|
125
|
-
res = true if (desc[:public_ip] == public_ip && desc[:instance_id] == instance_id)
|
126
|
-
end
|
127
|
-
if res
|
128
|
-
db = get_mysql_handle
|
129
|
-
db.execute("begin")
|
130
|
-
rows = db.execute("select master_lock from locks for update")
|
131
|
-
master = rows.fetch[0]
|
132
|
-
rows.finish
|
133
|
-
db.do("update locks set master_lock = '#{self_monitor_url}'")
|
134
|
-
@master = self_monitor_url
|
135
|
-
cancel_master_check_timer
|
136
|
-
db.do("commit")
|
137
|
-
end
|
138
|
-
res
|
139
|
-
end
|
140
|
-
|
141
|
-
def notify_awsm
|
142
|
-
Log.write "Notifying awsm that I won"
|
143
|
-
res = call_api("promote_instance_to_master", :instance_id => instance_id)
|
144
|
-
case res['status']
|
145
|
-
when 'ok'
|
146
|
-
true
|
147
|
-
when 'already_promoted'
|
148
|
-
am_i_master?
|
149
|
-
EM.add_timer(600) { setup_master_check_timer unless am_i_master? }
|
150
|
-
true
|
151
|
-
else
|
152
|
-
false
|
153
|
-
end
|
154
|
-
end
|
155
|
-
|
156
|
-
def instance_id
|
157
|
-
@instance_id ||= open("http://169.254.169.254/latest/meta-data/instance-id").read
|
158
|
-
end
|
159
|
-
|
160
|
-
def private_dns_name
|
161
|
-
@private_dns_name ||= open("http://169.254.169.254/latest/meta-data/local-hostname").read
|
162
|
-
end
|
163
|
-
|
164
|
-
def self_monitor_url
|
165
|
-
"http://#{private_dns_name}/haproxy/monitor"
|
166
|
-
end
|
167
|
-
|
168
|
-
def steal_ip
|
169
|
-
if @ec2.disassociate_address(public_ip)
|
170
|
-
@ec2.associate_address(instance_id, public_ip)
|
171
|
-
end
|
172
|
-
end
|
173
|
-
|
174
|
-
def public_ip
|
175
|
-
@public_ip ||= @json['master_app_server']['public_ip']
|
176
|
-
end
|
177
|
-
|
178
|
-
def get_local_json
|
179
|
-
@json = JSON.parse(File.read("/etc/chef/dna.json"))
|
180
|
-
end
|
181
|
-
|
182
|
-
def get_master_from_json
|
183
|
-
if host = @json['master_app_server']['private_dns_name']
|
184
|
-
@master = "http://#{host}/haproxy/monitor"
|
185
|
-
end
|
186
|
-
end
|
187
|
-
|
188
|
-
end
|
189
|
-
end
|
190
|
-
|