From 0be54b55858a61e7378e093b3eb0287d66de61a6 Mon Sep 17 00:00:00 2001 From: "Christopher H. Laco" Date: Sun, 3 Nov 2013 13:13:13 -0600 Subject: [PATCH] Added replacement rax_clb that does LB detailed creation --- library/cloud/rax_clb | 274 ++++++++++++++++++++++++++++++++++++ library/cloud/rax_clb_nodes | 2 +- 2 files changed, 275 insertions(+), 1 deletion(-) create mode 100644 library/cloud/rax_clb diff --git a/library/cloud/rax_clb b/library/cloud/rax_clb new file mode 100644 index 0000000000..498ab1414e --- /dev/null +++ b/library/cloud/rax_clb @@ -0,0 +1,274 @@ +#!/usr/bin/python -tt +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . + +DOCUMENTATION = ''' +--- +module: rax_clb +short_description: create / delete a load balancer in Rackspace Public Cloud +description: + - creates / deletes a Rackspace Public Cloud load balancer. +version_added: "1.4" +options: + state: + description: + - Indicate desired state of the resource + choices: ['present', 'absent'] + default: present + credentials: + description: + - File to find the Rackspace credentials in (ignored if C(api_key) and + C(username) are provided) + default: null + aliases: ['creds_file'] + api_key: + description: + - Rackspace API key (overrides C(credentials)) + username: + description: + - Rackspace username (overrides C(credentials)) + name: + description: + - Name to give the load balancer + default: null + algorithm: + description: + - algorithm for the balancer being created + choices: ['RANDOM', 'LEAST_CONNECTIONS', 'ROUND_ROBIN', 'WEIGHTED_LEAST_CONNECTIONS', 'WEIGHTED_ROUND_ROBIN'] + default: LEAST_CONNECTIONS + port: + description: + - Port for the balancer being created + default: 80 + protocol: + description: + - Protocol for the balancer being created + choices: ['DNS_TCP', 'DNS_UDP' ,'FTP', 'HTTP', 'HTTPS', 'IMAPS', 'IMAPv4', 'LDAP', 'LDAPS', 'MYSQL', 'POP3', 'POP3S', 'SMTP', 'TCP', 'TCP_CLIENT_FIRST', 'UDP', 'UDP_STREAM', 'SFTP'] + default: HTTP + timeout: + description: + - timeout for communication between the balancer and the node + default: 30 + type: + description: + - type of interface for the balancer being created + choices: ['PUBLIC', 'SERVICENET'] + default: PUBLIC + region: + description: + - Region to create the load balancer in + default: DFW + wait: + description: + - wait for the balancer to be in state 'running' before returning + default: "no" + choices: [ "yes", "no" ] + wait_timeout: + description: + - how long before wait gives up, in seconds + default: 300 +requirements: [ "pyrax" ] +author: Christopher H. Laco, Jesse Keating +notes: + - The following environment variables can be used, C(RAX_USERNAME), + C(RAX_API_KEY), C(RAX_CREDS), C(RAX_CREDENTIALS), C(RAX_REGION). + - C(RAX_CREDENTIALS) and C(RAX_CREDS) points to a credentials file + appropriate for pyrax + - C(RAX_USERNAME) and C(RAX_API_KEY) obviate the use of a credentials file + - C(RAX_REGION) defines a Rackspace Public Cloud region (DFW, ORD, LON, ...) +''' + +EXAMPLES = ''' +- name: Build a Load Balancer + gather_facts: False + + tasks: + - name: Provision Load Balancer + rax_lb: + credentials: ~/.raxpub + name: my-lb + port: 9000 + protocol: HTTP + type: SERVICENET + timeout: 30 + region: DFW + wait: yes + state: present + register: my_lb +''' + +import sys +import os +import time + +try: + import pyrax + import pyrax.utils + from pyrax import exc +except ImportError: + print("failed=True msg='pyrax required for this module'") + sys.exit(1) + + +def cloud_load_balancer(module, state, name, meta, algorithm, port, protocol, type, timeout, + wait, wait_timeout): + for arg in (state, name, port, protocol, type): + if not arg: + module.fail_json(msg='%s is required for cloud_loadbalancers' % arg) + + changed = False + balancer = None + balancers = [] + instances = [] + + for balancer in pyrax.cloud_loadbalancers.list(): + if name != balancer.name: + continue + + balancers.append(balancer) + + if state == 'present': + if not balancers: + try: + balancers=[pyrax.cloud_loadbalancers.create( + name, + metadata=meta, + algorithm=algorithm, + port=port, + protocol=protocol, + timeout=timeout, + virtual_ips=[pyrax.cloud_loadbalancers.VirtualIP(type=type)] + )] + changed = True + except Exception, e: + module.fail_json(msg='%s' % e.message) + + for balancer in balancers: + if wait: + pyrax.utils.wait_for_build(balancer, interval=5, attempts=5) + + if balancer.status == 'ACTIVE': + instance = dict( + id=balancer.id, + algorithm=balancer.algorithm, + cluster=balancer.cluster, + connectionLogging=balancer.connectionLogging, + contentCaching=balancer.contentCaching, + halfClosed=balancer.halfClosed, + port=balancer.port, + protocol=balancer.protocol, + sourceAddresses=balancer.sourceAddresses, + name=balancer.name, + timeout=balancer.timeout, + status=balancer.status + ) + instances.append(instance) + elif balancer.status == 'ERROR': + module.fail_json(msg='%s failed to build' % balancer.id) + elif wait: + module.fail_json(msg='Timeout waiting on %s' % balancer.id) + + elif state == 'absent': + if balancer: + try: + balancer.delete() + changed = True + except Exception, e: + module.fail_json(msg='%s' % e.message) + + instance = dict( + id=balancer.id, + algorithm=balancer.algorithm, + cluster=None, + connectionLogging=None, + contentCaching=None, + halfClosed=None, + port=balancer.port, + protocol=balancer.protocol, + sourceAddresses=None, + name=balancer.name, + timeout=balancer.timeout, + status=balancer.status + ) + instances.append(instance) + + module.exit_json(changed=changed, balancers=instances) + + +def main(): + module = AnsibleModule( + argument_spec=dict( + state=dict(default='present', + choices=['present', 'absent']), + credentials=dict(aliases=['creds_file']), + api_key=dict(), + username=dict(), + region=dict(), + name=dict(), + meta=dict(type='dict', default={}), + algorithm=dict(choices=['RANDOM', 'LEAST_CONNECTIONS', 'ROUND_ROBIN', 'WEIGHTED_LEAST_CONNECTIONS', 'WEIGHTED_ROUND_ROBIN'], default='LEAST_CONNECTIONS'), + port=dict(type='int', default=80), + protocol=dict(choices=['DNS_TCP', 'DNS_UDP' ,'FTP', 'HTTP', 'HTTPS', 'IMAPS', 'IMAPv4', 'LDAP', 'LDAPS', 'MYSQL', 'POP3', 'POP3S', 'SMTP', 'TCP', 'TCP_CLIENT_FIRST', 'UDP', 'UDP_STREAM', 'SFTP'], default='HTTP'), + type=dict(choices=['PUBLIC', 'SERVICENET'], default='PUBLIC'), + timeout=dict(type='int', default=30), + wait=dict(type='bool'), + wait_timeout=dict(default=300) + ) + ) + + credentials = module.params.get('credentials') + api_key = module.params.get('api_key') + username = module.params.get('username') + region = module.params.get('region') + state = module.params.get('state') + name = module.params.get('name') + meta = module.params.get('meta') + algorithm = module.params.get('algorithm') + port = module.params.get('port') + protocol = module.params.get('protocol') + type = module.params.get('type') + timeout = int(module.params.get('timeout')) + wait = module.params.get('wait') + wait_timeout = int(module.params.get('wait_timeout')) + + try: + username = username or os.environ.get('RAX_USERNAME') + api_key = api_key or os.environ.get('RAX_API_KEY') + credentials = (credentials or + os.environ.get('RAX_CREDENTIALS') or + os.environ.get('RAX_CREDS_FILE')) + region = region or os.environ.get('RAX_REGION') + + except KeyError, e: + module.fail_json(msg='Unable to load %s' % e.message) + + try: + pyrax.set_setting("identity_type", "rackspace") + if api_key and username: + pyrax.set_credentials(username, api_key=api_key, region=region) + elif credentials: + credentials = os.path.expanduser(credentials) + pyrax.set_credential_file(credentials, region=region) + else: + raise Exception('No credentials supplied!') + except Exception, e: + module.fail_json(msg='%s' % e.message) + + cloud_load_balancer(module, state, name, meta, algorithm, port, protocol, type, timeout, wait, wait_timeout) + +# this is magic, see lib/ansible/module_common.py +#<> + +main() diff --git a/library/cloud/rax_clb_nodes b/library/cloud/rax_clb_nodes index 9b850e9c81..ed6f3badab 100644 --- a/library/cloud/rax_clb_nodes +++ b/library/cloud/rax_clb_nodes @@ -16,7 +16,7 @@ DOCUMENTATION = ''' --- -module: rax_clb +module: rax_clb_nodes short_description: add, modify and remove nodes from a Rackspace Cloud Load Balancer description: - Adds, modifies and removes nodes from a Rackspace Cloud Load Balancer