ey_cloud_server 1.0.1 → 1.1.1.pre5
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/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
|
-
|