diff --git a/setup.py b/setup.py index 751145c..1c8f2ab 100644 --- a/setup.py +++ b/setup.py @@ -15,6 +15,8 @@ 'boto>=2.40.0', 'tabulate>=0.7.5', 'setuptools', + 'pytz', + 'tzlocal', ] tests_require = [ diff --git a/stacks/__about__.py b/stacks/__about__.py index 73cda9f..4d874e7 100644 --- a/stacks/__about__.py +++ b/stacks/__about__.py @@ -1,4 +1,4 @@ -__version__ = '0.4.0' +__version__ = '0.4.1' __licence__ = 'MIT' __url__ = 'https://stacks.tools' __maintainer__ = 'Vaidas Jablonskis' diff --git a/stacks/cf.py b/stacks/cf.py index aaf6e5a..3e93edd 100644 --- a/stacks/cf.py +++ b/stacks/cf.py @@ -12,6 +12,8 @@ import jinja2 import hashlib import boto +import pytz +import tzlocal from os import path from jinja2 import meta @@ -291,20 +293,20 @@ def sorted_events(events): return sorted(events, key=attrgetter('timestamp')) -def print_events(conn, stack_name, follow, lines=100, from_timestamp=0): +def print_events(conn, stack_name, follow, lines=100, from_dt=datetime.fromtimestamp(0, tz=pytz.UTC)): """Prints tabulated list of events""" events_display = [] seen_ids = set() next_token = None - from_timestamp = datetime.fromtimestamp(from_timestamp) while True: events, next_token = get_events(conn, stack_name, next_token) status = get_stack_status(conn, stack_name) if follow: - events_display = [(event.timestamp, event.resource_status, event.resource_type, - event.logical_resource_id, event.resource_status_reason) for event in events - if event.event_id not in seen_ids and event.timestamp >= from_timestamp] + normalize_events_timestamps(events) + events_display = [(ev.timestamp.astimezone(tzlocal.get_localzone()), ev.resource_status, ev.resource_type, + ev.logical_resource_id, ev.resource_status_reason) for ev in events + if ev.event_id not in seen_ids and ev.timestamp >= from_dt] if len(events_display) > 0: print(tabulate(events_display, tablefmt='plain'), flush=True) seen_ids |= set([event.event_id for event in events]) @@ -350,3 +352,8 @@ def stack_exists(conn, stack_name): if status == 'DELETE_COMPLETE' or status is None: return False return True + + +def normalize_events_timestamps(events): + for ev in events: + ev.timestamp = ev.timestamp.replace(tzinfo=pytz.UTC) diff --git a/stacks/main.py b/stacks/main.py index eda28b5..69fefe9 100755 --- a/stacks/main.py +++ b/stacks/main.py @@ -4,7 +4,8 @@ import sys import os import signal -from time import time +import pytz +from datetime import datetime import boto.ec2 import boto.vpc @@ -38,6 +39,7 @@ def main(): config_dir = vars(args).get('config_dir', None) env = vars(args).get('env', None) config = config_load(env, config_file, config_dir) + now = datetime.now(tz=pytz.UTC) if args.subcommand == 'config': print_config(config, args.property_name, output_format=args.output_format) @@ -132,19 +134,17 @@ def main(): if stack_status in FAILED_STACK_STATES + ROLLBACK_STACK_STATES: sys.exit(1) else: - from_timestamp = time() stack_name = cf.create_stack(cf_conn, args.name, args.template, config, update=True, dry=args.dry_run, create_on_update=args.create_on_update) if args.events_follow and not args.dry_run: - stack_status = cf.print_events(cf_conn, stack_name, args.events_follow, from_timestamp=from_timestamp) + stack_status = cf.print_events(cf_conn, stack_name, args.events_follow, from_dt=now) if stack_status in FAILED_STACK_STATES + ROLLBACK_STACK_STATES: sys.exit(1) if args.subcommand == 'delete': - from_timestamp = time() cf.delete_stack(cf_conn, args.name, region, profile, args.yes) if args.events_follow: - stack_status = cf.print_events(cf_conn, args.name, args.events_follow, from_timestamp=from_timestamp) + stack_status = cf.print_events(cf_conn, args.name, args.events_follow, from_dt=now) if stack_status in FAILED_STACK_STATES: sys.exit(1)