Esempio n. 1
0
def test_validate():
    s = Stack(name='teststack')

    aws_env = AWSEnv(regions=['us-east-1'])
    with default_region('us-east-1'):
        cfn_client = aws_env.client('cloudformation', region='us-east-1')

        stubber = Stubber(cfn_client)
        stubber.add_response('validate_template', {}, {'TemplateBody': ANY})
        stubber.add_response('validate_template', {}, {'TemplateURL': ANY})
        with stubber:
            s.validate()
            s.validate(url='noprotocol://nothing')
Esempio n. 2
0
def test_validate():
    s = Stack(name="teststack")

    aws_env = AWSEnv(regions=["us-east-1"])
    with default_region("us-east-1"):
        cfn_client = aws_env.client("cloudformation", region="us-east-1")

        stubber = Stubber(cfn_client)
        stubber.add_response("validate_template", {}, {"TemplateBody": ANY})
        stubber.add_response("validate_template", {}, {"TemplateURL": ANY})
        with stubber:
            s.validate()
            s.validate(url="noprotocol://nothing")
Esempio n. 3
0
    def execute_for_stack(self, stack: Stack) -> int:
        """Execute application for a given stack and return exit status.

        :param Stack: the stack on which the application executes
        """
        assert self.args is not None
        try:
            if self.args.command in ("push", "update"):

                # Synchronize resources to the S3 bucket
                s3 = self.aws_env.client("s3")
                with tempfile.TemporaryDirectory() as tempd:
                    # Push data associated with CFNMain and then all data
                    # related to the stack
                    self.create_data_dir(root_dir=tempd)
                    stack.create_data_dir(root_dir=tempd)

                    if self.s3_data_key is not None:

                        # synchronize data to the bucket before creating the stack
                        for f in find(tempd):
                            with open(f, "rb") as fd:
                                subkey = os.path.relpath(f, tempd).replace(
                                    "\\", "/")
                                logging.info(
                                    "Upload %s to %s:%s%s",
                                    subkey,
                                    self.s3_bucket,
                                    self.s3_data_key,
                                    subkey,
                                )
                                s3.put_object(
                                    Bucket=self.s3_bucket,
                                    Body=fd,
                                    ServerSideEncryption="AES256",
                                    Key=self.s3_data_key + subkey,
                                )

                if self.s3_template_key is not None:
                    logging.info("Upload template to %s:%s", self.s3_bucket,
                                 self.s3_template_key)
                    s3.put_object(
                        Bucket=self.s3_bucket,
                        Body=stack.body.encode("utf-8"),
                        ServerSideEncryption="AES256",
                        Key=self.s3_template_key,
                    )

                logging.info("Validate template for stack %s" % stack.name)
                try:
                    stack.validate(url=self.s3_template_url)
                except Exception:
                    logging.error("Invalid cloud formation template")
                    logging.error(stack.body)
                    raise

                if stack.exists():
                    changeset_name = "changeset%s" % int(time.time())
                    logging.info("Push changeset: %s" % changeset_name)
                    stack.create_change_set(changeset_name,
                                            url=self.s3_template_url)
                    result = stack.describe_change_set(changeset_name)
                    while result["Status"] in ("CREATE_PENDING",
                                               "CREATE_IN_PROGRESS"):
                        time.sleep(1.0)
                        result = stack.describe_change_set(changeset_name)

                    if result["Status"] == "FAILED":
                        change_executed = False
                        if ("The submitted information didn't contain changes"
                                in result["StatusReason"]):
                            logging.warning(result["StatusReason"])
                            change_executed = True
                        else:
                            logging.error(result["StatusReason"])

                        stack.delete_change_set(changeset_name)
                        if not change_executed:
                            return 1
                    else:
                        for el in result["Changes"]:
                            if "ResourceChange" not in el:
                                continue
                            logging.info(
                                "%-8s %-32s: (replacement:%s)",
                                el["ResourceChange"].get("Action"),
                                el["ResourceChange"].get("LogicalResourceId"),
                                el["ResourceChange"].get("Replacement", "n/a"),
                            )

                        if self.args.apply_changeset:
                            ask = input("Apply change (y/N): ")
                            if ask[0] in "Yy":
                                stack.execute_change_set(
                                    changeset_name=changeset_name,
                                    wait=self.args.wait_stack_creation,
                                )
                        return 0
                else:
                    logging.info("Create new stack")
                    stack.create(url=self.s3_template_url,
                                 wait=self.args.wait_stack_creation)
            elif self.args.command == "show":
                print(stack.body)
            elif self.args.command == "protect":
                # Enable termination protection
                result = stack.enable_termination_protection()

                if self.stack_policy_body is not None:
                    stack.set_stack_policy(self.stack_policy_body)
                else:
                    print("No stack policy to set")
            elif self.args.command == "show-cfn-policy":
                try:
                    print(
                        json.dumps(
                            stack.cfn_policy_document().
                            as_dict,  # type: ignore
                            indent=2,
                        ))
                except AttributeError as attr_e:
                    print(
                        f"command supported only with troposphere stacks: {attr_e}"
                    )
            elif self.args.command == "delete":
                stack.delete(wait=self.args.wait_stack_creation)

            return 0
        except botocore.exceptions.ClientError as e:
            logging.error(str(e))
            return 1