class ElasticAPM::Metadata::SystemInfo::ContainerInfo

@api private

Constants

CGROUP_PATH
CONTAINER_ID_REGEXES

rubocop:disable Style/RegexpLiteral

KUBEPODS_REGEXES
SYSTEMD_SCOPE_SUFFIX

Attributes

cgroup_path[R]
container_id[RW]
kubernetes_namespace[RW]
kubernetes_node_name[RW]
kubernetes_pod_name[RW]
kubernetes_pod_uid[RW]

Public Class Methods

new(cgroup_path: CGROUP_PATH) click to toggle source
# File lib/elastic_apm/metadata/system_info/container_info.rb, line 30
def initialize(cgroup_path: CGROUP_PATH)
  @cgroup_path = cgroup_path
end
read!(hostname) click to toggle source
# File lib/elastic_apm/metadata/system_info/container_info.rb, line 43
def self.read!(hostname)
  new.read!(hostname)
end

Public Instance Methods

container() click to toggle source
# File lib/elastic_apm/metadata/system_info/container_info.rb, line 47
def container
  @container ||=
    begin
      return unless container_id
      { id: container_id }
    end
end
kubernetes() click to toggle source
# File lib/elastic_apm/metadata/system_info/container_info.rb, line 55
def kubernetes
  @kubernetes =
    begin
      kubernetes = {
        namespace: kubernetes_namespace,
        node: { name: kubernetes_node_name },
        pod: {
          name: kubernetes_pod_name,
          uid: kubernetes_pod_uid
        }
      }
      return nil if kubernetes.values.all?(&:nil?)

      kubernetes
    end
end
read!(hostname) click to toggle source
# File lib/elastic_apm/metadata/system_info/container_info.rb, line 36
def read!(hostname)
  read_from_cgroup!
  self.kubernetes_pod_name = hostname if kubernetes_pod_uid
  read_from_env!
  self
end

Private Instance Methods

match_container(container_id) click to toggle source
# File lib/elastic_apm/metadata/system_info/container_info.rb, line 161
def match_container(container_id)
  CONTAINER_ID_REGEXES.each do |r|
    next unless (match = r.match(container_id))
    return match
  end

  nil
end
match_kubepods(directory) click to toggle source

rubocop:enable Metrics/PerceivedComplexity rubocop:enable Metrics/CyclomaticComplexity

# File lib/elastic_apm/metadata/system_info/container_info.rb, line 152
def match_kubepods(directory)
  KUBEPODS_REGEXES.each do |r|
    next unless (match = r.match(directory))
    return match
  end

  nil
end
read_from_cgroup!() click to toggle source

rubocop:disable Metrics/PerceivedComplexity rubocop:disable Metrics/CyclomaticComplexity

# File lib/elastic_apm/metadata/system_info/container_info.rb, line 105
def read_from_cgroup!
  return unless File.exist?(cgroup_path)
  IO.readlines(cgroup_path).each do |line|
    parts = line.strip.split(':')
    next if parts.length != 3

    cgroup_path = parts[2]

    # Depending on the filesystem driver used for cgroup
    # management, the paths in /proc/pid/cgroup will have
    # one of the following formats in a Docker container:
    #
    #   systemd: /system.slice/docker-<container-ID>.scope
    #   cgroupfs: /docker/<container-ID>
    #
    # In a Kubernetes pod, the cgroup path will look like:
    #
    #   systemd:
    #      /kubepods.slice/kubepods-<QoS-class>.slice/kubepods-\
    #        <QoS-class>-pod<pod-UID>.slice/<container-iD>.scope
    #   cgroupfs:
    #      /kubepods/<QoS-class>/pod<pod-UID>/<container-iD>
    directory, container_id = File.split(cgroup_path)

    if container_id.end_with?(SYSTEMD_SCOPE_SUFFIX)
      container_id = container_id[0...-SYSTEMD_SCOPE_SUFFIX.length]
      if container_id.include?('-')
        container_id = container_id.split('-', 2)[1]
      end
    end

    if (kubepods_match = match_kubepods(directory))
      unless (pod_id = kubepods_match[1])
        pod_id = kubepods_match[2]
        pod_id&.tr!('_', '-')
      end

      self.container_id = container_id
      self.kubernetes_pod_uid = pod_id
    elsif match_container(container_id)
      self.container_id = container_id
    end
  end
end
read_from_env!() click to toggle source
# File lib/elastic_apm/metadata/system_info/container_info.rb, line 74
def read_from_env!
  self.kubernetes_namespace =
    ENV.fetch('KUBERNETES_NAMESPACE', kubernetes_namespace)
  self.kubernetes_node_name =
    ENV.fetch('KUBERNETES_NODE_NAME', kubernetes_node_name)
  self.kubernetes_pod_name =
    ENV.fetch('KUBERNETES_POD_NAME', kubernetes_pod_name)
  self.kubernetes_pod_uid =
    ENV.fetch('KUBERNETES_POD_UID', kubernetes_pod_uid)
end