Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Incorrect hypervisors and virtual Facts with Unsupported Container Runtime Warning in Docker #2781

Open
molhamalnasr opened this issue Nov 27, 2024 · 5 comments
Labels
bug Something isn't working triaged Jira issue has been created for this

Comments

@molhamalnasr
Copy link

molhamalnasr commented Nov 27, 2024

Describe the Bug

When running Puppet Facter inside a Docker container, the hypervisors and virtual facts are incorrectly set. Additionally, a warning is displayed:
Warning: Facter: Container runtime, 'docker', is unsupported, setting to, 'container_other'.

Example Output:

# facter -p hypervisors
[2024-11-27 13:49:35.972235 ] WARN Facter::Resolvers::Containers - Container runtime, 'docker', is unsupported, setting to, 'container_other'

# facter -p virtual
[2024-11-27 13:49:42.488042 ] WARN Facter::Resolvers::Containers - Container runtime, 'docker', is unsupported, setting to, 'container_other'
container_other

Expected Behavior

In previous versions (e.g., Tag 4.7.0), the hypervisors and virtual facts returned the correct values:

# facter -p hypervisors
{
  docker => {
    id => "<STRING_ID>"
  }
}

# facter -p virtual
docker

Steps to Reproduce

  1. Run Puppet Agent/Facter inside a Docker container.
  2. Execute the command facter -p hypervisors or facter -p virtual.

Environment

  • Version: Puppet Agent 7.32.1
  • Platform: Ubuntu 24.04
  • Facter Version: 4.8.0

Additional Context

After debugging the repository, I identified the root cause in the following line within lib/facter/resolvers/containers.rb:

read_environ(fact_name) || read_cgroup(fact_name)

The call to read_environ(fact_name) always returns a value, which prevents read_cgroup(fact_name) from being executed. This causes the resolver to misidentify the container runtime and set incorrect values for the hypervisors and virtual facts.

@molhamalnasr molhamalnasr added the bug Something isn't working label Nov 27, 2024
@mhashizume mhashizume added the triaged Jira issue has been created for this label Dec 17, 2024
@mhashizume
Copy link
Contributor

Thank you for reporting this @molhamalnasr , we have added this issue to our backlog.

Copy link

Migrated issue to FACT-3488

@joshcooper
Copy link
Contributor

joshcooper commented Jan 7, 2025

@molhamalnasr I can't reproduce this ever working. In particular, read_environ returns nil, because there isn't a container environment variable defined for pid 1:

❯ docker run -it ubuntu:noble cat /proc/1/environ 
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/binHOSTNAME=00ddb9b41876TERM=xtermHOME=/root

Also it doesn't appear any version of facter correctly detects those facts:

❯ docker --version
Docker version 27.3.1, build ce12230

❯ docker run -it ubuntu:noble /bin/bash -c 'apt-get update > /dev/null && apt-get install -y ruby > /dev/null && gem install --no-document --version 4.7.0 facter && facter hypervisor virtual'
debconf: delaying package configuration, since apt-utils is not installed
Fetching thor-1.2.2.gem
Fetching hocon-1.4.0.gem
Fetching facter-4.7.0.gem
Successfully installed thor-1.2.2
Successfully installed hocon-1.4.0
Successfully installed facter-4.7.0
3 gems installed
hypervisor => 
virtual => physical

❯ docker run -it ubuntu:noble /bin/bash -c 'apt-get update > /dev/null && apt-get install -y ruby > /dev/null && gem install --no-document --version 4.8.0 facter && facter hypervisor virtual'
debconf: delaying package configuration, since apt-utils is not installed
Fetching facter-4.8.0.gem
Fetching thor-1.2.2.gem
Fetching hocon-1.4.0.gem
Successfully installed thor-1.2.2
Successfully installed hocon-1.4.0
Successfully installed facter-4.8.0
3 gems installed
hypervisor => 
virtual => physical

❯ docker run -it ubuntu:noble /bin/bash -c 'apt-get update > /dev/null && apt-get install -y ruby > /dev/null && gem install --no-document --version 4.9.0 facter && facter hypervisor virtual'
debconf: delaying package configuration, since apt-utils is not installed
Fetching facter-4.9.0.gem
Fetching thor-1.2.2.gem
Fetching hocon-1.4.0.gem
Successfully installed thor-1.2.2
Successfully installed hocon-1.4.0
Successfully installed facter-4.9.0
3 gems installed
hypervisor => 
virtual => physical

❯ docker run -it ubuntu:noble /bin/bash -c 'apt-get update > /dev/null && apt-get install -y ruby > /dev/null && gem install --no-document --version 4.10.0 facter && facter hypervisor virtual'
debconf: delaying package configuration, since apt-utils is not installed
Fetching hocon-1.4.0.gem
Fetching facter-4.10.0.gem
Fetching thor-1.2.2.gem
Successfully installed thor-1.2.2
Successfully installed hocon-1.4.0
Successfully installed facter-4.10.0
3 gems installed
hypervisor => 
virtual => physical

EDIT: The /proc/1/environ method looks specific to starting a container via systemd https://github.com/systemd/systemd/blob/16ac586e5a77942bf1147bc9eae684d544ded88f/docs/CONTAINER_INTERFACE.md?plain=1#L415-L417

