ey_cloud_awareness 0.1.7 → 0.1.8
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/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
|