def setUp(self): self.variables = [ Variable( 'Streams', { 'Stream1': { 'RetentionPeriodHours': 12, 'ShardCount': 4, 'StreamEncryption': { 'EncryptionType': 'KMS', 'KeyId': 'kms-1203123', }, }, 'Stream2': { 'ShardCount': 4, }, }), Variable('ReadRoles', [ 'Role1', 'Role2', ]), Variable('ReadWriteRoles', [ 'Role3', 'Role4', ]), ]
def test_variable_resolve_simple_lookup(self): var = Variable("Param1", "${output fakeStack::FakeOutput}") self.assertEqual(len(var.lookups), 1) self.provider.get_output.return_value = "resolved" var.resolve(self.context, self.provider) self.assertTrue(var.resolved) self.assertEqual(var.value, "resolved")
def json(blueprint, userdata_dict=None, function_dict=None): """Turn a stacker blueprint into CloudFormation JSON.""" if userdata_dict is None: userdata_dict = {} if function_dict is None: function_dict = {} # Check the blueprint for CFN parameters in its variables, and define bogus # values for those parameters so the template can be generated. # Easiest check to find variables that are CFN parameters (and not native # python types) seems to be looking for the 'parameter_type' attribute test_variables = [] for key, value in blueprint.defined_variables().iteritems(): if hasattr(value['type'], 'parameter_type'): test_variables.append(Variable(key, 'dummy_value')) # Populate the userdata via the file lookup for userdata in userdata_dict.iteritems(): parameterized_b64 = parameterized_codec(open(userdata[1], 'r').read(), True) # base64 test_variables.append(Variable(userdata[0], parameterized_b64)) # Populate the lambda functions via the file lookup for function in function_dict.iteritems(): parameterized = parameterized_codec(open(function[1], 'r').read(), False) # base64 test_variables.append(Variable(function[0], parameterized)) blueprint.resolve_variables(test_variables) print blueprint.render_template()[1]
def test_variable_resolve_default_lookup_empty(self): var = Variable("Param1", "${default fakeStack::}") self.assertEqual(len(var.lookups), 1) var.resolve(self.context, self.provider) self.assertTrue(var.resolved) self.assertEqual(var.value, "") self.assertEqual(len(var.lookups), 0)
def test_s3_static_website(self): """Test a static website blog bucket.""" ctx = Context(config=Config({'namespace': 'test'})) blueprint = Buckets('s3_static_website', ctx) v = self.variables = [ Variable( 'Buckets', { 'Blog': { 'AccessControl': 'PublicRead', 'WebsiteConfiguration': { 'IndexDocument': 'index.html' } }, }), Variable('ReadRoles', [ 'Role1', 'Role2', ]), Variable('ReadWriteRoles', [ 'Role3', 'Role4', ]), ] blueprint.resolve_variables(v) blueprint.create_template() self.assertRenderedBlueprint(blueprint)
def test_resolve_variables(self): class TestBlueprint(Blueprint): VARIABLES = { "Param1": { "default": 0, "type": int }, "Param2": { "type": str }, } blueprint = TestBlueprint(name="test", context=MagicMock()) variables = [ Variable("Param1", 1), Variable("Param2", "${output other-stack::Output}"), Variable("Param3", 3), ] resolved_lookups = { mock_lookup("other-stack::Output", "output"): "Test Output", } for var in variables: var.replace(resolved_lookups) blueprint.resolve_variables(variables) self.assertEqual(blueprint.resolved_variables["Param1"], 1) self.assertEqual(blueprint.resolved_variables["Param2"], "Test Output") self.assertIsNone(blueprint.resolved_variables.get("Param3"))
def test_create_template_record_set_grroup(self): blueprint = DNSRecords('route53_record_set_groups', self.ctx) blueprint.resolve_variables( [ Variable( "RecordSetGroups", { "Frontend": { "RecordSets": [ { "Name": "mysite.example.com", "Type": "CNAME", "SetIdentifier": "Frontend One", "Weight": "4", "ResourceRecords": ["example-ec2.amazonaws.com"], }, { "Name": "mysite.example.com", "Type": "CNAME", "SetIdentifier": "Frontend Two", "Weight": "6", "ResourceRecords": ["example-ec2-larger.amazonaws.com"], }, ] }, } ), Variable("HostedZoneId", "fake_zone_id"), ] ) blueprint.create_template() self.assertRenderedBlueprint(blueprint)
def test_variable_resolve_nested_lookup(self): stack = Stack(definition=generate_definition("vpc", 1), context=self.context) stack.set_outputs({ "FakeOutput": "resolved", "FakeOutput2": "resolved2", }) def mock_handler(value, context, provider, **kwargs): return "looked up: {}".format(value) register_lookup_handler("lookup", mock_handler) self.context.get_stack.return_value = stack var = Variable( "Param1", "${lookup ${lookup ${output fakeStack::FakeOutput}}}", ) self.assertEqual( len(var.lookups), 1, "should only parse out the first complete lookup first", ) var.resolve(self.context, self.provider) self.assertTrue(var.resolved) self.assertEqual(var.value, "looked up: looked up: resolved")
def test_alias_default_hosted_zone_id(self): blueprint = DNSRecords( 'test_route53_alias_default_hosted_zone_id', self.ctx ) blueprint.resolve_variables( [ Variable( "RecordSets", [ { "Name": "host.testdomain.com.", "Type": "A", "AliasTarget": { "DNSName": "original-gangster-host.testdomain.com.", # noqa }, }, ] ), Variable("HostedZoneId", "fake_zone_id"), ] ) record_sets = blueprint.create_template() self.assertEqual( record_sets[0].AliasTarget.HostedZoneId, "fake_zone_id" )
def test_variable_replace_lookups_mixed(self): value = { "something": [ "${output fakeStack::FakeOutput}", "other", ], "here": { "other": "${output fakeStack::FakeOutput2}", "same": "${output fakeStack::FakeOutput}", "mixed": "something:${output fakeStack::FakeOutput3}", }, } var = Variable("Param1", value) self.assertEqual(len(var.lookups), 3) resolved_lookups = { mock_lookup("fakeStack::FakeOutput", "output"): "resolved", mock_lookup("fakeStack::FakeOutput2", "output"): "resolved2", mock_lookup("fakeStack::FakeOutput3", "output"): "resolved3", } var.replace(resolved_lookups) self.assertEqual( var.value, { "something": [ "resolved", "other", ], "here": { "other": "resolved2", "same": "resolved", "mixed": "something:resolved3", }, })
def test_create_template_hosted_zone_name(self): blueprint = DNSRecords('route53_dnsrecords_zone_name', self.ctx) blueprint.resolve_variables([ Variable("RecordSets", [ { "Name": "host.testdomain.com.", "Type": "A", "ResourceRecords": ["10.0.0.1"], }, { "Name": "host2.testdomain.com.", "Type": "A", "ResourceRecords": ["10.0.0.2"], "Comment": "This is host2's record. : )", }, { "Name": "host3.testdomain.com.", "Type": "A", "ResourceRecords": ["10.0.0.3"], "Comment": "This record is present but disabled.", "Enabled": False, }, ]), Variable("HostedZoneName", "testdomain.com"), Variable("Comment", "test-testdomain-com"), ]) record_sets = blueprint.create_template() self.assertEqual(2, len(record_sets)) self.assertRenderedBlueprint(blueprint)
def test_kms_key_attributes_is_deprecated(self): blueprint = Key('kms_key_attributes_deprecated', self.ctx) blueprint.resolve_variables([ Variable("KeyAlias", "c-test-key"), Variable("Attributes", {"Description": "c KMS test-key."}), ]) with self.assertRaises(DeprecationWarning): blueprint.create_template()
def test_kms_key_alias_not_in_keyalias(self): blueprint = Key('kms_key_b', self.ctx) blueprint.resolve_variables([ Variable("KeyAlias", "b-test-key"), Variable("Properties", {"Description": "b KMS test-key."}), ]) blueprint.create_template() self.assertRenderedBlueprint(blueprint)
def test_variable_replace_simple_lookup(self): var = Variable("Param1", "${output fakeStack::FakeOutput}") self.assertEqual(len(var.lookups), 1) resolved_lookups = { mock_lookup("fakeStack::FakeOutput", "output"): "resolved", } var.replace(resolved_lookups) self.assertEqual(var.value, "resolved")
def test_variable_replace_no_lookups(self): var = Variable("Param1", "2") self.assertEqual(len(var.lookups), 0) resolved_lookups = { mock_lookup("fakeStack::FakeOutput"): "resolved", } var.replace(resolved_lookups) self.assertEqual(var.value, "2")
def test_variable_replace_no_lookups_list(self): var = Variable("Param1", ["something", "here"]) self.assertEqual(len(var.lookups), 0) resolved_lookups = { mock_lookup("fakeStack::FakeOutput", "output"): "resolved", } var.replace(resolved_lookups) self.assertEqual(var.value, ["something", "here"])
def test_resolve_variable_provided_resolved(self): var_name = "testVar" var_def = {"type": str} provided_variable = Variable(var_name, "${mock 1}") provided_variable.resolve(context=MagicMock(), provider=MagicMock()) blueprint_name = "testBlueprint" value = resolve_variable(var_name, var_def, provided_variable, blueprint_name) self.assertEqual(value, "1")
def test_resolve_variable_provided_resolved(self): var_name = "testVar" var_def = {"type": str} provided_variable = Variable(var_name, "${mock 1}") provided_variable.resolve(context=MagicMock(), provider=MagicMock()) blueprint_name = "testBlueprint" value = resolve_variable(var_name, var_def, provided_variable, blueprint_name) self.assertEqual(value, "1")
def test_variable_replace_lookups_list(self): value = ["something", "${fakeStack::FakeOutput}", "${fakeStack::FakeOutput2}"] var = Variable("Param1", value) self.assertEqual(len(var.lookups), 2) resolved_lookups = { mock_lookup("fakeStack::FakeOutput"): "resolved", mock_lookup("fakeStack::FakeOutput2"): "resolved2", } var.replace(resolved_lookups) self.assertEqual(var.value, ["something", "resolved", "resolved2"])
def update_var_dict(provided_var_dict, params_to_add): """Return a dictionary to add to resolve_variables()'s variable_dict.""" additional_vars = {} for param_to_add in params_to_add: if param_to_add['var_name'] in provided_var_dict: for key, value in provided_var_dict[ param_to_add['var_name']].value.iteritems(): # noqa pylint: disable=C0301 if isinstance(value, (dict, OrderedDict)): additional_vars[key] = Variable(key, dict(value)['Value']) else: additional_vars[key] = Variable(key, value) return additional_vars
def test_variable_replace_multiple_lookups_string(self): var = Variable( "Param1", "url://${fakeStack::FakeOutput}@${fakeStack::FakeOutput2}", ) self.assertEqual(len(var.lookups), 2) resolved_lookups = { mock_lookup("fakeStack::FakeOutput"): "resolved", mock_lookup("fakeStack::FakeOutput2"): "resolved2", } var.replace(resolved_lookups) self.assertEqual(var.value, "url://resolved@resolved2")
def test_resolve_variable_allowed_values(self): var_name = "testVar" var_def = {"type": str, "allowed_values": ["allowed"]} provided_variable = Variable(var_name, "not_allowed") blueprint_name = "testBlueprint" with self.assertRaises(ValueError): resolve_variable(var_name, var_def, provided_variable, blueprint_name) provided_variable = Variable(var_name, "allowed") value = resolve_variable(var_name, var_def, provided_variable, blueprint_name) self.assertEqual(value, "allowed")
def test_get_variables(self): class TestBlueprint(Blueprint): VARIABLES = { "Param1": {"type": int}, "Param2": {"type": str}, } blueprint = TestBlueprint(name="test", context=MagicMock()) variables = [Variable("Param1", 1), Variable("Param2", "Test Output")] blueprint.resolve_variables(variables) variables = blueprint.get_variables() self.assertEqual(variables["Param1"], 1) self.assertEqual(variables["Param2"], "Test Output")
def test_variable_replace_lookups_dict(self): value = { "something": "${output fakeStack::FakeOutput}", "other": "${output fakeStack::FakeOutput2}", } var = Variable("Param1", value) self.assertEqual(len(var.lookups), 2) resolved_lookups = { mock_lookup("fakeStack::FakeOutput", "output"): "resolved", mock_lookup("fakeStack::FakeOutput2", "output"): "resolved2", } var.replace(resolved_lookups) self.assertEqual(var.value, {"something": "resolved", "other": "resolved2"})
def test_get_parameter_values(self): class TestBlueprint(Blueprint): VARIABLES = { "Param1": {"type": int}, "Param2": {"type": CFNString}, } blueprint = TestBlueprint(name="test", context=MagicMock()) variables = [Variable("Param1", 1), Variable("Param2", "Value")] blueprint.resolve_variables(variables) variables = blueprint.get_variables() self.assertEqual(len(variables), 2) parameters = blueprint.get_parameter_values() self.assertEqual(len(parameters.keys()), 1) self.assertEqual(parameters["Param2"], "Value")
def test_create_template(self): blueprint = Function('test_aws_lambda_Function', self.ctx) blueprint.resolve_variables( [ Variable( "Code", Code(S3Bucket="test_bucket", S3Key="code_key") ), Variable("Description", "Test function."), Variable("Environment", {"TEST_NAME": "test_value"}), Variable("Runtime", "python2.7"), ] ) blueprint.create_template() self.assertRenderedBlueprint(blueprint)
def test_variable_resolve_simple_lookup(self): stack = Stack( definition=generate_definition("vpc", 1), context=self.context) stack.set_outputs({ "FakeOutput": "resolved", "FakeOutput2": "resolved2", }) self.context.get_stack.return_value = stack var = Variable("Param1", "${output fakeStack::FakeOutput}") var.resolve(self.context, self.provider) self.assertTrue(var.resolved) self.assertEqual(var.value, "resolved")
def test_error_when_specify_both_hosted_zone_id_and_name(self): blueprint = DNSRecords('route53_both_hosted_zone_id_and_name_error', self.ctx) blueprint.resolve_variables([ Variable("RecordSets", [ { "Name": "host.testdomain.com.", "Type": "A", "ResourceRecords": ["10.0.0.1"], }, ]), Variable("HostedZoneId", "fake_zone_id"), Variable("HostedZoneName", "fake_zone_name"), ]) with self.assertRaises(ValueError): blueprint.create_template()
def test_variable_replace_lookups_mixed(self): value = { "something": [ "${output fakeStack::FakeOutput}", "other", ], "here": { "other": "${output fakeStack::FakeOutput2}", "same": "${output fakeStack::FakeOutput}", "mixed": "something:${output fakeStack::FakeOutput3}", }, } var = Variable("Param1", value) var._value["something"][0]._resolve("resolved") var._value["here"]["other"]._resolve("resolved2") var._value["here"]["same"]._resolve("resolved") var._value["here"]["mixed"][1]._resolve("resolved3") self.assertEqual(var.value, { "something": [ "resolved", "other", ], "here": { "other": "resolved2", "same": "resolved", "mixed": "something:resolved3", }, })
def test_resolve_lookups_list_failed_variable_lookup(self): variable = Variable( "MyVar", [ "random string", "${output foo::bar}", "random string", ] ) self.resolve_lookups_with_output_handler_raise_valueerror(variable)
def test_resolve_lookups_list_unknown_lookup(self): with self.assertRaises(UnknownLookupType): Variable( "MyVar", [ "${bad_lookup foo}", "random string", ] )
def test_resolve_variables_lookup_returns_non_string_invalid_combo(self): class TestBlueprint(Blueprint): VARIABLES = { "Param1": {"type": list}, } def return_list_something(*_args, **_kwargs): return ["something"] register_lookup_handler("custom", return_list_something) variable = Variable( "Param1", "${custom non-string-return-val},${output some-stack::Output}", ) variable._value[0].resolve({}, {}) with self.assertRaises(InvalidLookupCombination): variable.value()
def test_variable_resolve_multiple_lookups_string(self): var = Variable( "Param1", "url://${output fakeStack::FakeOutput}@" "${output fakeStack::FakeOutput2}", ) stack = Stack( definition=generate_definition("vpc", 1), context=self.context) stack.set_outputs({ "FakeOutput": "resolved", "FakeOutput2": "resolved2", }) self.context.get_stack.return_value = stack var.resolve(self.context, self.provider) self.assertTrue(var.resolved) self.assertEqual(var.value, "url://resolved@resolved2")
def test_variable_resolve_nested_lookup(self): stack = Stack( definition=generate_definition("vpc", 1), context=self.context) stack.set_outputs({ "FakeOutput": "resolved", "FakeOutput2": "resolved2", }) def mock_handler(value, context, provider, **kwargs): return "looked up: {}".format(value) register_lookup_handler("lookup", mock_handler) self.context.get_stack.return_value = stack var = Variable( "Param1", "${lookup ${lookup ${output fakeStack::FakeOutput}}}", ) var.resolve(self.context, self.provider) self.assertTrue(var.resolved) self.assertEqual(var.value, "looked up: looked up: resolved")
def test_variable_resolve_default_lookup_empty(self): var = Variable("Param1", "${default fakeStack::}") var.resolve(self.context, self.provider) self.assertTrue(var.resolved) self.assertEqual(var.value, "")