EDIT: Commit 7bc38cc#diff-79c60e634be9bb4ac1da2dd02e3563d596b747d0135748bc1486cbb49f93380fR18 changed the order of reading from the environment vs cgroup. If /proc/1/environ has a non-empty value for container, that doesn't match our case statement, then we never fall back to read_cgroup.

molhamalnasr pushed a commit to molhamalnasr/facter that referenced this issue Jan 14, 2025
puppetlabs#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.
@molhamalnasr
Copy link
Author

Hi @joshcooper

Thanks for checking into this! The difference I’m seeing is due to setting the environment variable container=docker. That variable triggers the Containers resolver in Facter to detect Docker (and sometimes misidentify it as container_other). Below are two Dockerfiles I’m using to install Puppet Enterprise agents on Ubuntu, plus the commands I ran to test Facter versions 4.8.0 and 4.7.0.


Dockerfile for Ubuntu 22.04 (Puppet Agent 7.30.0)
FROM ubuntu:22.04

ARG version="7.30.0"

ENV PUPPET_AGENT_VERSION="$version"
ENV PUPPET_SRV_VERSION="2021.7.8"
ENV UBUNTU_CODENAME="jammy"
ENV DONWLOAD_URI="https://pm.puppetlabs.com/puppet-agent/${PUPPET_SRV_VERSION}/${PUPPET_AGENT_VERSION}/repos/deb/${UBUNTU_CODENAME}/puppet7/puppet-agent_${PUPPET_AGENT_VERSION}-1${UBUNTU_CODENAME}_amd64.deb"
ENV PATH=$PATH:/opt/puppetlabs/puppet/bin:/opt/puppetlabs/bin
ENV container=docker

RUN apt-get update && \
    apt-get -y dist-upgrade && \
    DEBIAN_FRONTEND=noninteractive apt-get install -yq --no-install-recommends \
      curl \
      systemd \
      systemd-cron \
      wget \
      sudo \
      ca-certificates

RUN  wget $DONWLOAD_URI && \
  dpkg -i puppet-agent_${PUPPET_AGENT_VERSION}-1${UBUNTU_CODENAME}_amd64.deb && \
  rm puppet-agent_${PUPPET_AGENT_VERSION}-1${UBUNTU_CODENAME}_amd64.deb

CMD ["/sbin/init", "--log-target=journal"]
Dockerfile for Ubuntu 24.04 (Puppet Agent 7.32.1)
FROM ubuntu:24.04

ARG version="7.32.1"

ENV PUPPET_AGENT_VERSION="$version"
ENV PUPPET_SRV_VERSION="2021.7.9"
ENV UBUNTU_CODENAME="noble"
ENV DONWLOAD_URI="https://pm.puppetlabs.com/puppet-agent/${PUPPET_SRV_VERSION}/${PUPPET_AGENT_VERSION}/repos/deb/${UBUNTU_CODENAME}/puppet7/puppet-agent_${PUPPET_AGENT_VERSION}-1${UBUNTU_CODENAME}_amd64.deb"
ENV PATH=$PATH:/opt/puppetlabs/puppet/bin:/opt/puppetlabs/bin
ENV container=docker

RUN apt-get update && \
    apt-get -y dist-upgrade && \
    DEBIAN_FRONTEND=noninteractive apt-get install -yq --no-install-recommends \
      curl \
      systemd \
      systemd-cron \
      wget \
      sudo \
      ca-certificates

RUN  wget $DONWLOAD_URI && \
  dpkg -i puppet-agent_${PUPPET_AGENT_VERSION}-1${UBUNTU_CODENAME}_amd64.deb && \
  rm puppet-agent_${PUPPET_AGENT_VERSION}-1${UBUNTU_CODENAME}_amd64.deb

CMD ["/sbin/init", "--log-target=journal"]

Testing Facter 4.8.0 vs. 4.7.0
When I run the following commands (note the -e container=docker flag), I get different results:

docker run -it --rm -e container=docker ubuntu:noble \
  /bin/bash -c 'apt-get update > /dev/null && \
  apt-get install -y ruby > /dev/null && \
  gem install --no-document --version 4.8.0 facter && \
  facter hypervisor virtual'

[2025-01-14 10:39:50.880775 ] WARN Facter::Resolvers::Containers - Container runtime, 'docker', is unsupported, setting to, 'container_other'
hypervisor => 
virtual => container_other
docker run -it --rm -e container=docker ubuntu:noble \
  /bin/bash -c 'apt-get update > /dev/null && \
  apt-get install -y ruby > /dev/null && \
  gem install --no-document --version 4.7.0 facter && \
  facter hypervisor virtual'

hypervisor => 
virtual => docker

As you can see, with 4.8.0 it logs a warning and sets virtual => container_other, but with 4.7.0 it shows virtual => docker. In practice, Puppet Enterprise also sets ENV container=docker, which triggers the same behavior.

I hope this helps clarify the difference. Please let me know if you have any questions or need more details.

@joshcooper
Copy link
Contributor

Thanks @molhamalnasr! Could you provide more details about why you're running the agent in docker? And what you meant by

In practice, Puppet Enterprise also sets ENV container=docker

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working triaged Jira issue has been created for this
Projects
None yet
Development

No branches or pull requests

3 participants