Permalink
Browse files

updated hook implementation, hooks are now instance_eval'd within the…

… chef-deploy resource

see README for more info, way more usefull hooks now
  • Loading branch information...
2 parents b316e0a + 0027c32 commit ab690b10185b111c6a3b6c3e29ccdc1331ac74fa Ezra Zygmuntowicz committed Jun 26, 2009
Showing with 116 additions and 48 deletions.
  1. +18 −4 README.rdoc
  2. +2 −2 Rakefile
  3. +45 −17 lib/chef-deploy.rb
  4. +32 −10 lib/chef-deploy/cached_deploy.rb
  5. +9 −9 lib/chef-deploy/git.rb
  6. +10 −6 lib/chef-deploy/subversion.rb
View
@@ -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.
View
@@ -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"
@@ -54,4 +54,4 @@ task :make_spec do
File.open("#{GEM}.gemspec", "w") do |file|
file.puts spec.to_ruby
end
-end
+end
View
@@ -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')
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -249,7 +271,7 @@ def revision
end
def mark
- "(echo #{revision} > #{configuration[:release_path]}/REVISION)"
+ "(echo #{revision} > #{release_path}/REVISION)"
end
def copy_exclude
@@ -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
@@ -1,3 +1,5 @@
+require 'yaml'
+
class Subversion
def initialize(opts={})
@@ -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.
@@ -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
@@ -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.