-
Notifications
You must be signed in to change notification settings - Fork 69
No Op Deploys with Moonshine
With more recent versions, Moonshine supports doing a no-op deploy. Essentially, this process shows you any commands or changes Moonshine would make on the next deploy. This is really useful for testing out manifest changes, in particular when developing a new Moonshine plugin against an existing application (it also pairs well with capistrano-cowboy)!
In this example, we're going to assume that we are working on a new Moonshine plugin for a critical application that doesn't have a staging environment called very_important_app
. Being the dare-devils we are, we'll be testing these changes with cap cowboy deploy
— but we'll be doing some testing in the form of no-op deploys along the way.
Let's say we've generated this new Moonshine plugin for the sl
command line utility:
› rails g moonshine:plugin sl
create vendor/plugins/moonshine_sl/README.rdoc
create vendor/plugins/moonshine_sl/moonshine/init.rb
create vendor/plugins/moonshine_sl/lib/sl.rb
create vendor/plugins/moonshine_sl/spec/sl_spec.rb
create vendor/plugins/moonshine_sl/spec/spec_helper.rb
We've updated vendor/plugins/moonshine_sl/lib/sl.rb
to look like so:
module Sl
def sl(options = {})
package 'sl',
:ensure => :present
end
end
And our app/manifests/application_manifest.rb
looks like this:
require "#{File.dirname(__FILE__)}/../../vendor/plugins/moonshine/lib/moonshine.rb"
class ApplicationManifest < Moonshine::Manifest::Rails
recipe :default_stack
recipe :sl
def application_packages
end
recipe :application_packages
end
Now, we want to test these changes without applying them. Let's do a no-op deploy with capistrano-cowboy
! You'll notice that Moonshine prints out diffs of files and any commands it wants to run and any packages it wants to install: in essence, anything that Moonshine would change during a real deploy.
IMPORTANT: Make sure it's okay to run any custom Capistrano tasks/callbacks you may use, because this WILL cause (at least some of) them to run! There is a section below on making your customer deploy tasks no-op-friendly.
(There's more stuff after the big terminal output below, so just scroll on down!)
> cap cowboy noop deploy
triggering start callbacks for `cowboy'
* == Currently executing `moonshine:configure'
* == Currently executing `cowboy'
triggering start callbacks for `noop'
* == Currently executing `moonshine:configure'
* == Currently executing `noop'
triggering start callbacks for `deploy'
* == Currently executing `moonshine:configure'
* == Currently executing `deploy'
* == Currently executing `deploy:update'
** transaction: start
* == Currently executing `deploy:update_code'
triggering before callbacks for `deploy:update_code'
* == Currently executing `cowboy:configure'
* getting (via checkout) revision to /var/folders/Uf/UfoIWzizEt8A4CHWCu+B6E+++TI/-Tmp-/20110201031426
executing locally: cp -R . /var/folders/Uf/UfoIWzizEt8A4CHWCu+B6E+++TI/-Tmp-/20110201031426
* processing exclusions...
compressing /var/folders/Uf/UfoIWzizEt8A4CHWCu+B6E+++TI/-Tmp-/20110201031426 to /var/folders/Uf/UfoIWzizEt8A4CHWCu+B6E+++TI/-Tmp-/20110201031426.tar.gz
executing locally: tar czf 20110201031426.tar.gz 20110201031426
servers: ["very.important.app.managedmachine.com"]
** sftp upload /var/folders/Uf/UfoIWzizEt8A4CHWCu+B6E+++TI/-Tmp-/20110201031426.tar.gz -> /tmp/20110201031426.tar.gz
[very.important.app.managedmachine.com] /tmp/20110201031426.tar.gz
[very.important.app.managedmachine.com] done
* sftp upload complete
* executing "cd /srv/very_important_app/releases && tar xzf /tmp/20110201031426.tar.gz && rm /tmp/20110201031426.tar.gz"
servers: ["very.important.app.managedmachine.com"]
[very.important.app.managedmachine.com] executing command
command finished
* == Currently executing `deploy:finalize_update'
* executing "chmod -R g+w /srv/very_important_app/releases/20110201031426"
servers: ["very.important.app.managedmachine.com"]
[very.important.app.managedmachine.com] executing command
command finished
* executing "rm -rf /srv/very_important_app/releases/20110201031426/log /srv/very_important_app/releases/20110201031426/public/system /srv/very_important_app/releases/20110201031426/tmp/pids &&\\\n mkdir -p /srv/very_important_app/releases/20110201031426/public &&\\\n mkdir -p /srv/very_important_app/releases/20110201031426/tmp &&\\\n ln -s /srv/very_important_app/shared/log /srv/very_important_app/releases/20110201031426/log &&\\\n ln -s /srv/very_important_app/shared/system /srv/very_important_app/releases/20110201031426/public/system &&\\\n ln -s /srv/very_important_app/shared/pids /srv/very_important_app/releases/20110201031426/tmp/pids"
servers: ["very.important.app.managedmachine.com"]
[very.important.app.managedmachine.com] executing command
command finished
* executing "find /srv/very_important_app/releases/20110201031426/public/images /srv/very_important_app/releases/20110201031426/public/stylesheets /srv/very_important_app/releases/20110201031426/public/javascripts -exec touch -t 201102010314.28 {} ';'; true"
servers: ["very.important.app.managedmachine.com"]
[very.important.app.managedmachine.com] executing command
command finished
triggering after callbacks for `deploy:finalize_update'
* == Currently executing `local_config:upload'
* == Currently executing `local_config:symlink'
* == Currently executing `shared_config:symlink'
* == Currently executing `app:symlinks:update'
* == Currently executing `deploy:symlink'
triggering before callbacks for `deploy:symlink'
* == Currently executing `moonshine:noop_apply'
* executing "sudo -p 'sudo password: ' RAILS_ROOT=/srv/very_important_app/releases/20110201031426 DEPLOY_STAGE= RAILS_ENV=production shadow_puppet --noop /srv/very_important_app/releases/20110201031426/app/manifests/application_manifest.rb"
servers: ["very.important.app.managedmachine.com"]
[very.important.app.managedmachine.com] executing command
** [out :: very.important.app.managedmachine.com] 1,2c1
** [out :: very.important.app.managedmachine.com] < (in /srv/very_important_app/releases/20110201030801)
** [out :: very.important.app.managedmachine.com] < (in /srv/very_important_app/releases/20110201030801)
** [out :: very.important.app.managedmachine.com] ---
** [out :: very.important.app.managedmachine.com] >
** [out :: very.important.app.managedmachine.com] \ No newline at end of file
** [out :: very.important.app.managedmachine.com] 1,5c1
** [out :: very.important.app.managedmachine.com] < Linux very.important.app.managedmachine.com 2.6.35-23-virtual #41-Ubuntu SMP Wed Nov 24 12:29:11 UTC 2010 x86_64 GNU/Linux
** [out :: very.important.app.managedmachine.com] < Ubuntu 10.04 LTS
** [out :: very.important.app.managedmachine.com] <
** [out :: very.important.app.managedmachine.com] < Welcome to Ubuntu!
** [out :: very.important.app.managedmachine.com] < * Documentation: https://help.ubuntu.com/
** [out :: very.important.app.managedmachine.com] ---
** [out :: very.important.app.managedmachine.com] > Linux very.important.app.managedmachine.com 2.6.35-23-virtual #41-Ubuntu SMP Wed Nov 24 12:29:11 UTC 2010 x86_64
** [out :: very.important.app.managedmachine.com] notice: /ApplicationManifest#34128040/File[/var/run/motd]/content: is {md5}ce85278802394ab0e35e7c2122a2d7a7, should be {md5}f9bd5e619c3197cdbb7cd7f52c7c0c06 (noop)
** [out :: very.important.app.managedmachine.com] notice: /ApplicationManifest#34128040/Exec[apt-get update]/returns: is notrun, should be 0 (noop)
** [out :: very.important.app.managedmachine.com] notice: /ApplicationManifest#34128040/Package[sl]/ensure: is purged, should be present (noop)
** [out :: very.important.app.managedmachine.com] notice: /ApplicationManifest#34128040/Exec[bundle install]/returns: is notrun, should be 0 (noop)
** [out :: very.important.app.managedmachine.com] notice: /ApplicationManifest#34128040/Exec[rails_gems]/returns: is notrun, should be 0 (noop)
** [out :: very.important.app.managedmachine.com] notice: /ApplicationManifest#34128040/Exec[rake tasks]/returns: is notrun, should be 0 (noop)
** [out :: very.important.app.managedmachine.com] notice: /ApplicationManifest#34128040/Exec[rake db:migrate]/returns: is notrun, should be 0 (noop)
command finished
* executing "rm -f /srv/very_important_app/current && ln -s /srv/very_important_app/releases/20110201031426 /srv/very_important_app/current"
servers: ["very.important.app.managedmachine.com"]
[very.important.app.managedmachine.com] executing command
command finished
** transaction: commit
* == Currently executing `deploy:restart'
triggering after callbacks for `deploy:restart'
* == Currently executing `deploy:cleanup'
* executing "ls -x /srv/very_important_app/releases"
servers: ["very.important.app.managedmachine.com"]
[very.important.app.managedmachine.com] executing command
command finished
*** no old releases to clean up
triggering after callbacks for `deploy'
* == Currently executing `deploy:rollback'
* == Currently executing `deploy:rollback:revision'
* executing "rm /srv/very_important_app/current; ln -s /srv/very_important_app/releases/20110201030801 /srv/very_important_app/current"
servers: ["very.important.app.managedmachine.com"]
[very.important.app.managedmachine.com] executing command
command finished
* == Currently executing `deploy:restart'
triggering after callbacks for `deploy:restart'
* == Currently executing `deploy:cleanup'
*** no old releases to clean up
* == Currently executing `deploy:rollback:cleanup'
* executing "if [ `readlink /srv/very_important_app/current` != /srv/very_important_app/releases/20110201031426 ]; then rm -rf /srv/very_important_app/releases/20110201031426; fi"
servers: ["very.important.app.managedmachine.com"]
[very.important.app.managedmachine.com] executing command
command finished
Since that all looks good, we can run this deploy for real to confirm that Moonshine does what it said it would:
› cap cowboy deploy
triggering start callbacks for `cowboy'
* == Currently executing `moonshine:configure'
* == Currently executing `cowboy'
triggering start callbacks for `deploy'
* == Currently executing `moonshine:configure'
* == Currently executing `deploy'
* == Currently executing `deploy:update'
** transaction: start
* == Currently executing `deploy:update_code'
triggering before callbacks for `deploy:update_code'
* == Currently executing `cowboy:configure'
* getting (via checkout) revision to /var/folders/Uf/UfoIWzizEt8A4CHWCu+B6E+++TI/-Tmp-/20110201032448
executing locally: cp -R . /var/folders/Uf/UfoIWzizEt8A4CHWCu+B6E+++TI/-Tmp-/20110201032448
* processing exclusions...
compressing /var/folders/Uf/UfoIWzizEt8A4CHWCu+B6E+++TI/-Tmp-/20110201032448 to /var/folders/Uf/UfoIWzizEt8A4CHWCu+B6E+++TI/-Tmp-/20110201032448.tar.gz
executing locally: tar czf 20110201032448.tar.gz 20110201032448
servers: ["very.important.app.managedmachine.com"]
** sftp upload /var/folders/Uf/UfoIWzizEt8A4CHWCu+B6E+++TI/-Tmp-/20110201032448.tar.gz -> /tmp/20110201032448.tar.gz
[very.important.app.managedmachine.com] /tmp/20110201032448.tar.gz
[very.important.app.managedmachine.com] done
* sftp upload complete
* executing "cd /srv/very_important_app/releases && tar xzf /tmp/20110201032448.tar.gz && rm /tmp/20110201032448.tar.gz"
servers: ["very.important.app.managedmachine.com"]
[very.important.app.managedmachine.com] executing command
command finished
* == Currently executing `deploy:finalize_update'
* executing "chmod -R g+w /srv/very_important_app/releases/20110201032448"
servers: ["very.important.app.managedmachine.com"]
[very.important.app.managedmachine.com] executing command
command finished
* executing "rm -rf /srv/very_important_app/releases/20110201032448/log /srv/very_important_app/releases/20110201032448/public/system /srv/very_important_app/releases/20110201032448/tmp/pids &&\\\n mkdir -p /srv/very_important_app/releases/20110201032448/public &&\\\n mkdir -p /srv/very_important_app/releases/20110201032448/tmp &&\\\n ln -s /srv/very_important_app/shared/log /srv/very_important_app/releases/20110201032448/log &&\\\n ln -s /srv/very_important_app/shared/system /srv/very_important_app/releases/20110201032448/public/system &&\\\n ln -s /srv/very_important_app/shared/pids /srv/very_important_app/releases/20110201032448/tmp/pids"
servers: ["very.important.app.managedmachine.com"]
[very.important.app.managedmachine.com] executing command
command finished
* executing "find /srv/very_important_app/releases/20110201032448/public/images /srv/very_important_app/releases/20110201032448/public/stylesheets /srv/very_important_app/releases/20110201032448/public/javascripts -exec touch -t 201102010324.51 {} ';'; true"
servers: ["very.important.app.managedmachine.com"]
[very.important.app.managedmachine.com] executing command
command finished
triggering after callbacks for `deploy:finalize_update'
* == Currently executing `local_config:upload'
* == Currently executing `local_config:symlink'
* == Currently executing `shared_config:symlink'
* == Currently executing `app:symlinks:update'
* == Currently executing `deploy:symlink'
triggering before callbacks for `deploy:symlink'
* == Currently executing `moonshine:apply'
* executing "sudo -p 'sudo password: ' RAILS_ROOT=/srv/very_important_app/releases/20110201032448 DEPLOY_STAGE= RAILS_ENV=production shadow_puppet /srv/very_important_app/releases/20110201032448/app/manifests/application_manifest.rb"
servers: ["very.important.app.managedmachine.com"]
[very.important.app.managedmachine.com] executing command
** [out :: very.important.app.managedmachine.com] notice: /ApplicationManifest#35297420/File[/var/run/motd]: Filebucketed to with sum ce85278802394ab0e35e7c2122a2d7a7
** [out :: very.important.app.managedmachine.com] notice: /ApplicationManifest#35297420/File[/var/run/motd]/content: content changed '{md5}ce85278802394ab0e35e7c2122a2d7a7' to '{md5}f9bd5e619c3197cdbb7cd7f52c7c0c06'
** [out :: very.important.app.managedmachine.com] notice: /ApplicationManifest#35297420/Exec[apt-get update]/returns: executed successfully
** [out :: very.important.app.managedmachine.com] notice: /ApplicationManifest#35297420/Package[sl]/ensure: ensure changed 'purged' to 'present'
** [out :: very.important.app.managedmachine.com] notice: /ApplicationManifest#35297420/Exec[bundle install]/returns: Using rake (0.8.7)
** [out :: very.important.app.managedmachine.com] notice: /ApplicationManifest#35297420/Exec[bundle install]/returns: Using abstract (1.0.0)
** [out :: very.important.app.managedmachine.com] notice: /ApplicationManifest#35297420/Exec[bundle install]/returns: Using activesupport (3.0.3)
** [out :: very.important.app.managedmachine.com] notice: /ApplicationManifest#35297420/Exec[bundle install]/returns: Using builder (2.1.2)
** [out :: very.important.app.managedmachine.com] notice: /ApplicationManifest#35297420/Exec[bundle install]/returns: Using i18n (0.5.0)
** [out :: very.important.app.managedmachine.com] notice: /ApplicationManifest#35297420/Exec[bundle install]/returns: Using activemodel (3.0.3)
** [out :: very.important.app.managedmachine.com] notice: /ApplicationManifest#35297420/Exec[bundle install]/returns: Using erubis (2.6.6)
** [out :: very.important.app.managedmachine.com] notice: /ApplicationManifest#35297420/Exec[bundle install]/returns: Using rack (1.2.1)
** [out :: very.important.app.managedmachine.com] notice: /ApplicationManifest#35297420/Exec[bundle install]/returns: Using rack-mount (0.6.13)
** [out :: very.important.app.managedmachine.com] notice: /ApplicationManifest#35297420/Exec[bundle install]/returns: Using rack-test (0.5.7)
** [out :: very.important.app.managedmachine.com] notice: /ApplicationManifest#35297420/Exec[bundle install]/returns: Using tzinfo (0.3.24)
** [out :: very.important.app.managedmachine.com] notice: /ApplicationManifest#35297420/Exec[bundle install]/returns: Using actionpack (3.0.3)
** [out :: very.important.app.managedmachine.com] notice: /ApplicationManifest#35297420/Exec[bundle install]/returns: Using mime-types (1.16)
** [out :: very.important.app.managedmachine.com] notice: /ApplicationManifest#35297420/Exec[bundle install]/returns: Using polyglot (0.3.1)
** [out :: very.important.app.managedmachine.com] notice: /ApplicationManifest#35297420/Exec[bundle install]/returns: Using treetop (1.4.9)
** [out :: very.important.app.managedmachine.com] notice: /ApplicationManifest#35297420/Exec[bundle install]/returns: Using mail (2.2.15)
** [out :: very.important.app.managedmachine.com] notice: /ApplicationManifest#35297420/Exec[bundle install]/returns: Using actionmailer (3.0.3)
** [out :: very.important.app.managedmachine.com] notice: /ApplicationManifest#35297420/Exec[bundle install]/returns: Using arel (2.0.7)
** [out :: very.important.app.managedmachine.com] notice: /ApplicationManifest#35297420/Exec[bundle install]/returns: Using activerecord (3.0.3)
** [out :: very.important.app.managedmachine.com] notice: /ApplicationManifest#35297420/Exec[bundle install]/returns: Using activeresource (3.0.3)
** [out :: very.important.app.managedmachine.com] notice: /ApplicationManifest#35297420/Exec[bundle install]/returns: Using bundler (1.0.9)
** [out :: very.important.app.managedmachine.com] notice: /ApplicationManifest#35297420/Exec[bundle install]/returns: Using thor (0.14.6)
** [out :: very.important.app.managedmachine.com] notice: /ApplicationManifest#35297420/Exec[bundle install]/returns: Using railties (3.0.3)
** [out :: very.important.app.managedmachine.com] notice: /ApplicationManifest#35297420/Exec[bundle install]/returns: Using rails (3.0.3)
** [out :: very.important.app.managedmachine.com] notice: /ApplicationManifest#35297420/Exec[bundle install]/returns: Using sqlite3 (1.3.3)
** [out :: very.important.app.managedmachine.com] notice: /ApplicationManifest#35297420/Exec[bundle install]/returns: Using sqlite3-ruby (1.3.3)
** [out :: very.important.app.managedmachine.com] notice: /ApplicationManifest#35297420/Exec[bundle install]/returns: Your bundle is complete! It was installed into /srv/very_important_app/shared/bundle
** [out :: very.important.app.managedmachine.com] notice: /ApplicationManifest#35297420/Exec[bundle install]/returns: executed successfully
** [out :: very.important.app.managedmachine.com] notice: /ApplicationManifest#35297420/Exec[rails_gems]/returns: executed successfully
** [out :: very.important.app.managedmachine.com] notice: /ApplicationManifest#35297420/Exec[rake tasks]/returns: (in /srv/very_important_app/releases/20110201032448)
** [out :: very.important.app.managedmachine.com] notice: /ApplicationManifest#35297420/Exec[rake tasks]/returns: executed successfully
** [out :: very.important.app.managedmachine.com] notice: /ApplicationManifest#35297420/Exec[rake db:migrate]/returns: (in /srv/very_important_app/releases/20110201032448)
** [out :: very.important.app.managedmachine.com] notice: /ApplicationManifest#35297420/Exec[rake db:migrate]/returns: executed successfully
command finished
* executing "rm -f /srv/very_important_app/current && ln -s /srv/very_important_app/releases/20110201032448 /srv/very_important_app/current"
servers: ["very.important.app.managedmachine.com"]
[very.important.app.managedmachine.com] executing command
command finished
** transaction: commit
* == Currently executing `deploy:restart'
* executing "touch /srv/very_important_app/current/tmp/restart.txt"
servers: ["very.important.app.managedmachine.com"]
[very.important.app.managedmachine.com] executing command
command finished
triggering after callbacks for `deploy:restart'
* == Currently executing `deploy:cleanup'
* executing "ls -x /srv/very_important_app/releases"
servers: ["very.important.app.managedmachine.com"]
[very.important.app.managedmachine.com] executing command
command finished
*** no old releases to clean up
triggering after callbacks for `deploy'
Looks like Moonshine did just what it said it would! Now if we run sl
on the server, it should work:
rails@very:~$ which sl
/usr/games/sl
rails@very:~$ sl
Works like a charm!
Say we have a task set to restart god
after deploy:restart
:
namespace :god do
task :restart do
sudo 'restart god'
end
end
On a no-op, we don't want to do that though! So, we simply wrap the actions we don't want to run with a check for the no-op:
namespace :god do
task :restart do
if fetch(:noop)
sudo 'restart god'
else
puts "Not restarting god! (noop)"
end
end
end