Repository: ansible/ansible

Issue:
Ansible SERVICE module cannot disable a service on a SLES 11 server
##### ISSUE TYPE
 - Bug Report

##### COMPONENT NAME
Module "SERVICE"

##### ANSIBLE VERSION
```
ansible 2.2.1.0
  config file = /etc/ansible/ansible.cfg
  configured module search path = Default w/o overrides

```

##### CONFIGURATION
No changes in the default settings


##### OS / ENVIRONMENT

Running Ansible from = Red Hat Enterprise Linux Workstation release 6.8 (Santiago)
OS I am managing = SUSE Linux Enterprise Server 11 (x86_64), SP3


##### SUMMARY
I'm trying to disable from startup 1 service on several  SLES 11 SP3 servers.
Even though the ansible playbook completes without errors, it does not change the state of the service - the service is not disabled.

##### STEPS TO REPRODUCE
1. Playbook used:


```yaml
- hosts: TEST
  tasks:
  - name: Stop the old service
    service:
      name: "{{ item }}"
      enabled: no
    with_items:
      - service1
  ```
##### EXPECTED RESULTS
The playbook should disable from startup the old service: "service1"

##### ACTUAL RESULTS
```
# ansible-playbook disable_old_service.yml -i ./data/hosts --ask-vault-pass -vvv
Using /etc/ansible/ansible.cfg as config file
Vault password: 

PLAYBOOK: disable_old_service.yml *****************************
1 plays in disable_old_service.yml

PLAY [TEST] ********************************************************************

TASK [setup] *******************************************************************
Using module file /usr/lib/python2.6/site-packages/ansible/modules/core/system/setup.py
<192.168.1.31> ESTABLISH SSH CONNECTION FOR USER: test_user
<192.168.1.31> SSH: EXEC ssh -C -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o Port=22 -o 'IdentityFile="/home/test_user/Scripts/keys/test_user"' -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o User=test_user -o ConnectTimeout=10 -o ControlPath=/root/.ansible/cp/ansible-ssh-%h-%p-%r 192.168.1.31 '/bin/sh -c '"'"'( umask 77 && mkdir -p "` echo ~/.ansible/tmp/ansible-tmp-1492522180.29-23593537436870 `" && echo ansible-tmp-1492522180.29-23593537436870="` echo ~/.ansible/tmp/ansible-tmp-1492522180.29-23593537436870 `" ) && sleep 0'"'"''
<192.168.1.31> PUT /tmp/tmp6Cu5Ee TO /home/test_user.ansible/tmp/ansible-tmp-1492522180.29-23593537436870/setup.py
<192.168.1.31> SSH: EXEC scp -C -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o Port=22 -o 'IdentityFile="/home/test_user/Scripts/keys/test_user"' -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o User=test_user -o ConnectTimeout=10 -o ControlPath=/root/.ansible/cp/ansible-ssh-%h-%p-%r /tmp/tmp6Cu5Ee '[192.168.1.31]:/home/test_user/.ansible/tmp/ansible-tmp-1492522180.29-23593537436870/setup.py'
<192.168.1.31> ESTABLISH SSH CONNECTION FOR USER: test_user
<192.168.1.31> SSH: EXEC ssh -C -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o Port=22 -o 'IdentityFile="/home/test_user/Scripts/keys/test_user"' -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o User=test_user -o ConnectTimeout=10 -o ControlPath=/root/.ansible/cp/ansible-ssh-%h-%p-%r 192.168.1.31 '/bin/sh -c '"'"'chmod u+x /home/test_user/.ansible/tmp/ansible-tmp-1492522180.29-23593537436870/ /home/test_user/.ansible/tmp/ansible-tmp-1492522180.29-23593537436870/setup.py && sleep 0'"'"''
<192.168.1.31> ESTABLISH SSH CONNECTION FOR USER: test_user
<192.168.1.31> SSH: EXEC ssh -C -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o Port=22 -o 'IdentityFile="/home/test_user/Scripts/keys/test_user"' -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o User=test_user -o ConnectTimeout=10 -o ControlPath=/root/.ansible/cp/ansible-ssh-%h-%p-%r -tt 192.168.1.31 '/bin/sh -c '"'"'su  root -c '"'"'"'"'"'"'"'"'/bin/sh -c '"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'echo BECOME-SUCCESS-xnuiuiamhrfjswnlncoltvuykomqiejy; /usr/bin/python /home/test_user/.ansible/tmp/ansible-tmp-1492522180.29-23593537436870/setup.py; rm -rf "/home/test_user/.ansible/tmp/ansible-tmp-1492522180.29-23593537436870/" > /dev/null 2>&1'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"''"'"'"'"'"'"'"'"' && sleep 0'"'"''
ok: [SERVER1]

TASK [Stop the old service] ***
task path: /opt/Automation/disable_old_service.yml:5
Using module file /usr/lib/python2.6/site-packages/ansible/modules/core/system/service.py
<192.168.1.31> ESTABLISH SSH CONNECTION FOR USER: test_user
<192.168.1.31> SSH: EXEC ssh -C -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o Port=22 -o 'IdentityFile="/home/test_user/Scripts/keys/test_user"' -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o User=test_user -o ConnectTimeout=10 -o ControlPath=/root/.ansible/cp/ansible-ssh-%h-%p-%r 192.168.1.31 '/bin/sh -c '"'"'( umask 77 && mkdir -p "` echo ~/.ansible/tmp/ansible-tmp-1492522184.33-119751508463899 `" && echo ansible-tmp-1492522184.33-119751508463899="` echo ~/.ansible/tmp/ansible-tmp-1492522184.33-119751508463899 `" ) && sleep 0'"'"''
<192.168.1.31> PUT /tmp/tmp6Cu5Ee TO /home/test_user/.ansible/tmp/ansible-tmp-1492522184.33-119751508463899/service.py
<192.168.1.31> SSH: EXEC scp -C -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o Port=22 -o 'IdentityFile="/home/test_user/Scripts/keys/test_user"' -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o User=test_user -o ConnectTimeout=10 -o ControlPath=/root/.ansible/cp/ansible-ssh-%h-%p-%r /tmp/tmp6Cu5Ee '[192.168.1.31]:/home/test_user/.ansible/tmp/ansible-tmp-1492522184.33-119751508463899/service.py'
<192.168.1.31> ESTABLISH SSH CONNECTION FOR USER: test_user
<192.168.1.31> SSH: EXEC ssh -C -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o Port=22 -o 'IdentityFile="/home/test_user/Scripts/keys/test_user"' -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o User=test_user -o ConnectTimeout=10 -o ControlPath=/root/.ansible/cp/ansible-ssh-%h-%p-%r 192.168.1.31 '/bin/sh -c '"'"'chmod u+x /home/test_user/.ansible/tmp/ansible-tmp-1492522184.33-119751508463899/ /home/test_user/.ansible/tmp/ansible-tmp-1492522184.33-119751508463899/service.py && sleep 0'"'"''
<192.168.1.31> ESTABLISH SSH CONNECTION FOR USER: test_user
<192.168.1.31> SSH: EXEC ssh -C -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o Port=22 -o 'IdentityFile="/home/test_user/Scripts/keys/test_user"' -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o User=test_user -o ConnectTimeout=10 -o ControlPath=/root/.ansible/cp/ansible-ssh-%h-%p-%r -tt 192.168.1.31 '/bin/sh -c '"'"'su  root -c '"'"'"'"'"'"'"'"'/bin/sh -c '"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'echo BECOME-SUCCESS-hwduqogudgoyxnotvzvlaaozwimondfz; /usr/bin/python /home/test_user/.ansible/tmp/ansible-tmp-1492522184.33-119751508463899/service.py; rm -rf "/home/test_user/.ansible/tmp/ansible-tmp-1492522184.33-119751508463899/" > /dev/null 2>&1'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"''"'"'"'"'"'"'"'"' && sleep 0'"'"''
ok: [SERVER1] => (item=service1) => {
    "changed": false, 
    "enabled": false, 
    "invocation": {
        "module_args": {
            "arguments": "", 
            "enabled": false, 
            "name": "service1", 
            "pattern": null, 
            "runlevel": "default", 
            "sleep": null, 
            "state": null
        }
    }, 
    "item": "service1", 
    "name": "service1"
}


PLAY RECAP *********************************************************************
SERVER1                   : ok=1    changed=0    unreachable=0    failed=0   


```



