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,21 @@
1
+ require 'engineyard-serverside/callbacks/hooks/base'
2
+
3
+ module EY
4
+ module Serverside
5
+ module Callbacks
6
+ module Hooks
7
+
8
+ class App < Base
9
+ def to_s
10
+ "deploy/#{callback_name}"
11
+ end
12
+
13
+ def short_name
14
+ callback_name
15
+ end
16
+ end
17
+
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,43 @@
1
+ require 'pathname'
2
+
3
+ module EY
4
+ module Serverside
5
+ module Callbacks
6
+ module Hooks
7
+
8
+ class Base
9
+ attr_reader :path, :callback_name, :flavor
10
+
11
+ def initialize(file_path)
12
+ @path = Pathname.new(file_path)
13
+
14
+ filename = path.basename
15
+
16
+ callback = filename.basename('.rb')
17
+
18
+ @flavor = filename == callback ? :executable : :ruby
19
+
20
+ @callback_name = callback.to_s.to_sym
21
+ end
22
+
23
+ def matches?(callback)
24
+ callback_name == callback
25
+ end
26
+
27
+ def read
28
+ path.read
29
+ end
30
+
31
+ def to_s
32
+ raise "Unimplemented"
33
+ end
34
+
35
+ def short_name
36
+ raise "Unimplemented"
37
+ end
38
+ end
39
+
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,28 @@
1
+ require 'engineyard-serverside/callbacks/hooks/base'
2
+
3
+ module EY
4
+ module Serverside
5
+ module Callbacks
6
+ module Hooks
7
+
8
+ class Service < Base
9
+ attr_reader :service_name
10
+
11
+ def initialize(file_path)
12
+ super
13
+ @service_name = path.dirname.basename.to_s
14
+ end
15
+
16
+ def to_s
17
+ "service/#{service_name}/#{callback_name}"
18
+ end
19
+
20
+ def short_name
21
+ "#{service_name}/#{callback_name}"
22
+ end
23
+ end
24
+
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,20 @@
1
+ require 'pathname'
2
+
3
+ require 'engineyard-serverside/callbacks/base_hook'
4
+
5
+ module EY
6
+ module Serverside
7
+ module Callbacks
8
+
9
+ class ServiceHook < BaseHook
10
+ attr_reader :service_name
11
+
12
+ def initialize(file_path)
13
+ super
14
+ @service_name = path.dirname.basename.to_s
15
+ end
16
+ end
17
+
18
+ end
19
+ end
20
+ end
@@ -1,232 +1,11 @@
1
- require 'thor'
2
- require 'pathname'
3
- require 'engineyard-serverside/about'
4
- require 'engineyard-serverside/deploy'
5
- require 'engineyard-serverside/shell'
6
- require 'engineyard-serverside/servers'
7
- require 'engineyard-serverside/cli_helpers'
1
+ require 'engineyard-serverside/cli/app'
8
2
 
9
3
  module EY
10
4
  module Serverside
