Skip to content

Instantly share code, notes, and snippets.

@mattkasa
Last active June 13, 2018 23:00
Show Gist options
  • Save mattkasa/89fbd7a88fbb24f1f59758fe392a600d to your computer and use it in GitHub Desktop.
Save mattkasa/89fbd7a88fbb24f1f59758fe392a600d to your computer and use it in GitHub Desktop.
#!/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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment