engineyard 1.2.4 → 1.3.0
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/engineyard/cli.rb +8 -7
- data/lib/engineyard/model/environment.rb +53 -37
- data/lib/engineyard/model/instance.rb +30 -6
- data/lib/engineyard/serverside_version.rb +1 -1
- data/lib/engineyard/version.rb +1 -1
- data/spec/ey/deploy_spec.rb +34 -0
- data/spec/ey/rollback_spec.rb +34 -0
- data/spec/support/shared_behavior.rb +14 -7
- metadata +44 -44
data/lib/engineyard/cli.rb
CHANGED
@@ -46,6 +46,8 @@ module EY
|
|
46
46
|
:desc => "Name of the application to deploy"
|
47
47
|
method_option :verbose, :type => :boolean, :aliases => %w(-v),
|
48
48
|
:desc => "Be verbose"
|
49
|
+
method_option :extra_deploy_hook_options, :type => :hash, :default => {},
|
50
|
+
:desc => "Additional options to be made available in deploy hooks (in the 'config' hash)"
|
49
51
|
def deploy
|
50
52
|
app = fetch_app(options[:app])
|
51
53
|
environment = fetch_environment(options[:environment], app)
|
@@ -65,12 +67,7 @@ module EY
|
|
65
67
|
|
66
68
|
EY.ui.info "Beginning deploy for '#{app.name}' in '#{environment.name}' on server..."
|
67
69
|
|
68
|
-
|
69
|
-
# nil means don't do it
|
70
|
-
# true (the lazy default) means do it with the custom command
|
71
|
-
# a string means do it with this specific command
|
72
|
-
|
73
|
-
deploy_options = {}
|
70
|
+
deploy_options = {'extras' => options[:extra_deploy_hook_options]}
|
74
71
|
deploy_options['migrate'] = options['migrate'] if options.has_key?('migrate')
|
75
72
|
deploy_options['verbose'] = options['verbose'] if options.has_key?('verbose')
|
76
73
|
|
@@ -145,6 +142,8 @@ module EY
|
|
145
142
|
:desc => "Name of the application to roll back"
|
146
143
|
method_option :verbose, :type => :boolean, :aliases => %w(-v),
|
147
144
|
:desc => "Be verbose"
|
145
|
+
method_option :extra_deploy_hook_options, :type => :hash, :default => {},
|
146
|
+
:desc => "Additional options to be made available in deploy hooks (in the 'config' hash)"
|
148
147
|
def rollback
|
149
148
|
app = fetch_app(options[:app])
|
150
149
|
env = fetch_environment(options[:environment], app)
|
@@ -152,7 +151,9 @@ module EY
|
|
152
151
|
loudly_check_engineyard_serverside(env)
|
153
152
|
|
154
153
|
EY.ui.info("Rolling back '#{app.name}' in '#{env.name}'")
|
155
|
-
if env.rollback(app,
|
154
|
+
if env.rollback(app,
|
155
|
+
options[:extra_deploy_hook_options],
|
156
|
+
options[:verbose])
|
156
157
|
EY.ui.info "Rollback complete"
|
157
158
|
else
|
158
159
|
raise EY::Error, "Rollback failed"
|
@@ -36,44 +36,17 @@ module EY
|
|
36
36
|
end
|
37
37
|
|
38
38
|
def deploy(app, ref, deploy_options={})
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
# a string means migrate with this specific command
|
45
|
-
|
46
|
-
default_migration_command = config['migration_command'] || 'rake db:migrate --trace'
|
47
|
-
|
48
|
-
migration_from_config = if config.has_key?('migrate')
|
49
|
-
if config['migrate']
|
50
|
-
default_migration_command
|
51
|
-
else
|
52
|
-
nil
|
53
|
-
end
|
54
|
-
else
|
55
|
-
default_migration_command
|
56
|
-
end
|
57
|
-
|
58
|
-
migration_from_command_line = if deploy_options['migrate'].nil?
|
59
|
-
nil
|
60
|
-
elsif deploy_options['migrate'].respond_to?(:to_str)
|
61
|
-
deploy_options['migrate'].to_str
|
62
|
-
else
|
63
|
-
default_migration_command
|
64
|
-
end
|
65
|
-
|
66
|
-
cmd = if deploy_options.has_key?('migrate')
|
67
|
-
migration_from_command_line
|
68
|
-
else
|
69
|
-
migration_from_config
|
70
|
-
end
|
71
|
-
|
72
|
-
app_master!.deploy(app, ref, cmd, config, deploy_options['verbose'])
|
39
|
+
app_master!.deploy(app,
|
40
|
+
ref,
|
41
|
+
migration_command(deploy_options),
|
42
|
+
config.merge(deploy_options['extras']),
|
43
|
+
deploy_options['verbose'])
|
73
44
|
end
|
74
45
|
|
75
|
-
def rollback(app, verbose=false)
|
76
|
-
app_master!.rollback(app,
|
46
|
+
def rollback(app, extra_deploy_hook_options={}, verbose=false)
|
47
|
+
app_master!.rollback(app,
|
48
|
+
config.merge(extra_deploy_hook_options),
|
49
|
+
verbose)
|
77
50
|
end
|
78
51
|
|
79
52
|
def take_down_maintenance_page(app, verbose=false)
|
@@ -151,7 +124,50 @@ module EY
|
|
151
124
|
def shorten_name_for(app)
|
152
125
|
name.gsub(/^#{Regexp.quote(app.name)}_/, '')
|
153
126
|
end
|
127
|
+
|
128
|
+
private
|
129
|
+
|
130
|
+
def migration_command(deploy_options)
|
131
|
+
# regarding deploy_options['migrate']:
|
132
|
+
#
|
133
|
+
# missing means migrate how the yaml file says to
|
134
|
+
# nil means don't migrate
|
135
|
+
# true means migrate w/custom command (if present) or default
|
136
|
+
# a string means migrate with this specific command
|
137
|
+
if deploy_options.has_key?('migrate')
|
138
|
+
migration_command_from_command_line(deploy_options)
|
139
|
+
else
|
140
|
+
migration_command_from_config
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def migration_command_from_config
|
145
|
+
if config.has_key?('migrate')
|
146
|
+
if config['migrate']
|
147
|
+
default_migration_command
|
148
|
+
else
|
149
|
+
nil
|
150
|
+
end
|
151
|
+
else
|
152
|
+
default_migration_command
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
def migration_command_from_command_line(deploy_options)
|
157
|
+
if deploy_options['migrate'].nil?
|
158
|
+
nil
|
159
|
+
elsif deploy_options['migrate'].respond_to?(:to_str)
|
160
|
+
deploy_options['migrate'].to_str
|
161
|
+
else
|
162
|
+
default_migration_command
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
|
167
|
+
def default_migration_command
|
168
|
+
config['migration_command'] || 'rake db:migrate --trace'
|
169
|
+
end
|
170
|
+
|
154
171
|
end
|
155
172
|
end
|
156
|
-
|
157
173
|
end
|
@@ -96,6 +96,18 @@ module EY
|
|
96
96
|
"cd `mktemp -d` && #{gem_path} install engineyard-serverside --no-rdoc --no-ri -v #{ENGINEYARD_SERVERSIDE_VERSION}"]))
|
97
97
|
end
|
98
98
|
|
99
|
+
protected
|
100
|
+
|
101
|
+
def engineyard_serverside_hostname
|
102
|
+
# If we tell engineyard-serverside to use 'localhost', it'll run
|
103
|
+
# commands on the instance directly (#system). If we give it the
|
104
|
+
# instance's actual hostname, it'll SSH to itself.
|
105
|
+
#
|
106
|
+
# Using 'localhost' instead of its EC2 hostname speeds up
|
107
|
+
# deploys on solos and single-app-server clusters significantly.
|
108
|
+
app_master? ? 'localhost' : hostname
|
109
|
+
end
|
110
|
+
|
99
111
|
private
|
100
112
|
|
101
113
|
def ssh(remote_command, output = true)
|
@@ -113,13 +125,21 @@ module EY
|
|
113
125
|
|
114
126
|
def invoke_engineyard_serverside(deploy_args, verbose=false)
|
115
127
|
start = [engineyard_serverside_path, "_#{ENGINEYARD_SERVERSIDE_VERSION}_", 'deploy']
|
116
|
-
instance_args = environment.instances.find_all do |inst|
|
117
|
-
inst.has_app_code?
|
118
|
-
end.inject(['--instances']) do |command, inst|
|
119
|
-
instance_tuple = [inst.public_hostname, inst.role]
|
120
|
-
instance_tuple << inst.name if inst.name
|
121
128
|
|
122
|
-
|
129
|
+
instances = environment.instances.select { |inst| inst.has_app_code? }
|
130
|
+
instance_args = ['']
|
131
|
+
if !instances.empty?
|
132
|
+
instance_args << '--instances'
|
133
|
+
instance_args += instances.collect { |i| i.engineyard_serverside_hostname }
|
134
|
+
|
135
|
+
instance_args << '--instance-roles'
|
136
|
+
instance_args += instances.collect { |i| [i.engineyard_serverside_hostname, i.role].join(':') }
|
137
|
+
|
138
|
+
instance_names = instances.collect { |i| i.name ? [i.engineyard_serverside_hostname, i.name].join(':') : nil }.compact
|
139
|
+
unless instance_names.empty?
|
140
|
+
instance_args << '--instance-names'
|
141
|
+
instance_args += instance_names
|
142
|
+
end
|
123
143
|
end
|
124
144
|
|
125
145
|
framework_arg = ['--framework-env', environment.framework_env]
|
@@ -135,6 +155,10 @@ module EY
|
|
135
155
|
"/usr/local/ey_resin/ruby/bin/engineyard-serverside"
|
136
156
|
end
|
137
157
|
|
158
|
+
def app_master?
|
159
|
+
environment.app_master == self
|
160
|
+
end
|
161
|
+
|
138
162
|
def gem_path
|
139
163
|
"/usr/local/ey_resin/ruby/bin/gem"
|
140
164
|
end
|
data/lib/engineyard/version.rb
CHANGED
data/spec/ey/deploy_spec.rb
CHANGED
@@ -264,6 +264,40 @@ describe "ey deploy" do
|
|
264
264
|
end
|
265
265
|
end
|
266
266
|
|
267
|
+
context "--extra-deploy-hook-options" do
|
268
|
+
before(:all) do
|
269
|
+
api_scenario "one app, one environment"
|
270
|
+
end
|
271
|
+
|
272
|
+
def extra_deploy_hook_options
|
273
|
+
if @ssh_commands.last =~ /--config (.*?)(?: -|$)/
|
274
|
+
# the echo strips off the layer of shell escaping, leaving us
|
275
|
+
# with pristine JSON
|
276
|
+
JSON.parse `echo #{$1}`
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
it "passes the extra configuration to engineyard-serverside" do
|
281
|
+
ey "deploy --extra-deploy-hook-options some:stuff more:crap"
|
282
|
+
extra_deploy_hook_options.should_not be_nil
|
283
|
+
extra_deploy_hook_options['some'].should == 'stuff'
|
284
|
+
extra_deploy_hook_options['more'].should == 'crap'
|
285
|
+
end
|
286
|
+
|
287
|
+
context "when ey.yml is present" do
|
288
|
+
before do
|
289
|
+
write_yaml({"environments" => {"giblets" => {"beer" => "stout"}}})
|
290
|
+
end
|
291
|
+
|
292
|
+
after { File.unlink("ey.yml") }
|
293
|
+
|
294
|
+
it "overrides what's in ey.yml" do
|
295
|
+
ey "deploy --extra-deploy-hook-options beer:esb"
|
296
|
+
extra_deploy_hook_options['beer'].should == 'esb'
|
297
|
+
end
|
298
|
+
end
|
299
|
+
end
|
300
|
+
|
267
301
|
context "specifying the application" do
|
268
302
|
before(:all) do
|
269
303
|
api_scenario "one app, one environment"
|
data/spec/ey/rollback_spec.rb
CHANGED
@@ -27,4 +27,38 @@ describe "ey rollback" do
|
|
27
27
|
@ssh_commands.last.should =~ /--stack nginx_mongrel/
|
28
28
|
end
|
29
29
|
|
30
|
+
context "--extra-deploy-hook-options" do
|
31
|
+
before(:all) do
|
32
|
+
api_scenario "one app, one environment"
|
33
|
+
end
|
34
|
+
|
35
|
+
def extra_deploy_hook_options
|
36
|
+
if @ssh_commands.last =~ /--config (.*?)(?: -|$)/
|
37
|
+
# the echo strips off the layer of shell escaping, leaving us
|
38
|
+
# with pristine JSON
|
39
|
+
JSON.parse `echo #{$1}`
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
it "passes the extra configuration to engineyard-serverside" do
|
44
|
+
ey "rollback --extra-deploy-hook-options some:stuff more:crap"
|
45
|
+
extra_deploy_hook_options.should_not be_nil
|
46
|
+
extra_deploy_hook_options['some'].should == 'stuff'
|
47
|
+
extra_deploy_hook_options['more'].should == 'crap'
|
48
|
+
end
|
49
|
+
|
50
|
+
context "when ey.yml is present" do
|
51
|
+
before do
|
52
|
+
write_yaml({"environments" => {"giblets" => {"beer" => "stout"}}})
|
53
|
+
end
|
54
|
+
|
55
|
+
after { File.unlink("ey.yml") }
|
56
|
+
|
57
|
+
it "overrides what's in ey.yml" do
|
58
|
+
ey "deploy --extra-deploy-hook-options beer:esb"
|
59
|
+
extra_deploy_hook_options['beer'].should == 'esb'
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
30
64
|
end
|
@@ -150,12 +150,12 @@ shared_examples_for "it invokes engineyard-serverside" do
|
|
150
150
|
|
151
151
|
it "passes along instance information to engineyard-serverside" do
|
152
152
|
instance_args = [
|
153
|
-
|
154
|
-
|
155
|
-
|
153
|
+
/--instances localhost app_hostname[^\s]+ util_fluffy/,
|
154
|
+
/--instance-roles localhost:app_master app_hostname[^\s]+:app util_fluffy[^\s]+:util/,
|
155
|
+
/--instance-names util_fluffy_hostname[^\s]+:fluffy/
|
156
156
|
]
|
157
157
|
|
158
|
-
db_instance =
|
158
|
+
db_instance = /db_master/
|
159
159
|
|
160
160
|
# apps + utilities are all mentioned
|
161
161
|
instance_args.each do |i|
|
@@ -164,15 +164,22 @@ shared_examples_for "it invokes engineyard-serverside" do
|
|
164
164
|
|
165
165
|
# but not database instances
|
166
166
|
@ssh_commands.last.should_not =~ /#{db_instance}/
|
167
|
-
|
168
|
-
# and it's all after the option '--instances'
|
169
|
-
@ssh_commands.last.should match(/--instances (#{instance_args.join('|')})/)
|
170
167
|
end
|
171
168
|
|
172
169
|
it "passes the framework environment" do
|
173
170
|
@ssh_commands.last.should match(/--framework-env production/)
|
174
171
|
end
|
172
|
+
end
|
173
|
+
|
174
|
+
context "when no instances have names" do
|
175
|
+
before(:each) do
|
176
|
+
api_scenario "two apps"
|
177
|
+
run_ey({:env => 'giblets', :app => 'rails232app', :ref => 'master', :verbose => true})
|
178
|
+
end
|
175
179
|
|
180
|
+
it "omits the --instance-names parameter" do
|
181
|
+
@ssh_commands.last.should_not include("--instance-names")
|
182
|
+
end
|
176
183
|
end
|
177
184
|
|
178
185
|
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: engineyard
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 27
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 1
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 1.
|
8
|
+
- 3
|
9
|
+
- 0
|
10
|
+
version: 1.3.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- EY Cloud Team
|
@@ -15,100 +15,100 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-
|
18
|
+
date: 2010-09-13 00:00:00 -07:00
|
19
19
|
default_executable: ey
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
22
|
-
prerelease: false
|
23
22
|
version_requirements: &id001 !ruby/object:Gem::Requirement
|
24
23
|
none: false
|
25
24
|
requirements:
|
26
25
|
- - ~>
|
27
26
|
- !ruby/object:Gem::Version
|
28
|
-
hash:
|
27
|
+
hash: 39
|
29
28
|
segments:
|
30
|
-
-
|
31
|
-
-
|
32
|
-
-
|
33
|
-
version:
|
29
|
+
- 0
|
30
|
+
- 14
|
31
|
+
- 0
|
32
|
+
version: 0.14.0
|
34
33
|
requirement: *id001
|
35
34
|
type: :runtime
|
36
|
-
name:
|
37
|
-
- !ruby/object:Gem::Dependency
|
35
|
+
name: thor
|
38
36
|
prerelease: false
|
37
|
+
- !ruby/object:Gem::Dependency
|
39
38
|
version_requirements: &id002 !ruby/object:Gem::Requirement
|
40
39
|
none: false
|
41
40
|
requirements:
|
42
41
|
- - ~>
|
43
42
|
- !ruby/object:Gem::Version
|
44
|
-
hash:
|
43
|
+
hash: 7
|
45
44
|
segments:
|
46
|
-
-
|
47
|
-
-
|
48
|
-
|
49
|
-
version: 0.14.0
|
45
|
+
- 1
|
46
|
+
- 4
|
47
|
+
version: "1.4"
|
50
48
|
requirement: *id002
|
51
49
|
type: :runtime
|
52
|
-
name:
|
53
|
-
- !ruby/object:Gem::Dependency
|
50
|
+
name: rest-client
|
54
51
|
prerelease: false
|
52
|
+
- !ruby/object:Gem::Dependency
|
55
53
|
version_requirements: &id003 !ruby/object:Gem::Requirement
|
56
54
|
none: false
|
57
55
|
requirements:
|
58
|
-
- -
|
56
|
+
- - ~>
|
59
57
|
- !ruby/object:Gem::Version
|
60
|
-
hash:
|
58
|
+
hash: 7
|
61
59
|
segments:
|
62
|
-
-
|
63
|
-
|
60
|
+
- 1
|
61
|
+
- 5
|
62
|
+
- 2
|
63
|
+
version: 1.5.2
|
64
64
|
requirement: *id003
|
65
65
|
type: :runtime
|
66
|
-
name:
|
67
|
-
- !ruby/object:Gem::Dependency
|
66
|
+
name: highline
|
68
67
|
prerelease: false
|
68
|
+
- !ruby/object:Gem::Dependency
|
69
69
|
version_requirements: &id004 !ruby/object:Gem::Requirement
|
70
70
|
none: false
|
71
71
|
requirements:
|
72
|
-
- -
|
72
|
+
- - ">="
|
73
73
|
- !ruby/object:Gem::Version
|
74
|
-
hash:
|
74
|
+
hash: 3
|
75
75
|
segments:
|
76
76
|
- 0
|
77
|
-
|
78
|
-
- 4
|
79
|
-
version: 0.0.4
|
77
|
+
version: "0"
|
80
78
|
requirement: *id004
|
81
79
|
type: :runtime
|
82
|
-
name:
|
83
|
-
- !ruby/object:Gem::Dependency
|
80
|
+
name: ruby-termios
|
84
81
|
prerelease: false
|
82
|
+
- !ruby/object:Gem::Dependency
|
85
83
|
version_requirements: &id005 !ruby/object:Gem::Requirement
|
86
84
|
none: false
|
87
85
|
requirements:
|
88
|
-
- -
|
86
|
+
- - ">="
|
89
87
|
- !ruby/object:Gem::Version
|
90
|
-
hash:
|
88
|
+
hash: 3
|
91
89
|
segments:
|
92
|
-
-
|
93
|
-
|
94
|
-
version: "1.4"
|
90
|
+
- 0
|
91
|
+
version: "0"
|
95
92
|
requirement: *id005
|
96
93
|
type: :runtime
|
97
|
-
name:
|
98
|
-
- !ruby/object:Gem::Dependency
|
94
|
+
name: json_pure
|
99
95
|
prerelease: false
|
96
|
+
- !ruby/object:Gem::Dependency
|
100
97
|
version_requirements: &id006 !ruby/object:Gem::Requirement
|
101
98
|
none: false
|
102
99
|
requirements:
|
103
|
-
- -
|
100
|
+
- - ~>
|
104
101
|
- !ruby/object:Gem::Version
|
105
|
-
hash:
|
102
|
+
hash: 23
|
106
103
|
segments:
|
107
104
|
- 0
|
108
|
-
|
105
|
+
- 0
|
106
|
+
- 4
|
107
|
+
version: 0.0.4
|
109
108
|
requirement: *id006
|
110
109
|
type: :runtime
|
111
|
-
name:
|
110
|
+
name: escape
|
111
|
+
prerelease: false
|
112
112
|
description: This gem allows you to deploy your rails application to the Engine Yard cloud directly from the command line.
|
113
113
|
email: cloud@engineyard.com
|
114
114
|
executables:
|