Class: EY::Serverside::DeployBase

Inherits:
Task show all
Includes:
LoggedOutput
Defined in:
lib/engineyard-serverside/deploy.rb

Direct Known Subclasses

Deploy

Constant Summary

Constants included from Dataflow

Dataflow::UnificationError, Dataflow::VERSION

Instance Attribute Summary

Attributes inherited from Task

#config

Instance Method Summary collapse

Methods included from LoggedOutput

#debug, #info, logfile, logfile=, #logged_system, verbose=, verbose?, #verbose?

Methods inherited from Task

#initialize, #require_custom_tasks, #roles, #run, #sudo

Methods included from Dataflow

#barrier, #by_need, #flow, included, #local, #need_later, #unify

Constructor Details

This class inherits a constructor from EY::Serverside::Task

Instance Method Details

#bundleObject

task



131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# File 'lib/engineyard-serverside/deploy.rb', line 131

def bundle
  if File.exist?("#{c.release_path}/Gemfile")
    info "~> Gemfile detected, bundling gems"
    lockfile = File.join(c.release_path, "Gemfile.lock")

    bundler_installer = if File.exist?(lockfile)
                          get_bundler_installer(lockfile)
                        else
                          warn_about_missing_lockfile
                          bundler_09_installer(default_09_bundler)
                        end

    sudo "#{serverside_bin} install_bundler #{bundler_installer.version}"

    bundled_gems_path = File.join(c.shared_path, "bundled_gems")
    ruby_version_file = File.join(bundled_gems_path, "RUBY_VERSION")
    system_version_file = File.join(bundled_gems_path, "SYSTEM_VERSION")
    ruby_version = `ruby -v`
    system_version = `uname -m`

    if File.directory?(bundled_gems_path)
      rebundle = false

      rebundle = true if File.exist?(ruby_version_file) && File.read(ruby_version_file) != ruby_version
      rebundle = true if File.exist?(system_version_file) && File.read(system_version_file) != system_version

      if rebundle
        info "~> Ruby version change detected, cleaning bundled gems"
        run "rm -Rf #{bundled_gems_path}"
      end
    end

    run "cd #{c.release_path} && bundle _#{bundler_installer.version}_ install #{bundler_installer.options}"

    run "mkdir -p #{bundled_gems_path} && ruby -v > #{ruby_version_file} && uname -m > #{system_version_file}"
  end
end

#cached_deployObject



18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/engineyard-serverside/deploy.rb', line 18

def cached_deploy
  debug "Deploying app from cached copy at #{Time.now.asctime}"
  require_custom_tasks
  push_code

  info "~> Starting full deploy"
  copy_repository_cache

  with_failed_release_cleanup do
    create_revision_file
    run_with_callbacks(:bundle)
    symlink_configs
    conditionally_enable_maintenance_page
    run_with_callbacks(:migrate)
    callback(:before_symlink)
    symlink
  end

  callback(:after_symlink)
  run_with_callbacks(:restart)
  disable_maintenance_page

  cleanup_old_releases
  debug "Finished deploy at #{Time.now.asctime}"
rescue Exception
  debug "Finished failing to deploy at #{Time.now.asctime}"
  puts_deploy_failure
  raise
end

#callback(what) ⇒ Object



253
254
255
256
257
258
259
260
261
262
263
264
265
# File 'lib/engineyard-serverside/deploy.rb', line 253

def callback(what)
  @callbacks_reached ||= true
  if File.exist?("#{c.release_path}/deploy/#{what}.rb")
    run Escape.shell_command(base_callback_command_for(what)) do |server, cmd|
      per_instance_args = [
        '--current-roles', server.roles.join(' '),
        '--config', c.to_json,
      ]
      per_instance_args << '--current-name' << server.name.to_s if server.name
      cmd << " " << Escape.shell_command(per_instance_args)
    end
  end
end

#cleanup_old_releasesObject

task



170
171
172
173
174
175
# File 'lib/engineyard-serverside/deploy.rb', line 170

