engineyard-serverside 1.4.3.nodestack → 1.4.7.pre

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.
Files changed (33) hide show
  1. data/lib/core-ext/README.md +3 -0
  2. data/lib/core-ext/string.rb +9 -0
  3. data/lib/engineyard-serverside.rb +3 -1
  4. data/lib/engineyard-serverside/cli.rb +3 -2
  5. data/lib/engineyard-serverside/configuration.rb +1 -1
  6. data/lib/engineyard-serverside/deploy.rb +117 -23
  7. data/lib/engineyard-serverside/lockfile_parser.rb +3 -3
  8. data/lib/engineyard-serverside/logged_output.rb +0 -5
  9. data/lib/engineyard-serverside/task.rb +1 -0
  10. data/lib/engineyard-serverside/version.rb +1 -1
  11. data/lib/vendor/ruby_1.8.6_openssl.patch +7 -0
  12. data/spec/custom_deploy_spec.rb +14 -7
  13. data/spec/fixtures/gemfiles/activerecord_jdbcmysql/Gemfile +5 -0
  14. data/spec/fixtures/gemfiles/activerecord_jdbcmysql/Gemfile.lock +29 -0
  15. data/spec/fixtures/gemfiles/activerecord_jdbcpostgresql/Gemfile +5 -0
  16. data/spec/fixtures/gemfiles/activerecord_jdbcpostgresql/Gemfile.lock +29 -0
  17. data/spec/fixtures/gemfiles/activerecord_mysql/Gemfile +5 -0
  18. data/spec/fixtures/gemfiles/activerecord_mysql/Gemfile.lock +25 -0
  19. data/spec/fixtures/gemfiles/activerecord_mysql2/Gemfile +5 -0
  20. data/spec/fixtures/gemfiles/activerecord_mysql2/Gemfile.lock +25 -0
  21. data/spec/fixtures/gemfiles/activerecord_pg/Gemfile +5 -0
  22. data/spec/fixtures/gemfiles/activerecord_pg/Gemfile.lock +25 -0
  23. data/spec/fixtures/gemfiles/activerecord_sqlite3/Gemfile +5 -0
  24. data/spec/fixtures/gemfiles/activerecord_sqlite3/Gemfile.lock +25 -0
  25. data/spec/fixtures/gemfiles/diy_database_yml/Gemfile +5 -0
  26. data/spec/fixtures/gemfiles/diy_database_yml/Gemfile.lock +25 -0
  27. data/spec/fixtures/gemfiles/diy_database_yml/config/database.yml +7 -0
  28. data/spec/generate_configs_spec.rb +228 -0
  29. data/spec/lib/full_test_deploy.rb +86 -0
  30. data/spec/real_deploy_spec.rb +42 -121
  31. data/spec/spec_helper.rb +62 -1
  32. metadata +75 -9
  33. data/spec/fixtures/gitrepo/bar +0 -0
@@ -0,0 +1,3 @@
1
+ # methods for core Ruby classes that aren't available in ruby 1.8.6 (used by ey_resin)
2
+ # versions here are just workarounds
3
+ # FIXME remove this folder when ey_resin (and .rvmrc) updated to ruby 1.8.7 or 1.9.2
@@ -0,0 +1,9 @@
1
+ # methods for String that aren't available in ruby 1.8.6 (used by ey_resin)
2
+ # versions here are just workarounds
3
+ # FIXME remove this module when ey_resin (and .rvmrc) updated to ruby 1.8.7 or 1.9.2
4
+ module ModernString
5
+ def start_with?(prefix)
6
+ self.index(prefix) == 0
7
+ end
8
+ end
9
+ String.send(:include, ModernString)
@@ -4,6 +4,8 @@ $LOAD_PATH.unshift File.expand_path('vendor/escape/lib', File.dirname(__FILE__))
4
4
  $LOAD_PATH.unshift File.expand_path('vendor/json_pure/lib', File.dirname(__FILE__))
5
5
  $LOAD_PATH.unshift File.expand_path('vendor/dataflow', File.dirname(__FILE__))
