def is_valid(self): """ Runs the SAM Translator to determine if the template provided is valid. This is similar to running a ChangeSet in CloudFormation for a SAM Template Raises ------- InvalidSamDocumentException If the template is not valid, an InvalidSamDocumentException is raised """ managed_policy_map = self.managed_policy_loader.load() sam_translator = Translator(managed_policy_map=managed_policy_map, sam_parser=self.sam_parser, plugins=[]) self._replace_local_codeuri() try: template = sam_translator.translate(sam_template=self.sam_template, parameter_values={}) LOG.debug("Translated template is:\n%s", yaml_dump(template)) except InvalidDocumentException as e: raise InvalidSamDocumentException( functools.reduce( lambda message, error: message + " " + str(error), e.causes, str(e))) from e
def test_parse_yaml_preserve_elements_order(self): input_template = ("B_Resource:\n" " Key2:\n" " Name: name2\n" " Key1:\n" " Name: name1\n" "A_Resource:\n" " Key2:\n" " Name: name2\n" " Key1:\n" " Name: name1\n") output_dict = yaml_parse(input_template) expected_dict = OrderedDict([ ("B_Resource", OrderedDict([("Key2", { "Name": "name2" }), ("Key1", { "Name": "name1" })])), ("A_Resource", OrderedDict([("Key2", { "Name": "name2" }), ("Key1", { "Name": "name1" })])), ]) self.assertEqual(expected_dict, output_dict) output_template = yaml_dump(output_dict) self.assertEqual(input_template, output_template)
def test_yaml_with_tags(self): output = yaml_parse(self.yaml_with_tags) self.assertEquals(self.parsed_yaml_dict, output) # Make sure formatter and parser work well with each other formatted_str = yaml_dump(output) output_again = yaml_parse(formatted_str) self.assertEquals(output, output_again)
def test_yaml_dumps(self): input_yaml_dict = {"Resource": {"Key7": "012345678"}} expected_output = "Resource:\n Key7: '012345678'\n" output = yaml_dump(input_yaml_dict) self.assertEqual(output, expected_output)
def _export(self, template_path, use_json): template = Template(template_path, os.getcwd(), self.s3_uploader) exported_template = template.export() if use_json: exported_str = json.dumps(exported_template, indent=4, ensure_ascii=False) else: exported_str = yaml_dump(exported_template) return exported_str
def is_valid(self): """ Runs the SAM Translator to determine if the template provided is valid. This is similar to running a ChangeSet in CloudFormation for a SAM Template Raises ------- InvalidSamDocumentException If the template is not valid, an InvalidSamDocumentException is raised """ managed_policy_map = self.managed_policy_loader.load() sam_translator = Translator(managed_policy_map=managed_policy_map, sam_parser=self.sam_parser, plugins=[]) self._replace_local_codeuri() # In the Paser class, within the SAM Translator, they log a warning for when the template # does not match the schema. The logger they use is the root logger instead of one scoped to # their module. Currently this does not cause templates to fail, so we will suppress this # by patching the logging.warning method that is used in that class. class WarningSuppressLogger(object): def __init__(self, obj_to_patch): self.obj_to_patch = obj_to_patch def __enter__(self): self.obj_to_patch.warning = self.warning def __exit__(self, exc_type, exc_val, exc_tb): self.obj_to_patch.warning = self.obj_to_patch.warning def warning(self, message): pass try: with WarningSuppressLogger(parser.logging): template = sam_translator.translate( sam_template=self.sam_template, parameter_values={}) LOG.debug("Translated template is:\n%s", yaml_dump(template)) except InvalidDocumentException as e: raise InvalidSamDocumentException( functools.reduce( lambda message, error: message + ' ' + str(error), e.causes, str(e)))
def is_valid(self): """ Runs the SAM Translator to determine if the template provided is valid. This is similar to running a ChangeSet in CloudFormation for a SAM Template Raises ------- InvalidSamDocumentException If the template is not valid, an InvalidSamDocumentException is raised """ managed_policy_map = self.managed_policy_loader.load() sam_translator = Translator(managed_policy_map=managed_policy_map, sam_parser=self.sam_parser, plugins=[]) self._replace_local_codeuri() # In the Paser class, within the SAM Translator, they log a warning for when the template # does not match the schema. The logger they use is the root logger instead of one scoped to # their module. Currently this does not cause templates to fail, so we will suppress this # by patching the logging.warning method that is used in that class. class WarningSuppressLogger(object): def __init__(self, obj_to_patch): self.obj_to_patch = obj_to_patch def __enter__(self): self.obj_to_patch.warning = self.warning def __exit__(self, exc_type, exc_val, exc_tb): self.obj_to_patch.warning = self.obj_to_patch.warning def warning(self, message): pass try: with WarningSuppressLogger(parser.logging): template = sam_translator.translate(sam_template=self.sam_template, parameter_values={}) LOG.debug("Translated template is:\n%s", yaml_dump(template)) except InvalidDocumentException as e: raise InvalidSamDocumentException( functools.reduce(lambda message, error: message + ' ' + str(error), e.causes, str(e)))
def do_export(self, resource_id, resource_dict, parent_dir): """ If the nested stack template is valid, this method will export on the nested template, upload the exported template to S3 and set property to URL of the uploaded S3 template """ template_path = resource_dict.get(self.PROPERTY_NAME, None) if (template_path is None or is_s3_url(template_path) or template_path.startswith(self.uploader.s3.meta.endpoint_url) or template_path.startswith("https://s3.amazonaws.com/")): # Nothing to do return abs_template_path = make_abs_path(parent_dir, template_path) if not is_local_file(abs_template_path): raise exceptions.InvalidTemplateUrlParameterError( property_name=self.PROPERTY_NAME, resource_id=resource_id, template_path=abs_template_path) exported_template_dict = Template(template_path, parent_dir, self.uploaders, self.code_signer).export() exported_template_str = yaml_dump(exported_template_dict) with mktempfile() as temporary_file: temporary_file.write(exported_template_str) temporary_file.flush() url = self.uploader.upload_with_dedup(temporary_file.name, "template") # TemplateUrl property requires S3 URL to be in path-style format parts = S3Uploader.parse_s3_url(url, version_property="Version") s3_path_url = self.uploader.to_path_style_s3_url( parts["Key"], parts.get("Version", None)) set_value_from_jmespath(resource_dict, self.PROPERTY_NAME, s3_path_url)
def move_template(src_template_path, dest_template_path, template_dict): """ Move the SAM/CloudFormation template from ``src_template_path`` to ``dest_template_path``. For convenience, this method accepts a dictionary of template data ``template_dict`` that will be written to the destination instead of reading from the source file. SAM/CloudFormation template can contain certain properties whose value is a relative path to a local file/folder. This path is always relative to the template's location. Before writing the template to ``dest_template_path`, we will update these paths to be relative to the new location. This methods updates resource properties supported by ``aws cloudformation package`` command: https://docs.aws.amazon.com/cli/latest/reference/cloudformation/package.html You must use this method if you are reading a template from one location, modifying it, and writing it back to a different location. Parameters ---------- src_template_path : str Path to the original location of the template dest_template_path : str Path to the destination location where updated template should be written to template_dict : dict Dictionary containing template contents. This dictionary will be updated & written to ``dest`` location. """ original_root = os.path.dirname(src_template_path) new_root = os.path.dirname(dest_template_path) # Next up, we will be writing the template to a different location. Before doing so, we should # update any relative paths in the template to be relative to the new location. modified_template = _update_relative_paths(template_dict, original_root, new_root) # if a stack only has image functions, the directory for that directory won't be created. # here we make sure the directory the destination template file to write to exists. os.makedirs(os.path.dirname(dest_template_path), exist_ok=True) with open(dest_template_path, "w") as fp: fp.write(yaml_dump(modified_template))
def move_template(src_template_path, dest_template_path, template_dict): """ Move the SAM/CloudFormation template from ``src_template_path`` to ``dest_template_path``. For convenience, this method accepts a dictionary of template data ``template_dict`` that will be written to the destination instead of reading from the source file. SAM/CloudFormation template can contain certain properties whose value is a relative path to a local file/folder. This path is always relative to the template's location. Before writing the template to ``dest_template_path`, we will update these paths to be relative to the new location. This methods updates resource properties supported by ``aws cloudformation package`` command: https://docs.aws.amazon.com/cli/latest/reference/cloudformation/package.html You must use this method if you are reading a template from one location, modifying it, and writing it back to a different location. Parameters ---------- src_template_path : str Path to the original location of the template dest_template_path : str Path to the destination location where updated template should be written to template_dict : dict Dictionary containing template contents. This dictionary will be updated & written to ``dest`` location. """ original_root = os.path.dirname(src_template_path) new_root = os.path.dirname(dest_template_path) # Next up, we will be writing the template to a different location. Before doing so, we should # update any relative paths in the template to be relative to the new location. modified_template = _update_relative_paths(template_dict, original_root, new_root) with open(dest_template_path, "w") as fp: fp.write(yaml_dump(modified_template))
def test_unroll_yaml_anchors(self): properties = {"Foo": "bar", "Spam": "eggs"} template = { "Resources": { "Resource1": { "Properties": properties }, "Resource2": { "Properties": properties } } } expected = ("Resources:\n" " Resource1:\n" " Properties:\n" " Foo: bar\n" " Spam: eggs\n" " Resource2:\n" " Properties:\n" " Foo: bar\n" " Spam: eggs\n") actual = yaml_dump(template) self.assertEqual(actual, expected)