Class: Bolt::Transport::Docker::Connection

Inherits:
Object
  • Object
show all
Defined in:
lib/bolt/transport/docker/connection.rb

Instance Method Summary collapse

Constructor Details

#initialize(target) ⇒ Connection

Returns a new instance of Connection.



11
12
13
14
# File 'lib/bolt/transport/docker/connection.rb', line 11

def initialize(target)
  @target = target
  @logger = Logging.logger[target.host]
end

Instance Method Details

#connectObject



16
17
18
19
20
21
22
23
24
25
26
27
# File 'lib/bolt/transport/docker/connection.rb', line 16

def connect
  # Explicitly create the new Connection to avoid relying on global state in the Docker module.
  url = @target.options['service-url'] || ::Docker.url
  options = ::Docker.options.merge(@target.options['service-options'] || {})
  @container = ::Docker::Container.get(@target.host, {}, ::Docker::Connection.new(url, options))
  @logger.debug { "Opened session" }
rescue StandardError => e
  raise Bolt::Node::ConnectError.new(
    "Failed to connect to #{@target.uri}: #{e.message}",
    'CONNECT_ERROR'
  )
end

#execute(*command, options) ⇒ Object



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/bolt/transport/docker/connection.rb', line 29

def execute(*command, options)
  if options[:environment]
    envs = options[:environment].map { |env, val| "#{env}=#{val}" }
    command = ['env'] + envs + command
  end

  @logger.debug { "Executing: #{command}" }
  result = @container.exec(command, options) { |stream, chunk| @logger.debug("#{stream}: #{chunk}") }
  if result[2] == 0
    @logger.debug { "Command returned successfully" }
  else
    @logger.info { "Command failed with exit code #{result[2]}" }
  end
  result
rescue StandardError
  @logger.debug { "Command aborted" }
  raise
end

#make_executable(path) ⇒ Object



101
102
103
104
105
106
107
# File 'lib/bolt/transport/docker/connection.rb', line 101

def make_executable(path)
  _, stderr, exitcode = execute('chmod', 'u+x', path, {})
  if exitcode != 0
    message = "Could not make file '#{path}' executable: #{stderr.join}"
    raise Bolt::Node::FileError.new(message, 'CHMOD_ERROR')
  end
end

#make_tempdirObject



70
71
72
73
74
75
76
77
78
79
# File 'lib/bolt/transport/docker/connection.rb', line 70

def make_tempdir
  tmpdir = @target.options.fetch('tmpdir', '/tmp')
  tmppath = "#{tmpdir}/#{SecureRandom.uuid}"

  stdout, stderr, exitcode = execute('mkdir', '-m', '700', tmppath, {})
  if exitcode != 0
    raise Bolt::Node::FileError.new("Could not make tempdir: #{stderr.join}", 'TEMPDIR_ERROR')
  end
  tmppath || stdout.first
end

#mkdirs(dirs) ⇒ Object



62
63
64
65
66
67
68
# File 'lib/bolt/transport/docker/connection.rb', line 62

def mkdirs(dirs)
  _, stderr, exitcode = execute('mkdir', '-p', *dirs, {})
  if exitcode != 0
    message = "Could not create directories: #{stderr.join}"
    raise Bolt::Node::FileError.new(message, 'MKDIR_ERROR')
  end
end

#with_remote_tempdirObject



81
82
83
84
85
86
87
88
89
90
91
# File 'lib/bolt/transport/docker/connection.rb', line 81

def with_remote_tempdir
  dir = make_tempdir
  yield dir
ensure
  if dir
    _, stderr, exitcode = execute('rm', '-rf', dir, {})
    if exitcode != 0
      @logger.warn("Failed to clean up tempdir '#{dir}': #{stderr.join}")
    end
  end
end

#write_remote_directory(source, destination) ⇒ Object



54
55
56
57
58
59
60
# File 'lib/bolt/transport/docker/connection.rb', line 54

def write_remote_directory(source, destination)
  tar = ::Docker::Util.create_dir_tar(source)
  mkdirs([destination])
  @container.archive_in_stream(destination) { tar.read(Excon.defaults[:chunk_size]).to_s }
rescue StandardError => e
  raise Bolt::Node::FileError.new(e.message, 'WRITE_ERROR')
end

#write_remote_executable(dir, file, filename = nil) ⇒ Object



93
94
95
96
97
98
99
# File 'lib/bolt/transport/docker/connection.rb', line 93

def write_remote_executable(dir, file, filename = nil)
  filename ||= File.basename(file)
  remote_path = File.join(dir.to_s, filename)
  write_remote_file(file, remote_path)
  make_executable(remote_path)
  remote_path
end

#write_remote_file(source, destination) ⇒ Object



48
49
50
51
52
# File 'lib/bolt/transport/docker/connection.rb', line 48

def write_remote_file(source, destination)
  @container.store_file(destination, File.binread(source))
rescue StandardError => e
  raise Bolt::Node::FileError.new(e.message, 'WRITE_ERROR')
end