6
6
 
7
+ require 'core-ext/string' if RUBY_VERSION == '1.8.6'
8
+
7
9
  require 'escape'
8
10
  require 'json'
9
11
  require 'dataflow'
@@ -34,7 +36,7 @@ module EY
34
36
  {}.to_json
35
37
  end
36
38
  end
37
-
39
+
38
40
  RemoteFailure = Class.new StandardError
39
41
 
40
42
  private
@@ -1,5 +1,6 @@
1
1
  require 'thor'
2
2
  require 'pathname'
3
+ require 'tmpdir'
3
4
 
4
5
  module EY
5
6
  module Serverside
@@ -214,9 +215,9 @@ module EY
214
215
  def propagate
215
216
  config = EY::Serverside::Deploy::Configuration.new
216
217
  gem_filename = "engineyard-serverside-#{EY::Serverside::VERSION}.gem"
217
- local_gem_file = File.join(Gem.dir, 'cache', gem_filename)
218
+ local_gem_file = File.join(::Gem.dir, 'cache', gem_filename)
218
219
  remote_gem_file = File.join(Dir.tmpdir, gem_filename)
219
- gem_binary = File.join(Gem.default_bindir, 'gem')
220
+ gem_binary = File.join(::Gem.default_bindir, 'gem')
220
221
 
