Repository: ansible/ansible
Pull request: check /.dockerenv and /.dockerinit to guess a dockercontainer
##### SUMMARY
check ./dockerenv and /.dockerinit to guess if this is an dockercontainer. Fixes #74326:

##### ISSUE TYPE
- Bugfix Pull Request

##### COMPONENT NAME
linux.py

Problem statement:
docker not detected in centos, alpine, debian
### Summary

The facts for ansible_virtualization_type and ansible_virtualization_role are wrong if run in a dockercontainer of centos (tested with 8), alpine or debian (tested with buster). Only in an ubuntu-container (tested with focal or hirsute) are the values correct.
The problem can be reproduced with the latest stable version and the devel branch.

### Issue Type

Bug Report

### Component Name

setup, virtual/linux.py

### Ansible Version

```console
$ ansible --version
ansible 2.10.8
  config file = /etc/ansible/ansible.cfg
  configured module search path = ['/home/jfader/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3.9/site-packages/ansible
  executable location = /usr/bin/ansible
  python version = 3.9.3 (default, Apr  8 2021, 23:35:02) [GCC 10.2.0]
```


### Configuration

```console
$ ansible-config dump --only-changed

no changes recorded
```


### OS / Environment

Archlinux

### Steps to Reproduce

Start up two containers. One with centos:8 and one with ubuntu:hirsute:
```bash
docker run --name centos_8 -it centos:8 /bin/bash
dnf -y install python3
```
```bash
docker run --name ubuntu_hirsute -it ubuntu:hirsute /bin/bash
apt-get update && apt-get install -y python3
```
Inventory:
```
ubuntu_hirsute ansible_connection=docker
centos_8 ansible_connection=docker
```

Playbook:
```yaml
---
- hosts: centos_8,ubuntu_hirsute
  gather_facts: True
  tasks:

    - name: "output information about virtualization (type and role)"
      debug:
        var: "{{ item }}"
      loop:
        - ansible_virtualization_type
        - ansible_virtualization_role
```

### Expected Results
```console
TASK [output information about virtualization (type and role)] ************************************************
ok: [centos_8] => (item=ansible_virtualization_type) => {
    "ansible_loop_var": "item",
    "ansible_virtualization_type": "docker",
    "item": "ansible_virtualization_type"
}
ok: [ubuntu_hirsute] => (item=ansible_virtualization_type) => {
    "ansible_loop_var": "item",
    "ansible_virtualization_type": "docker",
    "item": "ansible_virtualization_type"
}
ok: [centos_8] => (item=ansible_virtualization_role) => {
    "ansible_loop_var": "item",
    "ansible_virtualization_role": "guest",
    "item": "ansible_virtualization_role"
}
ok: [ubuntu_hirsute] => (item=ansible_virtualization_role) => {
    "ansible_loop_var": "item",
    "ansible_virtualization_role": "guest",
    "item": "ansible_virtualization_role"
}
```
### Actual Results

```console
TASK [output information about virtualization (type and role)] ************************************************
ok: [centos_8] => (item=ansible_virtualization_type) => {
    "ansible_loop_var": "item",
    "ansible_virtualization_type": "NA",
    "item": "ansible_virtualization_type"
}
ok: [ubuntu_hirsute] => (item=ansible_virtualization_type) => {
    "ansible_loop_var": "item",
    "ansible_virtualization_type": "docker",
    "item": "ansible_virtualization_type"
}
ok: [centos_8] => (item=ansible_virtualization_role) => {
    "ansible_loop_var": "item",
    "ansible_virtualization_role": "NA",
    "item": "ansible_virtualization_role"
}
ok: [ubuntu_hirsute] => (item=ansible_virtualization_role) => {
    "ansible_loop_var": "item",
    "ansible_virtualization_role": "guest",
    "item": "ansible_virtualization_role"
}
```


### Code of Conduct

- [X] I agree to follow the Ansible Code of Conduct