Discussion:
@bcoca I believe you look after service module
How do you know the service is still enabled?
I went to the servers and I've run:
chkconfig --list service1.
From play output, Ansible seems to detect the service as already disabled, can you run with ANSIBLE_DEBUG=1 and copy the logs of what Ansible executes on the target?
Currently I dont have acces to the servers, I'll provide you the logs in aprox 12 hours. Thanks!
I've run the playbook using ANSIBLE_DEBUG=1.
It seems that the SERVICE module wrongly chooses "insserv" to disable the service, instead of "chkconfig".
I've also run the playbook against a remote RHEL 6 server and it uses chkconfig to disable the service.
Here are the logs from my remote SLES 11 server:

Apr 20 08:31:19 sasqpix0 sshd[32223]: Accepted publickey for test_user from 192.168.1.10 port 63199 ssh2
Apr 20 08:31:20 sasqpix0 su: (to root) test_user on /dev/pts/0
Apr 20 08:31:20 sasqpix0 ansible-setup: Invoked with filter=* gather_subset=['all'] fact_path=/etc/ansible/facts.d gather_timeout=10
Apr 20 08:31:20 sasqpix0 ansible-setup: Executing: /sbin/lspci -D
Apr 20 08:31:21 sasqpix0 ansible-setup: Executing: /sbin/vgs --noheadings --nosuffix --units g
Apr 20 08:31:21 sasqpix0 ansible-setup: Executing: /sbin/lvs --noheadings --nosuffix --units g
Apr 20 08:31:21 sasqpix0 ansible-setup: Executing: /bin/findmnt --list --noheadings --notruncate
Apr 20 08:31:21 sasqpix0 ansible-setup: Executing: /bin/lsblk --list --noheadings --paths --output NAME,UUID --exclude 2
Apr 20 08:31:21 sasqpix0 ansible-setup: Executing: /bin/ip -4 route get 8.8.8.8
Apr 20 08:31:21 sasqpix0 ansible-setup: Executing: /bin/ip -6 route get 2404:6800:400a:800::1012
Apr 20 08:31:21 sasqpix0 ansible-setup: Executing: /bin/ip addr show primary lo
Apr 20 08:31:21 sasqpix0 ansible-setup: Executing: /bin/ip addr show secondary lo
Apr 20 08:31:21 sasqpix0 ansible-setup: Executing: /bin/ip addr show primary eth0
Apr 20 08:31:21 sasqpix0 ansible-setup: Executing: /bin/ip addr show secondary eth0
Apr 20 08:31:21 sasqpix0 ansible-setup: Executing: /bin/ip addr show primary eth1
Apr 20 08:31:21 sasqpix0 ansible-setup: Executing: /bin/ip addr show secondary eth1
Apr 20 08:31:23 sasqpix0 su: (to root) test_user on /dev/pts/0
Apr 20 08:31:23 sasqpix0 ansible-service: Invoked with name=service1 pattern=None enabled=False state=None sleep=None arguments= runlevel=default
Apr 20 08:31:23 sasqpix0 ansible-service: Service instantiated - platform Linux
Apr 20 08:31:23 sasqpix0 ansible-service: Executing: **/sbin/insserv -nr service1**
Apr 20 08:31:38 sasqpix0 sshd[32656]: Postponed keyboard-interactive for test_user from 192.168.1.10 port 11568 ssh2 [preauth]
Apr 20 08:31:42 sasqpix0 sshd[32656]: error: PAM: Authentication failure for test_user from 192.168.1.10
Apr 20 08:31:42 sasqpix0 sshd[32656]: Postponed keyboard-interactive for test_user from 192.168.1.10 port 11568 ssh2 [preauth]
Apr 20 08:31:43 sasqpix0 sshd[32656]: Connection closed by 192.168.1.10 [preauth]

