class Aws::EC2Metadata
A client that can query version 2 of the EC2 Instance Metadata
Constants
- METADATA_TOKEN_PATH
-
Path for PUT request for token @api private
Public Class Methods
Source
# File lib/aws-sdk-core/ec2_metadata.rb, line 57 def initialize(options = {}) @token_ttl = options[:token_ttl] || 21_600 @retries = options[:retries] || 3 @backoff = backoff(options[:backoff]) endpoint_mode = options[:endpoint_mode] || 'IPv4' @endpoint = resolve_endpoint(options[:endpoint], endpoint_mode) @port = options[:port] || 80 @http_open_timeout = options[:http_open_timeout] || 1 @http_read_timeout = options[:http_read_timeout] || 1 @http_debug_output = options[:http_debug_output] @token = nil @mutex = Mutex.new end
Creates a client that can query version 2 of the EC2 Instance Metadata
service (IMDS).
@note Customers using containers may need to increase their hop limit
to access IMDSv2.
@param [Hash] options @option options [Integer] :token_ttl (21600) The session token’s TTL,
defaulting to 6 hours.
@option options [Integer] :retries (3) The number of retries for failed
requests.
@option options [String] :endpoint (‘169.254.169.254’) The IMDS
endpoint. This option has precedence over the :endpoint_mode.
@option options [String] :endpoint_mode (‘IPv4’) The endpoint mode for
the instance metadata service. This is either 'IPv4' ('http://169.254.169.254') or 'IPv6' ('http://[fd00:ec2::254]').
@option options [Integer] :port (80) The IMDS endpoint port. @option options [Integer] :http_open_timeout (1) The number of seconds to
wait for the connection to open.
@option options [Integer] :http_read_timeout (1) The number of seconds for
one chunk of data to be read.
@option options [IO] :http_debug_output An output stream for debugging. Do
not use this in production.
@option options [Integer,Proc] :backoff A backoff used for retryable
requests. When given an Integer, it sleeps that amount. When given a Proc, it is called with the current number of failed retries.
Public Instance Methods
Source
# File lib/aws-sdk-core/ec2_metadata.rb, line 110 def get(path) retry_errors(max_retries: @retries) do @mutex.synchronize do fetch_token unless @token && !@token.expired? end open_connection do |conn| http_get(conn, path, @token.value) end end end
Fetches a given metadata category using a String path, and returns the
result as a String. A path starts with the API version (usually "/latest/"). See the instance data categories for possible paths.
@example Fetching the instance ID
ec2_metadata = Aws::EC2Metadata.new ec2_metadata.get('/latest/meta-data/instance-id') => "i-023a25f10a73a0f79"
@note This implementation always returns a String and will not parse any
responses. Parsable responses may include JSON objects or directory listings, which are strings separated by line feeds (ASCII 10).
@example Fetching and parsing JSON meta-data
require 'json' data = ec2_metadata.get('/latest/dynamic/instance-identity/document') JSON.parse(data) => {"accountId"=>"012345678912", ... }
@example Fetching and parsing directory listings
listing = ec2_metadata.get('/latest/meta-data') listing.split(10.chr) => ["ami-id", "ami-launch-index", ...]
@note Unlike other services, IMDS does not have a service API model. This
means that we cannot confidently generate code with methods and response structures. This implementation ensures that new IMDS features are always supported by being deployed to the instance and does not require code changes.
@see docs.aws.amazon.com/AWSEC2/latest/UserGuide/instancedata-data-categories.html @see docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-identity-documents.html @param [String] path The full path to the metadata.
Private Instance Methods
Source
# File lib/aws-sdk-core/ec2_metadata.rb, line 213 def backoff(backoff) case backoff when Proc then backoff when Numeric then ->(_) { Kernel.sleep(backoff) } else ->(num_failures) { Kernel.sleep(1.2**num_failures) } end end
Source
# File lib/aws-sdk-core/ec2_metadata.rb, line 137 def fetch_token open_connection do |conn| created_time = Time.now token_value, token_ttl = http_put(conn, @token_ttl) @token = Token.new(value: token_value, ttl: token_ttl, created_time: created_time) end end
Source
# File lib/aws-sdk-core/ec2_metadata.rb, line 145 def http_get(connection, path, token) headers = { 'User-Agent' => "aws-sdk-ruby3/#{CORE_GEM_VERSION}", 'x-aws-ec2-metadata-token' => token } request = Net::HTTP::Get.new(path, headers) response = connection.request(request) case response.code.to_i when 200 response.body when 401 raise TokenExpiredError when 404 raise MetadataNotFoundError end end
Source
# File lib/aws-sdk-core/ec2_metadata.rb, line 163 def http_put(connection, ttl) headers = { 'User-Agent' => "aws-sdk-ruby3/#{CORE_GEM_VERSION}", 'x-aws-ec2-metadata-token-ttl-seconds' => ttl.to_s } request = Net::HTTP::Put.new(METADATA_TOKEN_PATH, headers) response = connection.request(request) case response.code.to_i when 200 [ response.body, response.header['x-aws-ec2-metadata-token-ttl-seconds'].to_i ] when 400 raise TokenRetrievalError when 403 raise RequestForbiddenError end end
Source
# File lib/aws-sdk-core/ec2_metadata.rb, line 184 def open_connection uri = URI.parse(@endpoint) http = Net::HTTP.new(uri.hostname || @endpoint, uri.port || @port) http.open_timeout = @http_open_timeout http.read_timeout = @http_read_timeout http.set_debug_output(@http_debug_output) if @http_debug_output http.start yield(http).tap { http.finish } end
Source
# File lib/aws-sdk-core/ec2_metadata.rb, line 124 def resolve_endpoint(endpoint, endpoint_mode) return endpoint if endpoint case endpoint_mode.downcase when 'ipv4' then 'http://169.254.169.254' when 'ipv6' then 'http://[fd00:ec2::254]' else raise ArgumentError, ':endpoint_mode is not valid, expected IPv4 or IPv6, '\ "got: #{endpoint_mode}" end end
Source
# File lib/aws-sdk-core/ec2_metadata.rb, line 194 def retry_errors(options = {}, &_block) max_retries = options[:max_retries] retries = 0 begin yield # These errors should not be retried. rescue TokenRetrievalError, MetadataNotFoundError, RequestForbiddenError raise # StandardError is not ideal but it covers Net::HTTP errors. # https://gist.github.com/tenderlove/245188 rescue StandardError, TokenExpiredError raise unless retries < max_retries @backoff.call(retries) retries += 1 retry end end