1#!/usr/bin/python 2 3# Copyright (c) 2018 Catalyst Cloud Ltd. 4# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) 5 6from __future__ import absolute_import, division, print_function 7 8__metaclass__ = type 9 10ANSIBLE_METADATA = {'metadata_version': '1.1', 11 'status': ['preview'], 12 'supported_by': 'community'} 13 14DOCUMENTATION = ''' 15--- 16module: os_pool 17short_description: Add/Delete a pool in the load balancing service from OpenStack Cloud 18extends_documentation_fragment: openstack 19version_added: "2.7" 20author: "Lingxian Kong (@lingxiankong)" 21description: 22 - Add or Remove a pool from the OpenStack load-balancer service. 23options: 24 name: 25 description: 26 - Name that has to be given to the pool 27 required: true 28 state: 29 description: 30 - Should the resource be present or absent. 31 choices: [present, absent] 32 default: present 33 loadbalancer: 34 description: 35 - The name or id of the load balancer that this pool belongs to. 36 Either loadbalancer or listener must be specified for pool creation. 37 listener: 38 description: 39 - The name or id of the listener that this pool belongs to. 40 Either loadbalancer or listener must be specified for pool creation. 41 protocol: 42 description: 43 - The protocol for the pool. 44 choices: [HTTP, HTTPS, PROXY, TCP, UDP] 45 default: HTTP 46 lb_algorithm: 47 description: 48 - The load balancing algorithm for the pool. 49 choices: [LEAST_CONNECTIONS, ROUND_ROBIN, SOURCE_IP] 50 default: ROUND_ROBIN 51 wait: 52 description: 53 - If the module should wait for the pool to be ACTIVE. 54 type: bool 55 default: 'yes' 56 timeout: 57 description: 58 - The amount of time the module should wait for the pool to get 59 into ACTIVE state. 60 default: 180 61 availability_zone: 62 description: 63 - Ignored. Present for backwards compatibility 64requirements: ["openstacksdk"] 65''' 66 67RETURN = ''' 68id: 69 description: The pool UUID. 70 returned: On success when I(state) is 'present' 71 type: str 72 sample: "39007a7e-ee4f-4d13-8283-b4da2e037c69" 73listener: 74 description: Dictionary describing the pool. 75 returned: On success when I(state) is 'present' 76 type: complex 77 contains: 78 id: 79 description: Unique UUID. 80 type: str 81 sample: "39007a7e-ee4f-4d13-8283-b4da2e037c69" 82 name: 83 description: Name given to the pool. 84 type: str 85 sample: "test" 86 description: 87 description: The pool description. 88 type: str 89 sample: "description" 90 loadbalancers: 91 description: A list of load balancer IDs. 92 type: list 93 sample: [{"id": "b32eef7e-d2a6-4ea4-a301-60a873f89b3b"}] 94 listeners: 95 description: A list of listener IDs. 96 type: list 97 sample: [{"id": "b32eef7e-d2a6-4ea4-a301-60a873f89b3b"}] 98 members: 99 description: A list of member IDs. 100 type: list 101 sample: [{"id": "b32eef7e-d2a6-4ea4-a301-60a873f89b3b"}] 102 loadbalancer_id: 103 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. 104 type: str 105 sample: "7c4be3f8-9c2f-11e8-83b3-44a8422643a4" 106 listener_id: 107 description: The listener ID the pool belongs to. 108 type: str 109 sample: "956aa716-9c2f-11e8-83b3-44a8422643a4" 110 provisioning_status: 111 description: The provisioning status of the pool. 112 type: str 113 sample: "ACTIVE" 114 operating_status: 115 description: The operating status of the pool. 116 type: str 117 sample: "ONLINE" 118 is_admin_state_up: 119 description: The administrative state of the pool. 120 type: bool 121 sample: true 122 protocol: 123 description: The protocol for the pool. 124 type: str 125 sample: "HTTP" 126 lb_algorithm: 127 description: The load balancing algorithm for the pool. 128 type: str 129 sample: "ROUND_ROBIN" 130''' 131 132EXAMPLES = ''' 133# Create a pool, wait for the pool to be active. 134- os_pool: 135 cloud: mycloud 136 endpoint_type: admin 137 state: present 138 name: test-pool 139 loadbalancer: test-loadbalancer 140 protocol: HTTP 141 lb_algorithm: ROUND_ROBIN 142 143# Delete a pool 144- os_pool: 145 cloud: mycloud 146 endpoint_type: admin 147 state: absent 148 name: test-pool 149''' 150 151import time 152 153from ansible.module_utils.basic import AnsibleModule 154from ansible.module_utils.openstack import openstack_full_argument_spec, \ 155 openstack_module_kwargs, openstack_cloud_from_module 156 157 158def _wait_for_pool_status(module, cloud, pool_id, status, failures, 159 interval=5): 160 timeout = module.params['timeout'] 161 162 total_sleep = 0 163 if failures is None: 164 failures = [] 165 166 while total_sleep < timeout: 167 pool = cloud.load_balancer.get_pool(pool_id) 168 provisioning_status = pool.provisioning_status 169 if provisioning_status == status: 170 return pool 171 if provisioning_status in failures: 172 module.fail_json( 173 msg="pool %s transitioned to failure state %s" % 174 (pool_id, provisioning_status) 175 ) 176 177 time.sleep(interval) 178 total_sleep += interval 179 180 module.fail_json( 181 msg="timeout waiting for pool %s to transition to %s" % 182 (pool_id, status) 183 ) 184 185 186def main(): 187 argument_spec = openstack_full_argument_spec( 188 name=dict(required=True), 189 state=dict(default='present', choices=['absent', 'present']), 190 loadbalancer=dict(default=None), 191 listener=dict(default=None), 192 protocol=dict(default='HTTP', 193 choices=['HTTP', 'HTTPS', 'TCP', 'UDP', 'PROXY']), 194 lb_algorithm=dict( 195 default='ROUND_ROBIN', 196 choices=['ROUND_ROBIN', 'LEAST_CONNECTIONS', 'SOURCE_IP'] 197 ) 198 ) 199 module_kwargs = openstack_module_kwargs( 200 mutually_exclusive=[['loadbalancer', 'listener']] 201 ) 202 module = AnsibleModule(argument_spec, **module_kwargs) 203 sdk, cloud = openstack_cloud_from_module(module) 204 205 loadbalancer = module.params['loadbalancer'] 206 listener = module.params['listener'] 207 208 try: 209 changed = False 210 pool = cloud.load_balancer.find_pool(name_or_id=module.params['name']) 211 212 if module.params['state'] == 'present': 213 if not pool: 214 loadbalancer_id = None 215 if not (loadbalancer or listener): 216 module.fail_json( 217 msg="either loadbalancer or listener must be provided" 218 ) 219 220 if loadbalancer: 221 lb = cloud.load_balancer.find_load_balancer(loadbalancer) 222 if not lb: 223 module.fail_json(msg='load balancer %s is not ' 224 'found' % loadbalancer) 225 loadbalancer_id = lb.id 226 227 listener_id = None 228 if listener: 229 listener_ret = cloud.load_balancer.find_listener(listener) 230 if not listener_ret: 231 module.fail_json(msg='listener %s is not found' 232 % listener) 233 listener_id = listener_ret.id 234 235 pool = cloud.load_balancer.create_pool( 236 name=module.params['name'], 237 loadbalancer_id=loadbalancer_id, 238 listener_id=listener_id, 239 protocol=module.params['protocol'], 240 lb_algorithm=module.params['lb_algorithm'] 241 ) 242 changed = True 243 244 if not module.params['wait']: 245 module.exit_json(changed=changed, 246 pool=pool.to_dict(), 247 id=pool.id) 248 249 if module.params['wait']: 250 pool = _wait_for_pool_status(module, cloud, pool.id, "ACTIVE", 251 ["ERROR"]) 252 253 module.exit_json(changed=changed, pool=pool.to_dict(), 254 id=pool.id) 255 256 elif module.params['state'] == 'absent': 257 if pool: 258 cloud.load_balancer.delete_pool(pool) 259 changed = True 260 261 module.exit_json(changed=changed) 262 except sdk.exceptions.OpenStackCloudException as e: 263 module.fail_json(msg=str(e), extra_data=e.extra_data) 264 265 266if __name__ == "__main__": 267 main() 268