From e1951c0588a4e31340263404c4a94cdd02945c2c Mon Sep 17 00:00:00 2001 From: Shinji Matsumoto Date: Thu, 13 Feb 2020 01:10:44 +0900 Subject: [PATCH] feat(deploy): Efficient deploy log fetching (#1768) --- samcli/lib/deploy/deployer.py | 12 +++++ tests/unit/lib/deploy/test_deployer.py | 72 ++++++++++++++++++++++++++ 2 files changed, 84 insertions(+) diff --git a/samcli/lib/deploy/deployer.py b/samcli/lib/deploy/deployer.py index d5776574ac..6a5b3582a2 100644 --- a/samcli/lib/deploy/deployer.py +++ b/samcli/lib/deploy/deployer.py @@ -338,10 +338,14 @@ def describe_stack_events(self, stack_name, time_stamp_marker, **kwargs): paginator = self._client.get_paginator("describe_stack_events") response_iterator = paginator.paginate(StackName=stack_name) stack_status = describe_stacks_resp["Stacks"][0]["StackStatus"] + latest_time_stamp_marker = time_stamp_marker for event_items in response_iterator: for event in event_items["StackEvents"]: if event["EventId"] not in events and utc_to_timestamp(event["Timestamp"]) > time_stamp_marker: events.add(event["EventId"]) + latest_time_stamp_marker = max( + latest_time_stamp_marker, utc_to_timestamp(event["Timestamp"]) + ) row_color = self.deploy_color.get_stack_events_status_color(status=event["ResourceStatus"]) pprint_columns( columns=[ @@ -357,6 +361,14 @@ def describe_stack_events(self, stack_name, time_stamp_marker, **kwargs): columns_dict=DESCRIBE_STACK_EVENTS_DEFAULT_ARGS.copy(), color=row_color, ) + # Skip already shown old event entries + elif utc_to_timestamp(event["Timestamp"]) <= time_stamp_marker: + time_stamp_marker = latest_time_stamp_marker + break + else: # go to next loop if not break from inside loop + time_stamp_marker = latest_time_stamp_marker # update marker if all events are new + continue + break # reached here only if break from inner loop! if self._check_stack_complete(stack_status): stack_change_in_progress = False diff --git a/tests/unit/lib/deploy/test_deployer.py b/tests/unit/lib/deploy/test_deployer.py index 592585bc26..0cadbe5404 100644 --- a/tests/unit/lib/deploy/test_deployer.py +++ b/tests/unit/lib/deploy/test_deployer.py @@ -364,6 +364,78 @@ def test_describe_stack_events(self, patched_time): self.deployer.describe_stack_events("test", time.time() - 1) + @patch("time.sleep") + @patch("samcli.lib.deploy.deployer.pprint_columns") + def test_describe_stack_events_skip_old_event(self, patched_pprint_columns, patched_time): + current_timestamp = datetime.utcnow() + + self.deployer._client.describe_stacks = MagicMock( + side_effect=[ + {"Stacks": [{"StackStatus": "CREATE_IN_PROGRESS"}]}, + {"Stacks": [{"StackStatus": "CREATE_IN_PROGRESS"}]}, + {"Stacks": [{"StackStatus": "CREATE_COMPLETE_CLEANUP_IN_PROGRESS"}]}, + {"Stacks": [{"StackStatus": "CREATE_COMPLETE"}]}, + ] + ) + sample_events = [ + { + "StackEvents": [ + { + "EventId": str(uuid.uuid4()), + "Timestamp": current_timestamp, + "ResourceStatus": "CREATE_IN_PROGRESS", + "ResourceType": "s3", + "LogicalResourceId": "mybucket", + } + ] + }, + { + "StackEvents": [ + { + "EventId": str(uuid.uuid4()), + "Timestamp": current_timestamp + timedelta(seconds=10), + "ResourceStatus": "CREATE_IN_PROGRESS", + "ResourceType": "kms", + "LogicalResourceId": "mykms", + } + ] + }, + { + "StackEvents": [ + { + "EventId": str(uuid.uuid4()), + "Timestamp": current_timestamp + timedelta(seconds=20), + "ResourceStatus": "CREATE_COMPLETE", + "ResourceType": "s3", + "LogicalResourceId": "mybucket", + } + ] + }, + { + "StackEvents": [ + { + "EventId": str(uuid.uuid4()), + "Timestamp": current_timestamp + timedelta(seconds=30), + "ResourceStatus": "CREATE_COMPLETE", + "ResourceType": "kms", + "LogicalResourceId": "mykms", + } + ] + }, + ] + invalid_event = {"StackEvents": [{}]} # if deployer() loop read this, KeyError would raise + self.deployer._client.get_paginator = MagicMock( + side_effect=[ + MockPaginator([sample_events[0]]), + MockPaginator([sample_events[1], sample_events[0], invalid_event]), + MockPaginator([sample_events[2], sample_events[1], invalid_event]), + MockPaginator([sample_events[3], sample_events[2], invalid_event]), + ] + ) + + self.deployer.describe_stack_events("test", time.time() - 1) + self.assertEqual(patched_pprint_columns.call_count, 4) + @patch("samcli.lib.deploy.deployer.math") @patch("time.sleep") def test_describe_stack_events_exceptions(self, patched_time, patched_math):