lib/capistrano-chef-solo.rb in yyuu-capistrano-chef-solo-0.1.1 vs lib/capistrano-chef-solo.rb in yyuu-capistrano-chef-solo-0.1.2

- old
+ new

@@ -120,11 +120,11 @@ end end # FIXME: # Some variables (such like :default_environment set by capistrano-rbenv) may be - # initialized without bootstrap settings during `on :start`. + # initialized without bootstrap settings during `on :load`. # Is there any way to avoid this without setting `:rbenv_setup_default_environment` # as false? set(:rbenv_setup_default_environment, false) desc("Setup chef-solo.") @@ -215,111 +215,101 @@ update_config(options) update_attributes(options) end def update_cookbooks(options={}) - tmpdir = run_locally("mktemp -d /tmp/chef-solo.XXXXXXXXXX").strip - remote_tmpdir = capture("mktemp -d /tmp/chef-solo.XXXXXXXXXX").strip - destination = File.join(tmpdir, "cookbooks") - remote_destination = File.join(chef_solo_path, "cookbooks") - filename = File.join(tmpdir, "cookbooks.tar.gz") - remote_filename = File.join(remote_tmpdir, "cookbooks.tar.gz") - begin - bundle_cookbooks(filename, destination) - run("mkdir -p #{remote_tmpdir.dump}") - distribute_cookbooks(filename, remote_filename, remote_destination) - ensure - run("rm -rf #{remote_tmpdir.dump}") rescue nil - run_locally("rm -rf #{tmpdir.dump}") rescue nil + _normalize_cookbooks(chef_solo_cookbooks).each do |name, variables| + begin + tmpdir = capture("mktemp -d /tmp/cookbooks.XXXXXXXXXX", options).strip + run("rm -rf #{tmpdir.dump} && mkdir -p #{tmpdir.dump}", options) + deploy_cookbooks(name, tmpdir, variables, options) + install_cookbooks(name, tmpdir, File.join(chef_solo_path, "cookbooks"), options) + ensure + run("rm -rf #{tmpdir.dump}", options) + end end end # # The definition of cookbooks. # By default, load cookbooks from local path of "config/cookbooks". # _cset(:chef_solo_cookbooks_name) { application } - _cset(:chef_solo_cookbooks_scm, :none) + _cset(:chef_solo_cookbooks_exclude, %w(.hg .git .svn)) + _cset(:chef_solo_cookbooks_default_variables) {{ + :scm => :none, + :deploy_via => :copy_subdir, + :deploy_subdir => nil, + :repository => ".", + :cookbooks_exclude => chef_solo_cookbooks_exclude, + :copy_cache => nil, + }} _cset(:chef_solo_cookbooks) { - cookbooks = {} - cookbooks[chef_solo_cookbooks_name] = {} - cookbooks[chef_solo_cookbooks_name][:cookbooks] = fetch(:chef_solo_cookbooks_subdir, "config/cookbooks") - cookbooks[chef_solo_cookbooks_name][:repository] = fetch(:chef_solo_cookbooks_repository) if exists?(:chef_solo_cookbooks_repository) - cookbooks[chef_solo_cookbooks_name][:revision] = fetch(:chef_solo_cookbooks_revision) if exists?(:chef_solo_cookbooks_revision) - cookbooks + variables = chef_solo_cookbooks_default_variables.dup + variables[:scm] = fetch(:chef_solo_cookbooks_scm) if exists?(:chef_solo_cookbooks_scm) + variables[:deploy_subdir] = fetch(:chef_solo_cookbooks_subdir, "config/cookbooks") + variables[:repository] = fetch(:chef_solo_cookbooks_repository) if exists?("chef_solo_cookbooks_repository") + variables[:revision] = fetch(:chef_solo_cookbooks_revision) if exists?(:chef_solo_cookbooks_revision) + { chef_solo_cookbooks_name => variables } } - _cset(:chef_solo_cookbooks_exclude, %w(.hg .git .svn)) + _cset(:chef_solo_repository_cache) { File.expand_path("tmp/cookbooks-cache") } def _normalize_cookbooks(cookbooks) - xs = cookbooks.map { |name, options| - options[:scm] ||= chef_solo_cookbooks_scm - options[:cookbooks_exclude] ||= chef_solo_cookbooks_exclude - [name, options] + xs = cookbooks.map { |name, variables| + variables = chef_solo_cookbooks_default_variables.merge(variables) + variables[:application] ||= name + # use :cookbooks as :deploy_subdir for backward compatibility with prior than 0.1.2 + variables[:deploy_subdir] ||= variables[:cookbooks] + if variables[:scm] != :none + variables[:copy_cache] ||= File.expand_path(name, chef_solo_repository_cache) + end + [name, variables] } Hash[xs] end - _cset(:chef_solo_repository_cache) { File.expand_path("./tmp/cookbooks-cache") } - def bundle_cookbooks(filename, destination) - dirs = [ File.dirname(filename), destination ].uniq - run_locally("mkdir -p #{dirs.map { |x| x.dump }.join(" ")}") - cookbooks = _normalize_cookbooks(chef_solo_cookbooks) - cookbooks.each do |name, options| - case options[:scm].to_sym - when :none - fetch_cookbooks_none(name, destination, options) - else - fetch_cookbooks_repository(name, destination, options) + def deploy_cookbooks(name, destination, variables={}, options={}) + logger.debug("retrieving cookbooks `#{name}' from #{variables[:repository]} via #{variables[:deploy_via]}.") + begin + releases_path = capture("mktemp -d /tmp/releases.XXXXXXXXXX", options).strip + release_path = File.join(releases_path, release_name) + run("rm -rf #{releases_path.dump} && mkdir -p #{releases_path.dump}", options) + c = _middle_copy(top) # create new configuration with separated @variables + c.instance_eval do + set(:deploy_to, File.dirname(releases_path)) + set(:releases_path, releases_path) + set(:release_path, release_path) + set(:revision) { source.head } + set(:source) { ::Capistrano::Deploy::SCM.new(scm, self) } + set(:real_revision) { source.local.query_revision(revision) { |cmd| with_env("LC_ALL", "C") { run_locally(cmd) } } } + set(:strategy) { ::Capistrano::Deploy::Strategy.new(deploy_via, self) } + variables.each do |key, val| + set(key, val) + end + strategy.deploy! end + run("rsync -lrpt #{(release_path + "/").dump} #{destination.dump}", options) + ensure + run("rm -rf #{releases_path.dump}", options) end - run_locally("cd #{File.dirname(destination).dump} && tar chzf #{filename.dump} #{File.basename(destination).dump}") end - def _fetch_cookbook(source, destination, options) - exclusions = options.fetch(:cookbooks_exclude, []).map { |e| "--exclude=#{e.dump}" }.join(" ") - run_locally("rsync -lrpt #{exclusions} #{source}/ #{destination}") - end - - def _fetch_cookbooks(source, destination, options) - cookbooks = [ options.fetch(:cookbooks, "/") ].flatten.compact - cookbooks.each do |cookbook| - _fetch_cookbook(File.join(source, cookbook), destination, options) + def _middle_copy(object) + o = object.clone + object.instance_variables.each do |k| + v = object.instance_variable_get(k) + o.instance_variable_set(k, v ? v.clone : v) end + o end - def fetch_cookbooks_none(name, destination, options={}) - _fetch_cookbooks(options.fetch(:repository, "."), destination, options) + def install_cookbooks(name, source, destination, options={}) + logger.debug("installing cookbooks `#{name}' to #{destination}.") + run("mkdir -p #{source.dump} #{destination.dump}", options) + run("rsync -lrpt #{(source + "/").dump} #{destination.dump}", options) end - def fetch_cookbooks_repository(name, destination, options={}) - configuration = Capistrano::Configuration.new - # refreshing just :source, :revision and :real_revision is enough? - options = { - :source => lambda { Capistrano::Deploy::SCM.new(configuration[:scm], configuration) }, - :revision => lambda { configuration[:source].head }, - :real_revision => lambda { - configuration[:source].local.query_revision(configuration[:revision]) { |cmd| with_env("LC_ALL", "C") { run_locally(cmd) } } - }, - }.merge(options) - variables.merge(options).each do |key, val| - configuration.set(key, val) - end - repository_cache = File.join(chef_solo_repository_cache, name) - if File.exist?(repository_cache) - run_locally(configuration[:source].sync(configuration[:real_revision], repository_cache)) - else - run_locally(configuration[:source].checkout(configuration[:real_revision], repository_cache)) - end - _fetch_cookbooks(repository_cache, destination, options) - end - - def distribute_cookbooks(filename, remote_filename, remote_destination) - upload(filename, remote_filename) - run("rm -rf #{remote_destination.dump}") - run("cd #{File.dirname(remote_destination).dump} && tar xzf #{remote_filename.dump}") - end - _cset(:chef_solo_config) { (<<-EOS).gsub(/^\s*/, "") file_cache_path #{File.join(chef_solo_path, "cache").dump} cookbook_path #{File.join(chef_solo_path, "cookbooks").dump} EOS @@ -418,15 +408,17 @@ def update_attributes(options={}) run_list = options.delete(:run_list) servers = find_servers_for_task(current_task) servers.each do |server| + logger.debug("updating chef-solo attributes for #{server.host}.") attributes = _generate_attributes(:hosts => server.host, :roles => role_names_for_host(server), :run_list => run_list) top.put(_json_attributes(attributes), chef_solo_attributes_file, options.merge(:hosts => server.host)) end end def invoke(options={}) + logger.debug("invoking chef-solo.") args = fetch(:chef_solo_options, []) args << "-c #{chef_solo_config_file.dump}" args << "-j #{chef_solo_attributes_file.dump}" run("cd #{chef_solo_path.dump} && #{sudo} #{bundle_cmd} exec #{chef_solo_cmd} #{args.join(" ")}", options) end