Example #1
0
 def test_create_stack_with_extra(self, mocked_args, mocked_set_args,
                                  mocked_execute, mocked_wait):
     mocked_args.return_value = {"StackName": "testing_stack"}
     create_stack(wait=True, extra=True)
     mocked_execute.assert_called_with(StackName="testing_stack")
     mocked_set_args.assert_called_with(search_from_root=False)
     mocked_wait.assert_called_once()
Example #2
0
    def test_local_creation(
        self,
        mocked_local,
        mocked_validate,
        mocked_input,
        mocked_execute,
        mocked_wait,
        mocked_process,
    ):

        mocked_input.return_value = "testing_stack"
        self.data_path = os.path.join(
            os.path.dirname(os.path.abspath(__file__)),
            "../data/cloudformation_template.yaml",
        )
        mocked_local.return_value = self.data_path
        create_stack(local_path=True, root=True, wait=True)

        mocked_local.assert_called_with(search_from_root=True,
                                        cloudformation=True)
        mocked_validate.assert_called_with("default",
                                           "us-east-1",
                                           local_path=self.data_path,
                                           no_print=True)
        mocked_execute.assert_called_with(
            Parameters=[],
            StackName="testing_stack",
            TemplateBody=ANY,
            cloudformation_action=ANY,
        )
        mocked_wait.assert_called_with("stack_create_complete",
                                       "Waiting for stack to be ready ...")

        mocked_local.reset_mock()
        create_stack(profile="root",
                     region="us-east-1",
                     local_path=self.data_path,
                     wait=True)
        mocked_local.assert_not_called()
        mocked_validate.assert_called_with("root",
                                           "us-east-1",
                                           local_path=self.data_path,
                                           no_print=True)
        mocked_execute.assert_called_with(
            Parameters=[],
            StackName="testing_stack",
            TemplateBody=ANY,
            cloudformation_action=ANY,
        )
        mocked_wait.assert_called_with("stack_create_complete",
                                       "Waiting for stack to be ready ...")
