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

show cloudformation events while creating and deleting the stack #70

Merged
merged 4 commits into from
Apr 20, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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, []))