Repository: ansible-collections/community.general

Issue:
Module haproxy times out instead setting HAProxy backends into DRAIN mode followed by MAINT when the Backend is down / unreachable
### Summary

This is a similar bug to: https://github.com/ansible-collections/community.general

HAProxy allows setting backends into DRAIN mode, which waits until the server has no active connections before transitioning them into MAINT mode.

The corresponding Ansible haproxy module offers a state and parameter named 'drain' to achieve this functionality.

However, if the backend is unreachable and thus in a failed state, the haproxy module times out and fails instead of entering MAINT mode. The expected behavior would be to either directly fail or bypass the DRAIN mode and enter MAINT immediately.

Additionally, I noticed that "drain: true" does not work properly unless "wait: true" is also specified. Therefore, "wait: true" should be a mandatory parameter when using "drain: true".

I would appreciate it if this issue could be investigated and fixed.

Thank you for your time and consideration.

### Issue Type

Bug Report

### Component Name

haproxy

### Ansible Version

```console (paste below)
$ ansible --version
ansible [core 2.16.4]
  config file = /home/user/stuff/ansible/ansible.cfg
  configured module search path = ['/home/user/stuff/ansible/plugins/library']
  ansible python module location = /usr/lib/python3.12/site-packages/ansible
  ansible collection location = /home/user/.ansible/collections:/usr/share/ansible/collections
  executable location = /usr/bin/ansible
  python version = 3.12.2 (main, Feb 21 2024, 00:00:00) [GCC 13.2.1 20231205 (Red Hat 13.2.1-6)] (/usr/bin/python3)
  jinja version = 3.1.3
  libyaml = True

```


### Community.general Version

```console (paste below)
$ ansible-galaxy collection list community.general
# /home/user/.ansible/collections/ansible_collections
Collection        Version
----------------- -------
community.general 5.6.0  

# /usr/lib/python3.12/site-packages/ansible_collections
Collection        Version
----------------- -------
community.general 8.4.0  
```


### Configuration

```console (paste below)
$ ansible-config dump --only-changed

```


### OS / Environment

testet on RHEL 7 - 9

### Steps to Reproduce

<!--- Paste example playbooks or commands between quotes below -->
```yaml (paste below)
# the backend needs to be DOWN
    - name: Set backend state
      community.general.haproxy:
        state: disabled
        host: "{{ _host }}"
        socket: /tmp/haproxy.admin.sock
        wait: true
        drain: true
        wait_interval: 5
        wait_retries: 25
      become: true
```


### Expected Results

The expected behavior would be to either directly fail or bypass the DRAIN mode and enter MAINT immediately.

### Actual Results

```console (paste below)

```


### Code of Conduct

- [X] I agree to follow the Ansible Code of Conduct


Discussion:
Files identified in the description:
* [`plugins/modules/haproxy.py`](https://github.com/ansible-collections/community.general/blob/main/plugins/modules/haproxy.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 --->
cc @Normo @ravibhure
[click here for bot help](https://github.com/ansible/ansibullbot/blob/devel/ISSUE_HELP.md)
<!--- boilerplate: notify --->
This could be fixed by changing [plugins/modules/haproxy.py](https://github.com/ansible-collections/community.general/blob/6fab46710a5a91babf5412c678dadb58d305a47c/plugins/modules/haproxy.py#L344) line 344 to:
`if state is not None and wait_for_status is not "DRAIN" and state is not "DOWN":`

Resolving patch:
diff --git a/plugins/modules/haproxy.py b/plugins/modules/haproxy.py
--- a/plugins/modules/haproxy.py
+++ b/plugins/modules/haproxy.py
@@ -343,7 +343,7 @@ def execute_for_backends(self, cmd, pxname, svname, wait_for_status=None):
 
             if state is not None:
                 self.execute(Template(cmd).substitute(pxname=backend, svname=svname))
-                if self.wait:
+                if self.wait and not (wait_for_status == "DRAIN" and state == "DOWN"):
                     self.wait_until_status(backend, svname, wait_for_status)
 
     def get_state_for(self, pxname, svname):


Test patch: