ansible-collections-openstack/plugins/modules/lb_health_monitor.py
Jakob Meng 1b38b7c500 Properly documented openstacksdk version requirements
With "extends_documentation_fragment: ['openstack.cloud.openstack']"
it is not necessary to list required Python libraries in section
'requirements' of DOCUMENTATION docstring in modules. Ansible will
merge requirements from doc fragments and DOCUMENTATION docstring
which previously resulted in duplicates such as in server module [0]:

* openstacksdk
* openstacksdk >= 0.36, < 0.99.0
* python >= 3.6

When removing the 'requirements' section from server module, then
Ansible will list openstacksdk once only:

* openstacksdk >= 0.36, < 0.99.0
* python >= 3.6

To see what documentation Ansible will produce for server module run:

  ansible-doc --type module openstack.cloud.server

[0] https://docs.ansible.com/ansible/latest/collections/openstack/\
    cloud/server_module.html

Change-Id: I727ed95ee480bb644b5a533f6a9526973677064c
2023-01-16 13:51:01 +01:00

359 lines
12 KiB
Python

#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright (c) 2020 Jesper Schmitz Mouridsen.
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
DOCUMENTATION = r'''
---
module: lb_health_monitor
author: OpenStack Ansible SIG
short_description: Manage health monitor in a OpenStack load-balancer pool
description:
- Add, update or remove health monitor from a load-balancer pool in OpenStack
cloud.
options:
delay:
description:
- The interval, in seconds, between health checks.
- Required when I(state) is C(present).
type: int
expected_codes:
description:
- The list of HTTP status codes expected in response from the member to
declare it healthy. Specify one of the following values.
- For example, I(expected_codes) could be a single value, such as C(200),
a list, such as C(200, 202) or a range, such as C(200-204).
- "Octavia's default for I(expected_codes) is C(200)."
type: str
health_monitor_timeout:
description:
- The time, in seconds, after which a health check times out.
- Must be less than I(delay).
- Required when I(state) is C(present).
type: int
aliases: ['resp_timeout']
http_method:
description:
- The HTTP method that the health monitor uses for requests.
- For example, I(http_method) could be C(CONNECT), C(DELETE), C(GET),
C(HEAD), C(OPTIONS), C(PATCH), C(POST), C(PUT), or C(TRACE).
- "Octavia's default for I(http_method) is C(GET)."
type: str
is_admin_state_up:
description:
- Whether the health monitor is up or down.
type: bool
aliases: ['admin_state_up']
max_retries:
description:
- The number of successful checks before changing the operating status
of the member to ONLINE.
- Required when I(state) is C(present).
type: int
max_retries_down:
description:
- The number of allowed check failures before changing the operating
status of the member to ERROR. A valid value is from 1 to 10.
type: int
name:
description:
- Name that has to be given to the health monitor.
- This attribute cannot be updated.
type: str
required: true
pool:
description:
- The pool name or id to monitor by the health monitor.
- Required when I(state) is C(present).
- This attribute cannot be updated.
type: str
state:
description:
- Should the resource be present or absent.
choices: [present, absent]
default: present
type: str
type:
default: HTTP
description:
- The type of health monitor.
- For example, I(type) could be C(HTTP), C(HTTPS), C(PING), C(SCTP),
C(TCP), C(TLS-HELLO) or C(UDP-CONNECT).
- This attribute cannot be updated.
type: str
url_path:
description:
- The HTTP URL path of the request sent by the monitor to test the health
of a backend member.
- Must be a string that begins with a forward slash (C(/)).
- "Octavia's default URL path is C(/)."
type: str
extends_documentation_fragment:
- openstack.cloud.openstack
'''
RETURN = r'''
health_monitor:
description: Dictionary describing the load-balancer health monitor.
returned: On success when I(state) is C(present).
type: dict
contains:
created_at:
description: The UTC date and timestamp when the resource was created.
type: str
delay:
description: The time, in seconds, between sending probes to members.
type: int
expected_codes:
description: The list of HTTP status codes expected in response from the
member to declare it healthy.
type: str
http_method:
description: The HTTP method that the health monitor uses for requests.
type: str
id:
description: The health monitor UUID.
type: str
is_admin_state_up:
description: The administrative state of the resource.
type: bool
max_retries:
description: The number of successful checks before changing the
operating status of the member to ONLINE.
type: int
max_retries_down:
description: The number of allowed check failures before changing the
operating status of the member to ERROR.
type: int
name:
description: Human-readable name of the resource.
type: str
operating_status:
description: The operating status of the resource.
type: str
pool_id:
description: The id of the pool.
type: str
pools:
description: List of associated pool ids.
type: list
project_id:
description: The ID of the project owning this resource.
type: str
provisioning_status:
description: The provisioning status of the resource.
type: str
tags:
description: A list of associated tags.
type: list
timeout:
description: The maximum time, in seconds, that a monitor waits to
connect before it times out.
type: int
type:
description: The type of health monitor.
type: str
updated_at:
description: The UTC date and timestamp when the resource was last
updated.
type: str
url_path:
description: The HTTP URL path of the request sent by the monitor to
test the health of a backend member.
type: str
'''
EXAMPLES = r'''
- name: Create a load-balancer health monitor
openstack.cloud.lb_health_monitor:
cloud: devstack
delay: 10
expected_codes: '200'
health_monitor_timeout: 5
http_method: GET
is_admin_state_up: true
max_retries: 3
max_retries_down: 4
name: healthmonitor01
pool: lb_pool
state: present
url_path: '/status'
- name: Delete a load-balancer health monitor
openstack.cloud.lb_health_monitor:
cloud: devstack
name: healthmonitor01
state: absent
'''
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import OpenStackModule
class LoadBalancerHealthMonitorModule(OpenStackModule):
argument_spec = dict(
delay=dict(type='int'),
expected_codes=dict(),
health_monitor_timeout=dict(type='int', aliases=['resp_timeout']),
http_method=dict(),
is_admin_state_up=dict(type='bool', aliases=['admin_state_up']),
max_retries=dict(type='int'),
max_retries_down=dict(type='int'),
name=dict(required=True),
pool=dict(),
state=dict(default='present', choices=['absent', 'present']),
type=dict(default='HTTP'),
url_path=dict(),
)
module_kwargs = dict(
required_if=[
('state', 'present', ('delay', 'health_monitor_timeout',
'max_retries', 'pool',)),
],
supports_check_mode=True,
)
def run(self):
state = self.params['state']
health_monitor = self._find()
if self.ansible.check_mode:
self.exit_json(changed=self._will_change(state, health_monitor))
if state == 'present' and not health_monitor:
# Create health_monitor
health_monitor = self._create()
self.exit_json(
changed=True,
health_monitor=health_monitor.to_dict(computed=False))
elif state == 'present' and health_monitor:
# Update health_monitor
update = self._build_update(health_monitor)
if update:
health_monitor = self._update(health_monitor, update)
self.exit_json(
changed=bool(update),
health_monitor=health_monitor.to_dict(computed=False))
elif state == 'absent' and health_monitor:
# Delete health_monitor
self._delete(health_monitor)
self.exit_json(changed=True)
elif state == 'absent' and not health_monitor:
# Do nothing
self.exit_json(changed=False)
def _build_update(self, health_monitor):
update = {}
non_updateable_keys = [k for k in ['type']
if self.params[k] is not None
and self.params[k] != health_monitor[k]]
pool_name_or_id = self.params['pool']
pool = self.conn.load_balancer.find_pool(name_or_id=pool_name_or_id,
ignore_missing=False)
# Field pool_id is not returned from self.conn.load_balancer.\
# find_pool() so use pools instead.
if health_monitor['pools'] != [dict(id=pool.id)]:
non_updateable_keys.append('pool')
if non_updateable_keys:
self.fail_json(msg='Cannot update parameters {0}'
.format(non_updateable_keys))
attributes = dict((k, self.params[k])
for k in ['delay', 'expected_codes', 'http_method',
'is_admin_state_up', 'max_retries',
'max_retries_down', 'type', 'url_path']
if self.params[k] is not None
and self.params[k] != health_monitor[k])
health_monitor_timeout = self.params['health_monitor_timeout']
if health_monitor_timeout is not None \
and health_monitor_timeout != health_monitor['timeout']:
attributes['timeout'] = health_monitor_timeout
if attributes:
update['attributes'] = attributes
return update
def _create(self):
kwargs = dict((k, self.params[k])
for k in ['delay', 'expected_codes', 'http_method',
'is_admin_state_up', 'max_retries',
'max_retries_down', 'name', 'type', 'url_path']
if self.params[k] is not None)
health_monitor_timeout = self.params['health_monitor_timeout']
if health_monitor_timeout is not None:
kwargs['timeout'] = health_monitor_timeout
pool_name_or_id = self.params['pool']
pool = self.conn.load_balancer.find_pool(name_or_id=pool_name_or_id,
ignore_missing=False)
kwargs['pool_id'] = pool.id
health_monitor = \
self.conn.load_balancer.create_health_monitor(**kwargs)
if self.params['wait']:
health_monitor = self.sdk.resource.wait_for_status(
self.conn.load_balancer, health_monitor,
status='active',
failures=['error'],
wait=self.params['timeout'],
attribute='provisioning_status')
return health_monitor
def _delete(self, health_monitor):
self.conn.load_balancer.delete_health_monitor(health_monitor.id)
def _find(self):
name = self.params['name']
return self.conn.load_balancer.find_health_monitor(name_or_id=name)
def _update(self, health_monitor, update):
attributes = update.get('attributes')
if attributes:
health_monitor = self.conn.load_balancer.update_health_monitor(
health_monitor.id, **attributes)
if self.params['wait']:
health_monitor = self.sdk.resource.wait_for_status(
self.conn.load_balancer, health_monitor,
status='active',
failures=['error'],
wait=self.params['timeout'],
attribute='provisioning_status')
return health_monitor
def _will_change(self, state, health_monitor):
if state == 'present' and not health_monitor:
return True
elif state == 'present' and health_monitor:
return bool(self._build_update(health_monitor))
elif state == 'absent' and health_monitor:
return True
else:
# state == 'absent' and not health_monitor:
return False
def main():
module = LoadBalancerHealthMonitorModule()
module()
if __name__ == "__main__":
main()