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.
@@ -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
- # missing means do what the yaml file says
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, options[:verbose])
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
- # regarding deploy_options['migrate']:
40
- #
41
- # missing means migrate how the yaml file says to
42
- # nil means don't migrate
43
- # true means migrate w/custom command (if present) or default
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, config, verbose)
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
- command << instance_tuple.join(',')
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
@@ -1,3 +1,3 @@
1
1
  module EY
2
- ENGINEYARD_SERVERSIDE_VERSION = ENV['ENGINEYARD_SERVERSIDE_VERSION'] || '1.2.2'
2
+ ENGINEYARD_SERVERSIDE_VERSION = ENV['ENGINEYARD_SERVERSIDE_VERSION'] || '1.3.1'
3
3
  end
@@ -1,3 +1,3 @@
1
1
  module EY
2
- VERSION = '1.2.4'
2
+ VERSION = '1.3.0'
3
3
  end
@@ -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"
@@ -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
- Regexp.quote("app_master_hostname.compute-1.amazonaws.com,app_master"),
154
- Regexp.quote("app_hostname.compute-1.amazonaws.com,app"),
155
- Regexp.quote("util_fluffy_hostname.compute-1.amazonaws.com,util,fluffy"),
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 = Regexp.quote("db_master_hostname.compute-1.amazonaws.com,db_master")
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: 23
4
+ hash: 27
5
5
  prerelease: false
6
6
  segments:
7
7
  - 1
8
- - 2
9
- - 4
10
- version: 1.2.4
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-08-31 00:00:00 -07:00
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: 7
27
+ hash: 39
29
28
  segments:
30
- - 1
31
- - 5
32
- - 2
33
- version: 1.5.2
29
+ - 0
30
+ - 14
31
+ - 0
32
+ version: 0.14.0
34
33
  requirement: *id001
35
34
  type: :runtime
36
- name: highline
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: 39
43
+ hash: 7
45
44
  segments:
46
- - 0
47
- - 14
48
- - 0
49
- version: 0.14.0
45
+ - 1
46
+ - 4
47
+ version: "1.4"
50
48
  requirement: *id002
51
49
  type: :runtime
52
- name: thor
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: 3
58
+ hash: 7
61
59
  segments:
62
- - 0
63
- version: "0"
60
+ - 1
61
+ - 5
62
+ - 2
63
+ version: 1.5.2
64
64
  requirement: *id003
65
65
  type: :runtime
66
- name: ruby-termios
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: 23
74
+ hash: 3
75
75
  segments:
76
76
  - 0
77
- - 0
78
- - 4
79
- version: 0.0.4
77
+ version: "0"
80
78
  requirement: *id004
81
79
  type: :runtime
82
- name: escape
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: 7
88
+ hash: 3
91
89
  segments:
92
- - 1
93
- - 4
94
- version: "1.4"
90
+ - 0
91
+ version: "0"
95
92
  requirement: *id005
96
93
  type: :runtime
97
- name: rest-client
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: 3
102
+ hash: 23
106
103
  segments:
107
104
  - 0
108
- version: "0"
105
+ - 0
106
+ - 4
107
+ version: 0.0.4
109
108
  requirement: *id006
110
109
  type: :runtime
111
- name: json_pure
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: