engineyard-serverside 2.0.0.pre4 → 2.0.0.pre5

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.
@@ -34,7 +34,25 @@ module EY
34
34
  EY::Serverside::Deploy.new(servers, config, shell).send(default_task)
35
35
  end
36
36
 
37
+ account_app_env_options
38
+ config_option
39
+ instances_options
40
+ verbose_option
41
+ desc "enable_maintenance", "Enable maintenance page (disables web access)"
42
+ def enable_maintenance
43
+ servers, config, shell = init_and_propagate(options, 'enable_maintenance')
44
+ EY::Serverside::Maintenance.new(servers, config, shell).manually_enable
45
+ end
37
46
 
47
+ account_app_env_options
48
+ config_option
49
+ instances_options
50
+ verbose_option
51
+ desc "disable_maintenance", "Disable maintenance page (enables web access)"
52
+ def disable_maintenance
53
+ servers, config, shell = init_and_propagate(options, 'disable_maintenance')
54
+ EY::Serverside::Maintenance.new(servers, config, shell).manually_disable
55
+ end
38
56
 
39
57
  method_option :release_path, :type => :string,
40
58
  :desc => "Value for #release_path in hooks (mostly for internal coordination)",
@@ -95,7 +113,6 @@ module EY
95
113
  desc "restart", "Restart app servers, conditionally enabling maintenance page"
96
114
  def restart
97
115
  servers, config, shell = init_and_propagate(options, 'restart')
98
-
99
116
  EY::Serverside::Deploy.new(servers, config, shell).restart_with_maintenance_page
100
117
  end
101
118
 
@@ -3,6 +3,7 @@ require 'base64'
3
3
  require 'fileutils'
4
4
  require 'json'
5
5
  require 'engineyard-serverside/rails_asset_support'
6
+ require 'engineyard-serverside/maintenance'
6
7
 
7
8
  module EY
8
9
  module Serverside
@@ -33,7 +34,7 @@ module EY
33
34
  check_for_ey_config
34
35
  symlink_configs
35
36
  setup_sqlite3_if_necessary
36
- conditionally_enable_maintenance_page
37
+ enable_maintenance_page
37
38
  run_with_callbacks(:migrate)
38
39
  run_with_callbacks(:compile_assets) # defined in RailsAssetSupport
39
40
  callback(:before_symlink)
@@ -44,7 +45,7 @@ module EY
44
45
 
45
46
  callback(:after_symlink)
46
47
  run_with_callbacks(:restart)
47
- conditionally_disable_maintenance_page
48
+ disable_maintenance_page
48
49
 
49
50
  cleanup_old_releases
50
51
  shell.status "Finished deploy at #{Time.now.asctime}"
@@ -117,79 +118,17 @@ To fix this problem, commit your Gemfile.lock to your repository and redeploy.
117
118
 
118
119
  def restart_with_maintenance_page
119
120
  require_custom_tasks
120
- with_maintenance_page { restart }
121
+ enable_maintenance_page
122
+ restart
123
+ disable_maintenance_page
121
124
  end
122
125
 
123
126
  def enable_maintenance_page
124
- maintenance_page_candidates = [
125
- "public/maintenance.html.custom",
126
- "public/maintenance.html.tmp",
127
- "public/maintenance.html",
128
- "public/system/maintenance.html.default",
129
- ].map do |file|
130
- File.join(c.latest_release, file)
131
- end
132
-
133
- # this one is guaranteed to exist
134
- maintenance_page_candidates << File.expand_path("default_maintenance_page.html", File.dirname(__FILE__))
135
-
136
- # put in the maintenance page
137
- maintenance_file = maintenance_page_candidates.detect do |file|
138
- File.exists?(file)
139
- end
140
-
141
- shell.status "Enabling maintenance page."
142
- @maintenance_up = true
143
- roles :app_master, :app, :solo do
144
- run Escape.shell_command(['mkdir', '-p', File.dirname(c.maintenance_page_enabled_path)])
145
- run Escape.shell_command(['cp', maintenance_file, c.maintenance_page_enabled_path])
146
- end
147
- end
148
-
149
- def conditionally_enable_maintenance_page
150
- if c.enable_maintenance_page?
151
- enable_maintenance_page
152
- else
153
- explain_not_enabling_maintenance_page
154
- end
155
- end
156
-
157
- def explain_not_enabling_maintenance_page
158
- if c.migrate?
159
- if !c.maintenance_on_migrate? && !c.maintenance_on_restart?
160
- shell.status "Skipping maintenance page. (maintenance_on_migrate is false in ey.yml)"
161
- shell.notice "[Caution] No maintenance migrations must be non-destructive!"
162
- shell.notice "Requests may be served during a partially migrated state."
163
- end
164
- else
165
- if c.required_downtime_stack? && !c.maintenance_on_restart?
166
- shell.status "Skipping maintenance page. (maintenance_on_restart is false in ey.yml, overriding recommended default)"
167
- unless File.exist?(c.maintenance_page_enabled_path)
168
- shell.warning <<-WARN
169
- No maintenance page! Brief downtime may be possible during restart.
170
- This application stack does not support no-downtime restarts.
171
- WARN
172
- end
173
- elsif !c.required_downtime_stack?
174
- shell.status "Skipping maintenance page. (no-downtime restarts supported)"
175
- end
176
- end
127
+ maintenance.conditionally_enable
177
128
  end
