Search code examples
serviceansibleapache2windows-subsystem-for-linuxubuntu-20.04

Failed to start Apache2 using Ansible Module Service on Localhost in WSL Ubuntu 20.04.3 LTS (focal)


I tried to start Apache2 service using 'sudo service' command and it works, but when I tried to use ansible service module to start the apache2, I got the error message saying "Service is in unknown state".

I do upgraded my ansible to the latest version. I am working in WSL Ubuntu 20.04.3LTS. And I do have set up the SSH correctly so that i can run other ansible ad-hoc command using modules like apt, command and shell, etc.

Any clue where the problem may be?

After digging a little further, I found that seems like ansible has a bug in service_mgr.py at the method 'is_systemd_managed_offline(module), which makes ansible think the service manager is systemd while it is actually service (or sysv init):

if module.get_bin_path('systemctl'):
            # check if /sbin/init is a symlink to systemd
            # on SUSE, /sbin/init may be missing if systemd-sysvinit package is not installed.
            if os.path.islink('/sbin/init') and os.path.basename(os.readlink('/sbin/init')) == 'systemd':
                return True
        return False

This is because on my WSL Ubuntu 20.04 LTS, there is indeed a link from /sbin/init to systemd, as shown:

/sbin/init -> /lib/systemd/systemd*

However, the service manager actually should be set to sysv init, which would be set at the end of the elif part of code in service_mgr.py if everything works normally:

        elif collected_facts.get('ansible_system') == 'Linux':
            # FIXME: mv is_systemd_managed
            if self.is_systemd_managed(module=module):
                service_mgr_name = 'systemd'
            elif module.get_bin_path('initctl') and os.path.exists("/etc/init/"):
                service_mgr_name = 'upstart'
            elif os.path.exists('/sbin/openrc'):
                service_mgr_name = 'openrc'
            elif self.is_systemd_managed_offline(module=module):
                service_mgr_name = 'systemd'
            elif os.path.exists('/etc/init.d/'):
                service_mgr_name = 'sysvinit'

        if not service_mgr_name:
            # if we cannot detect, fallback to generic 'service'
            service_mgr_name = 'service'

However, due to the existing link shown above, ansible stop at the elif line of is_system_managed_offline and will not continue to the end of the elif series.

As shown here below, the service manager is shown to be init (sysv init):

$ ps -p 1 -o comm=
init

Any clue how to work this around?

//////////IT IS SOLVED/////////////////// By checking the documentation of service module on ansible docs website, and using the argument 'use' to force ansible to use 'service' instead of 'systemd' as service manager (although from ansible setup module, ansible still think wrongly that systemd is the service manager of my WSL Ubuntu 20.04.3 LTS, because of code bug as shown above.

Hope in the future version of Ansible, the code bug (of elif for checking service manager available on the Linux machine) above can be solved, especially by taking the WSL Ubuntu and other WSL variant into account.

A quick fix would be to rearrange the elif order to put the 'is_systemd_managed_offline' variant at the end of the elif list and move os.path.exists('/etc/init.d') higher in the list, as shown:

    elif collected_facts.get('ansible_system') == 'Linux':
            # FIXME: mv is_systemd_managed
            if self.is_systemd_managed(module=module):
                service_mgr_name = 'systemd'
            elif module.get_bin_path('initctl') and os.path.exists("/etc/init/"):
                service_mgr_name = 'upstart'
            elif os.path.exists('/sbin/openrc'):
                service_mgr_name = 'openrc'
            *elif os.path.exists('/etc/init.d/'):
                service_mgr_name = 'sysvinit'
            elif self.is_systemd_managed_offline(module=module):
                service_mgr_name = 'systemd'*

Solution

  • I think you can force your service module to use "service" instead of systemctl:

    ansible  localhost -m service -a "use=service name=apache2 state=stopped"
    

    Service use reference