Skip to content
This repository has been archived by the owner on Jan 19, 2022. It is now read-only.

Commit

Permalink
Merge pull request #70 from ministryofjustice/show_events
Browse files Browse the repository at this point in the history
show cloudformation events while creating and deleting the stack
  • Loading branch information
pidah committed Apr 20, 2015
2 parents 583a4e3 + 54021e1 commit 62bdaee
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 12 deletions.
33 changes: 21 additions & 12 deletions bootstrap_cfn/fab_tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@
from fabric.api import env, task, sudo, put
from fabric.contrib.project import upload_project
from fabric.utils import abort
from fabric.colors import green, red, yellow

from bootstrap_cfn.config import ProjectConfig, ConfigParser
from bootstrap_cfn.cloudformation import Cloudformation
from bootstrap_cfn.ec2 import EC2
from bootstrap_cfn.iam import IAM

from bootstrap_cfn.utils import tail


# GLOBAL VARIABLES
Expand Down Expand Up @@ -112,6 +113,7 @@ def get_connection(klass):
_validate_fabric_env()
return klass(env.aws, env.aws_region)


@task
def cfn_delete(force=False):
if not force:
Expand All @@ -122,16 +124,22 @@ def cfn_delete(force=False):
cfn_config = get_config()
cfn = get_connection(Cloudformation)
cfn.delete(stack_name)
print "\n\nSTACK {0} DELETING...".format(stack_name)
print green("\nSTACK {0} DELETING...\n").format(stack_name)

if hasattr(env, 'blocking') and env.blocking.lower() == 'false':
print 'Running in non blocking mode. Exiting.'
sys.exit(0)

# Wait for stacks to delete
print 'Waiting for stack to delete.'
cfn.wait_for_stack_missing(stack_name)
print "Stack successfully deleted"

tail(cfn, stack_name)

if cfn.stack_missing(stack_name):
print green("Stack successfully deleted")
else:
print red("Stack deletion was unsuccessfull")

if 'ssl' in cfn_config.data:
iam = get_connection(IAM)
iam.delete_ssl_certificate(cfn_config.ssl(), stack_name)
Expand All @@ -148,21 +156,22 @@ def cfn_create():
iam = get_connection(IAM)
iam.upload_ssl_certificate(cfn_config.ssl(), stack_name)
# Useful for debug
# print cfn_config.process()
#print cfn_config.process()
# Inject security groups in stack template and create stacks.
stack = cfn.create(stack_name, cfn_config.process())
print "\n\nSTACK {0} CREATING...".format(stack_name)
try:
stack = cfn.create(stack_name, cfn_config.process())
except Exception as e:
abort(red("Failed to create: {error}".format(error=e.message)))

print green("\nSTACK {0} CREATING...\n").format(stack_name)

if hasattr(env, 'blocking') and env.blocking.lower() == 'false':
print 'Running in non blocking mode. Exiting.'
sys.exit(0)

# Wait for stacks to complete
print 'Waiting for stack to complete.'
cfn.wait_for_stack_done(stack)
print 'Stacks completed, checking results.'
tail(cfn, stack_name)
stack_evt = cfn.get_last_stack_event(stack)
print '{0}: {1}'.format(stack_evt.stack_name, stack_evt.resource_status)

if stack_evt.resource_status == 'CREATE_COMPLETE':
print 'Successfully built stack {0}.'.format(stack)
else:
Expand Down
57 changes: 57 additions & 0 deletions bootstrap_cfn/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import os

import bootstrap_cfn.errors as errors
from fabric.colors import green, red, yellow
from copy import deepcopy


Expand Down Expand Up @@ -53,6 +54,7 @@ def connect_to_aws(module, instance):
except boto.provider.ProfileNotFoundError as e:
raise errors.ProfileNotFoundError(instance.aws_profile_name)


def dict_merge(target, *args):
# Merge multiple dicts
if len(args) > 1:
Expand All @@ -70,3 +72,58 @@ def dict_merge(target, *args):
else:
target[k] = deepcopy(v)
return target


def tail(stack, stack_name):
"""Show and then tail the event log"""

def colorize(e):
if e.endswith("_IN_PROGRESS"):
return yellow(e)
elif e.endswith("_FAILED"):
return red(e)
elif e.endswith("_COMPLETE"):
return green(e)
else:
return e

def tail_print(e):
print("%s %s %s" % (colorize(e.resource_status).ljust(30), e.resource_type.ljust(50), e.event_id))

# First dump the full list of events in chronological order and keep
# track of the events we've seen already
seen = set()
initial_events = get_events(stack, stack_name)
for e in initial_events:
tail_print(e)
seen.add(e.event_id)

# Now keep looping through and dump the new events
while 1:
if stack.stack_missing(stack_name):
break
elif stack.stack_done(stack_name):
break
events = get_events(stack, stack_name)
for e in events:
if e.event_id not in seen:
tail_print(e)
seen.add(e.event_id)
time.sleep(2)


def get_events(stack, stack_name):
"""Get the events in batches and return in chronological order"""
next = None
event_list = []
while 1 and not stack.stack_missing(stack_name):
try:
events = stack.conn_cfn.describe_stack_events(stack_name, next)
except:
break
event_list.append(events)
if events.next_token is None:
break
next = events.next_token
time.sleep(1)
return reversed(sum(event_list, []))

0 comments on commit 62bdaee

Please sign in to comment.