1b38b7c500
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
359 lines
12 KiB
Python
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()
|