def cleanup_old_releases
  @cleanup_failed = true
  info "~> Cleaning up old releases"
  sudo "ls #{c.release_dir} | head -n -3 | xargs -I{} rm -rf #{c.release_dir}/{}"
  @cleanup_failed = false
end

#conditionally_enable_maintenance_pageObject



85
86
87
88
89
# File 'lib/engineyard-serverside/deploy.rb', line 85

def conditionally_enable_maintenance_page
  if c.migrate? || required_downtime_stack?
    enable_maintenance_page
  end
end

#copy_repository_cacheObject

task



209
210
211
212
213
214
215
# File 'lib/engineyard-serverside/deploy.rb', line 209

def copy_repository_cache
  info "~> Copying to #{c.release_path}"
  run("mkdir -p #{c.release_path} && rsync -aq #{c.exclusions} #{c.repository_cache}/ #{c.release_path}")

  info "~> Ensuring proper ownership"
  sudo("chown -R #{c.user}:#{c.group} #{c.deploy_to}")
end

#create_revision_fileObject



217
218
219
# File 'lib/engineyard-serverside/deploy.rb', line 217

def create_revision_file
  run create_revision_file_command
end

#deployObject

default task



12
13
14
15
16
# File 'lib/engineyard-serverside/deploy.rb', line 12

def deploy
  debug "Starting deploy at #{Time.now.asctime}"
  update_repository_cache
  cached_deploy
end

#disable_maintenance_pageObject



95
96
97
98
99
100
# File 'lib/engineyard-serverside/deploy.rb', line 95

def disable_maintenance_page
  @maintenance_up = false
  roles :app_master, :app, :solo do
    run "rm -f #{File.join(c.shared_path, "system", "maintenance.html")}"
  end
end

#enable_maintenance_pageObject



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/engineyard-serverside/deploy.rb', line 55

def enable_maintenance_page
  maintenance_page_candidates = [
    "public/maintenance.html.custom",
    "public/maintenance.html.tmp",
    "public/maintenance.html",
    "public/system/maintenance.html.default",
  ].map do |file|
    File.join(c.latest_release, file)
  end

  # this one is guaranteed to exist
  maintenance_page_candidates <<  File.expand_path(
    "default_maintenance_page.html",
    File.dirname(__FILE__)
    )

  # put in the maintenance page
  maintenance_file = maintenance_page_candidates.detect do |file|
    File.exists?(file)
  end

  @maintenance_up = true
  roles :app_master, :app, :solo do
    maint_page_dir = File.join(c.shared_path, "system")
    visible_maint_page = File.join(maint_page_dir, "maintenance.html")
    run Escape.shell_command(['mkdir', '-p', maint_page_dir])
    run Escape.shell_command(['cp', maintenance_file, visible_maint_page])
  end
end

#get_bundler_installer(lockfile) ⇒ Object



327
328
329
330
331
332
333
334
335
336
337
# File 'lib/engineyard-serverside/deploy.rb', line 327

def get_bundler_installer(lockfile)
  parser = LockfileParser.new(File.read(lockfile))
  case parser.lockfile_version
  when :bundler09
    bundler_09_installer(parser.bundler_version)
  when :bundler10
    bundler_10_installer(parser.bundler_version)
  else
    raise "Unknown lockfile version #{parser.lockfile_version}"
  end
end

#migrateObject

task



198
199
200
201
202
203
204
205
206
# File 'lib/engineyard-serverside/deploy.rb', line 198

def migrate
  return unless c.migrate?
  @migrations_reached = true
  roles :app_master, :solo do
    cmd = "cd #{c.release_path} && PATH=#{c.binstubs_path}:$PATH #{c.framework_envs} #{c.migration_command}"
    info "~> Migrating: #{cmd}"
    run(cmd)
  end
end

#push_codeObject

task



109
110
111
112
113
114
# File 'lib/engineyard-serverside/deploy.rb', line 109

