Module: Ohai::Mixin::Ec2Metadata
- Defined in:
- lib/ohai/mixin/ec2_metadata.rb
Overview
This code parses the EC2 Instance Metadata API to provide details of the running instance.
Earlier version of this code assumed a specific version of the metadata API was available. Unfortunately the API versions supported by a particular instance are determined at instance launch and are not extended over the life of the instance. As such the earlier code would fail depending on the age of the instance.
The updated code probes the instance metadata endpoint for available versions, determines the most advanced version known to work and executes the metadata retrieval using that version.
If no compatible version is found, an empty hash is returned.
Instance Method Summary collapse
-
#best_api_version ⇒ String
The latest metadata version in EC2_SUPPORTED_VERSIONS that this instance supports in AWS supported metadata versions are determined at instance start so we need to be cautious here in case an instance has been running for a long time.
- #fetch_dir_metadata(id, api_version) ⇒ Object
- #fetch_dynamic_data ⇒ Object
- #fetch_json_dir_metadata(id, api_version) ⇒ Object
- #fetch_metadata(id = "", api_version = nil) ⇒ Object
- #fetch_userdata ⇒ Object
-
#http_client ⇒ Net::HTTP
a net/http client with a timeout of 10s and a keepalive of 10s.
-
#metadata_get(id, api_version) ⇒ Object
Get metadata for a given path and API version.
-
#v2_token ⇒ NilClass, String
Fetch an API token for use querying AWS IMDSv2 or return nil if no token if found AWS like systems (think OpenStack) will not respond with a token here.
Instance Method Details
#best_api_version ⇒ String
The latest metadata version in EC2_SUPPORTED_VERSIONS that this instance supports in AWS supported metadata versions are determined at instance start so we need to be cautious here in case an instance has been running for a long time
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
# File 'lib/ohai/mixin/ec2_metadata.rb', line 84 def best_api_version @api_version ||= begin logger.trace("Mixin EC2: Fetching http://#{EC2_METADATA_ADDR}/ to determine the latest supported metadata release") response = http_client.get("/", { 'X-aws-ec2-metadata-token': v2_token }) if response.code == "404" logger.trace("Mixin EC2: Received HTTP 404 from metadata server while determining API version, assuming 'latest'") return "latest" elsif response.code != "200" raise "Mixin EC2: Unable to determine EC2 metadata version (returned #{response.code} response)" end # NOTE: Sorting the list of versions may have unintended consequences in # non-EC2 environments. It appears to be safe in EC2 as of 2013-04-12. versions = response.body.split("\n").sort until versions.empty? || EC2_SUPPORTED_VERSIONS.include?(versions.last) pv = versions.pop logger.trace("Mixin EC2: EC2 lists metadata version: #{pv} not yet supported by Ohai") unless pv == "latest" end logger.trace("Mixin EC2: Latest supported EC2 metadata version: #{versions.last}") if versions.empty? raise "Mixin EC2: Unable to determine EC2 metadata version (no supported entries found)" end versions.last end end |
#fetch_dir_metadata(id, api_version) ⇒ Object
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 |
# File 'lib/ohai/mixin/ec2_metadata.rb', line 188 def (id, api_version) = {} = (id, api_version) if .split("\n").each do |o| key = (o) if key[-1..-1] != "/" = ("#{id}#{key}", api_version) [(key)] = || "" elsif !key.eql?("/") [key[0..-2]] = ("#{id}#{key}", api_version) end end end end |
#fetch_dynamic_data ⇒ Object
231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 |
# File 'lib/ohai/mixin/ec2_metadata.rb', line 231 def fetch_dynamic_data @fetch_dynamic_data ||= begin response = http_client.get("/#{best_api_version}/dynamic/instance-identity/document/", { 'X-aws-ec2-metadata-token': v2_token }) if response.code == "200" json_data = parse_json(response.body, {}) if json_data.nil? logger.warn("Mixin Ec2Metadata: Metadata response is NOT valid JSON") end json_data else logger.warn("Mixin Ec2Metadata: Received response code #{response.code} requesting metadata") {} end end end |
#fetch_json_dir_metadata(id, api_version) ⇒ Object
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 |
# File 'lib/ohai/mixin/ec2_metadata.rb', line 205 def (id, api_version) = {} = (id, api_version) if .split("\n").each do |o| key = (o) if key[-1..-1] != "/" = ("#{id}#{key}", api_version) data = || "" json = String(data) parser = FFI_Yajl::Parser.new [(key)] = parser.parse(json) elsif !key.eql?("/") [key[0..-2]] = ("#{id}#{key}", api_version) end end end end |
#fetch_metadata(id = "", api_version = nil) ⇒ Object
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 |
# File 'lib/ohai/mixin/ec2_metadata.rb', line 158 def (id = "", api_version = nil) = {} = (id, best_api_version) if .split("\n").each do |o| key = ("#{id}#{o}") if key[-1..-1] != "/" [(key)] = if EC2_ARRAY_VALUES.include? key = (key, best_api_version) ? .split("\n") : else (key, best_api_version) end elsif (!key.eql?(id)) && (!key.eql?("/")) name = key[0..-2] sym = (name) if EC2_ARRAY_DIR.include?(name) [sym] = (key, best_api_version) elsif EC2_JSON_DIR.include?(name) [sym] = (key, best_api_version) else (key, best_api_version).each { |k, v| [k] = v } end end end end end |
#fetch_userdata ⇒ Object
225 226 227 228 229 |
# File 'lib/ohai/mixin/ec2_metadata.rb', line 225 def fetch_userdata logger.trace("Mixin EC2: Fetching http://#{EC2_METADATA_ADDR}/#{best_api_version}/user-data/") response = http_client.get("/#{best_api_version}/user-data/", { 'X-aws-ec2-metadata-token': v2_token }) response.code == "200" ? response.body : nil end |
#http_client ⇒ Net::HTTP
a net/http client with a timeout of 10s and a keepalive of 10s
113 114 115 116 117 118 |
# File 'lib/ohai/mixin/ec2_metadata.rb', line 113 def http_client @conn ||= Net::HTTP.start(EC2_METADATA_ADDR).tap do |h| h.read_timeout = 10 h.keep_alive_timeout = 10 end end |
#metadata_get(id, api_version) ⇒ Object
Get metadata for a given path and API version
Typically, a 200 response is expected for valid metadata. On certain instance types, traversing the provided metadata path produces a 404 for some unknown reason. In that event, return ‘nil` and continue the run instead of failing it.
143 144 145 146 147 148 149 150 151 152 153 154 155 156 |
# File 'lib/ohai/mixin/ec2_metadata.rb', line 143 def (id, api_version) path = "/#{api_version}/meta-data/#{id}" logger.trace("Mixin EC2: Fetching http://#{EC2_METADATA_ADDR}#{path}") response = http_client.get(path, { 'X-aws-ec2-metadata-token': v2_token }) case response.code when "200" response.body when "404" logger.trace("Mixin EC2: Encountered 404 response retrieving EC2 metadata path: #{path} ; continuing.") nil else raise "Mixin EC2: Encountered error retrieving EC2 metadata (#{path} returned #{response.code} response)" end end |
#v2_token ⇒ NilClass, String
Fetch an API token for use querying AWS IMDSv2 or return nil if no token if found AWS like systems (think OpenStack) will not respond with a token here
126 127 128 129 130 131 132 133 134 135 |
# File 'lib/ohai/mixin/ec2_metadata.rb', line 126 def v2_token @v2_token ||= begin request = http_client.put("/latest/api/token", nil, { 'X-aws-ec2-metadata-token-ttl-seconds': "60" }) if request.code == "404" # not on AWS nil else request.body end end end |