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
47
48
49
# File 'lib/bolt/transport/docker/connection.rb', line 29

def execute(*command, options)
  command.unshift(options[:interpreter]) if options[:interpreter]
  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[0] = result[0].join.force_encoding('UTF-8')
  result[1] = result[1].join.force_encoding('UTF-8')
  result
rescue StandardError
  @logger.debug { "Command aborted" }
  raise
end

#make_executable(path) ⇒ Object



104
105
106
107
108
109
110
# File 'lib/bolt/transport/docker/connection.rb', line 104

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

#make_tempdirObject



73
74
75
76
77
78
79
80
81
82
# File 'lib/bolt/transport/docker/connection.rb', line 73

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}", 'TEMPDIR_ERROR')
  end
  tmppath || stdout.first
end

#mkdirs(dirs) ⇒ Object



65
66
67
68
69
70
71
# File 'lib/bolt/transport/docker/connection.rb', line 65

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

#with_remote_tempdirObject



84
85
86
87
88
89
90
91
92
93
94
# File 'lib/bolt/transport/docker/connection.rb', line 84

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}")
    end
  end
end

#write_remote_directory(source, destination) ⇒ Object



57
58
59
60
61
62
63
# File 'lib/bolt/transport/docker/connection.rb', line 57

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



96
97
98
99
100
101
102
# File 'lib/bolt/transport/docker/connection.rb', line 96

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



51
52
53
54
55
# File 'lib/bolt/transport/docker/connection.rb', line 51

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