178
129
 
179
130
  def disable_maintenance_page
180
- shell.status "Removing maintenance page."
181
- @maintenance_up = false
182
- roles :app_master, :app, :solo do
183
- run "rm -f #{c.maintenance_page_enabled_path}"
184
- end
185
- end
186
-
187
- def conditionally_disable_maintenance_page
188
- if c.disable_maintenance_page?
189
- disable_maintenance_page
190
- elsif File.exists?(c.maintenance_page_enabled_path)
191
- shell.notice "[Attention] Maintenance page is still up.\nYou must remove it manually using `ey web enable`."
192
- end
131
+ maintenance.conditionally_disable
193
132
  end
194
133
 
195
134
  def run_with_callbacks(task)
@@ -296,7 +235,9 @@ chmod 0700 #{path}
296
235
  sudo "rm -rf #{rolled_back_release}"
297
236
  bundle
298
237
  shell.status "Restarting with previous release."
299
- with_maintenance_page { run_with_callbacks(:restart) }
238
+ enable_maintenance_page
239
+ run_with_callbacks(:restart)
240
+ disable_maintenance_page
300
241
  shell.status "Finished rollback at #{Time.now.asctime}"
301
242
  rescue Exception
302
243
  shell.status "Failed to rollback at #{Time.now.asctime}"
@@ -483,7 +424,7 @@ WRAP
483
424
  def puts_deploy_failure
484
425
  if @cleanup_failed
485
426
  shell.notice "[Relax] Your site is running new code, but clean up of old deploys failed."
486
- elsif @maintenance_up
427
+ elsif maintenance.up?
487
428
  message = "[Attention] Maintenance page still up, consider the following before removing:\n"
488
429
  message << " * Deploy hooks ran. This might cause problems for reverting to old code.\n" if @callbacks_reached
489
430
  message << " * Migrations ran. This might cause problems for reverting to old code.\n" if @migrations_reached
@@ -501,10 +442,8 @@ WRAP
501
442
  end
502
443
  end
503
444
 
504
- def with_maintenance_page
505
- conditionally_enable_maintenance_page
506
- yield if block_given?
507
- conditionally_disable_maintenance_page
445
+ def maintenance
446
+ @maintenance ||= Maintenance.new(servers, config, shell)
508
447
  end
509
448
 
510
449
  def with_failed_release_cleanup
