#!/usr/bin/env ruby require 'chef' require 'fileutils' app_name = ARGV[0] run_list = ARGV[1] if ENV.has_key?('CHEF_ENVIRONMENTS') && (!ENV.has_key?('TEST_GROUP') || ENV['TEST_GROUP'] == '1') environments = ENV['CHEF_ENVIRONMENTS'].split(/\s+/) branch = ENV.has_key?('TRAVIS_BRANCH') ? ENV['TRAVIS_BRANCH'] : ENV['BRANCH_NAME'] revision = ENV.has_key?('TRAVIS_COMMIT') ? ENV['TRAVIS_COMMIT'] : ENV['GIT_COMMIT'] if revision.nil? || revision == 'null' puts "Cannot deploy without a revision (restarting deploy builds is not supported)" exit(false) end environment = $1 if branch && branch =~ /^environment\/(.*)$/ if environment && environments.include?(environment) suffix = environment.upcase if %W(CHEF_SERVER_#{suffix} CHEF_USER_#{suffix} CHEF_CLIENT_#{suffix}).all? { |k| ENV.has_key?(k) } # Get the configuration from the environment chef_server = ENV["CHEF_SERVER_#{suffix}"] chef_org = chef_server.sub(/^.*\//, '') chef_user = ENV["CHEF_USER_#{suffix}"] chef_client = ENV["CHEF_CLIENT_#{suffix}"] # Configure knife and write client key chef_dir = File.join(Dir.pwd, '.chef') FileUtils.rm_rf(chef_dir) if Dir.exist?(chef_dir) exit(1) unless Dir.mkdir(chef_dir) File.write(File.join(chef_dir, "#{chef_user}.pem"), chef_client.gsub(/\\n/, "\n")) File.open(File.join(chef_dir, 'knife.rb'), 'w') do |file| file << "current_dir = File.dirname(__FILE__)\n\n" file << "log_level :info\n" file << "log_location STDOUT\n\n" file << "node_name '#{chef_user}'\n" file << "client_key \"\#{current_dir}/#{chef_user}.pem\"\n" file << "chef_server_url '#{chef_server}'\n\n" file << "ssl_verify_mode :verify_none\n" file << "knife[:ssh_user] = '#{chef_user}'\n" end # Load chef and config chef_configs = ['.chef/knife.rb', '~/.chef/knife.rb', '/etc/chef/knife.rb'] @chef_client_token ||= Chef::Config.from_file(chef_configs.find { |p| File.exists?(File.expand_path(p)) }) # Deploy search_environments = Chef::Environment.list.keys.select { |e| e =~ /^[a-z]{4}#{environment[0]}$/ } search = "(#{search_environments.map { |e| "chef_environment:#{e}" }.join(' OR ')}) AND #{run_list}" puts "Searching for nodes matching #{search}" query = Chef::Search::Query.new results = query.search(:node, search) nodes = results.first nodes.each do |node| current_revision = node[app_name]['revision'] if node[app_name] && node[app_name]['revision'] if current_revision == revision puts "#{node.name} already at #{revision}" else printf '%s', "Updating #{node.name} from #{current_revision} to #{revision}" succeeded = false (1..5).each do |try| begin printf "%s\n", '.' node.normal[app_name]['revision'] = revision saved_node = node.save; loaded_node = Chef::Node.load(node.name); if saved_node[app_name]['revision'] == revision && loaded_node[app_name]['revision'] == revision succeeded = true break end rescue end end if succeeded printf "%s\n", 'done' system("ssh -o StrictHostKeyChecking=no -o ConnectTimeout=5 #{chef_user}@#{node['fqdn']} \"sudo chef-client\"") else printf "%s\n", 'FAILED' end end end # TODO: knife ssh end end end