mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
HAProxy: add support for draining connections in maintenace mode (#25887)
* HAProxy: Support waiting for nodes to drain before maint mode A common task when working with a HAProxy-managed node is to first "drain" it and then place it into maintenance mode (to be repaired or redeployed). (Draining such a node consists of preventing new connections from being established while waiting for active sessions to expire/close.) This commit creates a new `drain' parameter for Ansible's HAProxy module, which, when set to `yes` in conjunction with `state: disabled` and `wait: yes`, causes the module to attempt to set a node to drain, wait for it to finish draining, and put the node into maintenance mode. The action is recorded as a success if these steps are completed before a maximum wait timeout is reached. Implements: https://github.com/ansible/ansible-modules-extras/issues/521 Acknowledgments: This is based on user krislindgren's pull request #21420 * Correct how drain option is handled Previously the `drain` parameter would have no effect, since the `disabled` state would still immediately place backend servers into maintenance mode.
This commit is contained in:
parent
549ef0f45d
commit
c342866016
1 changed files with 32 additions and 5 deletions
|
@ -35,6 +35,14 @@ options:
|
|||
- Name of the HAProxy backend pool.
|
||||
required: false
|
||||
default: auto-detected
|
||||
drain:
|
||||
description:
|
||||
- Wait until the server has no active connections or until the timeout
|
||||
determined by wait_interval and wait_retries is reached. Continue only
|
||||
after the status changes to 'MAINT'. This overrides the
|
||||
shutdown_sessions option.
|
||||
default: false
|
||||
version_added: "2.4"
|
||||
host:
|
||||
description:
|
||||
- Name of the backend host to change.
|
||||
|
@ -44,7 +52,8 @@ options:
|
|||
description:
|
||||
- When disabling a server, immediately terminate all the sessions attached
|
||||
to the specified server. This can be used to terminate long-running
|
||||
sessions after a server is put into maintenance mode.
|
||||
sessions after a server is put into maintenance mode. Overridden by the
|
||||
drain option.
|
||||
required: false
|
||||
default: false
|
||||
socket:
|
||||
|
@ -122,6 +131,19 @@ EXAMPLES = '''
|
|||
backend: www
|
||||
wait: yes
|
||||
|
||||
# Place server in drain mode, providing a socket file. Then check the server's
|
||||
# status every minute to see if it changes to maintenance mode, continuing if it
|
||||
# does in an hour and failing otherwise.
|
||||
- haproxy:
|
||||
state: disabled
|
||||
host: '{{ inventory_hostname }}'
|
||||
socket: /var/run/haproxy.sock
|
||||
backend: www
|
||||
wait: yes
|
||||
drain: yes
|
||||
wait_interval: 1
|
||||
wait_retries: 60
|
||||
|
||||
# disable backend server in 'www' backend pool and drop open sessions to it
|
||||
- haproxy:
|
||||
state: disabled
|
||||
|
@ -219,6 +241,7 @@ class HAProxy(object):
|
|||
self.wait = self.module.params['wait']
|
||||
self.wait_retries = self.module.params['wait_retries']
|
||||
self.wait_interval = self.module.params['wait_interval']
|
||||
self.drain = self.module.params['drain']
|
||||
self.command_results = {}
|
||||
|
||||
def execute(self, cmd, timeout=200, capture_output=True):
|
||||
|
@ -308,7 +331,7 @@ class HAProxy(object):
|
|||
r = csv.DictReader(data.splitlines())
|
||||
state = tuple(
|
||||
map(
|
||||
lambda d: {'status': d['status'], 'weight': d['weight']},
|
||||
lambda d: {'status': d['status'], 'weight': d['weight'], 'scur': d['scur']},
|
||||
filter(lambda d: (pxname is None or d['pxname'] == pxname) and d['svname'] == svname, r)
|
||||
)
|
||||
)
|
||||
|
@ -326,7 +349,8 @@ class HAProxy(object):
|
|||
|
||||
# We can assume there will only be 1 element in state because both svname and pxname are always set when we get here
|
||||
if state[0]['status'] == status:
|
||||
return True
|
||||
if not self.drain or (state[0]['scur'] == '0' and state == 'MAINT'):
|
||||
return True
|
||||
else:
|
||||
time.sleep(self.wait_interval)
|
||||
|
||||
|
@ -354,7 +378,7 @@ class HAProxy(object):
|
|||
cmd += "; shutdown sessions server $pxname/$svname"
|
||||
self.execute_for_backends(cmd, backend, host, 'MAINT')
|
||||
|
||||
def drain(self, host, backend):
|
||||
def drain(self, host, backend, status='DRAIN'):
|
||||
"""
|
||||
Drain action, sets the server to DRAIN mode.
|
||||
In this mode mode, the server will not accept any new connections
|
||||
|
@ -365,7 +389,7 @@ class HAProxy(object):
|
|||
# check if haproxy version suppots DRAIN state (starting with 1.5)
|
||||
if haproxy_version and (1, 5) <= haproxy_version:
|
||||
cmd = "set server $pxname/$svname state drain"
|
||||
self.execute_for_backends(cmd, backend, host, 'DRAIN')
|
||||
self.execute_for_backends(cmd, backend, host, status)
|
||||
|
||||
def act(self):
|
||||
"""
|
||||
|
@ -378,6 +402,8 @@ class HAProxy(object):
|
|||
# toggle enable/disbale server
|
||||
if self.state == 'enabled':
|
||||
self.enabled(self.host, self.backend, self.weight)
|
||||
elif self.state == 'disabled' and self.drain:
|
||||
self.drain(self.host, self.backend, status='MAINT')
|
||||
elif self.state == 'disabled':
|
||||
self.disabled(self.host, self.backend, self.shutdown_sessions)
|
||||
elif self.state == 'drain':
|
||||
|
@ -413,6 +439,7 @@ def main():
|
|||
wait=dict(required=False, default=False, type='bool'),
|
||||
wait_retries=dict(required=False, default=WAIT_RETRIES, type='int'),
|
||||
wait_interval=dict(required=False, default=WAIT_INTERVAL, type='int'),
|
||||
drain=dict(default=False, type='bool'),
|
||||
),
|
||||
)
|
||||
|
||||
|
|
Loading…
Reference in a new issue