From 07336b0e146fb451c2f1ebfc11422f48e2d77a7b Mon Sep 17 00:00:00 2001 From: Molham Al Nasr Date: Tue, 14 Jan 2025 11:32:32 +0100 Subject: [PATCH 1/2] fix(Containers resolver): properly detect Docker runtime in containers (#2781) Previously, the `Containers` resolver would always return a value from `read_environ`, preventing `read_cgroup` from being called. As a result, the `hypervisors` and `virtual` facts were often set incorrectly to `container_other` and displayed a misleading warning. Changes in this commit: - `read_cgroup` now returns early unless Docker or LXC matches are found. - `read_environ` returns `nil` when encountering an unsupported container. - If both methods return `nil`, `vm` defaults to `container_other` with a warning. These updates ensure that Facter correctly detects Docker and properly reports the `virtual` and `hypervisors` facts when running inside a Docker container. --- lib/facter/resolvers/containers.rb | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/lib/facter/resolvers/containers.rb b/lib/facter/resolvers/containers.rb index 030d7267a4..7851fc1b87 100644 --- a/lib/facter/resolvers/containers.rb +++ b/lib/facter/resolvers/containers.rb @@ -15,7 +15,17 @@ class << self def post_resolve(fact_name, _options) @fact_list.fetch(fact_name) do - read_environ(fact_name) || read_cgroup(fact_name) + environ_result = read_environ(fact_name) + cgroup_result = read_cgroup(fact_name) + + if environ_result.nil? && cgroup_result.nil? + @fact_list[:vm] = 'container_other' + @fact_list[:hypervisor] = '' + log.warn("Container runtime is unsupported, setting to 'container_other'") + @fact_list[fact_name] + else + environ_result || cgroup_result + end end end @@ -24,7 +34,8 @@ def read_cgroup(fact_name) return unless output_cgroup output_docker = %r{docker/(.+)}.match(output_cgroup) - output_lxc = %r{^/lxc/([^/]+)}.match(output_cgroup) + output_lxc = %r{^/lxc/([^/]+)}.match(output_cgroup) + return if output_docker.nil? && output_lxc.nil? info, vm = extract_vm_and_info(output_docker, output_lxc) @fact_list[:vm] = vm @@ -57,8 +68,7 @@ def read_environ(fact_name) vm = 'systemd_nspawn' info = { 'id' => Facter::Util::FileHelper.safe_read('/etc/machine-id', nil).strip } else - vm = 'container_other' - log.warn("Container runtime, '#{container}', is unsupported, setting to '#{vm}'") + return nil end @fact_list[:vm] = vm @fact_list[:hypervisor] = { vm.to_sym => info } if vm From a360b329890de67bcd1ae669af8382b4d779a4e6 Mon Sep 17 00:00:00 2001 From: Molham Al Nasr Date: Thu, 13 Feb 2025 13:59:59 +0100 Subject: [PATCH 2/2] fix(Containers resolver): remove dummy value return 'container_other' to allow VirtualDetector to continue it's checks --- lib/facter/resolvers/containers.rb | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/lib/facter/resolvers/containers.rb b/lib/facter/resolvers/containers.rb index 7851fc1b87..b0acd1ad65 100644 --- a/lib/facter/resolvers/containers.rb +++ b/lib/facter/resolvers/containers.rb @@ -1,5 +1,10 @@ # frozen_string_literal: true +# The Facter::Resolvers::Containers.resolve method must return either a valid container identifier (e.g., "docker", "lxc", etc.) +# or nil if no container is detected. It should not return a dummy value such as "container_other". This is critical because +# Facter::Util::Facts::Posix::VirtualDetector relies on a nil return value to continue checking other virtualization methods. +# Returning a non-nil dummy value would prematurely short-circuit these checks, leading to inaccurate detection results. + module Facter module Resolvers class Containers < BaseResolver @@ -15,17 +20,7 @@ class << self def post_resolve(fact_name, _options) @fact_list.fetch(fact_name) do - environ_result = read_environ(fact_name) - cgroup_result = read_cgroup(fact_name) - - if environ_result.nil? && cgroup_result.nil? - @fact_list[:vm] = 'container_other' - @fact_list[:hypervisor] = '' - log.warn("Container runtime is unsupported, setting to 'container_other'") - @fact_list[fact_name] - else - environ_result || cgroup_result - end + read_environ(fact_name) || read_cgroup(fact_name) end end