require ‘thread’ require ‘excon’ require ‘centurion/deploy’ require ‘tmpdir’
task :deploy do
invoke 'deploy:get_image' invoke 'deploy:stop' invoke 'deploy:start_new' invoke 'deploy:cleanup'
end
task :deploy_console do
invoke 'deploy:get_image' #invoke 'deploy:stop' invoke 'deploy:launch_console' invoke 'deploy:cleanup'
end
task :rolling_deploy do
invoke 'deploy:get_image' invoke 'deploy:rolling_deploy' invoke 'deploy:cleanup'
end
task :stop => [‘deploy:stop’] task :enter_container => [‘deploy:enter_container’]
namespace :dev do
task :export_only do # This removes the known-to-be-problematic bundler env # vars but doesn't try to sanitize the whole ENV. Doing # so breaks things like rbenv which we need to use when # testing. A /bin/bash -l will help further clean it up. ENV.reject! { |(var, val)| var =~ /^BUNDLE_/ } fetch(:env_vars).each { |(var, value)| ENV[var] = value } exec fetch(:development_shell, '/bin/bash -l') end
end
namespace :deploy do
include Centurion::Deploy namespace :dogestry do task :validate_pull_image do ['aws_access_key_id', 'aws_secret_key', 's3_bucket'].each do |env_var| unless fetch(env_var.to_sym) error "\n\n#{env_var} is not defined." exit(1) end end end task :pull_image do invoke 'deploy:dogestry:validate_pull_image' # Create Centurion::Dogestry instance registry = Centurion::Dogestry.new( aws_access_key_id: fetch(:aws_access_key_id), aws_secret_key: fetch(:aws_secret_key), s3_bucket: fetch(:s3_bucket), s3_region: fetch(:s3_region) || 'us-east-1', tlsverify: fetch(:tlsverify), tlscacert: fetch(:tlscacert), tlscert: fetch(:tlscert), original_docker_cert_path: fetch(:original_docker_cert_path) ) target_servers = Centurion::DockerServerGroup.new(fetch(:hosts), fetch(:docker_path)) pull_hosts = [] target_servers.each do |target_server| docker_host = "tcp://#{target_server.hostname}:#{target_server.port}" pull_hosts.push(docker_host) end image_and_tag = "#{fetch(:image)}:#{fetch(:tag)}" info "** Pulling image(#{image_and_tag}) from S3 to Docker Hosts: #{pull_hosts}" registry.pull(image_and_tag, pull_hosts) end end task :get_image do invoke 'deploy:pull_image' invoke 'deploy:determine_image_id_from_first_server' invoke 'deploy:verify_image' end # stop # - remote: list # - remote: stop task :stop do on_each_docker_host do |server| stop_containers(server, defined_service, fetch(:stop_timeout, 30)) end end # start # - remote: create # - remote: start # - remote: inspect container task :start_new do on_each_docker_host do |server| start_new_container(server, defined_service, defined_restart_policy) end end task :launch_console do on_first_docker_host do |server| defined_service.port_bindings.clear launch_console(server, defined_service) end end task :enter_container do on_first_docker_host do |server| enter_container(server, defined_service) end end task :rolling_deploy do on_each_docker_host do |server| service = defined_service stop_containers(server, service, fetch(:stop_timeout, 30)) container = start_new_container(server, service, defined_restart_policy) public_ports = service.public_ports - fetch(:rolling_deploy_skip_ports, []) public_ports.each do |port| wait_for_health_check_ok( fetch(:health_check, method(:http_status_ok?)), server, container['Id'], port, fetch(:status_endpoint, '/'), fetch(:image), fetch(:tag), fetch(:rolling_deploy_wait_time, 5), fetch(:rolling_deploy_retries, 24) ) end wait_for_load_balancer_check_interval end end task :cleanup do on_each_docker_host do |server| cleanup_containers(server, defined_service) end end task :determine_image_id do registry = Centurion::DockerRegistry.new( fetch(:docker_registry), fetch(:registry_user), fetch(:registry_password) ) exact_image = registry.digest_for_tag(fetch(:image), fetch(:tag)) set :image_id, exact_image info "RESOLVED #{fetch(:image)}:#{fetch(:tag)} => #{exact_image[0..11]}" end task :determine_image_id_from_first_server do on_each_docker_host do |target_server| image_detail = target_server.inspect_image(fetch(:image), fetch(:tag)) # Handle CamelCase in response from Docker API # See https://github.com/newrelic/centurion/issues/85 exact_image = image_detail["id"] || image_detail["Id"] set :image_id, exact_image info "RESOLVED #{fetch(:image)}:#{fetch(:tag)} => #{exact_image[0..11]}" break end end task :pull_image do if fetch(:no_pull) info "--no-pull option specified: skipping pull" next end info "Fetching image #{fetch(:image)}:#{fetch(:tag)} IN PARALLEL\n" if fetch(:registry) == 'dogestry' invoke 'deploy:dogestry:pull_image' else build_server_group.each_in_parallel do |target_server| target_server.pull(fetch(:image), fetch(:tag)) end end end task :verify_image do on_each_docker_host do |target_server| image_detail = target_server.inspect_image(fetch(:image), fetch(:tag)) # Handle CamelCase in response from Docker API # See https://github.com/newrelic/centurion/issues/85 found_image_id = image_detail["id"] || image_detail["Id"] if found_image_id == fetch(:image_id) info "Image #{found_image_id[0..7]} found on #{target_server.hostname}" else raise "Did not find image #{fetch(:image_id)} on host #{target_server.hostname}!" end # Again, handle CamelCase in response from Docker API container_config = image_detail["container_config"] || image_detail["ContainerConfig"] # Print the container config container_config.each_pair do |key,value| info "\t#{key} => #{value.inspect}" end end end task :promote_from_staging do if fetch(:environment) == 'staging' error "\n\nYour target environment needs to not be 'staging' to promote from staging." exit(1) end starting_environment = current_environment # Set our env to staging so we can grab the current tag. invoke 'environment:staging' staging_tags = get_current_tags_for(fetch(:image)).map { |t| t[:tags] }.flatten.uniq if staging_tags.size != 1 error "\n\nUh, oh: Not sure which staging tag to deploy! Found:(#{staging_tags.join(', ')})" exit(1) end info "Staging environment has #{staging_tags.first} deployed." # Make sure that we set our env back to production, then update the tag. set_current_environment(starting_environment) set :tag, staging_tags.first info "Deploying #{fetch(:tag)} to the #{starting_environment} environment" invoke 'deploy' end
end