I've further checked and I've noticed that there are 2 problems with the command invoked by ansible:
1. insserv -nr service1 =>returns error
Accepted command: insserv -n -r service1
2. The "-n" means dry run, no real actions are performed. The "-n" parameter should be removed.
Complete manual for insserv can be found at http://manpages.ubuntu.com/manpages/xenial/en/man8/insserv.8.html

Moreover, I think that chkconfig tool should have a higher precedence over insserv.



it is using the -n to check if it needs to actually run the action, insserv seesm to be returning that it doesn't need to disable the service.
Indeed, but on SLES, "insserv -nr" is not working. Correct syntax is: "insserv -n -r service"
can you test that this patch fixes the issue for you?
```python
diff --git a/lib/ansible/modules/system/service.py b/lib/ansible/modules/system/service.py
index 0420346ea..2c9280a51 100644
--- a/lib/ansible/modules/system/service.py
+++ b/lib/ansible/modules/system/service.py
@@ -859,7 +859,7 @@ class LinuxService(Service):
             if self.enable:
                 (rc, out, err) = self.execute_command("%s -n %s" % (self.enable_cmd, self.name))
             else:
-                (rc, out, err) = self.execute_command("%s -nr %s" % (self.enable_cmd, self.name))
+                (rc, out, err) = self.execute_command("%s -n -r %s" % (self.enable_cmd, self.name))

             self.changed = False
             for line in err.splitlines():

```
Unfortunately, on SLES the output is not as expected in the service.py module.
When the service is enabled, by running the command "insserv -n -r service1", there is no output at all.
In order to have some output, we need to add the "-v" argument.
The command "/sbin/insserv -n -r -v service1" has the following output:
**(0)[root@sasqpix0 ~]# /sbin/insserv -n -r -v service1
rm /etc/init.d/rc3.d/S50service1
rm /etc/init.d/rc3.d/K50service1
rm /etc/init.d/rc5.d/S50service1
rm /etc/init.d/rc5.d/K50service1**