11
- class CLI < Thor
12
-
13
- extend CLIHelpers
14
-
15
- method_option :migrate, :type => :string,
16
- :desc => "Run migrations with this deploy",
17
- :aliases => ["-m"]
18
-
19
- method_option :branch, :type => :string,
20
- :desc => "Git ref to deploy, defaults to master. May be a branch, a tag, or a SHA",
21
- :aliases => %w[-b --ref --tag]
22
-
23
- method_option :repo, :type => :string,
24
- :desc => "Remote repo to deploy",
25
- :aliases => ["-r"]
26
-
27
-
28
- # Archive source strategy
29
- method_option :archive, :type => :string,
30
- :desc => "Remote URI for archive to download and unzip"
31
-
32
- # Git source strategy
33
- method_option :git, :type => :string,
34
- :desc => "Remote git repo to deploy"
35
-
36
- method_option :clean, :type => :boolean,
37
- :desc => "Run deploy without relying on existing files"
38
-
39
-
40
- account_app_env_options
41
- config_option
42
- framework_env_option
43
- instances_options
44
- stack_option
45
- verbose_option
46
-
47
- desc "deploy", "Deploy code to /data/<app>"
48
- def deploy(default_task=:deploy)
49
- init_and_propagate(options, default_task.to_s) do |servers, config, shell|
50
- EY::Serverside::Deploy.new(servers, config, shell).send(default_task)
51
- end
52
- end
53
-
54
- account_app_env_options
55
- config_option
56
- instances_options
57
- verbose_option
58
- desc "enable_maintenance", "Enable maintenance page (disables web access)"
59
- def enable_maintenance
60
- init_and_propagate(options, 'enable_maintenance') do |servers, config, shell|
61
- EY::Serverside::Maintenance.new(servers, config, shell).manually_enable
62
- end
63
- end
64
-
65
- account_app_env_options
66
- config_option
67
- instances_options
68
- verbose_option
69
- desc "maintenance_status", "Maintenance status"
70
- def maintenance_status
71
- init(options, "maintenance-status") do |servers, config, shell|
72
- EY::Serverside::Maintenance.new(servers, config, shell).status
73
- end
74
- end
75
-
76
- account_app_env_options
77
- config_option
78
- instances_options
79
- verbose_option
80
- desc "disable_maintenance", "Disable maintenance page (enables web access)"
81
- def disable_maintenance
82
- init_and_propagate(options, 'disable_maintenance') do |servers, config, shell|
83
- EY::Serverside::Maintenance.new(servers, config, shell).manually_disable
84
- end
85
- end
86
-
87
- method_option :release_path, :type => :string,
88
- :desc => "Value for #release_path in hooks (mostly for internal coordination)",
89
- :aliases => ["-r"]
90
-
91
- method_option :current_roles, :type => :array,
92
- :desc => "Value for #current_roles in hooks"
93
-
94
- method_option :current_name, :type => :string,
95
- :desc => "Value for #current_name in hooks"
96
- account_app_env_options
97
- config_option
98
- framework_env_option
99
- verbose_option
100
- desc "hook [NAME]", "Run a particular deploy hook"
101
- def hook(hook_name)
102
- init(options, "hook-#{hook_name}") do |servers, config, shell|
103
- EY::Serverside::DeployHook.new(config, shell, hook_name).call
104
- end
105
- end
106
-
107
- method_option :ignore_existing, :type => :boolean,
108
- :desc => "When syncing /data/app directory, don't overwrite destination files"
109
- account_app_env_options
110
- config_option
111
- framework_env_option
112
- instances_options
113
- stack_option
114
- verbose_option
115
- desc "integrate", "Integrate other instances into this cluster"
116
- def integrate
117
- app_dir = Pathname.new "/data/#{options[:app]}"
118
- current_app_dir = app_dir.join("current")
119
-
120
- # so that we deploy to the same place there that we have here
121
- integrate_options = options.dup
122
- integrate_options[:release_path] = current_app_dir.realpath.to_s
123
-
124
- # we have to deploy the same SHA there as here
125
- integrate_options[:branch] = current_app_dir.join('REVISION').read.strip
126
-
127
- # always rebundle gems on integrate to make sure the instance comes up correctly.
128
- integrate_options[:clean] = true
129
-
130
- logname = "integrate-#{options[:instances].join('-')}".gsub(/[^-.\w]/,'')
131
-
132
- init_and_propagate(integrate_options, logname) do |servers, config, shell|
133
-
134
- # We have to rsync the entire app dir, so we need all the permissions to be correct!
135
- chown_command = %|find #{app_dir} \\( -not -user #{config.user} -or -not -group #{config.group} \\) -exec chown -h #{config.user}:#{config.group} "{}" +|
136
- shell.logged_system("sudo sh -l -c '#{chown_command}'", servers.detect {|s| s.local?})
137
-
138
- servers.run_for_each! do |server|
139
- chown = server.command_on_server('sudo sh -l -c', chown_command)
140
- sync = server.sync_directory_command(app_dir, options[:ignore_existing])
141
- clean = server.command_on_server('sh -l -c', "rm -rf #{current_app_dir}")
142
- "(#{chown}) && (#{sync}) && (#{clean})"
143
- end
144
-
145
- # deploy local-ref to other instances into /data/$app/local-current
146
- EY::Serverside::Deploy.new(servers, config, shell).cached_deploy
147
- end
148
- end
149
-
150
- account_app_env_options
151
- instances_options
152
- stack_option
153
- verbose_option
154
- desc "restart", "Restart app servers, conditionally enabling maintenance page"
155
- def restart
156
- options = self.options.dup
157
- options[:release_path] = Pathname.new("/data/#{options[:app]}/current").realpath.to_s
158
-
159
- init_and_propagate(options, 'restart') do |servers, config, shell|
160
- EY::Serverside::Deploy.new(servers, config, shell).restart_with_maintenance_page
161
- end
162
- end
163
-
164
- private
165
-
166
- def init_and_propagate(*args)
167
- init(*args) do |servers, config, shell|
168
- propagate(servers, shell)
169
- yield servers, config, shell
170
- end
171
- end
172
-
173
- def init(options, action)
174
- config = EY::Serverside::Deploy::Configuration.new(options)
175
- shell = EY::Serverside::Shell.new(
176
- :verbose => config.verbose,
177
- :log_path => File.join(ENV['HOME'], "#{config.app}-#{action}.log")
178
- )
179
- shell.debug "Initializing #{About.name_with_version}."
180
- servers = load_servers(config, shell)
181
- begin
182
- yield servers, config, shell
183
- rescue EY::Serverside::RemoteFailure => e
184
- shell.fatal e.message
185
- raise
186
- rescue Exception => e
187
- shell.fatal "#{e.backtrace[0]}: #{e.message} (#{e.class})"
188
- raise
189
- end
190
- end
191
-
192
- def propagate(servers, shell)
193
- shell.status "Verifying and propagating #{About.name_with_version} to all servers."
194
-
195
- gem_binary = File.join(Gem.default_bindir, 'gem')
196
- remote_gem_file = File.join(Dir.tmpdir, About.gem_filename)
197
-
198
- # the [,)] is to stop us from looking for e.g. 0.5.1, seeing
199
- # 0.5.11, and mistakenly thinking 0.5.1 is there
200
- check_command = %{#{gem_binary} list #{About.gem_name} | grep "#{About.gem_name}" | egrep -q "#{About.version.gsub(/\./, '\.')}[,)]"}
201
- install_command = "#{gem_binary} install --no-rdoc --no-ri '#{remote_gem_file}'"
202
-
203
- servers.remote.run_for_each! do |server|
204
- check = server.command_on_server('sh -l -c', check_command)
205
- scp = server.scp_command(About.gem_file, remote_gem_file)
206
- install = server.command_on_server('sudo sh -l -c', install_command)
207
-
208
- "(#{check}) || ((#{scp}) && (#{install}))"
209
- end
210
- end
211
-
212
- def load_servers(config, shell)
213
- EY::Serverside::Servers.from_hashes(assemble_instance_hashes(config), shell)
214
- end
215
-
216
- def assemble_instance_hashes(config)
217
- if options[:instances]
218
- options[:instances].collect { |hostname|
219
- { :hostname => hostname,
220
- :roles => options[:instance_roles][hostname].to_s.split(','),
221
- :name => options[:instance_names][hostname],
222
- :user => config.user,
223
- }
224
- }
225
- else
226
- []
227
- end
228
- end
229
5
 
6
+ # CLI is a namespace that encompasses all concepts around command-line
7
+ # interactions with EY::Serverside
8
+ module CLI
230
9
  end
231
10
  end
232
11
  end
@@ -0,0 +1,136 @@
1
+ require 'thor'
2
+ require 'pathname'
3
+ require 'engineyard-serverside/about'
4
+ require 'engineyard-serverside/deploy'
5
+ require 'engineyard-serverside/propagator'
6
+ require 'engineyard-serverside/shell'
7
+ require 'engineyard-serverside/cli/server_hash_extractor'
8
+ require 'engineyard-serverside/servers'
9
+ require 'engineyard-serverside/cli/helpers'
10
+ require 'engineyard-serverside/cli/workflows'
11
+
12
+ module EY
13
+ module Serverside
14
+ module CLI
15
+
16
+ # App is the actual Thor-based entry point for the engineyard-serverside
17
+ # CLI application
18
+ class App < Thor
19
+
20
+ extend Helpers
21
+
22
+ method_option :migrate, :type => :string,
23
+ :desc => "Run migrations with this deploy",
24
+ :aliases => ["-m"]
25
+
26
+ method_option :branch, :type => :string,
27
+ :desc => "Git ref to deploy, defaults to master. May be a branch, a tag, or a SHA",
28
+ :aliases => %w[-b --ref --tag]
29
+
30
+ method_option :repo, :type => :string,
31
+ :desc => "Remote repo to deploy",
32
+ :aliases => ["-r"]
33
+
34
+
35
+ # Archive source strategy
36
+ method_option :archive, :type => :string,
37
+ :desc => "Remote URI for archive to download and unzip"
38
+
39
+ # Git source strategy
40
+ method_option :git, :type => :string,
41
+ :desc => "Remote git repo to deploy"
42
+
43
+ method_option :clean, :type => :boolean,
44
+ :desc => "Run deploy without relying on existing files"
45
+
46
+
47
+ account_app_env_options
48
+ config_option
49
+ framework_env_option
50
+ instances_options
51
+ stack_option
52
+ verbose_option
53
+
54
+ desc "deploy", "Deploy code to /data/<app>"
55
+ def deploy(default_task=:deploy)
56
+
57
+ # By default, we'll want to perform the :deploy workflow, but this
58
+ # method is also the entry point for the rollback workflow. So,
59
+ # we'll just let the workflow system figure out what to do based on
60
+ # the task passed in from the command line.
61
+ Workflows.perform(default_task, options)
62
+ end
63
+
64
+ account_app_env_options
65
+ config_option
66
+ instances_options
67
+ verbose_option
68
+ desc "enable_maintenance", "Enable maintenance page (disables web access)"
69
+ def enable_maintenance
70
+ Workflows.perform(:enable_maintenance, options)
71
+ end
72
+
73
+ account_app_env_options
74
+ config_option
75
+ instances_options
76
+ verbose_option
77
+ desc "maintenance_status", "Maintenance status"
78
+ def maintenance_status
79
+ Workflows.perform(:maintenance_status, options)
80
+ end
81
+
82
+ account_app_env_options
83
+ config_option
84
+ instances_options
85
+ verbose_option
86
+ desc "disable_maintenance", "Disable maintenance page (enables web access)"
87
+ def disable_maintenance
88
+ Workflows.perform(:disable_maintenance, options)
89
+ end
90
+
91
+ method_option :release_path, :type => :string,
92
+ :desc => "Value for #release_path in hooks (mostly for internal coordination)",
93
+ :aliases => ["-r"]
94
+
95
+ method_option :current_roles, :type => :array,
96
+ :desc => "Value for #current_roles in hooks"
97
+
98
+ method_option :current_name, :type => :string,
99
+ :desc => "Value for #current_name in hooks"
100
+ account_app_env_options
101
+ config_option
102
+ framework_env_option
103
+ verbose_option
104
+ desc "hook [NAME]", "Run a particular deploy hook"
105
+ def hook(hook_name)
106
+ Workflows.perform(
107
+ :hook,
108
+ options.merge(:hook_name => hook_name)
109
+ )
110
+ end
111
+
112
+ method_option :ignore_existing, :type => :boolean,
113
+ :desc => "When syncing /data/app directory, don't overwrite destination files"
114
+ account_app_env_options
115
+ config_option
116
+ framework_env_option
117
+ instances_options
118
+ stack_option
119
+ verbose_option
120
+ desc "integrate", "Integrate other instances into this cluster"
121
+ def integrate
122
+ Workflows.perform(:integrate, options)
123
+ end
124
+
125
+ account_app_env_options
126
+ instances_options
127
+ stack_option
128
+ verbose_option
129
+ desc "restart", "Restart app servers, conditionally enabling maintenance page"
130
+ def restart
131
+ Workflows.perform(:restart, options)
132
+ end
133
+ end
134
+ end
135
+ end
136
+ end