Fix Promenade: Introduce flag to only warn on missing sub source
This PS introduces a flag to only warn on missing substitution sources because right now Promenade is failing on that. However, a PS will also have to be added to Promenade to set the new flag -- `fail_on_missing_sub_src` -- to False during genesis. Change-Id: I462f721c41e23d2e5e3e698c0bd452b6764d51eb
This commit is contained in:
parent
3d278a2b08
commit
87d7f94134
@ -265,7 +265,8 @@ class DocumentLayering(object):
|
|||||||
details='The following pre-validation errors occurred '
|
details='The following pre-validation errors occurred '
|
||||||
'(schema, name, error): %s.' % val_errors)
|
'(schema, name, error): %s.' % val_errors)
|
||||||
|
|
||||||
def __init__(self, documents, substitution_sources=None, validate=True):
|
def __init__(self, documents, substitution_sources=None, validate=True,
|
||||||
|
fail_on_missing_sub_src=True):
|
||||||
"""Contructor for ``DocumentLayering``.
|
"""Contructor for ``DocumentLayering``.
|
||||||
|
|
||||||
:param layering_policy: The document with schema
|
:param layering_policy: The document with schema
|
||||||
@ -280,6 +281,9 @@ class DocumentLayering(object):
|
|||||||
:param validate: Whether to pre-validate documents using built-in
|
:param validate: Whether to pre-validate documents using built-in
|
||||||
schema validation. Default is True.
|
schema validation. Default is True.
|
||||||
:type validate: bool
|
:type validate: bool
|
||||||
|
:param fail_on_missing_sub_src: Whether to fail on a missing
|
||||||
|
substitution source. Default is True.
|
||||||
|
:type fail_on_missing_sub_src: bool
|
||||||
|
|
||||||
:raises LayeringPolicyNotFound: If no LayeringPolicy was found among
|
:raises LayeringPolicyNotFound: If no LayeringPolicy was found among
|
||||||
list of ``documents``.
|
list of ``documents``.
|
||||||
@ -349,7 +353,8 @@ class DocumentLayering(object):
|
|||||||
self._calc_all_document_children()
|
self._calc_all_document_children()
|
||||||
self._substitution_sources = substitution_sources or []
|
self._substitution_sources = substitution_sources or []
|
||||||
self.secrets_substitution = secrets_manager.SecretsSubstitution(
|
self.secrets_substitution = secrets_manager.SecretsSubstitution(
|
||||||
self._substitution_sources)
|
self._substitution_sources,
|
||||||
|
fail_on_missing_sub_src=fail_on_missing_sub_src)
|
||||||
|
|
||||||
del self._documents_by_layer
|
del self._documents_by_layer
|
||||||
del self._documents_by_labels
|
del self._documents_by_labels
|
||||||
|
@ -105,7 +105,8 @@ class SecretsManager(object):
|
|||||||
class SecretsSubstitution(object):
|
class SecretsSubstitution(object):
|
||||||
"""Class for document substitution logic for YAML files."""
|
"""Class for document substitution logic for YAML files."""
|
||||||
|
|
||||||
def __init__(self, substitution_sources=None):
|
def __init__(self, substitution_sources=None,
|
||||||
|
fail_on_missing_sub_src=True):
|
||||||
"""SecretSubstitution constructor.
|
"""SecretSubstitution constructor.
|
||||||
|
|
||||||
This class will automatically detect documents that require
|
This class will automatically detect documents that require
|
||||||
@ -115,9 +116,12 @@ class SecretsSubstitution(object):
|
|||||||
:param substitution_sources: List of documents that are potential
|
:param substitution_sources: List of documents that are potential
|
||||||
sources for substitution. Should only include concrete documents.
|
sources for substitution. Should only include concrete documents.
|
||||||
:type substitution_sources: List[dict]
|
:type substitution_sources: List[dict]
|
||||||
|
:param bool fail_on_missing_sub_src: Whether to fail on a missing
|
||||||
|
substitution source. Default is True.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self._substitution_sources = {}
|
self._substitution_sources = {}
|
||||||
|
self._fail_on_missing_sub_src = fail_on_missing_sub_src
|
||||||
|
|
||||||
for document in substitution_sources:
|
for document in substitution_sources:
|
||||||
if not isinstance(document, document_wrapper.DocumentDict):
|
if not isinstance(document, document_wrapper.DocumentDict):
|
||||||
@ -175,11 +179,15 @@ class SecretsSubstitution(object):
|
|||||||
message = ('Could not find substitution source document '
|
message = ('Could not find substitution source document '
|
||||||
'[%s] %s among the provided '
|
'[%s] %s among the provided '
|
||||||
'`substitution_sources`.', src_schema, src_name)
|
'`substitution_sources`.', src_schema, src_name)
|
||||||
LOG.error(message)
|
if self._fail_on_missing_sub_src:
|
||||||
raise errors.SubstitutionSourceNotFound(
|
LOG.error(message)
|
||||||
src_schema=src_schema, src_name=src_name,
|
raise errors.SubstitutionSourceNotFound(
|
||||||
document_schema=document.schema,
|
src_schema=src_schema, src_name=src_name,
|
||||||
document_name=document.name)
|
document_schema=document.schema,
|
||||||
|
document_name=document.name)
|
||||||
|
else:
|
||||||
|
LOG.warning(message)
|
||||||
|
continue
|
||||||
|
|
||||||
# If the data is a dictionary, retrieve the nested secret
|
# If the data is a dictionary, retrieve the nested secret
|
||||||
# via jsonpath_parse, else the secret is the primitive/string
|
# via jsonpath_parse, else the secret is the primitive/string
|
||||||
|
@ -14,7 +14,10 @@
|
|||||||
|
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
|
import mock
|
||||||
|
|
||||||
from deckhand.engine import layering
|
from deckhand.engine import layering
|
||||||
|
from deckhand.engine import secrets_manager
|
||||||
from deckhand import errors
|
from deckhand import errors
|
||||||
from deckhand import factories
|
from deckhand import factories
|
||||||
from deckhand.tests.unit import base as test_base
|
from deckhand.tests.unit import base as test_base
|
||||||
@ -88,6 +91,34 @@ class TestDocumentLayering(test_base.DeckhandTestCase):
|
|||||||
self.assertEmpty(global_docs)
|
self.assertEmpty(global_docs)
|
||||||
|
|
||||||
|
|
||||||
|
class TestDocumentLayeringScenarios(TestDocumentLayering):
|
||||||
|
|
||||||
|
@mock.patch.object(secrets_manager, 'LOG', autospec=True)
|
||||||
|
def test_layering_with_missing_substitution_source_log_warning(self,
|
||||||
|
m_log):
|
||||||
|
"""Validate that a missing substitution source document fails."""
|
||||||
|
mapping = {
|
||||||
|
"_SITE_SUBSTITUTIONS_1_": [{
|
||||||
|
"dest": {
|
||||||
|
"path": ".c"
|
||||||
|
},
|
||||||
|
"src": {
|
||||||
|
"schema": "example/Kind/v1",
|
||||||
|
"name": "nowhere-to-be-found",
|
||||||
|
"path": "."
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
doc_factory = factories.DocumentFactory(2, [1, 1])
|
||||||
|
documents = doc_factory.gen_test(mapping, site_abstract=False)
|
||||||
|
|
||||||
|
self._test_layering(documents, site_expected={},
|
||||||
|
fail_on_missing_sub_src=False)
|
||||||
|
self.assertTrue(m_log.warning.called)
|
||||||
|
self.assertRegex(m_log.warning.mock_calls[0][1][0][0],
|
||||||
|
r'Could not find substitution source document .*')
|
||||||
|
|
||||||
|
|
||||||
class TestDocumentLayering2Layers(TestDocumentLayering):
|
class TestDocumentLayering2Layers(TestDocumentLayering):
|
||||||
|
|
||||||
def test_layering_default_scenario(self):
|
def test_layering_default_scenario(self):
|
||||||
|
Loading…
Reference in New Issue
Block a user