Hints from issue discussion:
Files identified in the description:
* [`lib/ansible/modules/setup.py`](https://github.com/ansible/ansible/blob/devel/lib/ansible/modules/setup.py)

If these files are incorrect, please update the `component name` section of the description or use the `!component` bot command.

[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: components_banner --->
Files identified in the description:
* [`lib/ansible/module_utils/facts/virtual/linux.py`](https://github.com/ansible/ansible/blob/devel/lib/ansible/module_utils/facts/virtual/linux.py)
* [`lib/ansible/modules/setup.py`](https://github.com/ansible/ansible/blob/devel/lib/ansible/modules/setup.py)

If these files are incorrect, please update the `component name` section of the description or use the `!component` bot command.

[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: components_banner --->
Found the problem with the help of the ansible-IRC-channel and will create a PR for the problem.
The newest virt-what 1.21 uses a check for /.dockerenv and /.dockerinit: http://git.annexia.org/?p=virt-what.git;a=commitdiff;h=e2c49cda221f95cb65b1b3ac3ae15aa41d92f519

Commit message: add changelog for #74349

Patch to review:
diff --git a/changelogs/fragments/74349-improve-docker-detection.yml b/changelogs/fragments/74349-improve-docker-detection.yml
new file mode 100644
index 00000000000000..5d386a3daad935
--- /dev/null
+++ b/changelogs/fragments/74349-improve-docker-detection.yml
@@ -0,0 +1,2 @@
+bugfixes:
+  - setup - detect docker container with check for ./dockerenv or ./dockinit (https://github.com/ansible/ansible/pull/74349).
diff --git a/lib/ansible/module_utils/facts/virtual/linux.py b/lib/ansible/module_utils/facts/virtual/linux.py
index 066cf5e13c971b..3ddb4db98efee5 100644
--- a/lib/ansible/module_utils/facts/virtual/linux.py
+++ b/lib/ansible/module_utils/facts/virtual/linux.py
@@ -109,6 +109,11 @@ def get_virtual_facts(self):
                 virtual_facts['virtualization_type'] = systemd_container
                 virtual_facts['virtualization_role'] = 'guest'
                 found_virt = True
+        elif os.path.exists('/.dockerenv') or os.path.exists('/.dockerinit'):
+            guest_tech.add('docker')
+            virtual_facts['virtualization_type'] = 'docker'
+            virtual_facts['virtualization_role'] = 'guest'
+            found_virt = True
 
         # ensure 'container' guest_tech is appropriately set
         if guest_tech.intersection(set(['docker', 'lxc', 'podman', 'openvz', 'containerd'])) or systemd_container:


Code review comments:
diff_hunk: @@ -109,6 +109,11 @@ def get_virtual_facts(self):
                 virtual_facts['virtualization_type'] = systemd_container
                 virtual_facts['virtualization_role'] = 'guest'
                 found_virt = True
+        elif os.path.exists('/.dockerenv') or os.path.exists('/.dockerinit'):
+            guest_tech.add('docker')
+            virtual_facts['virtualization_type'] = 'docker'
+            virtual_facts['virtualization_role'] = 'guest'
+            found_virt = True
path: lib/ansible/module_utils/facts/virtual/linux.py
text: @user1:
```suggestion

        # If docker/containerd has a custom cgroup parent, checking /proc/1/cgroup (above) might fail.
        # https://docs.docker.com/engine/reference/commandline/dockerd/#default-cgroup-parent
        # Fallback to more rudimentary checks.
        if os.path.exists('/.dockerenv') or os.path.exists('/.dockerinit'):
            guest_tech.add('docker')
            if not found_virt:
                virtual_facts['virtualization_type'] = 'docker'
                virtual_facts['virtualization_role'] = 'guest'
                found_virt = True
```

What does this check have to do with systemd? I think it should be separate.
Also, only update `virtualization_type` if `found_virt` is False (similar to other `if not found_virt` blocks in this file).

@user2:
I agree and I have a feeling this fix is going to become more and more important with current and future Linux distributions. I made a pull request as well before I realized this one existed.

https://github.com/ansible/ansible/pull/75340/files#diff-48cedf55779922152790325bc5bccee4ca72603a3866e81345d47352cfcecc32R71-R78