Skip to content

Commit

Permalink
updated hook implementation, hooks are now instance_eval'd within the…
Browse files Browse the repository at this point in the history
… chef-deploy resource

see README for more info, way more usefull hooks now
  • Loading branch information
Ezra Zygmuntowicz committed Jun 26, 2009
2 parents b316e0a + 0027c32 commit ab690b1
Show file tree
Hide file tree
Showing 6 changed files with 116 additions and 48 deletions.
22 changes: 18 additions & 4 deletions README.rdoc
Expand Up @@ -40,9 +40,23 @@ APP_ROOT/
before_restart.rb
after_restart.rb

These scripts will be called with two command line params in ARGV:
These scripts will be instance_eval'd in the context of the chef-deploy resource. This means that you will have certain commands and variables available to you in these hooks. For example:

ruby before_migrate.rb production app_master
run "echo 'release_path: #{release_path}' >> #{shared_path}/logs.log"
run "echo 'current_path: #{current_path}' >> #{shared_path}/logs.log"
run "echo 'shared_path: #{shared_path}' >> #{shared_path}/logs.log"
sudo "echo 'sudo works' >> /root/sudo.log"

Where ARGV[0] is the RAILS_ENV, MERB_ENV or RACK_ENV and ARGV[1] is the role passed in to the deploy resource, this
can be used to identify certain servers as database, application, cache, etc roles so you can act accordingly

You have access to a run command and a sudo command. Both of these will run shell commands, run will run as your normal unix user that the app is deployed as and sudo will run as root for when you need more permissions.

You will have variables like in capistrano:

release_path: this is the full path to the current release: /data/appname/releases/12345678
shared_path: this is the path to the shared dir: /data/appname/shared
current_path: this is the path to the currently symlinked release: /data/appname/current
node: node is the full chef node object, this will have all of the JSON collected by ohai as well as any custom json you passed into your client run. THis way you can get at *any* data you have available to any of your chef recipes.

Using subversion:

In your deploy block, simply add: scm 'subversion' (as well as svn_username and svn_password, if needed). Obviously, git-specific options like enable_submodules can be removed as they're not applicable.
4 changes: 2 additions & 2 deletions Rakefile
Expand Up @@ -5,7 +5,7 @@ require 'date'
require 'spec/rake/spectask'

GEM = "chef-deploy"
GEM_VERSION = "0.1.3"
GEM_VERSION = "0.2.0"
AUTHOR = "Ezra Zygmuntowicz"
EMAIL = "Your Email"
HOMEPAGE = "http://example.com"
Expand Down Expand Up @@ -54,4 +54,4 @@ task :make_spec do
File.open("#{GEM}.gemspec", "w") do |file|
file.puts spec.to_ruby
end
end
end
62 changes: 45 additions & 17 deletions lib/chef-deploy.rb
@@ -1,3 +1,4 @@
require File.join(File.dirname(__FILE__), 'chef-deploy/subversion')
require File.join(File.dirname(__FILE__), 'chef-deploy/git')
require File.join(File.dirname(__FILE__), 'chef-deploy/cached_deploy')

Expand Down Expand Up @@ -151,6 +152,30 @@ def git_ssh_wrapper(arg=nil)
:kind_of => [ String ]
)
end

def scm(arg=nil)
set_or_return(
:scm,
arg,
:kind_of => [ String ]
)
end

def svn_username(arg=nil)
set_or_return(
:svn_username,
arg,
:kind_of => [ String ]
)
end

def svn_password(arg=nil)
set_or_return(
:svn_password,
arg,
:kind_of => [ String ]
)
end

