pytest-dev / pytest-testinfra

Testinfra test your infrastructures
https://testinfra.readthedocs.io
Apache License 2.0
2.37k stars 355 forks source link

Service is_enabled KO #416

Open rgarrigue opened 5 years ago

rgarrigue commented 5 years ago

Hi

I'm testing a salt formula via kitchen, installing and enabling caddy service. As you can see, the service is enabled

kitchen@74cb1d70442b:~$ sudo su
root@74cb1d70442b:/home/kitchen# systemctl status caddy
● caddy.service - Caddy HTTP/2 web server
   Loaded: loaded (/lib/systemd/system/caddy.service; enabled; vendor preset: enabled)
   Active: active (running) since Tue 2019-03-19 10:45:59 UTC; 32min ago
     Docs: https://caddyserver.com/docs
 Main PID: 3042 (caddy)
    Tasks: 10 (limit: 4915)
   CGroup: /docker/74cb1d70442be3231e88e77c241e11f01e3af60b87eeb25c89df9140535eaa55/system.slice/caddy.service
           └─3042 /usr/bin/caddy -log stdout -agree=true -email admin@cozycloud.cc -conf=/etc/caddy/Caddyfile -root=/var/tmp

But testinfra thinks otherwise

============================= test session starts ==============================
platform linux2 -- Python 2.7.13, pytest-4.3.0, py-1.8.0, pluggy-0.9.0
rootdir: /var/lib/jenkins/workspace/salt-formula-caddy/test, inifile: pytest.ini
plugins: testinfra-1.19.0, metadata-1.8.0, html-1.20.0
collected 6 items

test/integration/test_caddy.py ....FF                                    [100%]

=================================== FAILURES ===================================
_ test_service[docker://74cb1d70442be3231e88e77c241e11f01e3af60b87eeb25c89df9140535eaa55] _

host = <testinfra.host.Host object at 0x7ffb77697710>

    def test_service(host):
        s = host.service("caddy")
        assert s.is_running
>       assert s.is_enabled
E       assert False
E        +  where False = <service caddy>.is_enabled

Here's the kitchen verifier command if that might help

verifier:
  name: shell
  remote_exec: false
  command: pytest --junitxml=test/${KITCHEN_INSTANCE}_test_report.xml --html=test/${KITCHEN_INSTANCE}_test_report.html --self-contained-html --color=yes --host="docker://root@${KITCHEN_CONTAINER_ID}" "test/integration/"
philpep commented 5 years ago

Hi,

You can run py.test with -vvs flags to enable debug output and see what command is actually run by testinfra.

In this case I think testinfra run systemctl is-enabled caddy what is the output of this command ?

sblaisot commented 5 years ago

Ok, I found why. https://github.com/philpep/testinfra/blob/master/testinfra/modules/service.py#L54

We are running tests in a docker container and systemd is lauched by docker, so there is no /sbin/init link and testinfra fallback to SysVinit which can't work.

I got around by adding the missing link in our containers.

philpep commented 5 years ago

Maybe we should look for /proc/1/exe instead of /sbin/init That being said, IIRC, some commands work with systemd not being pid 1 (like systemctl is-enabled).

Frzk commented 5 years ago

That's also an issue I get with a container based on Archlinux. The link /sbin/init doesn't exist and Testinfra falls back to SysVinit.

cating /proc/1/comm seems to give good results (here are some tests I did on vagrant boxes):

Also, wouldn't it be a better idea to fall back to SystemdService ?

I'm volunteering to write a PR if the above sounds OK to you :-)

jsf9k commented 5 years ago

Ok, I found why. https://github.com/philpep/testinfra/blob/master/testinfra/modules/service.py#L54

We are running tests in a docker container and systemd is lauched by docker, so there is no /sbin/init link and testinfra fallback to SysVinit which can't work.

I got around by adding the missing link in our containers.

I have this exact same problem when running tests using a systemd-enabled Debian 9 image. In my case, though, I'm running systemd inside of a Docker container, and so my systemd process is not PID 1.

jsf9k commented 5 years ago

Ok, I found why. https://github.com/philpep/testinfra/blob/master/testinfra/modules/service.py#L54 We are running tests in a docker container and systemd is lauched by docker, so there is no /sbin/init link and testinfra fallback to SysVinit which can't work. I got around by adding the missing link in our containers.

I have this exact same problem when running tests using a systemd-enabled Debian 9 image. In my case, though, I'm running systemd inside of a Docker container, and so my systemd process is not PID 1.

In case anyone else encounters this issue when exercising testinfra via molecule, I was able to get around it by creating molecule/default/prepare.yml with the following content:

- name: Group hosts by OS distribution
  hosts: all
  tasks:
    - name: Group hosts by OS distribution
      group_by:
        key: os_{{ ansible_facts['distribution'] }}
- name: Install init (Debian)
  hosts: os_Debian
  tasks:
    - name: Install init (Debian)
      package:
        name:
          - init
fauust commented 4 years ago

Hi, it seems that adding the systemd-sysv package to docker resolves the problem. See: https://github.com/geerlingguy/docker-debian10-ansible/pull/4

fauust commented 4 years ago

So I can confirm that testinfra (3.4.0) test now passes with those services:

assert host.service("postfix").is_enabled
assert host.service("mariadb").is_enabled
assert host.service("nftables").is_enabled
assert host.service("ntp").is_enabled
assert host.service("rsync").is_enabled
assert host.service("ssh").is_enabled
assert host.service("zabbix-agent").is_enabled