Service.py script detects if it needs to actually run the action if the output of the dry run contains "remove service" => this will never happen on my SLES boxes.
The same is for enabling the service: we need to add the -v argument and the output for "insserv -v service1" is:
**(0)[root@sasqpix0 ~]# /sbin/insserv -v service1
ln -s ../service1 /etc/init.d/rc3.d/S50service1
ln -s ../service1 /etc/init.d/rc5.d/S50service1
ln -s ../service1 /etc/init.d/rc3.d/K50service1
ln -s ../service1 /etc/init.d/rc5.d/K50service1**

As stated previsously, the easiest solution for me was to prefer chkconfig over insserv.
Here are the changes that I've done in service.py, in "check_systemd" method.
**Before:**
_elif self.svc_initscript:
            # service is managed by with SysV init scripts
            if location.get('update-rc.d', False):
                # and uses update-rc.d
                self.enable_cmd = location['update-rc.d']
            elif location.get('insserv', None):
                # and uses insserv
                self.enable_cmd = location['insserv']				
            elif location.get('chkconfig', False):
                # and uses chkconfig
                self.enable_cmd = location['chkconfig']_
**After:**
_elif self.svc_initscript:
            # service is managed by with SysV init scripts
            if location.get('update-rc.d', False):
                # and uses update-rc.d
                self.enable_cmd = location['update-rc.d']
            elif location.get('chkconfig', False):
                # and uses chkconfig
                self.enable_cmd = location['chkconfig']
            elif location.get('insserv', None):
                # and uses insserv
                self.enable_cmd = location['insserv']_





The problem with changing priority is that this affects MORE than SLES and will cause problems in other platforms, the current fix seems to add -v.

Resolving patch:
diff --git a/lib/ansible/modules/system/service.py b/lib/ansible/modules/system/service.py
--- a/lib/ansible/modules/system/service.py
+++ b/lib/ansible/modules/system/service.py
@@ -853,13 +853,13 @@ def write_to_override_file(file_name, file_contents, ):
             return
 
         #
-        # insserv (Debian 7)
+        # insserv (Debian <=7, SLES, others)
         #
         if self.enable_cmd.endswith("insserv"):
             if self.enable:
-                (rc, out, err) = self.execute_command("%s -n %s" % (self.enable_cmd, self.name))
+                (rc, out, err) = self.execute_command("%s -n -v %s" % (self.enable_cmd, self.name))
             else:
-                (rc, out, err) = self.execute_command("%s -nr %s" % (self.enable_cmd, self.name))
+                (rc, out, err) = self.execute_command("%s -n -r -v %s" % (self.enable_cmd, self.name))
 
             self.changed = False
             for line in err.splitlines():


Test patch: