Esempio n. 1
0
def construct_local_creation_args(cloudformation: Cloudformation,
                                  local_path: str) -> Dict[str, Any]:
    """Construct cloudformation create argument for local file.

    Perform fzf search on local files json/yaml and then use validate_stack to
    validate stack through boto3 API before constructing the argument.

    :param cloudformation: Cloudformation instance
    :type cloudformation: Cloudformation
    :param local_path: local file path
    :type local_path: str
    :return: return the constructed args thats ready for use with boto3
    :rtype: Dict[str, Any]
    """
    # validate file type, has to be either yaml or json
    check_is_valid(local_path)

    validate_stack(
        cloudformation.profile,
        cloudformation.region,
        local_path=local_path,
        no_print=True,
    )

    stack_name: str = input("StackName: ")
    if not stack_name:
        raise NoNameEntered("No stack name specified")

    fileloader = FileLoader(path=local_path)
    file_data: Dict[str, Any] = {}
    if is_yaml(local_path):
        file_data = fileloader.process_yaml_file()
    elif is_json(local_path):
        file_data = fileloader.process_json_file()

    # get params
    if "Parameters" in file_data["dictBody"]:
        paramprocessor = ParamProcessor(
            cloudformation.profile,
            cloudformation.region,
            file_data["dictBody"]["Parameters"],
        )
        paramprocessor.process_stack_params()
        create_parameters = paramprocessor.processed_params
    else:
        create_parameters = []

    cloudformation_args = {
        "cloudformation_action": cloudformation.client.create_stack,
        "StackName": stack_name,
        "TemplateBody": file_data["body"],
        "Parameters": create_parameters,
    }

    return cloudformation_args
Esempio n. 2
0
def local_replacing_update(cloudformation: Cloudformation,
                           local_path: str) -> Dict[str, Any]:
    """Format cloudformation argument for a local replacing update.

    Local replacing update as in using a template in the local machine
    to perform stack update.

    Process the new template and also comparing with previous parameter
    value to provide an old value preview.

    :param cloudformation: Cloudformation instance
    :type cloudformation: Cloudformation
    :param local_path: local file path to the template
    :type local_path: str
    :return: formatted argument thats ready to be used by boto3
    :rtype: Dict[str, Any]
    """
    check_is_valid(local_path)

    validate_stack(
        cloudformation.profile,
        cloudformation.region,
        local_path=local_path,
        no_print=True,
    )

    fileloader = FileLoader(path=local_path)
    file_data: Dict[str, Any] = {}
    if is_yaml(local_path):
        file_data = fileloader.process_yaml_file()
    elif is_json(local_path):
        file_data = fileloader.process_json_file()

    # process params
    if "Parameters" in file_data["dictBody"]:
        paramprocessor = ParamProcessor(
            cloudformation.profile,
            cloudformation.region,
            file_data["dictBody"]["Parameters"],
            cloudformation.stack_details.get("Parameters"),
        )
        paramprocessor.process_stack_params()
        updated_parameters = paramprocessor.processed_params
    else:
        updated_parameters = []

    cloudformation_args = {
        "cloudformation_action": cloudformation.client.update_stack,
        "StackName": cloudformation.stack_name,
        "TemplateBody": file_data["body"],
        "UsePreviousTemplate": False,
        "Parameters": updated_parameters,
    }

    return cloudformation_args
Esempio n. 3
0
def construct_s3_creation_args(cloudformation: Cloudformation,
                               bucket: Optional[str],
                               version: Union[str, bool]) -> Dict[str, Any]:
    """Construct cloudformation argument for template in s3.

    Retrieve the template from s3 bucket and validate and process the content in it
    then return the ready to use cloudformation argument for boto3.

    :param cloudformation: Cloudformation instance
    :type cloudformation: Cloudformation
    :param bucket: bucket name
    :type bucket: 
    :return: return the formated cloudformation argument thats ready to use by boto3
    :rtype: Dict[str, Any]
    """
    s3 = S3(cloudformation.profile, cloudformation.region)
    s3.set_bucket_and_path(bucket)
    if not s3.bucket_name:
        s3.set_s3_bucket(header="select a bucket which contains the template")
    if not s3.path_list[0]:
        s3.set_s3_object()

    # check file type is yaml or json
    check_is_valid(s3.path_list[0])

    # if version is requested but not set through cmd line, get user to select a version
    if version == True:
        version = s3.get_object_version(s3.bucket_name,
                                        s3.path_list[0])[0].get(
                                            "VersionId", False)

    # validate the template through boto3
    validate_stack(
        cloudformation.profile,
        cloudformation.region,
        bucket="%s/%s" % (s3.bucket_name, s3.path_list[0]),
        version=version if version else False,
        no_print=True,
    )

    file_type: str = ""
    if is_yaml(s3.path_list[0]):
        file_type = "yaml"
    elif is_json(s3.path_list[0]):
        file_type = "json"

    stack_name: str = input("StackName: ")
    if not stack_name:
        raise NoNameEntered("No stack name specified")

    file_data: dict = s3.get_object_data(file_type)
    if "Parameters" in file_data:
        paramprocessor = ParamProcessor(cloudformation.profile,
                                        cloudformation.region,
                                        file_data["Parameters"])
        paramprocessor.process_stack_params()
        create_parameters = paramprocessor.processed_params
    else:
        create_parameters = []

    template_body_loacation: str = s3.get_object_url(
        version="" if not version else str(version))
    cloudformation_args = {
        "cloudformation_action": cloudformation.client.create_stack,
        "StackName": stack_name,
        "TemplateURL": template_body_loacation,
        "Parameters": create_parameters,
    }

    return cloudformation_args
