engineyard-serverside 2.7.8pre2 → 2.8.0.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (96) hide show
  1. data/bin/engineyard-serverside +1 -1
  2. data/bin/engineyard-serverside-execute-hook +1 -1
  3. data/bin/engineyard-serverside-execute-service-hook +35 -0
  4. data/lib/engineyard-serverside.rb +0 -1
  5. data/lib/engineyard-serverside/about.rb +11 -8
  6. data/lib/engineyard-serverside/callbacks.rb +11 -0
  7. data/lib/engineyard-serverside/callbacks/collection.rb +17 -0
  8. data/lib/engineyard-serverside/callbacks/collection/base.rb +79 -0
  9. data/lib/engineyard-serverside/callbacks/collection/combined.rb +45 -0
  10. data/lib/engineyard-serverside/callbacks/collection/deploy_hooks.rb +21 -0
  11. data/lib/engineyard-serverside/callbacks/collection/service_hooks.rb +17 -0
  12. data/lib/engineyard-serverside/callbacks/collection/service_hooks/collection.rb +24 -0
  13. data/lib/engineyard-serverside/callbacks/collection/service_hooks/combined.rb +40 -0
  14. data/lib/engineyard-serverside/callbacks/distributor.rb +21 -0
  15. data/lib/engineyard-serverside/callbacks/distributor/remote.rb +76 -0
  16. data/lib/engineyard-serverside/callbacks/distributor/viability_filter.rb +66 -0
  17. data/lib/engineyard-serverside/callbacks/executor.rb +23 -0
  18. data/lib/engineyard-serverside/callbacks/executor/base.rb +44 -0
  19. data/lib/engineyard-serverside/callbacks/executor/executable.rb +123 -0
  20. data/lib/engineyard-serverside/callbacks/executor/ruby.rb +20 -0
  21. data/lib/engineyard-serverside/callbacks/executor/ruby/context.rb +81 -0
  22. data/lib/engineyard-serverside/callbacks/executor/ruby/executor.rb +118 -0
  23. data/{spec/fixtures/gitrepo/bar → lib/engineyard-serverside/callbacks/hooks.rb} +0 -0
  24. data/lib/engineyard-serverside/callbacks/hooks/app.rb +21 -0
  25. data/lib/engineyard-serverside/callbacks/hooks/base.rb +43 -0
  26. data/lib/engineyard-serverside/callbacks/hooks/service.rb +28 -0
  27. data/lib/engineyard-serverside/callbacks/service_hook.rb +20 -0
  28. data/lib/engineyard-serverside/cli.rb +4 -225
  29. data/lib/engineyard-serverside/cli/app.rb +136 -0
  30. data/lib/engineyard-serverside/cli/helpers.rb +58 -0
  31. data/lib/engineyard-serverside/cli/server_hash_extractor.rb +49 -0
  32. data/lib/engineyard-serverside/cli/workflows.rb +45 -0
  33. data/lib/engineyard-serverside/cli/workflows/base.rb +78 -0
  34. data/lib/engineyard-serverside/cli/workflows/calling_deploy_hooks.rb +31 -0
  35. data/lib/engineyard-serverside/cli/workflows/deploying_applications.rb +28 -0
  36. data/lib/engineyard-serverside/cli/workflows/disabling_maintenance.rb +29 -0
  37. data/lib/engineyard-serverside/cli/workflows/enabling_maintenance.rb +29 -0
  38. data/lib/engineyard-serverside/cli/workflows/errors.rb +13 -0
  39. data/lib/engineyard-serverside/cli/workflows/helpers.rb +21 -0
  40. data/lib/engineyard-serverside/cli/workflows/integrating_servers.rb +71 -0
  41. data/lib/engineyard-serverside/cli/workflows/restarting_applications.rb +36 -0
  42. data/lib/engineyard-serverside/cli/workflows/rolling_back_applications.rb +28 -0
  43. data/lib/engineyard-serverside/cli/workflows/showing_maintenance_status.rb +28 -0
  44. data/lib/engineyard-serverside/configuration.rb +1 -0
  45. data/lib/engineyard-serverside/dependency_manager/bundler.rb +46 -18
  46. data/lib/engineyard-serverside/dependency_manager/npm.rb +12 -1
  47. data/lib/engineyard-serverside/deploy.rb +7 -45
  48. data/lib/engineyard-serverside/maintenance.rb +1 -9
  49. data/lib/engineyard-serverside/paths.rb +11 -0
  50. data/lib/engineyard-serverside/propagator.rb +59 -0
  51. data/lib/engineyard-serverside/rails_assets.rb +2 -1
  52. data/lib/engineyard-serverside/slug.rb +7 -0
  53. data/lib/engineyard-serverside/slug/distributor.rb +58 -0
  54. data/lib/engineyard-serverside/slug/enabler.rb +100 -0
  55. data/lib/engineyard-serverside/slug/failure_handler.rb +24 -0
  56. data/lib/engineyard-serverside/slug/finalizer.rb +86 -0
  57. data/lib/engineyard-serverside/slug/generator.rb +29 -0
  58. data/lib/engineyard-serverside/slug/migrator.rb +41 -0
  59. data/lib/engineyard-serverside/slug/restarter.rb +103 -0
  60. data/lib/engineyard-serverside/slug/source.rb +16 -0
  61. data/lib/engineyard-serverside/slug/source/updater.rb +194 -0
  62. data/lib/engineyard-serverside/version.rb +1 -1
  63. data/lib/railway.rb +43 -0
  64. data/lib/result.rb +7 -0
  65. data/lib/result/base.rb +41 -0
  66. data/lib/result/dsl.rb +16 -0
  67. data/lib/result/failure.rb +29 -0
  68. data/lib/result/success.rb +24 -0
  69. data/lib/runner.rb +34 -0
  70. data/spec/archive_deploy_spec.rb +1 -1
  71. data/spec/bundler_deploy_spec.rb +22 -1
  72. data/spec/configuration_spec.rb +1 -0
  73. data/spec/deploy_hook_spec.rb +148 -132
  74. data/spec/fixtures/lockfiles/1.15.1-no-bundler +51 -0
  75. data/spec/fixtures/repos/assets_error/Gemfile +5 -0
  76. data/spec/fixtures/repos/assets_error/Gemfile.lock +88 -0
  77. data/spec/fixtures/repos/assets_error/README +1 -0
  78. data/spec/fixtures/repos/assets_error/Rakefile +4 -0
  79. data/spec/fixtures/{gitrepo/foo → repos/assets_error/app/assets/empty} +0 -0
  80. data/spec/fixtures/repos/assets_error/config/application.rb +5 -0
  81. data/spec/fixtures/repos/assets_error/config/ey.yml +4 -0
  82. data/spec/fixtures/repos/bundler_old/Gemfile +5 -0
  83. data/spec/fixtures/repos/bundler_old/Gemfile.lock +15 -0
  84. data/spec/fixtures/repos/bundler_old/README +1 -0
  85. data/spec/fixtures/repos/no_ey_config_no_warning/Gemfile +3 -0
  86. data/spec/fixtures/repos/no_ey_config_no_warning/Gemfile.lock +10 -0
  87. data/spec/fixtures/repos/no_ey_config_no_warning/README +1 -0
  88. data/spec/fixtures/repos/no_ey_config_no_warning/ey.yml +5 -0
  89. data/spec/lockfile_parser_spec.rb +5 -1
  90. data/spec/rails31_deploy_spec.rb +8 -0
  91. data/spec/rollback_spec.rb +1 -1
  92. data/spec/services_deploy_spec.rb +12 -0
  93. data/spec/spec_helper.rb +14 -8
  94. metadata +488 -429
  95. data/lib/engineyard-serverside/cli_helpers.rb +0 -53
  96. data/lib/engineyard-serverside/deploy_hook.rb +0 -142