@@ -0,0 +1,112 @@
1
+ module EY
2
+ module Serverside
3
+ class Maintenance
4
+
5
+ def initialize(servers, config, shell)
6
+ @servers, @config, @shell = servers, config, shell
7
+ end
8
+
9
+ def exist?
10
+ enabled_maintenance_page_pathname.exist?
11
+ end
12
+
13
+ def up?
14
+ @up
15
+ end
16
+
17
+ def manually_enable
18
+ if paths.deployed?
19
+ enable
20
+ else
21
+ shell.fatal "Cannot enabled maintenance page. Application #{config.app_name} has never been deployed."
22
+ false
23
+ end
24
+ end
25
+
26
+ def manually_disable
27
+ if paths.deployed?
28
+ disable
29
+ else
30
+ shell.fatal "Cannot enabled maintenance page. Application #{config.app_name} has never been deployed."
31
+ false
32
+ end
33
+ end
34
+
35
+ def conditionally_enable
36
+ if config.enable_maintenance_page?
37
+ enable
38
+ else
39
+ explain_not_enabling
40
+ end
41
+ end
42
+
43
+ def conditionally_disable
44
+ if config.disable_maintenance_page?
45
+ disable
46
+ elsif exist?
47
+ shell.notice "[Attention] Maintenance page is still up.\nYou must remove it manually using `ey web enable`."
48
+ end
49
+ end
50
+
51
+ protected
52
+
53
+ attr_reader :config, :shell
54
+
55
+ def enable
56
+ shell.status "Enabling maintenance page."
57
+ @up = true
58
+ run "mkdir -p #{maintenance_page_dirname}"
59
+ run "cp #{source_path} #{enabled_maintenance_page_pathname}"
60
+ end
61
+
62
+ def disable
63
+ shell.status "Removing maintenance page."
64
+ @up = false
65
+ run "rm -f #{enabled_maintenance_page_pathname}"
66
+ end
67
+
68
+ def run(cmd)
69
+ @servers.roles(:app_master, :app, :solo).run(shell, cmd)
70
+ end
71
+
72
+ def paths
73
+ config.paths
74
+ end
75
+
76
+ def source_path
77
+ paths.maintenance_page_candidates.detect {|path| path.exist? }
78
+ end
79
+
80
+ def enabled_maintenance_page_pathname
81
+ paths.enabled_maintenance_page
82
+ end
83
+
84
+ def maintenance_page_dirname
85
+ enabled_maintenance_page_pathname.dirname
86
+ end
87
+
88
+ def explain_not_enabling
89
+ if config.migrate?
90
+ if !config.maintenance_on_migrate? && !config.maintenance_on_restart?
91
+ shell.status "Skipping maintenance page. (maintenance_on_migrate is false in ey.yml)"
92
+ shell.notice "[Caution] No maintenance migrations must be non-destructive!"
93
+ shell.notice "Requests may be served during a partially migrated state."
94
+ end
95
+ else
96
+ if config.required_downtime_stack? && !config.maintenance_on_restart?
97
+ shell.status "Skipping maintenance page. (maintenance_on_restart is false in ey.yml, overriding recommended default)"
98
+ unless exist?
99
+ shell.warning <<-WARN
100
+ No maintenance page! Brief downtime may be possible during restart.
101
+ This application stack does not support no-downtime restarts.
102
+ WARN
103
+ end
104
+ elsif !config.required_downtime_stack?
105
+ shell.status "Skipping maintenance page. (no-downtime restarts supported)"
106
+ end
107
+ end
108
+ end
109
+
110
+ end
111
+ end
112
+ end
@@ -27,10 +27,23 @@ module EY
27
27
  def ssh_identity_file() paths.ssh_identity.to_s end
28
28
  end
29
29
 
30
+ # Maintenance page candidates in order of search preference.
31
+ MAINTENANCE_CANDIDATES = [
32
+ "public/maintenance.html.custom",
33
+ "public/maintenance.html.tmp",
34
+ "public/maintenance.html",
35
+ "public/system/maintenance.html.default",
36
+ ]
37
+
38
+ # This one is guaranteed to exist.
39
+ DEFAULT_MAINTENANCE_PAGE = Pathname.new("default_maintenance_page.html").expand_path(File.dirname(__FILE__))
40
+
41
+ # Define methods that get us paths
30
42
  def self.def_path(name, parts)
31
43
  define_method(name.to_sym) { path(*parts) }
32
44
  end
33
45
 
46
+ # Load a path given a root and more parts
34
47
  def path(root, *parts)
35
48
  send(root).join(*parts)
36
49
  end
@@ -93,8 +106,24 @@ module EY
93
106
  all_releases.last
94
107
  end
95
108
 
109
+ def deployed?
110
+ !!latest_release
111
+ end
112
+
113
+ def maintenance_page_candidates
114
+ if latest_release
115
+ candidates = MAINTENANCE_CANDIDATES.map do |file|
116
+ path(:latest_release, file)
117
+ end
118
+ else
119
+ candidates = []
120
+ end
121
+ candidates << DEFAULT_MAINTENANCE_PAGE
122
+ candidates
123
+ end
124
+
96
125
  def rollback
97
- if previous_release
126
+ if deployed? && previous_release
98
127
  self.class.new(@opts.dup.merge(:active_release => previous_release))