Esempio n. 4
0
def validate_stack(
    profile: Optional[Union[str, bool]] = False,
    region: Optional[Union[str, bool]] = False,
    local_path: Union[str, bool] = False,
    root: bool = False,
    bucket: str = None,
    version: Union[str, bool] = False,
    no_print: bool = False,
) -> None:
    """Validate the selected cloudformation template using boto3 api.

    This is also used internally by create_stack and update_stack
    operations.

    :param profile: Use a different profile for this operation
    :type profile: Union[bool, str], optional
    :param region: Use a different region for this operation
    :type region: Union[bool, str], optional
    :param local_path: Select a template from local machine
    :type local_path: Union[bool, str], optional
    :param root: Search local file from root directory
    :type root: bool, optional
    :param bucket: specify a bucket/bucketpath to skip s3 selection
    :type bucket: str, optional
    :param version: use a previous version of the template
    :type version: Union[bool, str], optional
    :param no_print: Don't print the response, only check excpetion
    :type no_print: bool, optional
    """
    cloudformation = Cloudformation(profile, region)

    if local_path:
        if type(local_path) != str:
            fzf = Pyfzf()
            local_path = str(
                fzf.get_local_file(
                    search_from_root=root,
                    cloudformation=True,
                    header="select a cloudformation template to validate",
                ))
        check_is_valid(local_path)
        with open(local_path, "r") as file_body:
            response = cloudformation.client.validate_template(
                TemplateBody=file_body.read())
    else:
        s3 = S3(profile, region)
        s3.set_bucket_and_path(bucket)
        if not s3.bucket_name:
            s3.set_s3_bucket(
                header="select a bucket which contains the template")
        if not s3.path_list[0]:
            s3.set_s3_object()

        check_is_valid(s3.path_list[0])

        if version == True:
            version = s3.get_object_version(s3.bucket_name,
                                            s3.path_list[0])[0].get(
                                                "VersionId", False)

        template_body_loacation = s3.get_object_url(
            "" if not version else str(version))
        response = cloudformation.client.validate_template(
            TemplateURL=template_body_loacation)

    if not no_print:
        response.pop("ResponseMetadata", None)
        print(json.dumps(response, indent=4, default=str))
Esempio n. 5
0
 def test_check_is_valid(self):
     check_is_valid("hello.yaml")
     check_is_valid("hello.json")
     check_is_valid("hello.yml")
     self.assertRaises(InvalidFileType, check_is_valid, "hello.txt")
Esempio n. 6
0
def s3_replacing_update(cloudformation: Cloudformation, bucket: Optional[str],
                        version: Union[str, bool]) -> Dict[str, Any]:
    """Format argument for a replacing updating through providing template on s3.

    Read the template from s3, comparing parameter names with the original stack
    to provide a preview of value if possible.

    :param cloudformation: Cloudformation instance
    :type cloudformation: Cloudformation
    :param bucket: bucket path, if set, skip fzf selection
    :type bucket: str, optional
    :param version: whether to use a versioned template in s3
    :type version: Union[str, bool]
    :return: formatted argument thats ready to be used by boto3
    :rtype: Dict[str, Any]
    """
    s3 = S3(profile=cloudformation.profile, region=cloudformation.region)
    s3.set_bucket_and_path(bucket)
    if not s3.bucket_name:
        s3.set_s3_bucket()
    if not s3.path_list[0]:
        s3.set_s3_object()

    check_is_valid(s3.path_list[0])

    if version == True:
        version = s3.get_object_version(s3.bucket_name,
                                        s3.path_list[0])[0].get(
                                            "VersionId", False)

    validate_stack(
        cloudformation.profile,
        cloudformation.region,
        bucket="%s/%s" % (s3.bucket_name, s3.path_list[0]),
        version=version if version else False,
        no_print=True,
    )

    file_type: str = ""
    if is_yaml(s3.path_list[0]):
        file_type = "yaml"
    elif is_json(s3.path_list[0]):
        file_type = "json"

    file_data: Dict[str, Any] = s3.get_object_data(file_type)
    if "Parameters" in file_data:
        paramprocessor = ParamProcessor(
            cloudformation.profile,
            cloudformation.region,
            file_data["Parameters"],
            cloudformation.stack_details.get("Parameters"),
        )
        paramprocessor.process_stack_params()
        updated_parameters = paramprocessor.processed_params
    else:
        updated_parameters = []

    template_body_loacation = s3.get_object_url(
        "" if not version else str(version))

    cloudformation_args = {
        "cloudformation_action": cloudformation.client.update_stack,
        "StackName": cloudformation.stack_name,
        "TemplateURL": template_body_loacation,
        "UsePreviousTemplate": False,
        "Parameters": updated_parameters,
    }

    return cloudformation_args