f59e832292
In order to simplify the workflow with the GCE modules, it's now possible to add the parameters and project name as arguments to the various GCE modules. The inventory plugin also returns the IP of the host in `ansible_ssh_host` so that you don't have to specify IPs into the inventory file. Some update to the documentation are also added. Closes #5583.
336 lines
12 KiB
Python
336 lines
12 KiB
Python
#!/usr/bin/python
|
|
# Copyright 2013 Google Inc.
|
|
#
|
|
# 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 <http://www.gnu.org/licenses/>.
|
|
|
|
DOCUMENTATION = '''
|
|
---
|
|
module: gce_lb
|
|
version_added: "1.5"
|
|
short_description: create/destroy GCE load-balancer resources
|
|
description:
|
|
- This module can create and destroy Google Compute Engine C(loadbalancer)
|
|
and C(httphealthcheck) resources. The primary LB resource is the
|
|
C(load_balancer) resource and the health check parameters are all
|
|
prefixed with I(httphealthcheck).
|
|
The full documentation for Google Compute Engine load balancing is at
|
|
U(https://developers.google.com/compute/docs/load-balancing/). However,
|
|
the ansible module simplifies the configuration by following the
|
|
libcloud model.
|
|
Full install/configuration instructions for the gce* modules can
|
|
be found in the comments of ansible/test/gce_tests.py.
|
|
options:
|
|
httphealthcheck_name:
|
|
description:
|
|
- the name identifier for the HTTP health check
|
|
required: false
|
|
default: null
|
|
httphealthcheck_port:
|
|
description:
|
|
- the TCP port to use for HTTP health checking
|
|
required: false
|
|
default: 80
|
|
httphealthcheck_path:
|
|
description:
|
|
- the url path to use for HTTP health checking
|
|
required: false
|
|
default: "/"
|
|
httphealthcheck_interval:
|
|
description:
|
|
- the duration in seconds between each health check request
|
|
required: false
|
|
default: 5
|
|
httphealthcheck_timeout:
|
|
description:
|
|
- the timeout in seconds before a request is considered a failed check
|
|
required: false
|
|
default: 5
|
|
httphealthcheck_unhealthy_count:
|
|
description:
|
|
- number of consecutive failed checks before marking a node unhealthy
|
|
required: false
|
|
default: 2
|
|
httphealthcheck_healthy_count:
|
|
description:
|
|
- number of consecutive successful checks before marking a node healthy
|
|
required: false
|
|
default: 2
|
|
httphealthcheck_host:
|
|
description:
|
|
- host header to pass through on HTTP check requests
|
|
required: false
|
|
default: null
|
|
name:
|
|
description:
|
|
- name of the load-balancer resource
|
|
required: false
|
|
default: null
|
|
protocol:
|
|
description:
|
|
- the protocol used for the load-balancer packet forwarding, tcp or udp
|
|
required: false
|
|
default: "tcp"
|
|
choices: ['tcp', 'udp']
|
|
region:
|
|
description:
|
|
- the GCE region where the load-balancer is defined
|
|
required: false
|
|
choices: ["us-central1", "us-central2", "europe-west1"]
|
|
external_ip:
|
|
description:
|
|
- the external static IPv4 (or auto-assigned) address for the LB
|
|
required: false
|
|
default: null
|
|
port_range:
|
|
description:
|
|
- the port (range) to forward, e.g. 80 or 8000-8888 defaults to all ports
|
|
required: false
|
|
default: null
|
|
members:
|
|
description:
|
|
- a list of zone/nodename pairs, e.g ['us-central1-a/www-a', ...]
|
|
required: false
|
|
aliases: ['nodes']
|
|
state:
|
|
description:
|
|
- desired state of the LB
|
|
default: "present"
|
|
choices: ["active", "present", "absent", "deleted"]
|
|
aliases: []
|
|
service_account_email:
|
|
version_added: 1.5.1
|
|
description:
|
|
- service account email
|
|
required: false
|
|
default: null
|
|
aliases: []
|
|
pem_file:
|
|
version_added: 1.5.1
|
|
description:
|
|
- path to the pem file associated with the service account email
|
|
required: false
|
|
default: null
|
|
aliases: []
|
|
project_id:
|
|
version_added: 1.5.1
|
|
description:
|
|
- your GCE project ID
|
|
required: false
|
|
default: null
|
|
aliases: []
|
|
|
|
requirements: [ "libcloud" ]
|
|
author: Eric Johnson <erjohnso@google.com>
|
|
'''
|
|
|
|
EXAMPLES = '''
|
|
# Simple example of creating a new LB, adding members, and a health check
|
|
- local_action:
|
|
module: gce_lb
|
|
name: testlb
|
|
region: us-central1
|
|
members: ["us-central1-a/www-a", "us-central1-b/www-b"]
|
|
httphealthcheck_name: hc
|
|
httphealthcheck_port: 80
|
|
httphealthcheck_path: "/up"
|
|
'''
|
|
|
|
import sys
|
|
|
|
|
|
try:
|
|
from libcloud.compute.types import Provider
|
|
from libcloud.compute.providers import get_driver
|
|
from libcloud.loadbalancer.types import Provider as Provider_lb
|
|
from libcloud.loadbalancer.providers import get_driver as get_driver_lb
|
|
from libcloud.common.google import GoogleBaseError, QuotaExceededError, \
|
|
ResourceExistsError, ResourceNotFoundError
|
|
_ = Provider.GCE
|
|
except ImportError:
|
|
print("failed=True " + \
|
|
"msg='libcloud with GCE support required for this module.'")
|
|
sys.exit(1)
|
|
|
|
|
|
def main():
|
|
module = AnsibleModule(
|
|
argument_spec = dict(
|
|
httphealthcheck_name = dict(),
|
|
httphealthcheck_port = dict(default=80),
|
|
httphealthcheck_path = dict(default='/'),
|
|
httphealthcheck_interval = dict(default=5),
|
|
httphealthcheck_timeout = dict(default=5),
|
|
httphealthcheck_unhealthy_count = dict(default=2),
|
|
httphealthcheck_healthy_count = dict(default=2),
|
|
httphealthcheck_host = dict(),
|
|
name = dict(),
|
|
protocol = dict(default='tcp'),
|
|
region = dict(),
|
|
external_ip = dict(),
|
|
port_range = dict(),
|
|
members = dict(type='list'),
|
|
state = dict(default='present'),
|
|
service_account_email = dict(),
|
|
pem_file = dict(),
|
|
project_id = dict(),
|
|
)
|
|
)
|
|
|
|
gce = gce_connect(module)
|
|
|
|
httphealthcheck_name = module.params.get('httphealthcheck_name')
|
|
httphealthcheck_port = module.params.get('httphealthcheck_port')
|
|
httphealthcheck_path = module.params.get('httphealthcheck_path')
|
|
httphealthcheck_interval = module.params.get('httphealthcheck_interval')
|
|
httphealthcheck_timeout = module.params.get('httphealthcheck_timeout')
|
|
httphealthcheck_unhealthy_count = \
|
|
module.params.get('httphealthcheck_unhealthy_count')
|
|
httphealthcheck_healthy_count = \
|
|
module.params.get('httphealthcheck_healthy_count')
|
|
httphealthcheck_host = module.params.get('httphealthcheck_host')
|
|
name = module.params.get('name')
|
|
protocol = module.params.get('protocol')
|
|
region = module.params.get('region')
|
|
external_ip = module.params.get('external_ip')
|
|
port_range = module.params.get('port_range')
|
|
members = module.params.get('members')
|
|
state = module.params.get('state')
|
|
|
|
try:
|
|
gcelb = get_driver_lb(Provider_lb.GCE)(gce_driver=gce)
|
|
gcelb.connection.user_agent_append("%s/%s" % (
|
|
USER_AGENT_PRODUCT, USER_AGENT_VERSION))
|
|
except Exception, e:
|
|
module.fail_json(msg=unexpected_error_msg(e), changed=False)
|
|
|
|
changed = False
|
|
json_output = {'name': name, 'state': state}
|
|
|
|
if not name and not httphealthcheck_name:
|
|
module.fail_json(msg='Nothing to do, please specify a "name" ' + \
|
|
'or "httphealthcheck_name" parameter', changed=False)
|
|
|
|
if state in ['active', 'present']:
|
|
# first, create the httphealthcheck if requested
|
|
hc = None
|
|
if httphealthcheck_name:
|
|
json_output['httphealthcheck_name'] = httphealthcheck_name
|
|
try:
|
|
hc = gcelb.ex_create_healthcheck(httphealthcheck_name,
|
|
host=httphealthcheck_host, path=httphealthcheck_path,
|
|
port=httphealthcheck_port,
|
|
interval=httphealthcheck_interval,
|
|
timeout=httphealthcheck_timeout,
|
|
unhealthy_threshold=httphealthcheck_unhealthy_count,
|
|
healthy_threshold=httphealthcheck_healthy_count)
|
|
changed = True
|
|
except ResourceExistsError:
|
|
hc = gce.ex_get_healthcheck(httphealthcheck_name)
|
|
except Exception, e:
|
|
module.fail_json(msg=unexpected_error_msg(e), changed=False)
|
|
|
|
if hc is not None:
|
|
json_output['httphealthcheck_host'] = hc.extra['host']
|
|
json_output['httphealthcheck_path'] = hc.path
|
|
json_output['httphealthcheck_port'] = hc.port
|
|
json_output['httphealthcheck_interval'] = hc.interval
|
|
json_output['httphealthcheck_timeout'] = hc.timeout
|
|
json_output['httphealthcheck_unhealthy_count'] = \
|
|
hc.unhealthy_threshold
|
|
json_output['httphealthcheck_healthy_count'] = \
|
|
hc.healthy_threshold
|
|
|
|
# create the forwarding rule (and target pool under the hood)
|
|
lb = None
|
|
if name:
|
|
if not region:
|
|
module.fail_json(msg='Missing required region name',
|
|
changed=False)
|
|
nodes = []
|
|
output_nodes = []
|
|
json_output['name'] = name
|
|
# members is a python list of 'zone/inst' strings
|
|
if members:
|
|
for node in members:
|
|
try:
|
|
zone, node_name = node.split('/')
|
|
nodes.append(gce.ex_get_node(node_name, zone))
|
|
output_nodes.append(node)
|
|
except:
|
|
# skip nodes that are badly formatted or don't exist
|
|
pass
|
|
try:
|
|
if hc is not None:
|
|
lb = gcelb.create_balancer(name, port_range, protocol,
|
|
None, nodes, ex_region=region, ex_healthchecks=[hc],
|
|
ex_address=external_ip)
|
|
else:
|
|
lb = gcelb.create_balancer(name, port_range, protocol,
|
|
None, nodes, ex_region=region, ex_address=external_ip)
|
|
changed = True
|
|
except ResourceExistsError:
|
|
lb = gcelb.get_balancer(name)
|
|
except Exception, e:
|
|
module.fail_json(msg=unexpected_error_msg(e), changed=False)
|
|
|
|
if lb is not None:
|
|
json_output['members'] = output_nodes
|
|
json_output['protocol'] = protocol
|
|
json_output['region'] = region
|
|
json_output['external_ip'] = lb.ip
|
|
json_output['port_range'] = lb.port
|
|
hc_names = []
|
|
if 'healthchecks' in lb.extra:
|
|
for hc in lb.extra['healthchecks']:
|
|
hc_names.append(hc.name)
|
|
json_output['httphealthchecks'] = hc_names
|
|
|
|
if state in ['absent', 'deleted']:
|
|
# first, delete the load balancer (forwarding rule and target pool)
|
|
# if specified.
|
|
if name:
|
|
json_output['name'] = name
|
|
try:
|
|
lb = gcelb.get_balancer(name)
|
|
gcelb.destroy_balancer(lb)
|
|
changed = True
|
|
except ResourceNotFoundError:
|
|
pass
|
|
except Exception, e:
|
|
module.fail_json(msg=unexpected_error_msg(e), changed=False)
|
|
|
|
# destroy the health check if specified
|
|
if httphealthcheck_name:
|
|
json_output['httphealthcheck_name'] = httphealthcheck_name
|
|
try:
|
|
hc = gce.ex_get_healthcheck(httphealthcheck_name)
|
|
gce.ex_destroy_healthcheck(hc)
|
|
changed = True
|
|
except ResourceNotFoundError:
|
|
pass
|
|
except Exception, e:
|
|
module.fail_json(msg=unexpected_error_msg(e), changed=False)
|
|
|
|
|
|
json_output['changed'] = changed
|
|
print json.dumps(json_output)
|
|
sys.exit(0)
|
|
|
|
# import module snippets
|
|
from ansible.module_utils.basic import *
|
|
from ansible.module_utils.gce import *
|
|
|
|
main()
|