def push_code
  info "~> Pushing code to all servers"
  barrier *(EY::Serverside::Server.all.map do |server|
    need_later { server.sync_directory(config.repository_cache) }
  end)
end

#required_downtime_stack?Boolean

Returns:

  • (Boolean)


91
92
93
# File 'lib/engineyard-serverside/deploy.rb', line 91

def required_downtime_stack?
  %w[ nginx_mongrel glassfish ].include? c.stack
end

#restartObject

task



117
118
119
120
121
122
123
124
# File 'lib/engineyard-serverside/deploy.rb', line 117

def restart
  @restart_failed = true
  info "~> Restarting app servers"
  roles :app_master, :app, :solo do
    run(restart_command)
  end
  @restart_failed = false
end

#restart_commandObject



126
127
128
# File 'lib/engineyard-serverside/deploy.rb', line 126

def restart_command
  "/engineyard/bin/app_#{c.app} deploy"
end

#restart_with_maintenance_pageObject



48
49
50
51
52
53
# File 'lib/engineyard-serverside/deploy.rb', line 48

def restart_with_maintenance_page
  require_custom_tasks
  conditionally_enable_maintenance_page
  restart
  disable_maintenance_page
end

#rollbackObject

task



178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
# File 'lib/engineyard-serverside/deploy.rb', line 178

def rollback
  if c.all_releases.size > 1
    rolled_back_release = c.latest_release
    c.release_path = c.previous_release(rolled_back_release)

    revision = File.read(File.join(c.release_path, 'REVISION')).strip
    info "~> Rolling back to previous release: #{short_log_message(revision)}"

    run_with_callbacks(:symlink)
    sudo "rm -rf #{rolled_back_release}"
    bundle
    info "~> Restarting with previous release"
    with_maintenance_page { run_with_callbacks(:restart) }
  else
    info "~> Already at oldest release, nothing to roll back to"
    exit(1)
  end
end

#run_with_callbacks(task) ⇒ Object



102
103
104
105
106
# File 'lib/engineyard-serverside/deploy.rb', line 102

def run_with_callbacks(task)
  callback("before_#{task}")
  send(task)
  callback("after_#{task}")
end

task



243
244
245
246
247
248
249
250
251
# File 'lib/engineyard-serverside/deploy.rb', line 243

def symlink(release_to_link=c.release_path)
  info "~> Symlinking code"
  run "rm -f #{c.current_path} && ln -nfs #{release_to_link} #{c.current_path} && chown -R #{c.user}:#{c.group} #{c.current_path}"
  @symlink_changed = true
rescue Exception
  sudo "rm -f #{c.current_path} && ln -nfs #{c.previous_release(release_to_link)} #{c.current_path} && chown -R #{c.user}:#{c.group} #{c.current_path}"
  @symlink_changed = false
  raise
end


221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
# File 'lib/engineyard-serverside/deploy.rb', line 221

def symlink_configs(release_to_link=c.release_path)
  info "~> Symlinking configs"
  [ "chmod -R g+w #{release_to_link}",
    "rm -rf #{release_to_link}/log #{release_to_link}/public/system #{release_to_link}/tmp/pids",
    "mkdir -p #{release_to_link}/tmp",
    "ln -nfs #{c.shared_path}/log #{release_to_link}/log",
    "mkdir -p #{release_to_link}/public",
    "mkdir -p #{release_to_link}/config",
    "ln -nfs #{c.shared_path}/system #{release_to_link}/public/system",
    "ln -nfs #{c.shared_path}/pids #{release_to_link}/tmp/pids",
    "find #{c.shared_path}/config -type f -exec ln -s {} #{release_to_link}/config \\;",
    "ln -nfs #{c.shared_path}/config/database.yml #{release_to_link}/config/database.yml",
    "ln -nfs #{c.shared_path}/config/mongrel_cluster.yml #{release_to_link}/config/mongrel_cluster.yml",
  ].each do |cmd|
    run cmd
  end

  sudo "chown -R #{c.user}:#{c.group} #{release_to_link}"
  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"
end