2013-04-30 05:40:17 +02:00
|
|
|
#!/usr/bin/python
|
|
|
|
# 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: ec2_elb
|
2013-04-30 15:00:10 +02:00
|
|
|
short_description: De-registers or registers instances from EC2 ELB(s)
|
2013-04-30 05:40:17 +02:00
|
|
|
description:
|
2013-04-30 15:00:10 +02:00
|
|
|
- This module de-registers or registers an AWS EC2 instance from the ELB(s)
|
2013-04-30 05:40:17 +02:00
|
|
|
that it belongs to.
|
2013-05-03 12:55:06 +02:00
|
|
|
- Returns fact "ec2_elbs" which is a list of elbs attached to the instance
|
|
|
|
if state=absent is passed as an argument.
|
2013-04-30 15:03:31 +02:00
|
|
|
- Will be marked changed when called only if there are ELBs found to operate on.
|
2013-04-30 05:40:17 +02:00
|
|
|
version_added: "1.2"
|
2013-08-01 22:50:01 +02:00
|
|
|
requirements: [ "boto", "urllib2" ]
|
2013-04-30 05:40:17 +02:00
|
|
|
author: John Jarvis
|
|
|
|
options:
|
2013-05-03 03:29:36 +02:00
|
|
|
state:
|
2013-04-30 05:40:17 +02:00
|
|
|
description:
|
|
|
|
- register or deregister the instance
|
|
|
|
required: true
|
|
|
|
|
|
|
|
instance_id:
|
|
|
|
description:
|
|
|
|
- EC2 Instance ID
|
2013-04-30 15:00:10 +02:00
|
|
|
required: true
|
2013-04-30 05:40:17 +02:00
|
|
|
|
2013-05-03 03:29:36 +02:00
|
|
|
ec2_elbs:
|
2013-04-30 05:40:17 +02:00
|
|
|
description:
|
2013-05-03 12:55:06 +02:00
|
|
|
- List of ELB names, required for registration. The ec2_elbs fact should be used if there was a previous de-register.
|
2013-04-30 05:40:17 +02:00
|
|
|
required: false
|
|
|
|
default: None
|
|
|
|
ec2_secret_key:
|
|
|
|
description:
|
|
|
|
- AWS Secret API key
|
|
|
|
required: false
|
|
|
|
default: None
|
|
|
|
ec2_access_key:
|
|
|
|
description:
|
|
|
|
- AWS Access API key
|
|
|
|
required: false
|
|
|
|
default: None
|
2013-08-01 22:50:01 +02:00
|
|
|
ec2_region:
|
|
|
|
description:
|
|
|
|
- AWS region of your load balancer. If not set then the region in which
|
|
|
|
this module is running will be used.
|
|
|
|
required: false
|
2013-04-30 05:40:17 +02:00
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
EXAMPLES = """
|
|
|
|
# basic pre_task and post_task example
|
|
|
|
pre_tasks:
|
|
|
|
- name: Gathering ec2 facts
|
|
|
|
ec2_facts:
|
|
|
|
- name: Instance De-register
|
|
|
|
local_action: ec2_elb
|
|
|
|
args:
|
|
|
|
instance_id: "{{ ansible_ec2_instance_id }}"
|
2013-05-03 03:29:36 +02:00
|
|
|
state: 'absent'
|
2013-04-30 05:40:17 +02:00
|
|
|
roles:
|
|
|
|
- myrole
|
|
|
|
post_tasks:
|
|
|
|
- name: Instance Register
|
|
|
|
local_action: ec2_elb
|
|
|
|
args:
|
|
|
|
instance_id: "{{ ansible_ec2_instance_id }}"
|
2013-05-03 03:29:36 +02:00
|
|
|
ec2_elbs: "{{ ec2_elbs }}"
|
|
|
|
state: 'present'
|
2013-04-30 05:40:17 +02:00
|
|
|
"""
|
|
|
|
|
|
|
|
import time
|
|
|
|
import sys
|
|
|
|
import os
|
|
|
|
|
2013-08-01 22:50:01 +02:00
|
|
|
AWS_REGIONS = ['ap-northeast-1',
|
|
|
|
'ap-southeast-1',
|
|
|
|
'ap-southeast-2',
|
|
|
|
'eu-west-1',
|
|
|
|
'sa-east-1',
|
|
|
|
'us-east-1',
|
|
|
|
'us-west-1',
|
|
|
|
'us-west-2']
|
|
|
|
|
2013-04-30 05:40:17 +02:00
|
|
|
try:
|
|
|
|
import boto
|
2013-08-01 22:50:01 +02:00
|
|
|
import boto.ec2.elb
|
|
|
|
from boto.regioninfo import RegionInfo
|
2013-04-30 05:40:17 +02:00
|
|
|
except ImportError:
|
|
|
|
print "failed=True msg='boto required for this module'"
|
|
|
|
sys.exit(1)
|
|
|
|
|
2013-08-01 22:50:01 +02:00
|
|
|
try:
|
|
|
|
import urllib2
|
|
|
|
except ImportError:
|
|
|
|
print "failed=True msg='urllib2 required for this module'"
|
|
|
|
sys.exit(1)
|
2013-04-30 05:40:17 +02:00
|
|
|
|
|
|
|
class ElbManager:
|
2013-04-30 15:00:10 +02:00
|
|
|
"""Handles EC2 instance ELB registration and de-registration"""
|
2013-04-30 05:40:17 +02:00
|
|
|
|
2013-05-03 03:29:36 +02:00
|
|
|
def __init__(self, module, instance_id=None, ec2_elbs=None,
|
2013-08-01 22:50:01 +02:00
|
|
|
ec2_access_key=None, ec2_secret_key=None, ec2_region=None):
|
2013-04-30 05:40:17 +02:00
|
|
|
self.ec2_access_key = ec2_access_key
|
|
|
|
self.ec2_secret_key = ec2_secret_key
|
|
|
|
self.module = module
|
|
|
|
self.instance_id = instance_id
|
2013-08-01 22:50:01 +02:00
|
|
|
self.ec2_region = ec2_region
|
2013-05-03 03:29:36 +02:00
|
|
|
self.lbs = self._get_instance_lbs(ec2_elbs)
|
2013-08-01 22:50:01 +02:00
|
|
|
|
2013-04-30 15:00:10 +02:00
|
|
|
# if there are no ELBs to operate on
|
|
|
|
# there will be no changes made
|
|
|
|
if len(self.lbs) > 0:
|
|
|
|
self.changed = True
|
|
|
|
else:
|
|
|
|
self.changed = False
|
2013-04-30 05:40:17 +02:00
|
|
|
|
|
|
|
def deregister(self):
|
2013-04-30 15:00:10 +02:00
|
|
|
"""De-register the instance from all ELBs and wait for the ELB
|
2013-04-30 05:40:17 +02:00
|
|
|
to report it out-of-service"""
|
|
|
|
|
|
|
|
for lb in self.lbs:
|
|
|
|
lb.deregister_instances([self.instance_id])
|
|
|
|
self._await_elb_instance_state(lb, 'OutOfService')
|
|
|
|
|
|
|
|
def register(self):
|
|
|
|
"""Register the instance for all ELBs and wait for the ELB
|
|
|
|
to report the instance in-service"""
|
|
|
|
|
|
|
|
for lb in self.lbs:
|
|
|
|
lb.register_instances([self.instance_id])
|
|
|
|
self._await_elb_instance_state(lb, 'InService')
|
|
|
|
|
2013-08-01 22:50:01 +02:00
|
|
|
def exists(self, lbtest):
|
|
|
|
""" Verify that the named ELB actually exists """
|
|
|
|
|
|
|
|
found = False
|
|
|
|
for lb in self.lbs:
|
|
|
|
if lb.name == lbtest:
|
|
|
|
found=True
|
|
|
|
break
|
|
|
|
return found
|
|
|
|
|
|
|
|
|
2013-04-30 05:40:17 +02:00
|
|
|
def _await_elb_instance_state(self, lb, awaited_state):
|
|
|
|
"""Wait for an ELB to change state
|
|
|
|
lb: load balancer
|
|
|
|
awaited_state : state to poll for (string)"""
|
|
|
|
|
|
|
|
while True:
|
|
|
|
state = lb.get_instance_health([self.instance_id])[0].state
|
|
|
|
if state == awaited_state:
|
|
|
|
break
|
|
|
|
else:
|
|
|
|
time.sleep(1)
|
|
|
|
|
2013-05-03 03:29:36 +02:00
|
|
|
def _get_instance_lbs(self, ec2_elbs=None):
|
2013-05-03 12:55:06 +02:00
|
|
|
"""Returns a list of ELBs attached to self.instance_id
|
|
|
|
ec2_elbs: an optional list of elb names that will be used
|
|
|
|
for elb lookup instead of returning what elbs
|
|
|
|
are attached to self.instance_id"""
|
2013-04-30 05:40:17 +02:00
|
|
|
|
|
|
|
try:
|
2013-08-01 22:50:01 +02:00
|
|
|
endpoint="elasticloadbalancing.%s.amazonaws.com" % self.ec2_region
|
|
|
|
connect_region = RegionInfo(name=self.ec2_region, endpoint=endpoint)
|
|
|
|
elb = boto.ec2.elb.ELBConnection(self.ec2_access_key, self.ec2_secret_key, region=connect_region)
|
2013-04-30 05:40:17 +02:00
|
|
|
except boto.exception.NoAuthHandlerFound, e:
|
|
|
|
self.module.fail_json(msg=str(e))
|
2013-08-01 22:50:01 +02:00
|
|
|
|
2013-04-30 05:40:17 +02:00
|
|
|
elbs = elb.get_all_load_balancers()
|
|
|
|
|
2013-05-03 03:29:36 +02:00
|
|
|
if ec2_elbs:
|
|
|
|
lbs = sorted(lb for lb in elbs if lb.name in ec2_elbs)
|
2013-04-30 05:40:17 +02:00
|
|
|
else:
|
|
|
|
lbs = []
|
|
|
|
for lb in elbs:
|
|
|
|
for info in lb.instances:
|
|
|
|
if self.instance_id == info.id:
|
|
|
|
lbs.append(lb)
|
|
|
|
return lbs
|
|
|
|
|
|
|
|
|
|
|
|
def main():
|
|
|
|
|
|
|
|
module = AnsibleModule(
|
|
|
|
argument_spec=dict(
|
2013-05-03 03:29:36 +02:00
|
|
|
state={'required': True,
|
|
|
|
'choices': ['present', 'absent']},
|
2013-04-30 05:40:17 +02:00
|
|
|
instance_id={'required': True},
|
2013-05-03 03:29:36 +02:00
|
|
|
ec2_elbs={'default': None, 'required': False},
|
2013-04-30 05:40:17 +02:00
|
|
|
ec2_secret_key={'default': None, 'aliases': ['EC2_SECRET_KEY']},
|
2013-08-01 22:50:01 +02:00
|
|
|
ec2_access_key={'default': None, 'aliases': ['EC2_ACCESS_KEY']},
|
|
|
|
ec2_region={'default': None, 'required': False, 'choices':AWS_REGIONS}
|
2013-04-30 05:40:17 +02:00
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
ec2_secret_key = module.params['ec2_secret_key']
|
|
|
|
ec2_access_key = module.params['ec2_access_key']
|
2013-05-03 03:29:36 +02:00
|
|
|
ec2_elbs = module.params['ec2_elbs']
|
2013-08-01 22:50:01 +02:00
|
|
|
ec2_region = module.params['ec2_region']
|
2013-04-30 05:40:17 +02:00
|
|
|
|
2013-05-03 12:55:06 +02:00
|
|
|
if module.params['state'] == 'present' and 'ec2_elbs' not in module.params:
|
2013-04-30 05:40:17 +02:00
|
|
|
module.fail_json(msg="ELBs are required for registration")
|
|
|
|
|
|
|
|
if not ec2_secret_key and 'EC2_SECRET_KEY' in os.environ:
|
|
|
|
ec2_secret_key = os.environ['EC2_SECRET_KEY']
|
|
|
|
if not ec2_access_key and 'EC2_ACCESS_KEY' in os.environ:
|
|
|
|
ec2_access_key = os.environ['EC2_ACCESS_KEY']
|
|
|
|
|
2013-08-01 22:50:01 +02:00
|
|
|
if not ec2_region and 'EC2_REGION' in os.environ:
|
|
|
|
ec2_region = os.environ['EC2_REGION']
|
|
|
|
|
|
|
|
if not ec2_region:
|
|
|
|
response = urllib2.urlopen('http://169.254.169.254/latest/meta-data/placement/availability-zone')
|
|
|
|
az = response.read()
|
|
|
|
for r in AWS_REGIONS:
|
|
|
|
if az.startswith(r):
|
|
|
|
ec2_region = r
|
|
|
|
break
|
|
|
|
|
|
|
|
if not ec2_region:
|
|
|
|
module.fail_json(msg = str("ec2_region not specified and unable to determine region from AWS."))
|
|
|
|
|
2013-04-30 05:40:17 +02:00
|
|
|
instance_id = module.params['instance_id']
|
2013-05-03 03:29:36 +02:00
|
|
|
elb_man = ElbManager(module, instance_id, ec2_elbs, ec2_access_key,
|
2013-08-01 22:50:01 +02:00
|
|
|
ec2_secret_key, ec2_region=ec2_region)
|
|
|
|
|
|
|
|
for elb in [ ec2_elbs ]:
|
|
|
|
if not elb_man.exists(elb):
|
|
|
|
str="ELB %s does not exist" % elb
|
|
|
|
module.fail_json(msg=str)
|
2013-04-30 05:40:17 +02:00
|
|
|
|
2013-05-03 12:55:06 +02:00
|
|
|
if module.params['state'] == 'present':
|
2013-04-30 05:40:17 +02:00
|
|
|
elb_man.register()
|
2013-05-03 12:55:06 +02:00
|
|
|
elif module.params['state'] == 'absent':
|
2013-04-30 05:40:17 +02:00
|
|
|
elb_man.deregister()
|
|
|
|
|
|
|
|
ansible_facts = {'ec2_elbs': [lb.name for lb in elb_man.lbs]}
|
2013-04-30 15:00:10 +02:00
|
|
|
ec2_facts_result = dict(changed=elb_man.changed, ansible_facts=ansible_facts)
|
2013-04-30 05:40:17 +02:00
|
|
|
|
|
|
|
module.exit_json(**ec2_facts_result)
|
|
|
|
|
|
|
|
# this is magic, see lib/ansible/module_common.py
|
|
|
|
#<<INCLUDE_ANSIBLE_MODULE_COMMON>>
|
|
|
|
|
|
|
|
main()
|