# frozen_string_literal: true
require 'tempfile'
namespace :docker do
namespace :compose do def docker_compose_cmd fetch(:docker_compose_cmd, 'docker-compose') end def docker_compose_project (fetch(:docker_compose_project) { fetch(:application) }) || raise('unable to discern docker_compose_project name; specify :application or :docker_compose_project') end def docker_compose_opts fetch(:docker_compose_opts, nil) end def docker_compose_up_opts fetch(:docker_compose_up_opts, '-d --no-build --remove-orphans') end def docker_compose_stop_opts fetch(:docker_compose_stop_opts, nil) end def docker_compose_down_opts fetch(:docker_compose_down_opts, '-v --remove-orphans') end # Relative path to the docker-compose.yml for deployments def docker_compose_file fetch(:docker_compose_file, 'docker-compose.yml') end # Path for docker-compose remote deployments def docker_compose_path fetch(:docker_compose_path) { build_path } end task :check_docker_compose_root do on roles(:docker_compose) do |remote| # info "ON HOST #{remote}" # info "checking docker_compose_path: #{docker_compose_path}" # should really fix this to preserve typical capistrano dir-tree, but meh for now... unless test("[ -d #{docker_compose_path} ]") warn "docker_compose_path does not exist on host (#{remote}): #{docker_compose_path}" warn "creating docker_compose_path on host (#{remote}): #{docker_compose_path}" warn 'this can break future `cap stage deploy` execution on build hosts' execute :mkdir, '-p', docker_compose_path end end end task :local_source_warning do run_locally do warn 'Using docker-compose files directly from local workspace... (typically undesirable)' warn '>> assign :docker_build role to enable remote builds' end end desc 'copies a new docker_compose_file from the docker_build role to each docker_compose role' task :upload do if roles(:docker_compose).empty? invoke 'docker:compose:upload_local' else invoke 'docker:compose:upload_remote' end end # copies a new docker-compose.yml file up to each docker_compose host task :upload_local do run_locally do info 'Nothing to do here, docker-compose will run locally...' end end # copies a new docker-compose.yml file up to each docker_compose host task :upload_remote => :check_docker_compose_root do tmp_file = Tempfile.new('upload_remote') tmp_file_path = tmp_file.path tmp_file.close(false) begin docker_build_role = roles(:docker_build).first upload_roles = roles(:docker_compose) - [docker_build_role] unless upload_roles.empty? if docker_build_role on docker_build_role do |build_remote| info "fetching #{build_remote}:#{docker_compose_path.join(docker_compose_file)}" download! docker_compose_path.join(docker_compose_file), tmp_file_path end else invoke 'docker:compose:local_source_warning' run_locally do warn "fetching #{docker_compose_file}" download! docker_compose_file, tmp_file_path end end on upload_roles do |upload_role| info "uploading to #{upload_role}:#{docker_compose_path.join(docker_compose_file)}" upload! tmp_file_path, docker_compose_path.join(docker_compose_file) end end ensure File.unlink(tmp_file_path) end end desc 'list current services state' task :ps do if roles(:docker_compose).empty? invoke 'docker:compose:ps_local' else invoke 'docker:compose:ps_remote' end end task :ps_local do current_build_dir = pwd run_locally do info "Current Working Directory: #{current_build_dir}" execute docker_compose_cmd, "--file=#{docker_compose_file}", "--project-name=#{docker_compose_project}", docker_compose_opts, :ps end end task :ps_remote do on roles(:docker_compose) do |buildremote| info "ON HOST #{buildremote}" within build_path do execute docker_compose_cmd, "--file=#{docker_compose_file}", "--project-name=#{docker_compose_project}", docker_compose_opts, :ps end end end desc 'starts/updates services' task :up do if roles(:docker_compose).empty? invoke 'docker:compose:up_local' else invoke 'docker:compose:up_remote' end end task :up_local do current_build_dir = pwd run_locally do info "Current Working Directory: #{current_build_dir}" execute docker_compose_cmd, "--file=#{docker_compose_file}", "--project-name=#{docker_compose_project}", docker_compose_opts, :up, docker_compose_up_opts end end task :up_remote do on roles(:docker_compose) do |buildremote| info "ON HOST #{buildremote}" within build_path do execute docker_compose_cmd, "--file=#{docker_compose_file}", "--project-name=#{docker_compose_project}", docker_compose_opts, :up, '-d', docker_compose_up_opts end end end desc 'stops services but leaves them created' task :stop do if roles(:docker_compose).empty? invoke 'docker:compose:stop_local' else invoke 'docker:compose:stop_remote' end end task :stop_local do current_build_dir = pwd run_locally do info "Current Working Directory: #{current_build_dir}" execute docker_compose_cmd, "--file=#{docker_compose_file}", "--project-name=#{docker_compose_project}", docker_compose_opts, :stop, docker_compose_stop_opts end end task :stop_remote do on roles(:docker_compose) do |buildremote| info "ON HOST #{buildremote}" within build_path do execute docker_compose_cmd, "--file=#{docker_compose_file}", "--project-name=#{docker_compose_project}", docker_compose_opts, :stop, docker_compose_stop_opts end end end desc 'stop and clean up all services' task :down do if roles(:docker_compose).empty? invoke 'docker:compose:down_local' else invoke 'docker:compose:down_remote' end end task :down_local do current_build_dir = pwd run_locally do info "Current Working Directory: #{current_build_dir}" execute docker_compose_cmd, "--file=#{docker_compose_file}", "--project-name=#{docker_compose_project}", docker_compose_opts, :down, docker_compose_down_opts end end task :down_remote do on roles(:docker_compose) do |buildremote| info "ON HOST #{buildremote}" within build_path do execute docker_compose_cmd, "--file=#{docker_compose_file}", "--project-name=#{docker_compose_project}", docker_compose_opts, :down, docker_compose_down_opts end end end desc 'Update docker-compose on all hosts and re-up' task :update do invoke 'docker:compose:upload' invoke 'docker:compose:up' end desc '(alias for docker:compose:update)' task :deploy => :update # Default `cap env deploy` flow hook task :capdeploy_hook do if fetch(:dockercompose_deployhook, true) invoke 'docker:compose:update' end end end # namespace :compose do
end # namespace :docker do