@@ -58,7 +58,8 @@ module EY
58
58
  # This is a hack right now, but I haven't iterated over it enough for a good solution yet.
59
59
  if config.experimental_sync_assets?
60
60
  shell.status "Compiling assets once on localhost (experimental_sync_assets: true)"
61
- shell.logged_system("sh -l -c '#{cd} && #{task}'")
61
+ compilation_result = shell.logged_system("sh -l -c '#{cd} && #{task}'")
62
+ raise "Assets compilation error" unless compilation_result.success?
62
63
 
63
64
  shell.status "Syncing assets to other remote servers (experimental_sync_assets: true)"
64
65
  runner.servers.remote.run_for_each do |server|
@@ -0,0 +1,7 @@
1
+ module EY
2
+ module Serverside
3
+ module Slug
4
+
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,58 @@
1
+ require 'railway'
2
+ require 'runner'
3
+
4
+ module EY
5
+ module Serverside
6
+ module Slug
7
+ class Distributor
8
+ include Railway
9
+ include Runner
10
+
11
+ step :find_remotes
12
+ step :distribute_to_remotes
13
+
14
+ def self.distribute(data = {})
15
+ new(data[:config], data[:shell], data[:servers]).call(data)
16
+ end
17
+
18
+ attr_reader :config, :shell, :servers
19
+
20
+ def initialize(config, shell, servers)
21
+ @config = config
22
+ @shell = shell
23
+ @servers = servers
24
+ end
25
+
26
+ private
27
+ def find_remotes(input = {})
28
+ remotes = servers.
29
+ to_a.
30
+ reject {|server| server.role.to_sym == :app_master}
31
+
32
+ Success(input.merge(:remotes => remotes))
33
+ end
34
+
35
+ def distribute_to_remotes(input = {})
36
+ remotes = input[:remotes]
37
+ releases_path = "/data/#{input[:app_name]}/releases"
38
+ package = "#{releases_path}/#{input[:release_name]}.tgz"
39
+ internal_key = config.paths.internal_key
40
+
41
+ remotes.each do |remote|
42
+ cmd = "scp -i #{internal_key} #{package} #{remote.user}@#{remote.hostname}:#{releases_path}"
43
+
44
+ unless run_and_success?(cmd)
45
+ return Failure(
46
+ input.merge(
47
+ :error => "Could not copy #{package} to #{remote.hostname}"
48
+ )
49
+ )
50
+ end
51
+ end
52
+
53
+ Success(input)
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,100 @@
1
+ require 'railway'
2
+ require 'runner'
3
+
4
+ module EY
5
+ module Serverside
6
+ module Slug
7
+
8
+ class Enabler
9
+ include Railway
10
+ include Runner
11
+
12
+ step :enable_remotes
13
+ step :enable_local
14
+
15
+ attr_reader :config, :shell, :servers
16
+
17
+ def initialize(config, shell, servers)
18
+ @config = config
19
+ @shell = shell
20
+ @servers = servers
21
+ end
22
+
23
+ private
24
+ def enable_remotes(data)
25
+ enabled = []
26
+
27
+ remotes.each do |remote|
28
+ if run_and_success?(remote_command(remote, data))
29
+ enabled.push(remote)
30
+ else
31
+ return Failure(
32
+ data.merge(
33
+ :enabled => enabled,
34
+ :error => "Could not enable #{data[:release_name]} on #{remote.hostname}"
35
+ )
36
+ )
37
+ end
38
+ end
39
+
40
+ Success(data.merge(:enabled => enabled))
41
+ end
42
+
43
+ def enable_local(data = {})
44
+ unless run_and_success?(local_command(data))
45
+ return Failure(data.merge(:error => "Could not enable #{data[:release_name]} on the app master"))
46
+ end
47
+
48
+ data[:enabled].push(servers.first {|server| server.role == :app_master || server.role == :solo})
49
+
50
+ Success(data)
51
+ end
52
+
53
+ def remotes
54
+ servers.reject {|server| server.role == :app_master}
55
+ end
56
+
57
+ def remote_command(remote, data)
58
+ "ssh -i #{config.paths.internal_key} #{remote.user}@#{remote.hostname} '#{create_release(data)} && #{unarchive(data)} && #{link_current(data)}'"
59
+ end
60
+
61
+ def local_command(data)
62
+ "#{unarchive(data)} && #{link_current(data)}"
63
+ end
64
+
65
+ def create_release(data)
66
+ "mkdir -p #{release_path(data)}"
67
+ end
68
+
69
+ def unarchive(data)
70
+ "tar -C #{release_path(data)} -z -x -f #{package(data)}"
71
+ end
72
+
73
+ def link_current(data)
74
+ "ln -nsf #{release_path(data)} #{current_path(data)}"
75
+ end
76
+
77
+ def package(data)
78
+ "#{release_path(data)}.tgz"
79
+ end
80
+
81
+ def release_path(data)
82
+ "#{all_releases(data)}/#{data[:release_name]}"
83
+ end
84
+
85
+ def all_releases(data)
86
+ "#{app_path(data)}/releases"
87
+ end
88
+
89
+ def current_path(data)
90
+ "#{app_path(data)}/current"
91
+ end
92
+
93
+ def app_path(data)
94
+ "/data/#{data[:app_name]}"
95
+ end
96
+ end
97
+
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,24 @@
1
+ require 'result'
2
+
3
+ module EY
4
+ module Serverside
5
+ module Slug
6
+
7
+ class FailureHandler
8
+ def self.handle(data = {})
9
+ new(data[:config], data[:shell], data[:servers]).call(data)
10
+ end
11
+
12
+ def initialize(config, shell, servers)
13
+ @config = config
14
+ @shell = shell
15
+ @servers = servers
16
+ end
17
+
18
+ def call(data = {})
19
+ Result::Failure.new(data)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,86 @@
1
+ require 'railway'
2
+ require 'runner'
3
+
4
+ module EY
5
+ module Serverside
6
+ module Slug
7
+
8
+ class Finalizer
9
+ include Railway
10
+ include Runner
11
+
12
+ step :finalize_remotes
13
+ step :finalize_local
14
+
15
+ attr_reader :config, :shell, :servers
16
+
17
+ def initialize(config, shell, servers)
18
+ @config = config
19
+ @shell = shell
20
+ @servers = servers
21
+ end
22
+
23
+ private
24
+ def finalize_remotes(data)
25
+ finalized = []
26
+
27
+ remotes.each do |remote|
28
+ if run_and_success?(remote_command(remote, data))
29
+ finalized.push(remote)
30
+ else
31
+ return Failure(
32
+ data.merge(
33
+ :finalized => finalized,
34
+ :error => "Could not finalize #{data[:release_name]} on #{remote.hostname}"
35
+ )
36
+ )
37
+ end
38
+ end
39
+
40
+ Success(data.merge(:finalized => finalized))
41
+ end
42
+
43
+ def finalize_local(data = {})
44
+ unless run_and_success?(finalize_command(data))
45
+ return Failure(data.merge(:error => "Could not finalize #{data[:release_name]} on the app master"))
46
+ end
47
+
48
+ data[:finalized].push(servers.first {|server| server.role == :app_master || server.role == :solo})
49
+
50
+ Success(data)
51
+ end
52
+
53
+ def remotes
54
+ servers.reject {|server| server.role == :app_master}
55
+ end
56
+
57
+ def remote_command(remote, data)
58
+ "ssh -i #{config.paths.internal_key} #{remote.user}@#{remote.hostname} '#{finalize_command(data)}'"
59
+ end
60
+
61
+ def finalize_command(data)
62
+ [
63
+ "for release in #{all_releases(data)}/*",
64
+ %{do if [ -d "${release}" ] && [ "$(basename "${release}")" != "#{data[:release_name]}"]},
65
+ 'then rm -rf "${release}"',
66
+ 'fi',
67
+ 'done'
68
+ ].join(' ; ')
69
+ end
70
+
71
+ def old_release_path(data)
72
+ "#{all_releases(data)}/#{data[:current_release_name]}"
73
+ end
74
+
75
+ def all_releases(data)
76
+ "#{app_path(data)}/releases"
77
+ end
78
+
79
+ def app_path(data)
80
+ "/data/#{data[:app_name]}"
81
+ end
82
+ end
83
+
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,29 @@
1
+ require 'result'
2
+
3
+ module EY
4
+ module Serverside
5
+ module Slug
6
+
7
+ module Generator
8
+ extend Result::DSL
9
+
10
+ def self.generate(data = {})
11
+ data[:shell].logged_system(ogun(data)).success? ?
12
+ Success(data.merge(:generated => true)) :
13
+ Failure(data.merge(:error => "Ogun build failed"))
14
+ end
15
+
16
+ def self.ogun(data = {})
17
+ [
18
+ "/engineyard/bin/ogun",
19
+ "build",
20
+ data[:app_name],
21
+ "--release",
22
+ data[:release_name]
23
+ ].join(' ')
24
+ end
25
+ end
26
+
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,41 @@
1
+ require 'result'
2
+ require 'runner'
3
+
4
+ module EY
5
+ module Serverside
6
+ module Slug
7
+ class Migrator
8
+ include Result::DSL
9
+ include Runner
10
+
11
+ attr_reader :config, :shell
12
+
13
+ def initialize(config, shell)
14
+ @config = config
15
+ @shell = shell
16
+ end
17
+
18
+ def call(data = {})
19
+ return Success(data) unless config.migrate?
20
+
21
+ cmd = "PATH=#{paths.binstubs}:$PATH #{config.framework_envs} #{config.migration_command}"
22
+
23
+ return Failure(
24
+ data.merge(:error => "Could not migrate database")
25
+ ) unless Dir.chdir(paths.active_release) {run_and_success?(cmd)}
26
+
27
+ Success(data.merge(:migrated => true))
28
+ end
29
+
30
+ private
31
+ def paths
32
+ config.paths
33
+ end
34
+
35
+ def self.migrate(data = {})
36
+ new(data[:config], data[:shell]).call(data)
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,103 @@
1
+ require 'railway'
2
+ require 'runner'
3
+
4
+ module EY
5
+ module Serverside
6
+ module Slug
7
+
8
+ class Restarter
9
+ include Railway
10
+ include Runner
11
+
12
+ step :restart_remote_apps
13
+ step :restart_local
14
+
15
+ attr_reader :config, :shell, :servers
16
+
17
+ def self.restart(data = {})
18
+ new(data[:config], data[:shell], data[:servers]).call(data)
19
+ end
20
+
21
+ def initialize(config, shell, servers)
22
+ @config = config
23
+ @shell = shell
24
+ @servers = servers
25
+ end
26
+
27
+ private
28
+ def restart_remote_apps(data = {})
29
+ restarted = []
30
+
31
+ remote_apps.each do |remote|
32
+ if run_and_success?(remote_command(remote, data))
33
+ restarted.push(remote)
34
+ else
35
+ return Failure(
36
+ data.merge(
37
+ :restarted => restarted,
38
+ :error => "Could not restart #{data[:release_name]} on #{remote.hostname}"
39
+ )
40
+ )
41
+ end
42
+ end
43
+
44
+ Success(data.merge(:restarted => restarted))
45
+ end
46
+
47
+ def restart_local(data = {})
48
+ unless run_and_success?(restart_command(data))
49
+ return Failure(data.merge(:error => "Could not restart #{data[:release_name]} on the app master"))
50
+ end
51
+
52
+ data[:restarted].push(master)
53
+
54
+ Success(data)
55
+ end
56
+
57
+ def remotes
58
+ server_array.reject {|server|
59
+ master?(server)
60
+ }
61
+ end
62
+
63
+ def remote_apps
64
+ remotes.select {|server| server.role == :app}
65
+ end
66
+
67
+ def master?(server)
68
+ server == master
69
+ end
70
+
71
+ def util?(server)
72
+ server.role == :util
73
+ end
74
+
75
+ def master
76
+ @master ||= server_array.find {|server|
77
+ master_roles.include?(server.role)
78
+ }
79
+ end
80
+
81
+ def master_roles
82
+ [:app_master, :solo]
83
+ end
84
+
85
+ def server_array
86
+ @server_array ||= servers.to_a
87
+ end
88
+
89
+ def remote_command(remote, data)
90
+ "ssh -i #{internal_key} #{remote.user}@#{remote.hostname} '#{restart_command(data)}'"
91
+ end
92
+
93
+ def restart_command(data)
94
+ %{LANG="en_US.UTF-8" /engineyard/bin/app_#{data[:app_name]} deploy}
95
+ end
96
+
97
+ def internal_key
98
+ config.paths.internal_key
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end