class Kitchen::Transport::Dokken::Connection

@author Sean OMeara <sean@chef.io>

def docker_connection

def docker_connection
  @docker_connection ||= ::Docker::Connection.new(options[:docker_host_url], options[:docker_host_options])
end

def execute(command)

def execute(command)
  return if command.nil?
  with_retries { @runner = ::Docker::Container.get(instance_name, {}, docker_connection) }
  with_retries do
    o = @runner.exec(Shellwords.shellwords(command), 'e' => { 'TERM' => 'xterm' }) { |_stream, chunk| print chunk.to_s }
    @exit_code = o[2]
  end
  raise Transport::DockerExecFailed, "Docker Exec (#{@exit_code}) for command: [#{command}]" if @exit_code != 0
end

def image_prefix

def image_prefix
  options[:image_prefix]
end

def instance_name

def instance_name
  options[:instance_name]
end

def login_command

def login_command
  @runner = options[:instance_name].to_s
  args = ['exec', '-it', @runner, '/bin/bash', '-login', '-i']
  LoginCommand.new('docker', args)
end

def upload(locals, remote)

def upload(locals, remote)
  port = options[:data_container][:NetworkSettings][:Ports][:"22/tcp"][0][:HostPort]
  if options[:host_ip_override]
    # Allow connecting to any ip/hostname to support sibling containers
    ip = options[:host_ip_override]
  elsif options[:docker_host_url] =~ /unix:/
    if options[:data_container][:NetworkSettings][:Ports][:"22/tcp"][0][:HostIp] == '0.0.0.0'
      ip = options[:data_container][:NetworkSettings][:IPAddress]
      port = '22'
    else
      # we should read the proper mapped ip, since this allows us to upload the files
      ip = options[:data_container][:NetworkSettings][:Ports][:"22/tcp"][0][:HostIp]
    end
  elsif options[:docker_host_url] =~ /tcp:/
    ip = options[:docker_host_url].split('tcp://')[1].split(':')[0]
  else
    raise Kitchen::UserError, 'docker_host_url must be tcp:// or unix://'
  end
  tmpdir = Dir.tmpdir
  FileUtils.mkdir_p "#{tmpdir}/dokken"
  File.write("#{tmpdir}/dokken/id_rsa", insecure_ssh_private_key)
  FileUtils.chmod(0600, "#{tmpdir}/dokken/id_rsa")
  begin
    rsync_cmd = '/usr/bin/rsync -a -e'
    rsync_cmd << ' \''
    rsync_cmd << 'ssh -2'
    rsync_cmd << " -i #{tmpdir}/dokken/id_rsa"
    rsync_cmd << ' -o CheckHostIP=no'
    rsync_cmd << ' -o Compression=no'
    rsync_cmd << ' -o PasswordAuthentication=no'
    rsync_cmd << ' -o StrictHostKeyChecking=no'
    rsync_cmd << ' -o UserKnownHostsFile=/dev/null'
    rsync_cmd << ' -o LogLevel=ERROR'
    rsync_cmd << " -p #{port}"
    rsync_cmd << '\''
    rsync_cmd << " #{locals.join(' ')} root@#{ip}:#{remote}"
    `#{rsync_cmd}`
  rescue Errno::ENOENT
    debug 'Rsync is not installed. Falling back to SCP.'
    locals.each do |local|
      Net::SCP.upload!(ip,
                       'root',
                       local,
                       remote,
                       recursive: true,
                       ssh: { port: port, keys: ["#{tmpdir}/dokken/id_rsa"] })
    end
  end
end

def with_retries

def with_retries
  tries = 20
  begin
    yield
    # Only catch errors that can be fixed with retries.
  rescue ::Docker::Error::ServerError, # 404
         ::Docker::Error::UnexpectedResponseError, # 400
         ::Docker::Error::TimeoutError,
         ::Docker::Error::IOError => e
    tries -= 1
    retry if tries > 0
    raise e
  end
end

def work_image

def work_image
  return "#{image_prefix}/#{instance_name}" unless image_prefix.nil?
  instance_name
end