end
end
Expand All @@ -161,24 +186,27 @@ class Deploy < Chef::Provider
def load_current_resource
FileUtils.mkdir_p "#{@new_resource.name}/shared"
FileUtils.mkdir_p "#{@new_resource.name}/releases"
@dep = CachedDeploy.new :user => @new_resource.user,
:group => @new_resource.group,
:role => @new_resource.role,
:branch => (@new_resource.branch || 'HEAD'),
:restart_command => (@new_resource.restart_command || ""),
:repository => @new_resource.repo,
:environment => @new_resource.environment,
:migration_command => @new_resource.migration_command,
:migrate => @new_resource.migrate,
:deploy_to => @new_resource.name,
:repository_cache => @new_resource.repository_cache,
:copy_exclude => @new_resource.copy_exclude,
:revision => (@new_resource.revision || ''),
@dep = CachedDeploy.new :user => @new_resource.user,
:group => @new_resource.group,
:role => @new_resource.role,
:branch => (@new_resource.branch || 'HEAD'),
:restart_command => (@new_resource.restart_command || ""),
:repository => @new_resource.repo,
:environment => @new_resource.environment,
:migration_command => @new_resource.migration_command,
:migrate => @new_resource.migrate,
:deploy_to => @new_resource.name,
:repository_cache => @new_resource.repository_cache,
:copy_exclude => @new_resource.copy_exclude,
:revision => (@new_resource.revision || ''),
:git_enable_submodules => @new_resource.enable_submodules,
:git_shallow_clone => @new_resource.shallow_clone,
:node => @node,
:new_resource => @new_resource,
:git_ssh_wrapper => @git_ssh_wrapper
:git_shallow_clone => @new_resource.shallow_clone,
:svn_username => @new_resource.svn_username,
:svn_password => @new_resource.svn_password,
:scm => @new_resource.scm || 'git',
:node => @node,
:new_resource => @new_resource,
:git_ssh_wrapper => @git_ssh_wrapper
end

def action_deploy
Expand Down
42 changes: 32 additions & 10 deletions lib/chef-deploy/cached_deploy.rb
Expand Up @@ -9,10 +9,11 @@ class CachedDeploy
def deploy
@configuration[:release_path] = "#{@configuration[:deploy_to]}/releases/#{Time.now.utc.strftime("%Y%m%d%H%M%S")}"
if @configuration[:revision] == ''
@configuration[:revision] = source.query_revision(@configuration[:branch]) {|cmd| run "#{cmd}"}
@configuration[:revision] = source.query_revision(@configuration[:branch]) {|cmd| run_with_result "#{cmd}"}
end

if check_current_revision_and_noop_if_same(@configuration[:revision])
Chef::Log.info "Revision is already deployed, running migrations if there are any"
migrate
symlink
return
Expand All @@ -24,7 +25,7 @@ def deploy
Chef::Log.info "deploying branch: #{@configuration[:branch]} rev: #{@configuration[:revision]}"
Chef::Log.info "updating the cached checkout"
chef_run(update_repository_cache)
Chef::Log.info "copying the cached version to #{configuration[:release_path]}"
Chef::Log.info "copying the cached version to #{release_path}"
chef_run(copy_repository_cache)
install_gems

Expand Down Expand Up @@ -58,7 +59,7 @@ def check_current_revision_and_noop_if_same(newrev)
def callback(what)
if File.exist?("#{latest_release}/deploy/#{what}.rb")
Chef::Log.info "running deploy hook: #{latest_release}/deploy/#{what}.rb"
chef_run("cd #{latest_release} && sudo -u #{user} ruby deploy/#{what}.rb #{@configuration[:environment]} #{@configuration[:role]}")
instance_eval(IO.read("#{latest_release}/deploy/#{what}.rb"))
end
end

Expand All @@ -76,7 +77,7 @@ def oldest_release
end

def all_releases
`ls #{release_path}`.split("\n").sort.map{|r| File.join(release_path, r)}
`ls #{release_dir}`.split("\n").sort.map{|r| File.join(release_dir, r)}
end

def cleanup
Expand Down Expand Up @@ -118,10 +119,18 @@ def shared_path
configuration[:shared_path]
end

def release_path
def release_dir
"#{@configuration[:deploy_to]}/releases"
end

def release_path
@configuration[:release_path]
end

def node
@configuration[:node]
end

def symlink(release_to_link=latest_release)
Chef::Log.info "symlinking and finishing deploy"
symlink = false
Expand All @@ -147,7 +156,7 @@ def symlink(release_to_link=latest_release)
end
end

def run(cmd)
def run_with_result(cmd)
res = `#{cmd} 2>&1`
raise(ChefDeployFailure, res) unless $? == 0
res
Expand All @@ -157,6 +166,14 @@ def chef_run(cmd)
Chef::Mixin::Command.run_command(:command => cmd)
end

def run(cmd)
Chef::Mixin::Command.run_command(:command => cmd, :user => user)
end

def sudo(cmd)
Chef::Mixin::Command.run_command(:command => cmd)
end

# :repository_cache
# :shared_path
# :repository
Expand All @@ -175,7 +192,12 @@ def configuration
end

def source
@source ||= Git.new(configuration)
@source ||= case configuration[:scm]
when 'git'
Git.new configuration
when 'svn'
Subversion.new configuration
end
end

private
Expand Down Expand Up @@ -237,10 +259,10 @@ def update_repository_cache

