1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
|
require "docker"
module Train::Transports
class Docker < Train.plugin(1)
name "docker"
include_options Train::Extras::CommandWrapper
option :host, required: true
option :docker_url, required: false
def connection(state = {}, &block)
opts = merge_options(options, state || {})
validate_options(opts)
if @connection && @connection_options == opts
reuse_connection(&block)
else
create_new_connection(opts, &block)
end
end
private
# Creates a new Docker connection instance and save it for potential future
# reuse.
#
# @param options [Hash] connection options
# @return [Docker::Connection] a Docker connection instance
# @api private
def create_new_connection(options, &block)
if @connection
logger.debug("[Docker] shutting previous connection #{@connection}")
@connection.close
end
@connection_options = options
@connection = Connection.new(options, &block)
end
# Return the last saved Docker connection instance.
#
# @return [Docker::Connection] a Docker connection instance
# @api private
def reuse_connection
logger.debug("[Docker] reusing existing connection #{@connection}")
yield @connection if block_given?
@connection
end
end
end
class Train::Transports::Docker
class Connection < BaseConnection
def initialize(conf)
super(conf)
@id = options[:host]
docker_url = options[:docker_url]
if RUBY_PLATFORM =~ /windows|mswin|msys|mingw|cygwin/
# Docker Desktop for windows. Must override socket location.
# https://docs.docker.com/desktop/faqs/#how-do-i-connect-to-the-remote-docker-engine-api
# docker_socket ||= "npipe:////./pipe/docker_engine" # # Doesn't require a settings change, but also doesn't work
docker_url ||= "tcp://localhost:2375"
end
Docker.url = docker_url if docker_url
@container = ::Docker::Container.get(@id) ||
raise("Can't find Docker container #{@id}")
@cmd_wrapper = nil
@cmd_wrapper = CommandWrapper.load(self, @options)
@probably_windows = nil
end
def close
# nothing to do at the moment
end
def uri
if @container.nil?
"docker://#{@id}"
else
"docker://#{@container.id}"
end
end
def unique_identifier
uuid = @container.nil? ? @id : @container.id # default uuid set to the docker host.
unless sniff_for_windows?
cmd = run_command_via_connection("head -1 /proc/self/cgroup|cut -d/ -f3") if file("/proc/self/cgroup").exist?
unless cmd.stdout.empty?
uuid = cmd.stdout.strip
end
end
uuid
end
private
def file_via_connection(path)
if os.aix?
Train::File::Remote::Aix.new(self, path)
elsif os.solaris?
Train::File::Remote::Unix.new(self, path)
elsif os.windows?
Train::File::Remote::Windows.new(self, path)
else
Train::File::Remote::Linux.new(self, path)
end
end
def run_command_via_connection(cmd, &_data_handler)
cmd = @cmd_wrapper.run(cmd) unless @cmd_wrapper.nil?
# Cannot use os.windows? here because it calls run_command_via_connection,
# causing infinite recursion during initial platform detection
if sniff_for_windows?
invocation = cmd_run_command(cmd)
else
invocation = sh_run_command(cmd)
end
stdout, stderr, exit_status = @container.exec(
invocation, user: @options[:user]
)
CommandResult.new(stdout.join, stderr.join, exit_status)
rescue ::Docker::Error::DockerError => _
raise
rescue => _
# @TODO: differentiate any other error
raise
end
def sh_run_command(cmd)
["/bin/sh", "-c", cmd]
end
def cmd_run_command(cmd)
["cmd.exe", "/s", "/c", cmd]
end
def sniff_for_windows?
return @probably_windows unless @probably_windows.nil?
# Run a command using /bin/sh, which should fail under Windows
stdout, _stderr, _exit_status = @container.exec(
sh_run_command("true"), user: @options[:user]
)
@probably_windows = !!stdout.detect { |l| l.include? "failure in a Windows system call" }
end
end
end
|