Class: Maze::AwsPublicIp

Inherits:
Object
  • Object
show all
Defined in:
lib/maze/aws_public_ip.rb

Overview

Determines the public IP address and port when running on Buildkite with the Elastic CI Stack for AWS

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeAwsPublicIp

Returns a new instance of AwsPublicIp.



13
14
15
16
17
18
19
# File 'lib/maze/aws_public_ip.rb', line 13

def initialize
  # This class is only relevant on Buildkite
  return unless ENV['BUILDKITE']

  @ip = determine_public_ip
  @port = determine_public_port Maze.config.port
end

Instance Attribute Details

#hostObject (readonly)

Returns the value of attribute host.



6
7
8
# File 'lib/maze/aws_public_ip.rb', line 6

def host
  @host
end

#portObject (readonly)

Returns the value of attribute port.



7
8
9
# File 'lib/maze/aws_public_ip.rb', line 7

def port
  @port
end

Instance Method Details

#addressObject



9
10
11
# File 'lib/maze/aws_public_ip.rb', line 9

def address
  "#{@ip}:#{@port}"
end

#determine_public_ipObject

Determines the public IP address of the running AWS instance



22
23
24
25
26
27
# File 'lib/maze/aws_public_ip.rb', line 22

def determine_public_ip
  # 169.254.169.254 is the address of the AWS instance metadata service
  # See https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instancedata-data-retrieval.html
  token = `curl --silent -H "X-aws-ec2-metadata-token-ttl-seconds: 120" -XPUT http://169.254.169.254/latest/api/token`
  `curl -H "X-aws-ec2-metadata-token: #{token}" --silent -XGET http://169.254.169.254/latest/meta-data/public-ipv4`
end

#determine_public_port(local_port) ⇒ Object

Determines the external port of the running Docker container that’s associated with the port given

Parameters:

  • local_port

    Local port to find the external port for



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
# File 'lib/maze/aws_public_ip.rb', line 31

def determine_public_port(local_port)
  port = 0
  count = 0
  max_attempts = 30
  invalid_response_retries = 0
  max_invalid_retries = 2

  # Give up after 30 seconds
  while port == 0 && count < max_attempts do
    hostname = ENV['HOSTNAME']
    command = "curl --silent -XGET --unix-socket /var/run/docker.sock http://localhost/containers/#{hostname}/json"
    result = Maze::Runner.run_command(command)
    if result[1] == 0
      begin
        json_string = result[0][0].strip
        json_result = JSON.parse(json_string)
        port = json_result['NetworkSettings']['Ports']["#{local_port}/tcp"][0]['HostPort']
      rescue NoMethodError => error
        if invalid_response_retries >= max_invalid_retries
          Bugsnag.notify error
          $logger.error "Public port response was invalid or incomplete: #{json_string}"
          $logger.error "This has occurred more than maximum allowed #{max_invalid_retries}, exiting port process"
          return 0
        else
          invalid_response_retries += 1
          $logger.warn "Public port response was invalid or incomplete: #{json_string}"
          $logger.warn "Attempting to acquire public port again, retry attempt: #{invalid_response_retries}"
        end
      rescue StandardError => error
        Bugsnag.notify error
        $logger.error "Unable to parse public port from: #{json_string}"
        return 0
      end
    end

    count += 1
    sleep 1 if port == 0 && count < max_attempts
  end
  $logger.error "Failed to determine public port within #{max_attempts} attempts" if port == 0 && count == max_attempts

  port
end