Esempio n. 1
0
    def describe_changeset(self, change_set_id, stack_name, **kwargs):
        """
        Call Cloudformation to describe a changeset

        :param change_set_id: ID of the changeset
        :param stack_name: Name of the CloudFormation stack
        :return: dictionary of changes described in the changeset.
        """
        paginator = self._client.get_paginator("describe_change_set")
        response_iterator = paginator.paginate(ChangeSetName=change_set_id, StackName=stack_name)
        changes = {"Add": [], "Modify": [], "Remove": []}
        changes_showcase = {"Add": "+ Add", "Modify": "* Modify", "Remove": "- Delete"}
        changeset = False
        for item in response_iterator:
            cf_changes = item.get("Changes")
            for change in cf_changes:
                changeset = True
                resource_props = change.get("ResourceChange")
                action = resource_props.get("Action")
                changes[action].append(
                    {
                        "LogicalResourceId": resource_props.get("LogicalResourceId"),
                        "ResourceType": resource_props.get("ResourceType"),
                        "Replacement": "N/A"
                        if resource_props.get("Replacement") is None
                        else resource_props.get("Replacement"),
                    }
                )

        for k, v in changes.items():
            for value in v:
                row_color = self.deploy_color.get_changeset_action_color(action=k)
                pprint_columns(
                    columns=[
                        changes_showcase.get(k, k),
                        value["LogicalResourceId"],
                        value["ResourceType"],
                        value["Replacement"],
                    ],
                    width=kwargs["width"],
                    margin=kwargs["margin"],
                    format_string=DESCRIBE_CHANGESET_FORMAT_STRING,
                    format_args=kwargs["format_args"],
                    columns_dict=DESCRIBE_CHANGESET_DEFAULT_ARGS.copy(),
                    color=row_color,
                )

        if not changeset:
            # There can be cases where there are no changes,
            # but could be an an addition of a SNS notification topic.
            pprint_columns(
                columns=["-", "-", "-", "-"],
                width=kwargs["width"],
                margin=kwargs["margin"],
                format_string=DESCRIBE_CHANGESET_FORMAT_STRING,
                format_args=kwargs["format_args"],
                columns_dict=DESCRIBE_CHANGESET_DEFAULT_ARGS.copy(),
            )

        return changes
Esempio n. 2
0
 def to_be_decorated(*args, **kwargs):
     pprint_columns(
         columns=["A", "B", "C"],
         width=kwargs["width"],
         margin=kwargs["margin"],
         format_args=kwargs["format_args"],
         format_string=TABLE_FORMAT_STRING,
         columns_dict=TABLE_FORMAT_ARGS.copy(),
     )
Esempio n. 3
0
 def _stack_outputs(self, stack_outputs, **kwargs):
     for output in stack_outputs:
         pprint_columns(
             columns=[" - ".join([output["OutputKey"], output.get("Description", "")]), output["OutputValue"]],
             width=kwargs["width"],
             margin=kwargs["margin"],
             format_string=OUTPUTS_FORMAT_STRING,
             format_args=kwargs["format_args"],
             columns_dict=OUTPUTS_DEFAULTS_ARGS.copy(),
         )
Esempio n. 4
0
    def describe_stack_events(self, stack_name, time_stamp_marker, **kwargs):
        """
        Calls CloudFormation to get current stack events
        :param stack_name: Name or ID of the stack
        :param time_stamp_marker: last event time on the stack to start streaming events from.
        :return:
        """

        stack_change_in_progress = True
        events = set()
        retry_attempts = 0

        while stack_change_in_progress and retry_attempts <= self.max_attempts:
            try:

                # Only sleep if there have been no retry_attempts
                time.sleep(self.client_sleep if retry_attempts == 0 else 0)
                describe_stacks_resp = self._client.describe_stacks(
                    StackName=stack_name)
                paginator = self._client.get_paginator("describe_stack_events")
                response_iterator = paginator.paginate(StackName=stack_name)
                stack_status = describe_stacks_resp["Stacks"][0]["StackStatus"]
                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"])
                            row_color = self.deploy_color.get_stack_events_status_color(
                                status=event["ResourceStatus"])
                            pprint_columns(
                                columns=[
                                    event["ResourceStatus"],
                                    event["ResourceType"],
                                    event["LogicalResourceId"],
                                    event.get("ResourceStatusReason", "-"),
                                ],
                                width=kwargs["width"],
                                margin=kwargs["margin"],
                                format_string=
                                DESCRIBE_STACK_EVENTS_FORMAT_STRING,
                                format_args=kwargs["format_args"],
                                columns_dict=DESCRIBE_STACK_EVENTS_DEFAULT_ARGS
                                .copy(),
                                color=row_color,
                            )

                if self._check_stack_complete(stack_status):
                    stack_change_in_progress = False
                    break
            except botocore.exceptions.ClientError:
                retry_attempts = retry_attempts + 1
                if retry_attempts > self.max_attempts:
                    raise
                # Sleep in exponential backoff mode
                time.sleep(math.pow(self.backoff, retry_attempts))
Esempio n. 5
0
 def _display_stack_outputs(stack_outputs: List[Dict], **kwargs) -> None:
     for counter, output in enumerate(stack_outputs):
         for k, v in [
             ("Key", output.get("OutputKey")),
             ("Description", output.get("Description", "-")),
             ("Value", output.get("OutputValue")),
         ]:
             pprint_columns(
                 columns=["{k:<{0}}{v:<{0}}".format(MIN_OFFSET, k=k, v=v)],
                 width=kwargs["width"],
                 margin=kwargs["margin"],
                 format_string=OUTPUTS_FORMAT_STRING,
                 format_args=kwargs["format_args"],
                 columns_dict=OUTPUTS_DEFAULTS_ARGS.copy(),
                 color="green",
                 replace_whitespace=False,
                 break_long_words=False,
                 drop_whitespace=False,
             )
         newline_per_item(stack_outputs, counter)
Esempio n. 6
0
    def describe_stack_events(self, stack_name, time_stamp_marker, **kwargs):
        """
        Calls CloudFormation to get current stack events
        :param stack_name: Name or ID of the stack
        :param time_stamp_marker: last event time on the stack to start streaming events from.
        :param kwargs: Other arguments to pass to pprint_columns()
        """

        stack_change_in_progress = True
        events = set()
        retry_attempts = 0

        while stack_change_in_progress and retry_attempts <= self.max_attempts:
            try:
                # Only sleep if there have been no retry_attempts
                time.sleep(0 if retry_attempts else self.client_sleep)
                describe_stacks_resp = self._client.describe_stacks(
                    StackName=stack_name)
                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=[
                                    event["ResourceStatus"],
                                    event["ResourceType"],
                                    event["LogicalResourceId"],
                                    event.get("ResourceStatusReason", "-"),
                                ],
                                width=kwargs["width"],
                                margin=kwargs["margin"],
                                format_string=
                                DESCRIBE_STACK_EVENTS_FORMAT_STRING,
                                format_args=kwargs["format_args"],
                                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
                    break
            except botocore.exceptions.ClientError as ex:
                retry_attempts = retry_attempts + 1
                if retry_attempts > self.max_attempts:
                    LOG.error("Describing stack events for %s failed: %s",
                              stack_name, str(ex))
                    return
                # Sleep in exponential backoff mode
                time.sleep(math.pow(self.backoff, retry_attempts))