Commit b0709a23 by John Jarvis

Implements simple rolling deploy logic.

Requires the latest ansible to use (you may need to remove and add it again if
you are in a virtualenv)

See `edxapp_rolling_example.yml`

A new module is necessary for ELB information since that is not
available in EC2 metadata (which is what ec2_facts fetches).

ec2_facts grabs the instance ids and other meta information
ec2_elb_facts fetches ELB information
elb_reg.py takes an elb and instance id and will either register or
deregister. (called as pre and post).

`Serial` should be set to the number of instances that you want to
operate on simultaneously, currently set to 1.
parent e0abca4e
# ansible-playbook -v --user=ubuntu edxapp_rolling_example.yml -i ./ec2.py --private-key=/path/to/deployment.pem --module-path /path/to/repo/modules
- hosts: tag_Group_anothermulti
serial: 1
vars_files:
- "vars/secure/edxapp_stage_vars.yml"
- "vars/secure/users.yml"
- "vars/secure/edxapp_stage_users.yml"
pre_tasks:
- name: Gathering ec2 facts
ec2_facts:
- name: Gathering ELB facts
local_action: ec2_elb_facts
- local_action: command util/elb_reg.py -e {{ ",".join(elbs[ansible_ec2_instance_id]) }} -i {{ ansible_ec2_instance_id }} deregister
roles:
- common
- nginx
- lms
post_tasks:
- local_action: command util/elb_reg.py -e {{ ",".join(elbs[ansible_ec2_instance_id]) }} -i {{ ansible_ec2_instance_id }} register
#!/usr/bin/python
# -*- coding: utf-8 -*-
# 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_facts
short_description: Creates a fact with instance to ELB mappings
version_added: "1.0"
options: {}
description:
- This module fetches data from AWS using the boto api and returns
a hash as a fact that maps instances to the ELB(s) that they belong to.
examples:
- code: ansible all -m ec2_elb_facts
description: Obtain ELB info using boto
requirements: [ "boto" ]
author: "John Jarvis <john@jarv.org>"
"""
try:
import boto
except ImportError:
print "failed=True msg='boto required for this module'"
sys.exit(1)
from collections import defaultdict
def get_elb_info(module):
try:
elb = boto.connect_elb()
except boto.exception.NoAuthHandlerFound, e:
module.fail_json(msg = str(e))
elbs = elb.get_all_load_balancers()
elb_info = defaultdict(set)
for lb in elbs:
for info in lb.instances:
elb_info[info.id].add(lb.name)
elb_info = {k: list(v) for k,v in elb_info.iteritems()}
return elb_info
def main():
module = AnsibleModule(argument_spec = dict())
elb_info = get_elb_info(module)
ec2_facts_result = dict(changed=False, ansible_facts={'elbs': elb_info})
module.exit_json(**ec2_facts_result)
# this is magic, see lib/ansible/module_common.py
#<<INCLUDE_ANSIBLE_MODULE_COMMON>>
main()
#!/usr/bin/env python
from argparse import ArgumentParser
import time
import boto
def await_elb_instance_state(lb, instance_id, awaited_state):
"""blocks until the ELB reports awaited_state
for instance_id.
lb = loadbalancer object
instance_id : instance_id (string)
awaited_state : state to poll for (string)"""
start_time = time.time()
while True:
state = lb.get_instance_health([instance_id])[0].state
if state == awaited_state:
print "Load Balancer {lb} is in awaited state " \
"{awaited_state}, proceeding.".format(
lb=lb.dns_name,
awaited_state=awaited_state)
break
else:
print "Checking again in 2 seconds. Elapsed time: {0}".format(
time.time() - start_time)
time.sleep(2)
def deregister():
"""Deregister the instance from all ELBs and wait for the ELB
to report them out-of-service"""
for lb in active_lbs:
lb.deregister_instances([args.instance])
await_elb_instance_state(lb, args.instance, 'OutOfService')
def register():
"""Register the instance for all ELBs and wait for the ELB
to report them in-service"""
for lb in active_lbs:
lb.register_instances([args.instance])
await_elb_instance_state(lb, args.instance, 'InService')
def parse_args():
parser = ArgumentParser()
subparsers = parser.add_subparsers(dest="sp_action")
subparsers.add_parser('register', help='register an instance')
subparsers.add_parser('deregister', help='deregister an instance')
parser.add_argument('-e', '--elbs', required=True,
help="Comma separated list of ELB names")
parser.add_argument('-i', '--instance', required=True,
help="Single instance to operate on")
return parser.parse_args()
if __name__ == '__main__':
args = parse_args()
elb = boto.connect_elb()
elbs = elb.get_all_load_balancers()
active_lbs = sorted(
lb
for lb in elbs
if lb.name in args.elbs.split(','))
print "ELB : " + str(args.elbs.split(','))
print "Instance: " + str(args.instance)
if args.sp_action == 'deregister':
print "Deregistering an instance"
deregister()
elif args.sp_action == 'register':
print "Registering an instance"
register()
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment