engineyard-serverside 2.7.8pre2 → 2.8.0.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 (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
@@ -0,0 +1,66 @@
1
+ require 'railway'
2
+
3
+ module EY
4
+ module Serverside
5
+ module Callbacks
6
+ module Distributor
7
+
8
+ class ViabilityFilter
9
+ include Railway
10
+
11
+ step :normalize_input
12
+ step :check_ruby_candidates
13
+ step :check_executable_candidates
14
+ step :calculate_callback_name
15
+
16
+ def normalize_input(input = {})
17
+ input[:viable] = []
18
+
19
+ unless input[:candidates].respond_to?(:each)
20
+ input[:candidates] = [input[:candidates]]
21
+ end
22
+
23
+ Success(input)
24
+ end
25
+
26
+ def check_ruby_candidates(input = {})
27
+ hooks = input[:candidates].
28
+ select {|hook| hook.flavor == :ruby}
29
+
30
+ hooks.each do |hook|
31
+ input[:viable].push(hook)
32
+ end
33
+
34
+ Success(input)
35
+ end
36
+
37
+ def check_executable_candidates(input = {})
38
+ hooks = input[:candidates].
39
+ select {|hook| hook.flavor == :executable}
40
+
41
+ hooks.each do |hook|
42
+ if hook.path.executable?
43
+ input[:viable].push(hook)
44
+ else
45
+ input[:shell].warning(
46
+ "Skipping possible deploy hook #{hook} because it is not executable."
47
+ )
48
+ end
49
+ end
50
+
51
+ Success(input)
52
+ end
53
+
54
+ def calculate_callback_name(input = {})
55
+ if input[:viable].empty?
56
+ return Failure(input.merge({:reason => :no_viable_hooks}))
57
+ end
58
+
59
+ Success(input[:viable].first.callback_name)
60
+ end
61
+ end
62
+
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,23 @@
1
+ require 'engineyard-serverside/callbacks/executor/executable'
2
+ require 'engineyard-serverside/callbacks/executor/ruby'
3
+
4
+ module EY
5
+ module Serverside
6
+ module Callbacks
7
+
8
+ module Executor
9
+ FLAVORS = {
10
+ :ruby => Ruby,
11
+ :executable => Executable
12
+ }
13
+
14
+ def self.execute(config, shell, hooks)
15
+ hooks.each do |hook|
16
+ FLAVORS[hook.flavor].execute(config, shell, hook)
17
+ end
18
+ end
19
+ end
20
+
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,44 @@
1
+ require 'railway'
2
+
3
+ module EY
4
+ module Serverside
5
+ module Callbacks
6
+ module Executor
7
+
8
+ class Base
9
+ include Railway
10
+
11
+ attr_reader :config, :shell, :hook
12
+
13
+ def self.execute(config, shell, hook)
14
+ new(config, shell, hook).execute
15
+ end
16
+
17
+ def initialize(config, shell, hook)
18
+ @config = config
19
+ @shell = shell
20
+ @hook = hook
21
+ end
22
+
23
+ def execute
24
+ call.or_else {|payload| handle_failure(payload)}
25
+ end
26
+
27
+ def handle_failure(payload = {})
28
+ raise "Unimplemented Hook Executor!"
29
+ end
30
+
31
+ def paths
32
+ config.paths
33
+ end
34
+
35
+ def hook_path
36
+ hook.path
37
+ end
38
+
39
+ end
40
+
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,123 @@
1
+ require 'escape'
2
+ require 'runner'
3
+ require 'engineyard-serverside/callbacks/executor/base'
4
+
5
+ module EY
6
+ module Serverside
7
+ module Callbacks
8
+ module Executor
9
+
10
+ class Executable < Base
11
+ include Runner
12
+
13
+ step :validate_hook
14
+ step :populate_environment
15
+ step :calculate_wrapper
16
+ step :run_hook
17
+
18
+ def handle_failure(payload = {})
19
+ case payload[:reason]
20
+
21
+ when :not_executable
22
+ true
23
+ when :execution_failed
24
+ abort "*** [Error] Hook failed to exit cleanly: #{hook_path} ***\n"
25
+ else
26
+ abort "*** [Error] An unknown error occurred for hook: #{hook_path} ***\n"
27
+ end
28
+ end
29
+
30
+ def validate_hook(input = {})
31
+ unless hook_path.executable?
32
+ return Failure(
33
+ input.merge(
34
+ {
35
+ :reason => :not_executable
36
+ }
37
+ )
38
+ )
39
+ end
40
+
41
+ Success(input)
42
+ end
43
+
44
+ def calculate_wrapper(input = {})
45
+ Success(
46
+ input.merge(
47
+ {
48
+ :wrapper => hook.respond_to?(:service_name) ?
49
+ About.service_hook_executor :
50
+ About.hook_executor
51
+ }
52
+ )
53
+ )
54
+ end
55
+
56
+ def run_hook(input = {})
57
+ env = "#{input[:environment]} #{config.framework_envs}"
58
+ wrapper = input[:wrapper]
59
+ name = hook.short_name
60
+
61
+ result = run("#{env} #{wrapper} #{name}")
62
+
63
+ unless result.success?
64
+ return Failure(
65
+ input.merge(
66
+ {
67
+ :reason => :execution_failed
68
+ }
69
+ )
70
+ )
71
+ end
72
+
73
+ Success(input)
74
+ end
75
+
76
+ def populate_environment(input = {})
77
+ env = {
78
+ 'EY_DEPLOY_ACCOUNT_NAME' => config.account_name,
79
+ 'EY_DEPLOY_APP' => config.app,
80
+ 'EY_DEPLOY_CONFIG' => config.to_json,
81
+ 'EY_DEPLOY_CURRENT_ROLES' => current_roles,
82
+ 'EY_DEPLOY_CURRENT_NAME' => current_name,
83
+ 'EY_DEPLOY_ENVIRONMENT_NAME' => config.environment_name,
84
+ 'EY_DEPLOY_FRAMEWORK_ENV' => config.framework_env.to_s,
85
+ 'EY_DEPLOY_RELEASE_PATH' => paths.active_release.to_s,
86
+ 'EY_DEPLOY_VERBOSE' => verbose,
87
+ }
88
+
89
+ Success(
90
+ input.merge(
91
+ {
92
+ :environment => env.
93
+ reject {|name, value| value.nil?}.
94
+ map {|name, value| "#{name}=#{Escape.shell_command([value])}"}.
95
+ join(' ')
96
+ }
97
+ )
98
+ )
99
+ end
100
+
101
+ def verbose
102
+ config.verbose ? '1' : '0'
103
+ end
104
+
105
+ def current_roles
106
+ config.current_roles.to_a.join(' ')
107
+ end
108
+
109
+ def current_name
110
+ name = config.current_name
111
+
112
+ unless name
113
+ return nil
114
+ end
115
+
116
+ name.to_s
117
+ end
118
+ end
119
+
120
+ end
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,20 @@
1
+ require 'rbconfig'
2
+ require 'railway'
3
+
4
+ require 'engineyard-serverside/callbacks/executor/ruby/executor'
5
+
6
+ module EY
7
+ module Serverside
8
+ module Callbacks
9
+ module Executor
10
+
11
+ module Ruby
12
+ def self.execute(config, shell, hook)
13
+ Executor.execute(config, shell,hook)
14
+ end
15
+ end
16
+
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,81 @@
1
+ require 'engineyard-serverside/shell/helpers'
2
+
3
+ module EY
4
+ module Serverside
5
+ module Callbacks
6
+ module Executor
7
+ module Ruby
8
+
9
+ class Context
10
+ include EY::Serverside::Shell::Helpers
11
+
12
+ attr_reader :configuration, :shell, :hook
13
+
14
+ def initialize(config, shell, hook)
15
+ @configuration = config
16
+ @configuration.set_framework_envs
17
+ @shell = shell
18
+ @node = config.node
19
+ @hook = hook
20
+ end
21
+
22
+ def config
23
+ @configuration
24
+ end
25
+
26
+ def inspect
27
+ "#<Callbacks::Executor::Ruby::Context #{hook.path.inspect}>"
28
+ end
29
+
30
+ def method_missing(meth, *args, &blk)
31
+ if config.respond_to?(meth)
32
+ shell.warning "Use of `#{meth}` (via method_missing) is deprecated in favor of `config.#{meth}` for improved error messages and compatibility.\n\tin #{hook.path}"
33
+ config.send(meth, *args, &blk)
34
+ else
35
+ super
36
+ end
37
+ end
38
+
39
+ def respond_to?(*a)
40
+ config.respond_to?(*a) || super
41
+ end
42
+
43
+ def run(cmd)
44
+ shell.logged_system(Escape.shell_command(["sh", "-l", "-c", cmd])).success?
45
+ end
46
+
47
+ def run!(cmd)
48
+ run(cmd) or raise("run!: Command failed. #{cmd}")
49
+ end
50
+
51
+ def sudo(cmd)
52
+ shell.logged_system(Escape.shell_command(["sudo", "sh", "-l", "-c", cmd])).success?
53
+ end
54
+
55
+ def sudo!(cmd)
56
+ sudo(cmd) or raise("sudo!: Command failed. #{cmd}")
57
+ end
58
+
59
+ # convenience functions for running on certain instance types
60
+ def on_app_master(&blk) on_roles(%w[solo app_master], &blk) end
61
+ def on_app_servers(&blk) on_roles(%w[solo app_master app], &blk) end
62
+ def on_app_servers_and_utilities(&blk) on_roles(%w[solo app_master app util], &blk) end
63
+
64
+ def on_utilities(*names, &blk)
65
+ names.flatten!
66
+ on_roles(%w[util]) do
67
+ blk.call if names.empty? || names.include?(config.current_name)
68
+ end
69
+ end
70
+
71
+ private
72
+ def on_roles(desired_roles)
73
+ yield if desired_roles.any? { |role| config.current_roles.include?(role) }
74
+ end
75
+ end
76
+
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,118 @@
1
+ require 'rbconfig'
2
+ require 'railway'
3
+ require 'engineyard-serverside/callbacks/executor/base'
4
+ require 'engineyard-serverside/callbacks/executor/ruby/context'
5
+
6
+ module EY
7
+ module Serverside
8
+ module Callbacks
9
+ module Executor
10
+ module Ruby
11
+
12
+ # An executor for Ruby hooks
13
+ class Executor < Base
14
+ step :validate_hook
15
+ step :display_deprecation_warnings
16
+ step :announce_execution
17
+ step :context_eval
18
+
19
+ def handle_failure(payload = {})
20
+ case payload[:reason]
21
+
22
+ # We tried to execute the hook, but doing so raised an exception.
23
+ # So, let us tell you all about that and propagate the error to
24
+ # the caller.
25
+ when :execution_failed
26
+ exception = payload[:exception]
27
+ display_hook_error(exception)
28
+ raise exception
29
+
30
+ # A syntax error was detected in the hook, so rather than trying
31
+ # to run it, we bail with some information for the user.
32
+ when :syntax_error
33
+ abort "*** [Error] Invalid Ruby syntax in hook: #{hook_path} ***\n*** #{payload[:syntax_error]} ***"
34
+
35
+ # Something most out of the ordinary happened, to the point that
36
+ # we don't know how to handle it. That being the case, we're going
37
+ # to just flat out bail.
38
+ else
39
+ abort "*** [Error] An unknown error occurred for hook: #{hook_path} ***"
40
+ end
41
+ end
42
+
43
+ def display_deprecation_warnings(input = {})
44
+ code = input[:code]
45
+
46
+ if code =~ /@configuration/
47
+ shell.warning("Use of `@configuration` in deploy hooks is deprecated.\nPlease use `config`, which provides access to the same object.\n\tin #{hook_path}")
48
+ end
49
+
50
+ if code =~ /@node/
51
+ shell.warning("Use of `@node` in deploy hooks is deprecated.\nPlease use `config.node`, which provides access to the same object.\n\tin #{hook_path}")
52
+ end
53
+
54
+ Success(input)
55
+ end
56
+
57
+ def announce_execution(input = {})
58
+ shell.info "Executing #{hook.path} ..."
59
+ Success(input)
60
+ end
61
+
62
+ def context_eval(input = {})
63
+ Dir.chdir(paths.active_release.to_s) do
64
+ begin
65
+ Context.new(config, shell, hook).instance_eval(input[:code])
66
+ rescue Exception => exception
67
+ return Failure(
68
+ input.merge(
69
+ {
70
+ :reason => :execution_failed,
71
+ :exception => exception
72
+ }
73
+ )
74
+ )
75
+ end
76
+ end
77
+
78
+ Success(input)
79
+ end
80
+
81
+ def validate_hook(input = {})
82
+ output = `#{ruby_bin} -c #{hook_path} 2>&1`
83
+ unless output =~ /Syntax OK/
84
+ return Failure(
85
+ input.merge(
86
+ {
87
+ :reason => :syntax_error,
88
+ :syntax_error => output
89
+ }
90
+ )
91
+ )
92
+ end
93
+
94
+ Success(input.merge({:code => hook.read}))
95
+ end
96
+
97
+ def ruby_bin
98
+ # Ideally, we'd use RbConfig.ruby, but that doesn't work on 1.8.7
99
+ File.join(RbConfig::CONFIG['bindir'], RbConfig::CONFIG['ruby_install_name'])
100
+ end
101
+
102
+ def display_hook_error(exception)
103
+ shell.fatal <<-ERROR
104
+ Exception raised in hook #{hook_path}.
105
+
106
+ #{exception.class}: #{exception.to_s}
107
+
108
+ Please fix this error before retrying.
109
+ ERROR
110
+ end
111
+
112
+ end
113
+
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end