99
128
  else
100
129
  nil
@@ -63,18 +63,18 @@ module EY
63
63
  end
64
64
 
65
65
  # Run a command on this set of servers.
66
- def run(cmd, &blk)
67
- run_on_servers('sh -l -c', cmd, &blk)
66
+ def run(shell, cmd, &blk)
67
+ run_on_servers(shell, 'sh -l -c', cmd, &blk)
68
68
  end
69
69
 
70
70
  # Run a sudo command on this set of servers.
71
- def sudo(cmd, &blk)
72
- run_on_servers('sudo sh -l -c', cmd, &blk)
71
+ def sudo(shell, cmd, &blk)
72
+ run_on_servers(shell, 'sudo sh -l -c', cmd, &blk)
73
73
  end
74
74
 
75
75
  private
76
76
 
77
- def run_on_servers(prefix, cmd, &block)
77
+ def run_on_servers(shell, prefix, cmd, &block)
78
78
  commands = map do |server|
79
79
  exec_cmd = server.command_on_server(prefix, cmd, &block)
80
80
  proc { shell.logged_system(exec_cmd) }
@@ -59,31 +59,14 @@ module EY
59
59
  end
60
60
  end
61
61
 
62
- def run(cmd, &blk)
63
- run_on_roles('sh -l -c', cmd, &blk)
62
+ def run(cmd, &block)
63
+ servers.roles(@roles).run(shell, cmd, &block)
64
64
  end
65
65
 
66
- def sudo(cmd, &blk)
67
- run_on_roles('sudo sh -l -c', cmd, &blk)
66
+ def sudo(cmd, &block)
67
+ servers.roles(@roles).sudo(shell, cmd, &block)
68
68
  end
69
69
 
70
- private
71
-
72
- def run_on_roles(prefix, cmd, &block)
73
- servers = @servers.roles(@roles)
74
-
75
- commands = servers.map do |server|
76
- exec_cmd = server.command_on_server(prefix, cmd, &block)
77
- proc { shell.logged_system(exec_cmd) }
78
- end
79
-
80
- futures = EY::Serverside::Future.call(commands)
81
-
82
- unless EY::Serverside::Future.success?(futures)
83
- failures = futures.select {|f| f.error? }.map {|f| f.inspect}.join("\n")
84
- raise EY::Serverside::RemoteFailure.new(failures)
85
- end
86
- end
87
70
  end
88
71
  end
89
72
  end
@@ -1,5 +1,5 @@
1
1
  module EY
2
2
  module Serverside
3
- VERSION = '2.0.0.pre4'
3
+ VERSION = '2.0.0.pre5'
4
4
  end
5
5
  end
@@ -18,19 +18,19 @@ describe "the EY::Serverside::Deploy API" do
18
18
  @call_order = []
19
19
  end
20
20
 
21
- def push_code() @call_order << 'push_code' end
22
- def copy_repository_cache() @call_order << 'copy_repository_cache' end
23
- def create_revision_file() @call_order << 'create_revision_file' end
24
- def bundle() @call_order << 'bundle' end
25
- def setup_services() @call_order << 'setup_services' end
26
- def symlink_configs() @call_order << 'symlink_configs' end
27
- def migrate() @call_order << 'migrate' end
28
- def compile_assets() @call_order << 'compile_assets' end
29
- def symlink() @call_order << 'symlink' end
30
- def restart() @call_order << 'restart' end
31
- def cleanup_old_releases() @call_order << 'cleanup_old_releases' end
32
- def conditionally_enable_maintenance_page() @call_order << 'conditionally_enable_maintenance_page' end
33
- def disable_maintenance_page() @call_order << 'disable_maintenance_page' end
21
+ def push_code() @call_order << 'push_code' end
22
+ def copy_repository_cache() @call_order << 'copy_repository_cache' end
23
+ def create_revision_file() @call_order << 'create_revision_file' end
24
+ def bundle() @call_order << 'bundle' end
25
+ def setup_services() @call_order << 'setup_services' end
26
+ def symlink_configs() @call_order << 'symlink_configs' end
27
+ def migrate() @call_order << 'migrate' end
28
+ def compile_assets() @call_order << 'compile_assets' end
29
+ def symlink() @call_order << 'symlink' end
30
+ def restart() @call_order << 'restart' end
31
+ def cleanup_old_releases() @call_order << 'cleanup_old_releases' end
32
+ def enable_maintenance_page() @call_order << 'enable_maintenance_page' end
33
+ def disable_maintenance_page() @call_order << 'disable_maintenance_page' end
34
34
  end