Example #3
0
def cloudformation(raw_args: List[Any]) -> None:
    """Parse arguments and direct traffic to handler, internal use only.

    The raw_args are the processed args through cli.py main function.
    It also already contains the user default args so no need to process
    default args anymore.

    :param raw_args: list of args to be parsed
    :type raw_args: list
    """
    parser = argparse.ArgumentParser(
        description="Perform operations and interact with aws CloudFormation.",
        prog="fzfaws cloudformation",
    )
    subparsers = parser.add_subparsers(dest="subparser_name")

    update_cmd = subparsers.add_parser(
        "update", description="Perform update on an existing stack."
    )
    update_cmd.add_argument(
        "-b",
        "--bucket",
        nargs=1,
        action="store",
        default=[],
        help="specify a s3 path (bucketName/filename or bucketName/path/ or bucketName/) and skip s3 bucket/path selection",
    )
    update_cmd.add_argument(
        "-v",
        "--version",
        nargs="?",
        action="store",
        default=False,
        help="choose a version of the template in s3 bucket",
    )
    update_cmd.add_argument(
        "-r",
        "--root",
        action="store_true",
        default=False,
        help="search local files from root",
    )
    update_cmd.add_argument(
        "-l",
        "--local",
        nargs="?",
        action="store",
        default=False,
        help="update the stack using template in local machine",
    )
    update_cmd.add_argument(
        "-x",
        "--replace",
        action="store_true",
        default=False,
        help="perform replacing update, replace the stack with a new template",
    )
    update_cmd.add_argument(
        "-w",
        "--wait",
        action="store_true",
        default=False,
        help="wait for stack to finish update",
    )
    update_cmd.add_argument(
        "-E",
        "--extra",
        action="store_true",
        default=False,
        help="configure extra settings during update stack (E.g.Tags, iam role, notification, policy etc)",
    )
    update_cmd.add_argument(
        "-P",
        "--profile",
        nargs="?",
        action="store",
        default=False,
        help="choose/specify a profile for the operation",
    )
    update_cmd.add_argument(
        "-R",
        "--region",
        nargs="?",
        action="store",
        default=False,
        help="choose/specify a region for the operation",
    )

    create_cmd = subparsers.add_parser("create", description="Create a new stack.")
    create_cmd.add_argument(
        "-b",
        "--bucket",
        nargs=1,
        action="store",
        default=[],
        help="specify a s3 path (bucketName/filename or bucketName/path/ or bucketName/) and skip s3 bucket/path selection",
    )
    create_cmd.add_argument(
        "-v",
        "--version",
        nargs="?",
        action="store",
        default=False,
        help="choose a version of the template in s3 bucket",
    )
    create_cmd.add_argument(
        "-r",
        "--root",
        action="store_true",
        default=False,
        help="search local files from root",
    )
    create_cmd.add_argument(
        "-l",
        "--local",
        nargs="?",
        action="store",
        default=False,
        help="create stack using template in local machine",
    )
    create_cmd.add_argument(
        "-w",
        "--wait",
        action="store_true",
        default=False,
        help="wait for the stack to finish create",
    )
    create_cmd.add_argument(
        "-E",
        "--extra",
        action="store_true",
        default=False,
        help="configure extra settings during create stack (E.g.Tags, iam role, notification, policy etc)",
    )
    create_cmd.add_argument(
        "-P",
        "--profile",
        nargs="?",
        action="store",
        default=False,
        help="choose/specify a profile for the operation",
    )
    create_cmd.add_argument(
        "-R",
        "--region",
        nargs="?",
        action="store",
        default=False,
        help="choose/specify a region for the operation",
    )

    delete_cmd = subparsers.add_parser(
        "delete", description="Delete an existing stack."
    )
    delete_cmd.add_argument(
        "-i",
        "--iam",
        nargs="?",
        action="store",
        default=False,
        help="choose/specify a iam arn that has the permission to delete the current stack",
    )
    delete_cmd.add_argument(
        "-w",
        "--wait",
        action="store_true",
        default=False,
        help="wait for the stack to be deleted",
    )
    delete_cmd.add_argument(
        "-P",
        "--profile",
        nargs="?",
        action="store",
        default=False,
        help="choose/specify a profile for the operation",
    )
    delete_cmd.add_argument(
        "-R",
        "--region",
        nargs="?",
        action="store",
        default=False,
        help="choose/specify a region for the operation",
    )

    ls_cmd = subparsers.add_parser(
        "ls", description="Display infomation of the selcted stack."
    )
    ls_cmd.add_argument(
        "-r",
        "--resource",
        action="store_true",
        default=False,
        help="display information on stack resources",
    )
    ls_cmd.add_argument(
        "-P",
        "--profile",
        nargs="?",
        action="store",
        default=False,
        help="choose/specify a profile for the operation",
    )
    ls_cmd.add_argument(
        "-R",
        "--region",
        nargs="?",
        action="store",
        default=False,
        help="choose/specify a region for the operation",
    )
    ls_cmd.add_argument(
        "--tag",
        action="store_true",
        default=False,
        help="display tag of the selected stack",
    )
    ls_cmd.add_argument(
        "--arn",
        action="store_true",
        default=False,
        help="display arn of the selected stack",
    )
    ls_cmd.add_argument(
        "--name",
        action="store_true",
        default=False,
        help="display name of the selected stack",
    )
    ls_cmd.add_argument(
        "--type",
        action="store_true",
        default=False,
        help="display the type of the selected stack resource",
    )

    drift_cmd = subparsers.add_parser(
        "drift", description="Detect drift on stack/resources."
    )
    drift_cmd.add_argument(
        "-i",
        "--info",
        action="store_true",
        default=False,
        help="check the current drift status",
    )
    drift_cmd.add_argument(
        "-s",
        "--select",
        action="store_true",
        default=False,
        help="select individual resources to detect drift",
    )
    drift_cmd.add_argument(
        "-w",
        "--wait",
        action="store_true",
        default=False,
        help="wait for the drift detection result",
    )
    drift_cmd.add_argument(
        "-P",
        "--profile",
        nargs="?",
        action="store",
        default=False,
        help="choose/specify a profile for the operation",
    )
    drift_cmd.add_argument(
        "-R",
        "--region",
        nargs="?",
        action="store",
        default=False,
        help="choose/specify a region for the operation",
    )

    changeset_cmd = subparsers.add_parser(
        "changeset", description="Create a change set for the selected stack."
    )
    changeset_cmd.add_argument(
        "-b",
        "--bucket",
        nargs=1,
        action="store",
        default=[],
        help="specify a s3 path (bucketName/filename or bucketName/path/ or bucketName/) and skip s3 bucket/path selection",
    )
    changeset_cmd.add_argument(
        "-v",
        "--version",
        nargs="?",
        action="store",
        default=False,
        help="choose a version of the template in s3 bucket",
    )
    changeset_cmd.add_argument(
        "-r",
        "--root",
        action="store_true",
        default=False,
        help="search local files from root",
    )
    changeset_cmd.add_argument(
        "-l",
        "--local",
        action="store_true",
        default=False,
        help="create the changeset using template in local machine",
    )
    changeset_cmd.add_argument(
        "-w",
        "--wait",
        action="store_true",
        default=False,
        help="wait for the changeset to finish create",
    )
    changeset_cmd.add_argument(
        "-x",
        "--replace",
        action="store_true",
        default=False,
        help="perform replacing changeset, replace the current template with a new template and create the changeset",
    )
    changeset_cmd.add_argument(
        "-i", "--info", action="store_true", help="view the result of the changeset"
    )
    changeset_cmd.add_argument(
        "-e",
        "--execute",
        action="store_true",
        help="execute update based on the selected changeset",
    )
    changeset_cmd.add_argument(
        "-d", "--delete", action="store_true", help="delete the selected changeset"
    )
    changeset_cmd.add_argument(
        "-E",
        "--extra",
        action="store_true",
        default=False,
        help="configure extra settings during creating a changeset (E.g.Tags, iam role, notification, policy etc)",
    )
    changeset_cmd.add_argument(
        "-P",
        "--profile",
        nargs="?",
        action="store",
        default=False,
        help="choose/specify a profile for the operation",
    )
    changeset_cmd.add_argument(
        "-R",
        "--region",
        nargs="?",
        action="store",
        default=False,
        help="choose/specify a region for the operation",
    )

    validate_cmd = subparsers.add_parser(
        "validate",
        description="Validate the selected template.",
    )
    validate_cmd.add_argument(
        "-b",
        "--bucket",
        nargs=1,
        action="store",
        default=[],
        help="specify a s3 path (bucketName/filename or bucketName/path/ or bucketName/) and skip s3 bucket/path selection",
    )
    validate_cmd.add_argument(
        "-l",
        "--local",
        nargs="?",
        action="store",
        default=False,
        help="validate template in local machine",
    )
    validate_cmd.add_argument(
        "-r",
        "--root",
        action="store_true",
        default=False,
        help="search files from root",
    )
    validate_cmd.add_argument(
        "-v",
        "--version",
        nargs="?",
        default=False,
        help="choose a version of the template in s3 bucket",
    )
    validate_cmd.add_argument(
        "-P",
        "--profile",
        nargs="?",
        action="store",
        default=False,
        help="choose/specify a profile for the operation",
    )
    validate_cmd.add_argument(
        "-R",
        "--region",
        nargs="?",
        action="store",
        default=False,
        help="choose/specify a region for the operation",
    )
    args = parser.parse_args(raw_args)

    # if no argument provided, display help message through fzf
    if not raw_args:
        available_commands = [
            "update",
            "create",
            "delete",
            "ls",
            "drift",
            "changeset",
            "validate",
        ]
        fzf = Pyfzf()
        for command in available_commands:
            fzf.append_fzf("%s\n" % command)
        selected_command = fzf.execute_fzf(
            empty_allow=True, print_col=1, preview="fzfaws cloudformation {} -h"
        )
        if selected_command == "update":
            update_cmd.print_help()
        elif selected_command == "create":
            create_cmd.print_help()
        elif selected_command == "delete":
            delete_cmd.print_help()
        elif selected_command == "ls":
            ls_cmd.print_help()
        elif selected_command == "drift":
            drift_cmd.print_help()
        elif selected_command == "changeset":
            changeset_cmd.print_help()
        elif selected_command == "validate":
            changeset_cmd.print_help()
        sys.exit(0)

    # when user set --profile/region flag but without argument
    # argparse will have a None value instead of default value False
    # convert to True for better processing
    if args.profile == None:
        args.profile = True
    if args.region == None:
        args.region = True
    if hasattr(args, "local") and args.local == None:
        args.local = True
    if hasattr(args, "bucket"):
        args.bucket = args.bucket[0] if args.bucket else None
    if hasattr(args, "version") and args.version == None:
        args.version = True

    if args.subparser_name == "create":
        create_stack(
            args.profile,
            args.region,
            args.local,
            args.root,
            args.wait,
            args.extra,
            args.bucket,
            args.version,
        )
    elif args.subparser_name == "update":
        update_stack(
            args.profile,
            args.region,
            args.replace,
            args.local,
            args.root,
            args.wait,
            args.extra,
            args.bucket,
            args.version,
        )
    elif args.subparser_name == "delete":
        if args.iam == None:
            args.iam = True
        delete_stack(args.profile, args.region, args.wait, args.iam)
    elif args.subparser_name == "ls":
        ls_stack(
            args.profile,
            args.region,
            args.resource,
            args.name,
            args.arn,
            args.tag,
            args.type,
        )
    elif args.subparser_name == "drift":
        drift_stack(args.profile, args.region, args.info, args.select, args.wait)
    elif args.subparser_name == "changeset":
        changeset_stack(
            args.profile,
            args.region,
            args.replace,
            args.local,
            args.root,
            args.wait,
            args.info,
            args.execute,
            args.delete,
            args.extra,
            args.bucket,
            args.version,
        )
    elif args.subparser_name == "validate":
        validate_stack(
            args.profile, args.region, args.local, args.root, args.bucket, args.version
        )
