lib/elastic_apm/metadata/cloud_info.rb (112 lines of code) (raw):
# Licensed to Elasticsearch B.V. under one or more contributor
# license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright
# ownership. Elasticsearch B.V. licenses this file to you under
# the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
# frozen_string_literal: true
require "http"
module ElasticAPM
class Metadata
# @api private
class CloudInfo
include Logging
AWS_URI = "http://169.254.169.254/latest/dynamic/instance-identity/document"
GCP_URI = "http://metadata.google.internal/computeMetadata/v1/?recursive=true"
AZURE_URI = "http://169.254.169.254/metadata/instance/compute?api-version=2019-08-15"
def initialize(config)
@config = config
@client = HTTP.timeout(connect: 0.1, read: 0.1)
end
attr_reader :config
attr_accessor(
:account_id,
:account_name,
:instance_id,
:instance_name,
:machine_type,
:project_id,
:project_name,
:availability_zone,
:provider,
:region
)
# rubocop:disable Metrics/CyclomaticComplexity
def fetch!
case config.cloud_provider
when "aws"
fetch_aws
when "gcp"
fetch_gcp
when "azure"
fetch_azure || read_azure_app_services
when "auto"
fetch_aws || fetch_gcp || fetch_azure || read_azure_app_services
when "none"
nil
else
error("Unknown setting for cloud_provider '#{config.cloud_provider}'")
end
self
end
# rubocop:enable Metrics/CyclomaticComplexity
private
def fetch_aws
resp = @client.get(AWS_URI)
return unless resp.status == 200
return unless (metadata = JSON.parse(resp.body.to_s))
self.provider = "aws"
self.account_id = metadata["accountId"]
self.instance_id = metadata["instanceId"]
self.availability_zone = metadata["availabilityZone"]
self.machine_type = metadata["instanceType"]
self.region = metadata["region"]
rescue HTTP::TimeoutError, HTTP::ConnectionError
nil
end
def fetch_gcp
resp = @client.headers("Metadata-Flavor" => "Google").get(GCP_URI)
return unless resp.status == 200
return unless (metadata = JSON.parse(resp.body.to_s))
self.provider = "gcp"
self.project_id = metadata["project"]["projectId"]
return unless metadata['instance']
zone = metadata["instance"]["zone"]&.split("/")&.at(-1)
self.availability_zone = zone
self.region = zone.split("-")[0..-2].join("-")
self.instance_id = metadata["instance"]["id"].to_s
self.instance_name = metadata["instance"]["name"]
self.machine_type = metadata["instance"]["machineType"]&.split("/")&.at(-1)
rescue HTTP::TimeoutError, HTTP::ConnectionError
nil
end
def fetch_azure
resp = @client.headers("Metadata" => "true").get(AZURE_URI)
return unless resp.status == 200
return unless (metadata = JSON.parse(resp.body.to_s))
self.provider = 'azure'
self.account_id = metadata["subscriptionId"]
self.instance_id = metadata["vmId"]
self.instance_name = metadata["name"]
self.project_name = metadata["resourceGroupName"]
self.availability_zone = metadata["zone"]
self.machine_type = metadata["vmSize"]
self.region = metadata["location"]
rescue HTTP::TimeoutError, HTTP::ConnectionError
nil
end
def read_azure_app_services
owner_name, instance_id, site_name, resource_group =
ENV.values_at(
'WEBSITE_OWNER_NAME',
'WEBSITE_INSTANCE_ID',
'WEBSITE_SITE_NAME',
'WEBSITE_RESOURCE_GROUP'
)
return unless owner_name && instance_id && site_name && resource_group
self.provider = 'azure'
self.instance_id = instance_id
self.instance_name = site_name
self.project_name = resource_group
self.account_id, self.region = parse_azure_app_services_owner_name(owner_name)
end
private
def parse_azure_app_services_owner_name(owner_name)
id, rest = owner_name.split('+')
*_, region = rest.split('-')
region.gsub!(/webspace.*$/, '')
[id, region]
end
end
end
end