def copy_repository_cache
if copy_exclude.empty?
return "cp -RPp #{repository_cache} #{configuration[:release_path]} && #{mark}"
return "cp -RPp #{repository_cache} #{release_path} && #{mark}"
else
exclusions = copy_exclude.map { |e| "--exclude=\"#{e}\"" }.join(' ')
return "rsync -lrpt #{exclusions} #{repository_cache}/* #{configuration[:release_path]} && #{mark}"
return "rsync -lrpt #{exclusions} #{repository_cache}/* #{release_path} && #{mark}"
end
end

Expand All @@ -249,7 +271,7 @@ def revision
end

def mark
"(echo #{revision} > #{configuration[:release_path]}/REVISION)"
"(echo #{revision} > #{release_path}/REVISION)"
end

def copy_exclude
Expand Down
18 changes: 9 additions & 9 deletions lib/chef-deploy/git.rb
Expand Up @@ -98,22 +98,22 @@ def log(from, to=nil)

# Getting the actual commit id, in case we were passed a tag
# or partial sha or something - it will return the sha if you pass a sha, too
def query_revision(revision)
raise ArgumentError, "Deploying remote branches is no longer supported. Specify the remote branch as a local branch for the git repository you're deploying from (ie: '#{revision.gsub('origin/', '')}' rather than '#{revision}')." if revision =~ /^origin\//
return revision if revision =~ /^[0-9a-f]{40}$/
command = scm('ls-remote', configuration[:repository], revision)
def query_revision(reference)
raise ArgumentError, "Deploying remote branches is no longer supported. Specify the remote branch as a local branch for the git repository you're deploying from (ie: '#{reference.gsub('origin/', '')}' rather than '#{reference}')." if reference =~ /^origin\//
sha_hash = '[0-9a-f]{40}'
return reference if reference =~ /^#{sha_hash}$/ # it's already a sha
command = scm('ls-remote', configuration[:repository], reference)
result = nil
begin
result = yield(command)
rescue ChefDeployFailure => e
raise obvious_error("Could not access the remote Git repository. If this is a private repository, please verify that the deploy key for your application has been added to your remote Git account.", e)
end
rev, ref = result.split(/[\t\n]/)
newrev = nil
if ref.sub(/refs\/.*?\//, '').strip == revision
newrev = rev
unless result =~ /^(#{sha_hash})\s+(\S+)/
raise "Unable to resolve reference for '#{reference}' on repository '#{configuration[:repository]}'."
end
raise "Unable to resolve revision for '#{revision}' on repository '#{configuration[:repository]}'." unless newrev =~ /^[0-9a-f]{40}$/
newrev = $1
newref = $2
return newrev
end

Expand Down
16 changes: 10 additions & 6 deletions lib/chef-deploy/subversion.rb
@@ -1,3 +1,5 @@
require 'yaml'

class Subversion

def initialize(opts={})
Expand Down Expand Up @@ -27,13 +29,13 @@ def checkout(revision, destination)
# Returns the command that will do an "svn update" to the given
# revision, for the working copy at the given destination.
def sync(revision, destination)
scm :update, arguments, verbose, authentication, "-r#{revision}", destination
scm :update, config[:arguments], verbose, authentication, "-r#{revision}", destination
end

# Returns the command that will do an "svn export" of the given revision
# to the given destination.
def export(revision, destination)
scm :export, arguments, verbose, authentication, "-r#{revision}", repository, destination
scm :export, config[:arguments], verbose, authentication, "-r#{revision}", repository, destination
end

# Returns the command that will do an "svn diff" for the two revisions.
Expand Down Expand Up @@ -72,15 +74,17 @@ def next_revision(revision)
# switch, since Capistrano will check for that prompt in the output
# and will respond appropriately.
def authentication
username = config(:svn_username)
username = config[:svn_username]
return "" unless username
result = "--username #{config(:svn_username)} "
result << "--password #{config(:svn_password)} "
result = "--username #{config[:svn_username]} "
result << "--password #{config[:svn_password]} "
result
end

# If verbose output is requested, return nil, otherwise return the
# command-line switch for "quiet" ("-q").
# FIXME: This is currently flipped logically since it doesn't check
# for any verbosity configuration flag
def verbose
"-q"
end
Expand All @@ -96,6 +100,6 @@ def scm(*args)
end

def svn_password_prompt
config[:password]
config[:svn_password]
end
end

0 comments on commit ab690b1

Please sign in to comment.