Example #4
0
    def test_s3_creation(
        self,
        mocked_version,
        mocked_data,
        mocked_url,
        mocked_validate,
        mocked_input,
        mocked_execute,
        mocked_wait,
        mocked_process,
    ):
        mocked_input.return_value = "testing_stack"
        mocked_version.return_value = [{"VersionId": "111111"}]
        fileloader = FileLoader(self.data_path)
        mocked_data.return_value = fileloader.process_yaml_file()
        mocked_url.return_value = "https://s3-ap-southeast-2.amazonaws.com/kazhala-lol/hello.yaml?versionId=111111"

        create_stack(bucket="kazhala-lol/hello.yaml", version=True)
        mocked_version.assert_called_with("kazhala-lol", "hello.yaml")
        mocked_validate.assert_called_with(
            "default",
            "us-east-1",
            bucket="kazhala-lol/hello.yaml",
            version="111111",
            no_print=True,
        )
        mocked_data.assert_called_with("yaml")
        mocked_url.assert_called_with(version="111111")
        mocked_execute.assert_called_with(
            Parameters=[],
            StackName="testing_stack",
            TemplateURL=
            "https://s3-ap-southeast-2.amazonaws.com/kazhala-lol/hello.yaml?versionId=111111",
            cloudformation_action=ANY,
        )
        mocked_wait.assert_not_called()

        mocked_version.reset_mock()
        create_stack(
            profile="root",
            region="us-east-1",
            bucket="kazhala-lol/hello.yaml",
            version="111111",
            wait=True,
        )
        mocked_version.assert_not_called()
        mocked_validate.assert_called_with(
            "root",
            "us-east-1",
            bucket="kazhala-lol/hello.yaml",
            version="111111",
            no_print=True,
        )
        mocked_data.assert_called_with("yaml")
        mocked_url.assert_called_with(version="111111")
        mocked_execute.assert_called_with(
            Parameters=[],
            StackName="testing_stack",
            TemplateURL=
            "https://s3-ap-southeast-2.amazonaws.com/kazhala-lol/hello.yaml?versionId=111111",
            cloudformation_action=ANY,
        )
        mocked_wait.assert_called_with("stack_create_complete",
                                       "Waiting for stack to be ready ...")