From 01ea93e44e12a3c37902dcd1a63326090ff42de8 Mon Sep 17 00:00:00 2001 From: troyready Date: Thu, 22 Feb 2018 16:33:08 -0800 Subject: [PATCH 1/3] fix diff against yaml templates --- stacker/actions/diff.py | 4 +- stacker/tests/actions/test_diff.py | 61 ++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 2 deletions(-) diff --git a/stacker/actions/diff.py b/stacker/actions/diff.py index 1a6bf963a..135c54611 100644 --- a/stacker/actions/diff.py +++ b/stacker/actions/diff.py @@ -178,12 +178,12 @@ def _normalize_json(self, template): """Normalizes our template for diffing Args: - template(str): json string representing the template + template(str): string representing the template Returns: list: json representation of the parameters """ - obj = json.loads(template) + obj = parse_cloudformation_template(template) json_str = json.dumps(obj, sort_keys=True, indent=4) result = [] lines = json_str.split("\n") diff --git a/stacker/tests/actions/test_diff.py b/stacker/tests/actions/test_diff.py index 08277b638..3636ff710 100644 --- a/stacker/tests/actions/test_diff.py +++ b/stacker/tests/actions/test_diff.py @@ -1,11 +1,14 @@ +import os import unittest from operator import attrgetter from stacker.actions.diff import ( diff_dictionaries, diff_parameters, + Action, DictValue ) +from stacker.context import Config, Context class TestDictValueFormat(unittest.TestCase): @@ -81,3 +84,61 @@ def test_diff_parameters_no_changes(self): param_diffs = diff_parameters(old_params, new_params) self.assertEquals(param_diffs, []) + + +class TestDiffAction(unittest.TestCase): + """Test diff Action class.""" + + def test_normalize_json(self): + """Ensure _normalize_json parses yaml correctly.""" + diff = Action( + context=Context(config=Config({"namespace": "namespace"})) + ) + with open(os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), # noqa + 'fixtures', + 'cfn_template.yaml'), 'r') as yamlfile: + template = yamlfile.read() + normalized_template = [ + '{\n', + ' "AWSTemplateFormatVersion": "2010-09-09", \n', + ' "Description": "TestTemplate", \n', + ' "Outputs": {\n', + ' "DummyId": {\n', + ' "Value": "dummy-1234"\n', + ' }\n', + ' }, \n', + ' "Parameters": {\n', + ' "Param1": {\n', + ' "Type": "String"\n', + ' }, \n', + ' "Param2": {\n', + ' "Default": "default", \n', + ' "Type": "CommaDelimitedList"\n', + ' }\n', + ' }, \n', + ' "Resources": {\n', + ' "Bucket": {\n', + ' "Properties": {\n', + ' "BucketName": {\n', + ' "Fn::Join": [\n', + ' "-", \n', + ' [\n', + ' {\n', + ' "Ref": "AWS::StackName"\n', + ' }, \n', + ' {\n', + ' "Ref": "AWS::Region"\n', + ' }\n', + ' ]\n', + ' ]\n', + ' }\n', + ' }, \n', + ' "Type": "AWS::S3::Bucket"\n', + ' }, \n', + ' "Dummy": {\n', + ' "Type": "AWS::CloudFormation::WaitConditionHandle"\n', + ' }\n', + ' }\n', + '}\n' + ] + self.assertEquals(normalized_template, diff._normalize_json(template)) From 40b8afe15a974e4e1dcfd9850c545d87f823a5f3 Mon Sep 17 00:00:00 2001 From: troyready Date: Fri, 23 Feb 2018 09:13:27 -0800 Subject: [PATCH 2/3] add bats test for diff with raw template --- tests/suite.bats | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/tests/suite.bats b/tests/suite.bats index cb079af64..c2d59e0c7 100755 --- a/tests/suite.bats +++ b/tests/suite.bats @@ -713,6 +713,45 @@ EOF assert_has_line "${STACKER_NAMESPACE}-vpc: complete (stack destroyed)" } +@test "stacker diff - raw template" { + needs_aws + + config1() { + cat < Date: Fri, 23 Feb 2018 09:56:46 -0800 Subject: [PATCH 3/3] move diff normalize_json to function; fix diff params not displaying --- stacker/actions/diff.py | 46 ++++++++++++++++-------------- stacker/tests/actions/test_diff.py | 14 ++++----- 2 files changed, 29 insertions(+), 31 deletions(-) diff --git a/stacker/actions/diff.py b/stacker/actions/diff.py index 135c54611..b907edda3 100644 --- a/stacker/actions/diff.py +++ b/stacker/actions/diff.py @@ -143,9 +143,27 @@ def diff_parameters(old_params, new_params): return diff +def normalize_json(template): + """Normalize our template for diffing. + + Args: + template(str): string representing the template + + Returns: + list: json representation of the parameters + """ + obj = parse_cloudformation_template(template) + json_str = json.dumps(obj, sort_keys=True, indent=4) + result = [] + lines = json_str.split("\n") + for line in lines: + result.append(line + "\n") + return result + + def print_stack_changes(stack_name, new_stack, old_stack, new_params, old_params): - """Prints out the paramters (if changed) and stack diff""" + """Prints out the parameters (if changed) and stack diff""" from_file = "old_%s" % (stack_name,) to_file = "new_%s" % (stack_name,) lines = difflib.context_diff( @@ -156,9 +174,10 @@ def print_stack_changes(stack_name, new_stack, old_stack, new_params, template_changes = list(lines) if not template_changes: print "*** No changes to template ***" - else: - param_diffs = diff_parameters(old_params, new_params) + param_diffs = diff_parameters(old_params, new_params) + if param_diffs: print format_params_diff(param_diffs) + if template_changes: print "".join(template_changes) @@ -174,23 +193,6 @@ class Action(build.Action): config. """ - def _normalize_json(self, template): - """Normalizes our template for diffing - - Args: - template(str): string representing the template - - Returns: - list: json representation of the parameters - """ - obj = parse_cloudformation_template(template) - json_str = json.dumps(obj, sort_keys=True, indent=4) - result = [] - lines = json_str.split("\n") - for line in lines: - result.append(line + "\n") - return result - def _print_new_stack(self, stack, parameters): """Prints out the parameters & stack contents of a new stack""" print "New template parameters:" @@ -229,7 +231,7 @@ def _diff_stack(self, stack, **kwargs): for p in parameters: new_params[p['ParameterKey']] = p['ParameterValue'] new_template = stack.blueprint.rendered - new_stack = self._normalize_json(new_template) + new_stack = normalize_json(new_template) print "============== Stack: %s ==============" % (stack.name,) # If this is a completely new template dump our params & stack @@ -244,7 +246,7 @@ def _diff_stack(self, stack, **kwargs): # -> # AWSTemplateFormatVersion: "2010-09-09" old_template = parse_cloudformation_template(old_template) - old_stack = self._normalize_json( + old_stack = normalize_json( json.dumps(old_template, sort_keys=True, indent=4) diff --git a/stacker/tests/actions/test_diff.py b/stacker/tests/actions/test_diff.py index 3636ff710..b4690afaf 100644 --- a/stacker/tests/actions/test_diff.py +++ b/stacker/tests/actions/test_diff.py @@ -5,10 +5,9 @@ from stacker.actions.diff import ( diff_dictionaries, diff_parameters, - Action, + normalize_json, DictValue ) -from stacker.context import Config, Context class TestDictValueFormat(unittest.TestCase): @@ -86,14 +85,11 @@ def test_diff_parameters_no_changes(self): self.assertEquals(param_diffs, []) -class TestDiffAction(unittest.TestCase): - """Test diff Action class.""" +class TestDiffFunctions(unittest.TestCase): + """Test functions in diff.""" def test_normalize_json(self): - """Ensure _normalize_json parses yaml correctly.""" - diff = Action( - context=Context(config=Config({"namespace": "namespace"})) - ) + """Ensure normalize_json parses yaml correctly.""" with open(os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), # noqa 'fixtures', 'cfn_template.yaml'), 'r') as yamlfile: @@ -141,4 +137,4 @@ def test_normalize_json(self): ' }\n', '}\n' ] - self.assertEquals(normalized_template, diff._normalize_json(template)) + self.assertEquals(normalized_template, normalize_json(template))