35
35
 
36
36
  config = EY::Serverside::Deploy::Configuration.new({
@@ -40,6 +40,17 @@ describe "the EY::Serverside::Deploy API" do
40
40
 
41
41
  td = TestDeploy.new(test_servers, config, test_shell)
42
42
  td.deploy
43
+
44
+ ############################# IMPORTANT ####################################
45
+ #
46
+ # Call order is referenced in the engineyard gem eydeploy.rb documentation.
47
+ #
48
+ # https://support.cloud.engineyard.com/entries/20996661-customize-your-deployment
49
+ #
50
+ # Changing call order or removing methods may adversely affect customers
51
+ # that are using eydeploy.rb and relying on this documentation.
52
+ #
53
+ ############################################################################
43
54
  td.call_order.should == %w(
44
55
  push_code
45
56
  copy_repository_cache
@@ -47,7 +58,7 @@ describe "the EY::Serverside::Deploy API" do
47
58
  bundle
48
59
  setup_services
49
60
  symlink_configs
50
- conditionally_enable_maintenance_page
61
+ enable_maintenance_page
51
62
  migrate
52
63
  compile_assets
53
64
  symlink
data/spec/restart_spec.rb CHANGED
@@ -20,12 +20,12 @@ describe "EY::Serverside::Deploy#restart_with_maintenance_page" do
20
20
  end
21
21
 
22
22
  it "puts up the maintenance page if necessary, restarts, and takes down the maintenance page" do
23
- config = EY::Serverside::Deploy::Configuration.new('app' => 'app_name')
23
+ config = EY::Serverside::Deploy::Configuration.new('deploy_to' => deploy_dir, 'app' => 'app_name')
24
24
  deployer = TestRestartWithMaintenancePage.new(test_servers, config, test_shell)
25
25
  deployer.restart_with_maintenance_page
26
26
  deployer.call_order.should == %w(
27
27
  require_custom_tasks
28
- conditionally_enable_maintenance_page
28
+ enable_maintenance_page
29
29
  restart
30
30
  disable_maintenance_page
31
31
  )
@@ -35,7 +35,7 @@ end
35
35
  describe "glassfish stack" do
36
36
 
37
37
  it "requires a maintenance page" do
38
- config = EY::Serverside::Deploy::Configuration.new(:stack => 'glassfish')
38
+ config = EY::Serverside::Deploy::Configuration.new('deploy_to' => deploy_dir, 'app' => 'app_name', 'stack' => 'glassfish')
39
39
  deployer = TestRestartDeploy.new(test_servers, config, test_shell)
40
40
  deployer.restart_with_maintenance_page
41
41
  deployer.call_order.should include('enable_maintenance_page')
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: engineyard-serverside
3
3
  version: !ruby/object:Gem::Version
4
- hash: 883885311
4
+ hash: 3919216497
5
5
  prerelease: 6
6
6
  segments:
7
7
  - 2
8
8
  - 0
9
9
  - 0
10
10
  - pre
11
- - 4
12
- version: 2.0.0.pre4
11
+ - 5
12
+ version: 2.0.0.pre5
13
13
  platform: ruby
14
14
  authors:
15
15
  - EY Cloud Team
@@ -17,7 +17,7 @@ autorequire:
17
17
  bindir: bin
18
18
  cert_chain: []
19
19
 
20
- date: 2012-06-13 00:00:00 Z
20
+ date: 2012-06-14 00:00:00 Z
21
21
  dependencies:
22
22
  - !ruby/object:Gem::Dependency
23
23
  name: rspec
@@ -115,6 +115,7 @@ files:
115
115
  - lib/engineyard-serverside/futures/celluloid.rb
116
116
  - lib/engineyard-serverside/futures/dataflow.rb
117
117
  - lib/engineyard-serverside/lockfile_parser.rb
118
+ - lib/engineyard-serverside/maintenance.rb
118
119
  - lib/engineyard-serverside/paths.rb
119
120
  - lib/engineyard-serverside/rails_asset_support.rb
120
121
  - lib/engineyard-serverside/server.rb