ey_cloud_awareness 0.1.7 → 0.1.8
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +79 -32
- data/VERSION +1 -1
- data/ey_cloud_awareness.gemspec +1 -1
- data/lib/engine_yard_cloud_instance.rb +25 -2
- data/lib/tasks/capistrano_tasks.rb +25 -9
- metadata +1 -1
data/README.rdoc
CHANGED
@@ -1,8 +1,12 @@
|
|
1
1
|
= ey_cloud_awareness
|
2
2
|
|
3
|
-
|
3
|
+
This gem makes it a little easier to live on the EngineYard cloud:
|
4
4
|
|
5
|
-
|
5
|
+
* automatically run cap tasks on all your instances
|
6
|
+
* automatically update your ssh aliases
|
7
|
+
* allow your app to get information about the cluster (aka "environment") it's running in
|
8
|
+
|
9
|
+
We use it over at http://brighterplanet.com.
|
6
10
|
|
7
11
|
== Quick start
|
8
12
|
|
@@ -10,22 +14,23 @@ Put this in <tt>config/environment.rb</tt>:
|
|
10
14
|
|
11
15
|
config.gem 'ey_cloud_awareness', :version => '[WHATEVER THE CURRENT GEM VERSION IS]', :lib => false, :source => 'http://gemcutter.org'
|
12
16
|
|
13
|
-
Put this in your <tt>config/deploy.rb</tt> (or
|
17
|
+
Put this in your <tt>config/deploy.rb</tt> (or whereever your Capfile is):
|
14
18
|
|
19
|
+
# don't miss this line just because it's at the top
|
15
20
|
load "#{Gem.searcher.find('ey_cloud_awareness').full_gem_path}/lib/tasks/capistrano_tasks.rb"
|
16
21
|
|
17
|
-
task :
|
22
|
+
task :my_production do
|
18
23
|
role :app_master, 'my_app.com' # or you can use its Elastic IP
|
19
24
|
set :rails_env, 'production' # required
|
20
25
|
set :deploy_to, '/data/my_app' # required
|
21
|
-
find_and_execute_task 'eyc_setup' #
|
26
|
+
find_and_execute_task 'eyc_setup' # required
|
22
27
|
end
|
23
28
|
|
24
|
-
task :
|
29
|
+
task :my_staging do
|
25
30
|
role :app_master, 'staging.my_app.com' # or you can use its Elastic IP
|
26
31
|
set :rails_env, 'production' # required
|
27
32
|
set :deploy_to, '/data/my_app' # required
|
28
|
-
find_and_execute_task 'eyc_setup' #
|
33
|
+
find_and_execute_task 'eyc_setup' # required
|
29
34
|
end
|
30
35
|
|
31
36
|
# add more tasks if you have more cloud environments
|
@@ -34,48 +39,90 @@ That should be all.
|
|
34
39
|
|
35
40
|
== Running capistrano tasks on your instances
|
36
41
|
|
37
|
-
|
42
|
+
Run <tt>monit:status</tt> on all the slices in the environment <tt>my_production</tt>:
|
43
|
+
|
44
|
+
cap my_production monit:status
|
38
45
|
|
39
|
-
|
46
|
+
Or you could run <tt>nginx:restart</tt> for <tt>my_staging</tt>:
|
40
47
|
|
41
|
-
|
48
|
+
cap my_staging nginx:restart
|
49
|
+
|
50
|
+
Your capistrano tasks will always have a fresh list of your environment's instances. Roles like <tt>:app</tt> and <tt>:db</tt> are set (so are <tt>:app_master</tt>, <tt>:db_master</tt>, and <tt>:utility</tt>, but you probably don't need those).
|
42
51
|
|
43
52
|
== SSH into your instances
|
44
53
|
|
45
|
-
|
54
|
+
Let's say you want to ssh into...
|
46
55
|
|
47
|
-
|
56
|
+
ssh my_production-app_master
|
48
57
|
|
49
|
-
|
58
|
+
Well, you need to keep your <tt>~/.ssh/config</tt> up-to-date. Easy!
|
50
59
|
|
51
|
-
|
60
|
+
cap my_production eyc:ssh
|
52
61
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
+
That will magically add or update a block like
|
63
|
+
|
64
|
+
# START StringReplacer my_production -- DO NOT MODIFY
|
65
|
+
|
66
|
+
# db_master
|
67
|
+
Host my_production-db_master
|
68
|
+
Hostname ec2-222-222-222-59.compute-1.amazonaws.com
|
69
|
+
User my_user
|
70
|
+
StrictHostKeyChecking no
|
71
|
+
|
72
|
+
# utility (1)
|
73
|
+
Host my_production-utility1
|
74
|
+
Hostname ec2-222-222-53-222.compute-1.amazonaws.com
|
75
|
+
User my_user
|
76
|
+
StrictHostKeyChecking no
|
77
|
+
|
78
|
+
# app_master
|
79
|
+
Host my_production-app_master
|
80
|
+
Hostname ec2-222-222-23-222.compute-1.amazonaws.com
|
81
|
+
User my_user
|
82
|
+
StrictHostKeyChecking no
|
83
|
+
|
84
|
+
# END StringReplacer my_production -- DO NOT MODIFY
|
85
|
+
|
86
|
+
Run that again as
|
87
|
+
|
88
|
+
cap my_staging eyc:ssh
|
89
|
+
|
90
|
+
... and it adds
|
91
|
+
|
92
|
+
# START StringReplacer my_staging -- DO NOT MODIFY
|
93
|
+
|
94
|
+
# app_master
|
95
|
+
Host my_staging-app_master
|
96
|
+
Hostname ec2-222-222-7-210.compute-1.amazonaws.com
|
97
|
+
User my_user
|
98
|
+
StrictHostKeyChecking no
|
99
|
+
|
100
|
+
# db_master
|
101
|
+
Host my_staging-db_master
|
102
|
+
Hostname ec2-222-222-52-8.compute-1.amazonaws.com
|
103
|
+
User my_user
|
104
|
+
StrictHostKeyChecking no
|
62
105
|
|
63
|
-
# END StringReplacer
|
106
|
+
# END StringReplacer my_staging -- DO NOT MODIFY
|
64
107
|
|
65
|
-
|
108
|
+
This leaves you with lots of useful aliases:
|
66
109
|
|
67
|
-
ssh
|
110
|
+
ssh my_production-db_master
|
111
|
+
ssh my_production-app_master
|
112
|
+
ssh my_production-utility1
|
113
|
+
ssh my_staging-app_master
|
114
|
+
ssh my_staging-db_master
|
68
115
|
|
69
|
-
Note that
|
116
|
+
Note that the numbers after app [slaves], db [slaves], and utility [slaves] may change every time you run the task.
|
70
117
|
|
71
118
|
== Just dumping information about your instances
|
72
119
|
|
73
120
|
Once you've done the quickstart, try:
|
74
121
|
|
75
|
-
cap
|
76
|
-
cap
|
77
|
-
cap
|
78
|
-
cap
|
122
|
+
cap my_production eyc:app # gets a list of your app instances, including app_master
|
123
|
+
cap my_production eyc:utility # ditto for utility instances
|
124
|
+
cap my_production eyc:db # ditto for db instances
|
125
|
+
cap my_production eyc:all # gets a list of all your instances
|
79
126
|
|
80
127
|
== Using the EngineYardCloudInstance class inside Rails
|
81
128
|
|
@@ -96,7 +143,7 @@ Or whatever you want:
|
|
96
143
|
>> pp all_app_instances.first.to_hash
|
97
144
|
{:dns_name=>"ec2-67-202-43-40.compute-1.amazonaws.com",
|
98
145
|
:instance_role=>"app",
|
99
|
-
:aws_groups=>["ey-
|
146
|
+
:aws_groups=>["ey-my_production-1256085955-3205-13340"],
|
100
147
|
:aws_instance_id=>"i-50cf5838",
|
101
148
|
:private_dns_name=>"domU-12-31-39-01-99-D3.compute-1.internal",
|
102
149
|
:aws_state=>"running"}
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.8
|
data/ey_cloud_awareness.gemspec
CHANGED
@@ -34,6 +34,10 @@ class EngineYardCloudInstance
|
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
37
|
+
def ==(other)
|
38
|
+
self.instance_id == other.instance_id
|
39
|
+
end
|
40
|
+
|
37
41
|
class_inheritable_accessor :proxy
|
38
42
|
|
39
43
|
class << self
|
@@ -48,12 +52,24 @@ class EngineYardCloudInstance
|
|
48
52
|
self
|
49
53
|
end
|
50
54
|
|
55
|
+
def environment
|
56
|
+
@_environment ||= first.environment
|
57
|
+
end
|
58
|
+
|
59
|
+
def app_master
|
60
|
+
find_all_by_instance_roles(:app_master).first
|
61
|
+
end
|
62
|
+
|
63
|
+
def db_master
|
64
|
+
find_all_by_instance_roles(:db_master).first
|
65
|
+
end
|
66
|
+
|
51
67
|
def app
|
52
68
|
find_all_by_instance_roles :app, :app_master
|
53
69
|
end
|
54
70
|
|
55
71
|
def db
|
56
|
-
find_all_by_instance_roles :
|
72
|
+
find_all_by_instance_roles :db_master, :db_slave
|
57
73
|
end
|
58
74
|
|
59
75
|
def utility
|
@@ -64,6 +80,10 @@ class EngineYardCloudInstance
|
|
64
80
|
data.map { |k, _| new k }
|
65
81
|
end
|
66
82
|
|
83
|
+
def with_roles
|
84
|
+
all.reject { |i| i.instance_role == 'unknown' }
|
85
|
+
end
|
86
|
+
|
67
87
|
def current
|
68
88
|
new cached_current_instance_id
|
69
89
|
end
|
@@ -99,7 +119,7 @@ class EngineYardCloudInstance
|
|
99
119
|
current = hash[instance_description[:aws_instance_id]]
|
100
120
|
# using current as a pointer
|
101
121
|
if dna[:db_host] == instance_description[:dns_name] or dna[:db_host] == instance_description[:private_dns_name]
|
102
|
-
current[:instance_role] = '
|
122
|
+
current[:instance_role] = 'db_master'
|
103
123
|
elsif Array.wrap(dna[:db_slaves]).include? instance_description[:private_dns_name]
|
104
124
|
current[:instance_role] = 'db_slave'
|
105
125
|
elsif Array.wrap(dna[:utility_instances]).include? instance_description[:private_dns_name]
|
@@ -108,6 +128,8 @@ class EngineYardCloudInstance
|
|
108
128
|
current[:instance_role] = 'app_master'
|
109
129
|
elsif instance_description[:aws_state] == 'running'
|
110
130
|
current[:instance_role] = 'app'
|
131
|
+
else
|
132
|
+
current[:instance_role] = 'unknown'
|
111
133
|
end
|
112
134
|
current[:private_dns_name] = instance_description[:private_dns_name]
|
113
135
|
current[:dns_name] = instance_description[:dns_name]
|
@@ -116,6 +138,7 @@ class EngineYardCloudInstance
|
|
116
138
|
current[:aws_instance_id] = instance_description[:aws_instance_id]
|
117
139
|
current[:users] = dna[:users]
|
118
140
|
current[:environment] = dna[:environment]
|
141
|
+
@_environment ||= dna[:environment]
|
119
142
|
end
|
120
143
|
@_data = hash.recursive_symbolize_keys!
|
121
144
|
end
|
@@ -26,6 +26,7 @@ task :eyc_setup, :roles => :app_master do
|
|
26
26
|
$stderr.puts output
|
27
27
|
raise
|
28
28
|
end
|
29
|
+
role :db_master, eyc_proxy.db_master.dns_name
|
29
30
|
eyc_proxy.app.each { |i| role :app, i.dns_name }
|
30
31
|
eyc_proxy.db.each { |i| role :db, i.dns_name }
|
31
32
|
end
|
@@ -38,6 +39,7 @@ namespace :eyc do
|
|
38
39
|
end
|
39
40
|
end
|
40
41
|
|
42
|
+
# Used by the eyc:ssh cap task to insert host information into ~/.ssh/config
|
41
43
|
class StringReplacer
|
42
44
|
NEWLINE = "AijQA6tD1wkWqgvLzXD"
|
43
45
|
START_MARKER = '# START StringReplacer %s -- DO NOT MODIFY'
|
@@ -70,18 +72,32 @@ end
|
|
70
72
|
namespace :eyc do
|
71
73
|
task :ssh, :roles => :app_master do
|
72
74
|
replacement = []
|
73
|
-
|
74
|
-
|
75
|
-
|
75
|
+
eyc_proxy.with_roles.each_with_index do |instance, index|
|
76
|
+
case instance.instance_role
|
77
|
+
when 'db_master'
|
78
|
+
explanation = ''
|
79
|
+
shorthand = 'db_master'
|
80
|
+
when 'app_master'
|
81
|
+
explanation = ''
|
82
|
+
shorthand = 'app_master'
|
83
|
+
else
|
84
|
+
explanation = " (#{index})"
|
85
|
+
shorthand = "#{instance.instance_role}#{index}"
|
86
|
+
end
|
76
87
|
replacement << %{
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
88
|
+
# #{instance.instance_role}#{explanation}
|
89
|
+
Host #{eyc_proxy.environment[:name]}-#{shorthand}
|
90
|
+
Hostname #{instance.dns_name}
|
91
|
+
User #{instance.users.first[:username]}
|
92
|
+
StrictHostKeyChecking no
|
81
93
|
}
|
82
94
|
end
|
83
95
|
replacement = replacement.join
|
84
|
-
|
85
|
-
r.
|
96
|
+
ssh_config_path = File.expand_path("~/.ssh/config")
|
97
|
+
r = StringReplacer.new ssh_config_path
|
98
|
+
r.replace! replacement, eyc_proxy.environment[:name]
|
99
|
+
|
100
|
+
$stderr.puts "[EY CLOUD AWARENESS GEM] Added this to #{ssh_config_path}"
|
101
|
+
$stderr.puts replacement
|
86
102
|
end
|
87
103
|
end
|