Class: TasteTester::Tunnel

Inherits:
Object
  • Object
show all
Includes:
BetweenMeals::Util, Logging
Defined in:
lib/taste_tester/tunnel.rb

Overview

Thin ssh tunnel wrapper

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Logging

#formatter, formatterproc=, logger, #logger, use_log_formatter=, verbosity=

Constructor Details

#initialize(host, server, timeout = 5) ⇒ Tunnel

Returns a new instance of Tunnel.



25
26
27
28
29
30
31
32
33
34
35
# File 'lib/taste_tester/tunnel.rb', line 25

def initialize(host, server, timeout = 5)
  @host = host
  @server = server
  @timeout = timeout
  if TasteTester::Config.testing_until
    @delta_secs = TasteTester::Config.testing_until.strftime('%s').to_i -
                  Time.now.strftime('%s').to_i
  else
    @delta_secs = TasteTester::Config.testing_time
  end
end

Instance Attribute Details

#portObject (readonly)

Returns the value of attribute port.



23
24
25
# File 'lib/taste_tester/tunnel.rb', line 23

def port
  @port
end

Class Method Details

.kill(name) ⇒ Object



75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/taste_tester/tunnel.rb', line 75

def self.kill(name)
  ssh = TasteTester::SSH.new(name)
  # Since commands are &&'d together, and we're using &&, we need to
  # surround this in paryns, and make sure as a whole it evaluates
  # to true so it doesn't mess up other things... even though this is
  # the only thing we're currently executing in this SSH.
  if TasteTester::Config.user != 'root'
    sudo = 'sudo '
  end
  cmd = "( [ -s #{TasteTester::Config.timestamp_file} ]" +
        " && #{sudo}kill -9 -- " +
        "-\$(cat #{TasteTester::Config.timestamp_file}) 2>/dev/null; " +
        ' true )'
  ssh << cmd
  ssh.run!
end

Instance Method Details

#cmdObject



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
# File 'lib/taste_tester/tunnel.rb', line 46

def cmd
  @max_ping = @delta_secs / 10
  pid = '$$'
  @ts = TasteTester::Config.testing_end_time.strftime('%y%m%d%H%M.%S')
  cmds = "ps -o pgid= -p $(ps -o ppid= -p #{pid}) | sed \"s| ||g\" " +
         " > #{TasteTester::Config.timestamp_file} &&" +
         " touch -t #{@ts} #{TasteTester::Config.timestamp_file} &&" +
         " sleep #{@delta_secs}"
  # As great as it would be to have ExitOnForwardFailure=yes,
  # we had multiple cases of tunnels dying
  # if -f and ExitOnForwardFailure are used together.
  # In most cases the first request from chef was "breaking" the tunnel,
  # in a way that port was still open, but subsequent requests were hanging.
  # This is reproducible and should be looked into.
  cmd = "#{TasteTester::Config.ssh_command} " +
        "-T -o BatchMode=yes -o ConnectTimeout=#{@timeout} " +
        '-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no ' +
        "-o ServerAliveInterval=10 -o ServerAliveCountMax=#{@max_ping} " +
        "-f -R #{@port}:localhost:#{@server.port} "
  if TasteTester::Config.user != 'root'
    cc = Base64.encode64(cmds).delete("\n")
    cmd += "#{TasteTester::Config.user}@#{@host} \"echo '#{cc}' | base64" +
           ' --decode | sudo bash -x"'
  else
    cmd += "root@#{@host} '#{cmds}'"
  end
  cmd
end

#runObject



37
38
39
40
41
42
43
44
# File 'lib/taste_tester/tunnel.rb', line 37

def run
  @port = TasteTester::Config.tunnel_port
  logger.info("Setting up tunnel on port #{@port}")
  @status, @output = exec!(cmd, logger)
rescue StandardError
  logger.error 'Failed bringing up ssh tunnel'
  exit(1)
end