Repository: ansible/ansible
Pull request: Add documentation for systemd reload
##### SUMMARY

Add documentation for systemd behavior when trying to reload a stopped service.

Fixes #80896 

##### ISSUE TYPE

- Docs Pull Request

##### ADDITIONAL INFORMATION



Problem statement:
Systemd module with "state: reloaded" restarts service if service is stopped
### Summary

When reloading a service via Ansible systemd module, if the service is stopped, Ansible restarts it. 

If I try to manually reload a service that is stopped I get this result : 

```
root@testvm:~# systemctl reload haproxy.service
haproxy.service is not active, cannot reload.
```

But when I reload a stopped service via Ansible, it is restarted. 

### Issue Type

~Bug Report~
Documentation Report

### Component Name

systemd

### Ansible Version

```console
$ ansible --version

ansible [core 2.14.6]
  config file = None
  configured module search path = ['/home/testuser/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /home/testuser/scripts/venvs/ansible_latest/lib/python3.9/site-packages/ansible
  ansible collection location = /home/testuser/.ansible/collections:/usr/share/ansible/collections
  executable location = /home/testuser/scripts/venvs/ansible_latest/bin/ansible
  python version = 3.9.2 (default, Feb 28 2021, 17:03:44) [GCC 10.2.1 20210110] (/home/testuser/scripts/venvs/ansible_latest/bin/python3)
  jinja version = 3.1.2
  libyaml = True
```


### Configuration

```console
# if using a version older than ansible-core 2.12 you should omit the '-t all'
$ ansible-config dump --only-changed -t all

CONFIG_FILE() = None
```


### OS / Environment

Debian 11 (bullseye)
Ansible installed via pip3 

### Steps to Reproduce

- On a test Debian 11 machine, install haproxy and disable it : 
```
apt update
apt install haproxy
systemctl stop haproxy
```

- Try to reload the service manually, it should return an error with a RC of 1 : 

```
systemctl reload haproxy.service
haproxy.service is not active, cannot reload.

echo $?
1
```

- Reload the service via Ansible, it returns a "changed" result :

```
- name: Reload HAProxy test 
  hosts: testvm
  tasks: 
    - name: Reload HAProxy
      systemd:
        name: haproxy.service
        state: reloaded
```

- Check the service state on the test vm, the service is started : 

```
systemctl status haproxy.service 
● haproxy.service - HAProxy Load Balancer
     Loaded: loaded (/lib/systemd/system/haproxy.service; enabled; vendor preset: enabled)
     Active: active (running) since Fri 2023-05-26 14:26:45 CEST; 9s ago
       Docs: man:haproxy(1)
             file:/usr/share/doc/haproxy/configuration.txt.gz
    Process: 325727 ExecStartPre=/usr/sbin/haproxy -f $CONFIG -c -q $EXTRAOPTS (code=exited, status=0/SUCCESS)
   Main PID: 325729 (haproxy)
      Tasks: 2 (limit: 2275)
     Memory: 15.6M
        CPU: 71ms
     CGroup: /system.slice/haproxy.service
             ├─325729 /usr/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid -S /run/haproxy-master.sock
             └─325731 /usr/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid -S /run/haproxy-master.sock
```




### Expected Results

The module should either ignore the reload if the service is not currently running (best option) or fail with an error similar to "haproxy.service is not active, cannot reload."

### Actual Results

```console
The service is restarted.
```


### 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/systemd.py`](https://github.com/ansible/ansible/blob/devel/lib/ansible/modules/systemd.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/devel/ISSUE_HELP.md)
<!--- boilerplate: components_banner --->
the Ansible service modules follow a common behavior, it is expected that if you ask for a service to be reloaded, it will be started if it was not running. This is not the exact same way systemd itself functions but the meanings do not map to each specific service manager but to the common theme.
Hello, thanks for your reply.
Ok I understand, so I adapted my job like this to prevent my service from starting : 

- The handler to reload the service is replaced by an include task : 

```
- name: Reload HAProxy
  include_tasks: "{{ role_path }}/tasks/haproxy_reload.yml"
```
- A default variable with all the states where a service is stopped is defined in the role's defaults : 

```
service_stopped_status: ["stopped","failed","unknown"]
```

- A block task dedicated to reload checks the service state and reloads it only if the service is running : 

```
- name: Reload HAProxy
  block:

    - name: Get services state
      service_facts: 
      register: services_state

    - name: Reload service
      systemd:
        name: haproxy.service
        state: reloaded
      when: "services_state['ansible_facts']['services']['haproxy.service']['state'] not in service_stopped_status"
```

I think that this behavior should be explained in the documentation as it can be a bit confusing for people who are used to systemd. 
Can I submit a PR to add this to the doc ?
yes, feel free to do so
@pippo571 did you already prepare some documentation? I guess it's good to have that explained.
@benibr Sorry but not yet, I'm planning to do this next week during my time off.

Commit message: Remove trailing whitespace

Patch to review:
diff --git a/lib/ansible/modules/systemd_service.py b/lib/ansible/modules/systemd_service.py
index 47ff3cf6ddb328..6f4cf61f21f9c4 100644
--- a/lib/ansible/modules/systemd_service.py
+++ b/lib/ansible/modules/systemd_service.py
@@ -26,7 +26,8 @@
     state:
         description:
             - V(started)/V(stopped) are idempotent actions that will not run commands unless necessary.
-              V(restarted) will always bounce the unit. V(reloaded) will always reload.
+              V(restarted) will always bounce the unit.
+              V(reloaded) will always reload and if the service is not running at the moment of the reload, it is restarted.
         type: str
         choices: [ reloaded, restarted, started, stopped ]
     enabled:


Code review comments:
diff_hunk: @@ -26,7 +26,8 @@
     state:
         description:
             - V(started)/V(stopped) are idempotent actions that will not run commands unless necessary.
-              V(restarted) will always bounce the unit. V(reloaded) will always reload.
+              V(restarted) will always bounce the unit.
+              V(reloaded) will always reload and if the service is not running at the moment of the reload, it is restarted.
path: lib/ansible/modules/systemd_service.py
text: @user1:
it is started .. not really 're'

@author:
Right, the service is only started if not running, correction done

@user1:
not what i meant, its not 're'started .. it is 'started'