diff --git a/lib/ansible/modules/cloud/openstack/os_pool.py b/lib/ansible/modules/cloud/openstack/os_pool.py new file mode 100644 index 0000000000..d205926a22 --- /dev/null +++ b/lib/ansible/modules/cloud/openstack/os_pool.py @@ -0,0 +1,266 @@ +#!/usr/bin/python + +# Copyright (c) 2018 Catalyst Cloud Ltd. +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +ANSIBLE_METADATA = {'metadata_version': '1.1', + 'status': ['preview'], + 'supported_by': 'community'} + +DOCUMENTATION = ''' +--- +module: os_pool +short_description: Add/Delete a pool in the load balancing service from OpenStack Cloud +extends_documentation_fragment: openstack +version_added: "2.7" +author: "Lingxian Kong (@lingxiankong)" +description: + - Add or Remove a pool from the OpenStack load-balancer service. +options: + name: + description: + - Name that has to be given to the pool + required: true + state: + description: + - Should the resource be present or absent. + choices: [present, absent] + default: present + loadbalancer: + description: + - The name or id of the load balancer that this pool belongs to. + Either loadbalancer or listener must be specified for pool creation. + listener: + description: + - The name or id of the listener that this pool belongs to. + Either loadbalancer or listener must be specified for pool creation. + protocol: + description: + - The protocol for the pool. + choices: [HTTP, HTTPS, PROXY, TCP, UDP] + default: HTTP + lb_algorithm: + description: + - The load balancing algorithm for the pool. + choices: [LEAST_CONNECTIONS, ROUND_ROBIN, SOURCE_IP] + default: ROUND_ROBIN + wait: + description: + - If the module should wait for the pool to be ACTIVE. + type: bool + default: 'yes' + timeout: + description: + - The amount of time the module should wait for the pool to get + into ACTIVE state. + default: 180 + availability_zone: + description: + - Ignored. Present for backwards compatibility +requirements: ["openstacksdk"] +''' + +RETURN = ''' +id: + description: The pool UUID. + returned: On success when I(state) is 'present' + type: string + sample: "39007a7e-ee4f-4d13-8283-b4da2e037c69" +listener: + description: Dictionary describing the pool. + returned: On success when I(state) is 'present' + type: complex + contains: + id: + description: Unique UUID. + type: string + sample: "39007a7e-ee4f-4d13-8283-b4da2e037c69" + name: + description: Name given to the pool. + type: string + sample: "test" + description: + description: The pool description. + type: string + sample: "description" + loadbalancers: + description: A list of load balancer IDs. + type: list + sample: [{"id": "b32eef7e-d2a6-4ea4-a301-60a873f89b3b"}] + listeners: + description: A list of listener IDs. + type: list + sample: [{"id": "b32eef7e-d2a6-4ea4-a301-60a873f89b3b"}] + members: + description: A list of member IDs. + type: list + sample: [{"id": "b32eef7e-d2a6-4ea4-a301-60a873f89b3b"}] + loadbalancer_id: + description: The load balancer ID the pool belongs to. This field is set when the pool doesn't belong to any listener in the load balancer. + type: string + sample: "7c4be3f8-9c2f-11e8-83b3-44a8422643a4" + listener_id: + description: The listener ID the pool belongs to. + type: string + sample: "956aa716-9c2f-11e8-83b3-44a8422643a4" + provisioning_status: + description: The provisioning status of the pool. + type: string + sample: "ACTIVE" + operating_status: + description: The operating status of the pool. + type: string + sample: "ONLINE" + is_admin_state_up: + description: The administrative state of the pool. + type: bool + sample: true + protocol: + description: The protocol for the pool. + type: string + sample: "HTTP" + lb_algorithm: + description: The load balancing algorithm for the pool. + type: string + sample: "ROUND_ROBIN" +''' + +EXAMPLES = ''' +# Create a pool, wait for the pool to be active. +- os_pool: + cloud: mycloud + endpoint_type: admin + state: present + name: test-pool + loadbalancer: test-loadbalancer + protocol: HTTP + lb_algorithm: ROUND_ROBIN + +# Delete a pool +- os_pool: + cloud: mycloud + endpoint_type: admin + state: absent + name: test-pool +''' + +import time + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.openstack import openstack_full_argument_spec, \ + openstack_module_kwargs, openstack_cloud_from_module + + +def _wait_for_pool_status(module, cloud, pool_id, status, failures, + interval=5): + timeout = module.params['timeout'] + + total_sleep = 0 + if failures is None: + failures = [] + + while total_sleep < timeout: + pool = cloud.load_balancer.get_pool(pool_id) + provisioning_status = pool.provisioning_status + if provisioning_status == status: + return pool + if provisioning_status in failures: + module.fail_json( + msg="pool %s transitioned to failure state %s" % + (pool_id, provisioning_status) + ) + + time.sleep(interval) + total_sleep += interval + + module.fail_json( + msg="timeout waiting for pool %s to transition to %s" % + (pool_id, status) + ) + + +def main(): + argument_spec = openstack_full_argument_spec( + name=dict(required=True), + state=dict(default='present', choices=['absent', 'present']), + loadbalancer=dict(default=None), + listener=dict(default=None), + protocol=dict(default='HTTP', + choices=['HTTP', 'HTTPS', 'TCP', 'UDP', 'PROXY']), + lb_algorithm=dict( + default='ROUND_ROBIN', + choices=['ROUND_ROBIN', 'LEAST_CONNECTIONS', 'SOURCE_IP'] + ) + ) + module_kwargs = openstack_module_kwargs( + mutually_exclusive=[['loadbalancer', 'listener']] + ) + module = AnsibleModule(argument_spec, **module_kwargs) + sdk, cloud = openstack_cloud_from_module(module) + + loadbalancer = module.params['loadbalancer'] + listener = module.params['listener'] + + try: + changed = False + pool = cloud.load_balancer.find_pool(name_or_id=module.params['name']) + + if module.params['state'] == 'present': + if not pool: + loadbalancer_id = None + if not (loadbalancer or listener): + module.fail_json("either loadbalancer or listener must " + "be provided") + + if loadbalancer: + lb = cloud.load_balancer.find_load_balancer(loadbalancer) + if not lb: + module.fail_json(msg='load balancer %s is not ' + 'found' % loadbalancer) + loadbalancer_id = lb.id + + listener_id = None + if listener: + listener_ret = cloud.load_balancer.find_listener(listener) + if not listener_ret: + module.fail_json(msg='listener %s is not found' + % listener) + listener_id = listener_ret.id + + pool = cloud.load_balancer.create_pool( + name=module.params['name'], + loadbalancer_id=loadbalancer_id, + listener_id=listener_id, + protocol=module.params['protocol'], + lb_algorithm=module.params['lb_algorithm'] + ) + changed = True + + if not module.params['wait']: + module.exit_json(changed=changed, + pool=pool.to_dict(), + id=pool.id) + + if module.params['wait']: + pool = _wait_for_pool_status(module, cloud, pool.id, "ACTIVE", + ["ERROR"]) + + module.exit_json(changed=changed, pool=pool.to_dict(), + id=pool.id) + + elif module.params['state'] == 'absent': + if pool: + cloud.load_balancer.delete_pool(pool) + changed = True + + module.exit_json(changed=changed) + except sdk.exceptions.OpenStackCloudException as e: + module.fail_json(msg=str(e), extra_data=e.extra_data) + + +if __name__ == "__main__": + main()