221
222
  barrier(*(EY::Serverside::Server.all.find_all do |server|
222
223
  !server.local? # of course this machine has it
@@ -119,7 +119,7 @@ module EY
119
119
  end
120
120
 
121
121
  def framework_envs
122
- "RAILS_ENV=#{environment} RACK_ENV=#{environment} APP_ENV=#{environment} MERB_ENV=#{environment}"
122
+ "RAILS_ENV=#{environment} RACK_ENV=#{environment} MERB_ENV=#{environment}"
123
123
  end
124
124
 
125
125
  def current_path
@@ -27,6 +27,7 @@ module EY
27
27
  create_revision_file
28
28
  run_with_callbacks(:bundle)
29
29
  symlink_configs
30
+ generate_configs
30
31
  conditionally_enable_maintenance_page
31
32
  run_with_callbacks(:migrate)
32
33
  callback(:before_symlink)
@@ -136,8 +137,9 @@ module EY
136
137
  bundler_installer = if File.exist?(lockfile)
137
138
  get_bundler_installer(lockfile)
138
139
  else
139
- warn_about_missing_lockfile
140
- bundler_09_installer(default_09_bundler)
140
+ missing_lock_version = EY::Serverside::LockfileParser::Parse10::DEFAULT
141
+ warn_about_missing_lockfile missing_lock_version
142
+ bundler_10_installer missing_lock_version
141
143
  end
142
144
 
143
145
  sudo "#{$0} _#{EY::Serverside::VERSION}_ install_bundler #{bundler_installer.version}"
@@ -164,15 +166,6 @@ module EY
164
166
 
165
167
  run "mkdir -p #{bundled_gems_path} && ruby -v > #{ruby_version_file} && uname -m > #{system_version_file}"
166
168
  end
167
- if File.exist?("#{c.release_path}/package.json")
168
- unless `which npm` =~ /npm/
169
- error "~> package.json detected, BUT npm not installed"
170
- else
171
- info "~> package.json detected, installing npm packages"
172
-
173
- run "cd #{c.release_path} && npm install"
174
- end
175
- end
176
169
  end
177
170
 
178
171
  # task
@@ -227,6 +220,7 @@ module EY
227
220
  run create_revision_file_command
228
221
  end
229
222
 
223
+ # symlink to shared path; may be overridden by #generate_configs
230
224
  def symlink_configs(release_to_link=c.release_path)
231
225
  info "~> Symlinking configs"
232
226
  [ "chmod -R g+w #{release_to_link}",
@@ -237,8 +231,8 @@ module EY
237
231
  "mkdir -p #{release_to_link}/config",
238
232
  "ln -nfs #{c.shared_path}/system #{release_to_link}/public/system",
239
233
  "ln -nfs #{c.shared_path}/pids #{release_to_link}/tmp/pids",
240
- "find #{c.shared_path}/config -type f -exec ln -s {} #{release_to_link}/config \\;",
241
- "ln -nfs #{c.shared_path}/config/database.yml #{release_to_link}/config/database.yml",
234
+ "find #{c.shared_path}/config ! -name 'database.yml*' -type f -exec ln -s {} #{release_to_link}/config \\;",
235
+ # database.yml generated or symlink created in #generate_database_yml
242
236
  "ln -nfs #{c.shared_path}/config/mongrel_cluster.yml #{release_to_link}/config/mongrel_cluster.yml",
243
237
  ].each do |cmd|
244
238
  run cmd
@@ -248,6 +242,84 @@ module EY
248
242
  run "if [ -f \"#{c.shared_path}/config/newrelic.yml\" ]; then ln -nfs #{c.shared_path}/config/newrelic.yml #{release_to_link}/config/newrelic.yml; fi"
249
243
  end
250
244
 
245
+ def generate_configs(release_to_link=c.release_path)
246
+ generate_database_yml(release_to_link)
247
+ end
248
+
249
+ # Do nothing if there is no Gemfile.lock to determine what ORM gems are being used
250
+ # (falls back to using the symlinked shared/database.yml file)
251
+ def generate_database_yml(release_to_link)
252
+ return if keep_database_yml?(release_to_link)
253
+ if config["db_adapter"] || File.exist?("#{c.release_path}/Gemfile.lock")
254
+ info "~> Generating database.yml from Gemfile.lock"
255
+ database_yml = "#{release_to_link}/config/database.yml"
256
+ node = EY::Serverside.node
257
+ node_app = node["engineyard"]["environment"]["apps"].find { |app| app['name'] == c['app'] }
258
+ abort("Invalid application name for target environment: #{c['app']}") unless node_app
259
+
260
+ db_stack_name = node[:engineyard][:environment][:db_stack_name]
261
+ instances = node[:engineyard][:environment][:instances]
262
+ db_master = {"public_hostname" => "localhost"} # you know, just in case
263
+ db_slaves = []
264
+ instances.each do |i|
265
+ case i['role']
266
+ when 'db_master', 'solo'
267
+ db_master = i
268
+ when 'db_slave'
269
+ db_slaves << i
270
+ end
271
+ end
272
+ db_host = db_master["public_hostname"]
273
+ db_slaves_hosts = db_slaves.map {|slave| slave["public_hostname"]}
274
+
275
+ if config["db_adapter"]
276
+ adapter = config["db_adapter"]
277
+ elsif bundler_gems_include?("mysql2")
278
+ adapter = "mysql2"
279
+ elsif bundler_gems_include?("mysql")
280
+ adapter = "mysql"
281
+ elsif bundler_gems_include?("pg")
282
+ adapter = "postgresql"
283
+ elsif bundler_gems_include?("jdbc-mysql")
284
+ adapter = "mysql"
285
+ elsif bundler_gems_include?("jdbc-postgres")
286
+ adapter = "postgresql"
287
+ elsif db_stack_name && db_stack_name =~ /postgres/
288
+ adapter = "postgresql"
289
+ else
290
+ adapter = "mysql"
291
+ end
292
+
293
+ File.open(database_yml, "w") do |file|
294
+ contents = <<-EOS.gsub(/^\s{12}/, '')
295
+ #{node[:engineyard][:environment][:framework_env]}:
296
+ adapter: #{adapter}
297
+ database: #{node_app[:database_name]}
298
+ username: #{node[:engineyard][:environment][:ssh_username]}
299
+ password: #{node[:engineyard][:environment][:ssh_password]}
300
+ host: #{db_host}
301
+ reconnect: true
302
+ EOS
303
+ db_slaves_hosts.each_with_index do |host, n|
304
+ slave_name = n.zero? ? "slave" : "slave_#{n}"
305
+ contents << <<-EOS.gsub(/^\s{14}/, '')
306
+ #{slave_name}:
307
+ adapter: #{adapter}
308
+ database: #{node_app[:database_name]}
309
+ username: #{node[:engineyard][:environment][:ssh_username]}
310
+ password: #{node[:engineyard][:environment][:ssh_password]}
311
+ host: #{host}
312
+ reconnect: true
313
+ EOS
314
+ end
315
+ file << contents
316
+ end
317
+ else
318
+ info "~> Symlinking database.yml config"
319
+ run "ln -nfs #{c.shared_path}/config/database.yml #{release_to_link}/config/database.yml"
320
+ end
321
+ end
322
+
251
323
  # task
252
324
  def symlink(release_to_link=c.release_path)
253
325
  info "~> Symlinking code"
@@ -319,7 +391,7 @@ module EY
319
391
  raise
320
392
  end
321
393
 
322
- def warn_about_missing_lockfile
394
+ def warn_about_missing_lockfile(missing_lock_version)
323
395
  info "!>"
324
396
  info "!> WARNING: Gemfile.lock is missing!"
325
397
  info "!> You can get different gems in production than what you tested with."
@@ -329,30 +401,52 @@ module EY
329
401
  info "!> Fix this by running \"git add Gemfile.lock; git commit\" and deploying again."
330
402
  info "!> If you don't have a Gemfile.lock, run \"bundle lock\" to create one."
331
403
  info "!>"
332
- info "!> This deployment will use bundler #{default_09_bundler} to run 'bundle install'."
404
+ info "!> This deployment will use bundler #{missing_lock_version} to run 'bundle install'."
333
405
  info "!>"
334
406
  end
335
407
 
336
- def get_bundler_installer(lockfile)
408
+ def keep_database_yml?(release_to_link=c.release_path)
409
+ File.exists?(File.join(release_to_link, "config", "keep.database.yml"))
410
+ end
411
+
412
+ # returns true if "bundle list" includes all gems requested
413
+ def bundler_gems_include?(*gems)
414
+ lockfile = File.join(c.release_path, "Gemfile.lock")
415
+ @lockfile_contents ||= File.read(lockfile)
416
+
417
+ # Parsing Gemfile.lock which looks like
418
+ # GEM
419
+ # remote: http://rubygems.org/
420
+ # specs:
421
+ # activemodel (3.0.10)
422
+ # activesupport (= 3.0.10)
423
+ # builder (~> 2.1.2)
424
+ # i18n (~> 0.5.0)
425
+ #
426
+ gems.inject(true) {|found_all, gem| found_all && (@lockfile_contents =~ / #{gem} \(/)}
427
+ end
428
+
429
+ def get_bundler_installer(lockfile, options = '')
337
430
  parser = LockfileParser.new(File.read(lockfile))
338
431
  case parser.lockfile_version
339
432
  when :bundler09
340
- bundler_09_installer(parser.bundler_version)
433
+ bundler_09_installer(parser.bundler_version, options)
341
434
  when :bundler10
342
- bundler_10_installer(parser.bundler_version)
435
+ bundler_10_installer(parser.bundler_version, options)
343
436
  else
344
437
  raise "Unknown lockfile version #{parser.lockfile_version}"
345
438
  end
346
439
  end
347
440
  public :get_bundler_installer
348
441
 
349
- def bundler_09_installer(version)
350
- BundleInstaller.new(version, '--without=development --without=test')
442
+ def bundler_09_installer(version, options = '')
443
+ default_options = '--without=development --without=test'
444
+ BundleInstaller.new(version, default_options + options)
351
445
  end
352
446
 
353
- def bundler_10_installer(version)
354
- BundleInstaller.new(version,
355
- "--deployment --path #{c.shared_path}/bundled_gems --binstubs #{c.binstubs_path} --without development test")
447
+ def bundler_10_installer(version, options = '')
448
+ default_options = "--deployment --path #{c.shared_path}/bundled_gems --binstubs #{c.binstubs_path} --without development test"
449
+ BundleInstaller.new(version, default_options + options)
356
450
  end
357
451
  end # DeployBase
358
452
 
@@ -79,11 +79,11 @@ module EY
79
79
  when '='
80
80
  bundler_version
81
81
  when '>='
82
- Gem::Version.new(bundler_version) > Gem::Version.new(DEFAULT) ? bundler_version : DEFAULT
82
+ ::Gem::Version.new(bundler_version) > ::Gem::Version.new(DEFAULT) ? bundler_version : DEFAULT
83
83
  when '~>'
84
- bundler_gem_version = Gem::Version.new(bundler_version)
84
+ bundler_gem_version = ::Gem::Version.new(bundler_version)
85
85
  recommendation = bundler_gem_version.spermy_recommendation.gsub(/~>\s*(.+)$/, '\1.')
86
- DEFAULT.start_with?(recommendation) && Gem::Version.new(DEFAULT) > bundler_gem_version ? DEFAULT : bundler_version
86
+ DEFAULT.start_with?(recommendation) && ::Gem::Version.new(DEFAULT) > bundler_gem_version ? DEFAULT : bundler_version
87
87
  end
88
88
  end
89
89
 
@@ -41,11 +41,6 @@ module EY
41
41
  EY::Serverside::LoggedOutput.verbose?
42
42
  end
43
43
 
44
- # TODO color output
45
- def error(msg)
46
- info(msg)
47
- end
48
-
49
44
  def info(msg)
50
45
  with_logfile do |log|
51
46
  Tee.new($stdout, log) << (msg + "\n")
@@ -54,6 +54,7 @@ module EY
54
54
  need_later { server.run(Escape.shell_command(wrapper + [to_run])) }
55
55
  end
56
56
  barrier *results
57
+
57
58
  # MRI's truthiness check is an internal C thing that does not call
58
59
  # any methods... so Dataflow cannot proxy it & we must "x == true"
59
60
  # Rubinius, wherefore art thou!?
@@ -1,5 +1,5 @@
1
1
  module EY
2
2
  module Serverside
3
- VERSION = '1.4.3.nodestack'
3
+ VERSION = '1.4.7.pre'
4
4
  end
5
5
  end
@@ -0,0 +1,7 @@
1
+ diff --git a/ext/openssl/openssl_missing.h b/ext/openssl/openssl_missing.h
2
+ index 2ebf61a..8a0202a 100644
3
+ --- a/ext/openssl/openssl_missing.h
4
+ +++ b/ext/openssl/openssl_missing.h
5
+ @@ -123,2 +122,0 @@ int BN_mod_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m, BN_
6
+ -int BN_rand_range(BIGNUM *r, BIGNUM *range);
7
+ -int BN_pseudo_rand_range(BIGNUM *r, BIGNUM *range);
@@ -1,4 +1,5 @@
1
1
  require File.dirname(__FILE__) + '/spec_helper'
2
+ require 'fileutils'
2
3
 
3
4
  describe "the EY::Serverside::Deploy API" do
4
5
  it "calls tasks in the right order" do
@@ -29,9 +30,12 @@ describe "the EY::Serverside::Deploy API" do
29
30
  def cleanup_old_releases() @call_order << 'cleanup_old_releases' end
30
31
  def conditionally_enable_maintenance_page() @call_order << 'conditionally_enable_maintenance_page' end
31
32
  def disable_maintenance_page() @call_order << 'disable_maintenance_page' end
33
+ def generate_database_yml(path) @call_order << 'generate_database_yml' end
32
34
  end
33
35
 
34
- td = TestDeploy.new(EY::Serverside::Deploy::Configuration.new)
36
+ setup_dna_json
37
+
38
+ td = TestDeploy.new(EY::Serverside::Deploy::Configuration.new('app' => 'myfirstapp'))
35
39
  td.deploy
36
40
  td.call_order.should == %w(
37
41
  push_code
@@ -39,6 +43,7 @@ describe "the EY::Serverside::Deploy API" do
39
43
  create_revision_file
40
44
  bundle
41
45
  symlink_configs
46
+ generate_database_yml
42
47
  conditionally_enable_maintenance_page
43
48
  migrate
44
49
  symlink
@@ -53,15 +58,17 @@ describe "the EY::Serverside::Deploy API" do
53
58
  end
54
59
 
55
60
  before(:each) do
56
- @tempdir = `mktemp -d -t custom_deploy_spec.XXXXX`.strip
57
- @config = EY::Serverside::Deploy::Configuration.new('repository_cache' => @tempdir)
58
- @deploy = TestQuietDeploy.new(@config)
61
+ @tempdir = File.join(Dir.tmpdir, "serverside-deploy-#{Time.now.to_i}-#{$$}")
62
+ @config = EY::Serverside::Deploy::Configuration.new('repository_cache' => @tempdir)
63
+ @deploy = TestQuietDeploy.new(@config)
64
+ end
65
+
66
+ after do
67
+ FileUtils.rm_rf(@tempdir)
59
68
  end
60
69
 
61
70
  def write_eydeploy(relative_path, contents = "def got_new_methods() 'from the file on disk' end")
62
- FileUtils.mkdir_p(File.join(
63
- @tempdir,
64
- File.dirname(relative_path)))
71
+ FileUtils.mkdir_p(File.join(@tempdir, File.dirname(relative_path)))
65
72
 
66
73
  File.open(File.join(@tempdir, relative_path), 'w') do |f|
67
74
  f.write contents
@@ -0,0 +1,5 @@
1
+ # A sample Gemfile
2
+ source "http://rubygems.org"
3
+
4
+ gem "activerecord"
5
+ gem "activerecord-jdbcmysql-adapter"
@@ -0,0 +1,29 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ activemodel (3.0.10)
5
+ activesupport (= 3.0.10)
6
+ builder (~> 2.1.2)
7
+ i18n (~> 0.5.0)
8
+ activerecord (3.0.10)
9
+ activemodel (= 3.0.10)
10
+ activesupport (= 3.0.10)
11
+ arel (~> 2.0.10)
12
+ tzinfo (~> 0.3.23)
13
+ activerecord-jdbc-adapter (1.1.3)
14
+ activerecord-jdbcmysql-adapter (1.1.3)
15
+ activerecord-jdbc-adapter (= 1.1.3)
16
+ jdbc-mysql (~> 5.1.0)
17
+ activesupport (3.0.10)
18
+ arel (2.0.10)
19
+ builder (2.1.2)
20
+ i18n (0.5.0)
21
+ jdbc-mysql (5.1.13)
22
+ tzinfo (0.3.29)
23
+
24
+ PLATFORMS
25
+ ruby
26
+
27
+ DEPENDENCIES
28
+ activerecord
29
+ activerecord-jdbcmysql-adapter
@@ -0,0 +1,5 @@
1
+ # A sample Gemfile
2
+ source "http://rubygems.org"
3
+
4
+ gem "activerecord"
5
+ gem "activerecord-jdbcpostgresql-adapter"
@@ -0,0 +1,29 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ activemodel (3.0.10)
5
+ activesupport (= 3.0.10)
6
+ builder (~> 2.1.2)
7
+ i18n (~> 0.5.0)
8
+ activerecord (3.0.10)
9
+ activemodel (= 3.0.10)
10
+ activesupport (= 3.0.10)
11
+ arel (~> 2.0.10)
12
+ tzinfo (~> 0.3.23)
13
+ activerecord-jdbc-adapter (1.1.3)
14
+ activerecord-jdbcpostgresql-adapter (1.1.3)
15
+ activerecord-jdbc-adapter (= 1.1.3)
16
+ jdbc-postgres (~> 9.0.0)
17
+ activesupport (3.0.10)
18
+ arel (2.0.10)
19
+ builder (2.1.2)
20
+ i18n (0.5.0)
21
+ jdbc-postgres (9.0.801)
22
+ tzinfo (0.3.29)
23
+
24
+ PLATFORMS
25
+ ruby
26
+
27
+ DEPENDENCIES
28
+ activerecord
29
+ activerecord-jdbcpostgresql-adapter