diff --git a/deckhand/engine/layering.py b/deckhand/engine/layering.py index 62f399dd..585ede84 100644 --- a/deckhand/engine/layering.py +++ b/deckhand/engine/layering.py @@ -483,16 +483,20 @@ class DocumentLayering(object): self._documents_by_index[(doc.schema, doc.name)] = ( rendered_data) - # Update the actual document data if concrete. - if not doc.is_abstract: + # Perform substitutions on abstract data for child documents that + # inherit from it, but only update the document's data if concrete. + if doc.substitutions: substituted_data = list( self.secrets_substitution.substitute_all(doc)) if substituted_data: rendered_data = substituted_data[0] - doc.data = rendered_data.data + # Update the actual document data if concrete. + if not doc.is_abstract: + doc.data = rendered_data.data self.secrets_substitution.update_substitution_sources( doc.schema, doc.name, rendered_data.data) - self._documents_by_index[(doc.schema, doc.name)] = doc + self._documents_by_index[(doc.schema, doc.name)] = ( + rendered_data) # Return only concrete documents. return [d for d in self._sorted_documents if d.is_abstract is False] diff --git a/deckhand/tests/unit/engine/test_document_layering_and_substitution.py b/deckhand/tests/unit/engine/test_document_layering_and_substitution.py index 63dca721..030ce0c3 100644 --- a/deckhand/tests/unit/engine/test_document_layering_and_substitution.py +++ b/deckhand/tests/unit/engine/test_document_layering_and_substitution.py @@ -676,3 +676,40 @@ class TestDocumentLayeringWithSubstitution( global_expected=global_expected, substitution_sources=[ certificate, certificate_key] + documents) + + def test_layering_and_substitution_site_abstract_and_global_concrete(self): + """Verifies that if a global document is abstract, yet has + substitutions, those substitutions are performed and carry down to + concrete children that inherit from the abstract parent. + """ + secrets_factory = factories.DocumentSecretFactory() + certificate = secrets_factory.gen_test( + 'Certificate', 'cleartext', data='global-secret', + name='global-cert') + + mapping = { + "_GLOBAL_DATA_1_": {"data": {"global": "random"}}, + "_GLOBAL_SUBSTITUTIONS_1_": [{ + "dest": { + "path": ".cert" + }, + "src": { + "schema": certificate['schema'], + "name": certificate['metadata']['name'], + "path": "." + } + }], + "_SITE_DATA_1_": {"data": {"site": "stuff"}}, + "_SITE_ACTIONS_1_": { + "actions": [{"method": "merge", "path": "."}]} + } + doc_factory = factories.DocumentFactory(2, [1, 1]) + documents = doc_factory.gen_test(mapping, site_abstract=False, + global_abstract=True) + + site_expected = {"global": "random", "cert": "global-secret", + "site": "stuff"} + global_expected = None + self._test_layering(documents, site_expected, + global_expected=global_expected, + substitution_sources=[certificate])