deckhand/deckhand/tests/unit/engine/test_document_layering_and_...

431 lines
12 KiB
Python

# Copyright 2018 AT&T Intellectual Property. All other rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import inspect
import itertools
import os
import yaml
from deckhand.tests.unit.engine import test_document_layering
REPLACEMENT_3_TIER_SAMPLE = list(yaml.safe_load_all(inspect.cleandoc(
"""
---
schema: deckhand/LayeringPolicy/v1
metadata:
schema: metadata/Control/v1
name: layering-policy
storagePolicy: cleartext
data:
layerOrder:
- global
- region
- site
---
schema: armada/Chart/v1
metadata:
schema: metadata/Document/v1
name: nova-global
storagePolicy: cleartext
labels:
name: nova-global
component: nova
layeringDefinition:
abstract: false
layer: global
data:
values:
pod:
replicas:
server: 16
---
schema: armada/Chart/v1
metadata:
schema: metadata/Document/v1
name: nova
storagePolicy: cleartext
labels:
name: nova-5ec
component: nova
layeringDefinition:
abstract: false
layer: region
parentSelector:
name: nova-global
actions:
- method: merge
path: .
data: {}
---
schema: armada/Chart/v1
metadata:
schema: metadata/Document/v1
replacement: true
storagePolicy: cleartext
name: nova
layeringDefinition:
abstract: false
layer: site
parentSelector:
name: nova-5ec
actions:
- method: merge
path: .
data:
values:
pod:
replicas:
api_metadata: 16
placement: 2
osapi: 16
conductor: 16
consoleauth: 2
scheduler: 2
novncproxy: 2
""")))
class TestDocumentLayeringWithReplacement(
test_document_layering.TestDocumentLayering):
def setUp(self):
super(TestDocumentLayeringWithReplacement, self).setUp()
self.documents = list(yaml.safe_load_all("""
---
schema: deckhand/LayeringPolicy/v1
metadata:
schema: metadata/Control/v1
name: layering-policy
storagePolicy: cleartext
data:
layerOrder:
- global
- site
---
schema: aic/Versions/v1
metadata:
schema: metadata/Document/v1
name: a
storagePolicy: cleartext
labels:
selector: foo
layeringDefinition:
abstract: False
layer: global
data:
conf:
foo: default
---
schema: aic/Versions/v1
metadata:
schema: metadata/Document/v1
name: a
storagePolicy: cleartext
labels:
selector: baz
replacement: true
layeringDefinition:
abstract: False
layer: site
parentSelector:
selector: foo
actions:
- method: merge
path: .
data:
conf:
bar: override
---
schema: armada/Chart/v1
metadata:
schema: metadata/Document/v1
name: c
storagePolicy: cleartext
layeringDefinition:
abstract: False
layer: global
substitutions:
- src:
schema: aic/Versions/v1
name: a
path: .conf
dest:
path: .application.conf
data:
application:
conf: {}
...
"""))
def test_basic_replacement(self):
"""Verify that the replacement document is the only one returned."""
site_expected = [{"conf": {"foo": "default", "bar": "override"}}]
global_expected = None
self.documents = self.documents[:-1]
self._test_layering(self.documents, site_expected,
global_expected=global_expected)
def test_replacement_with_substitution_from_replacer(self):
"""Verify that using a replacement document as a substitution source
works.
"""
site_expected = [{"conf": {"foo": "default", "bar": "override"}}]
global_expected = [
{"application": {"conf": {"foo": "default", "bar": "override"}}}]
# The replacer should be used as the source.
self._test_layering(self.documents, site_expected,
global_expected=global_expected)
# Try different permutations of document orders for good measure.
for documents in list(itertools.permutations(self.documents))[:10]:
self._test_layering(
documents, site_expected=site_expected,
global_expected=global_expected)
def test_replacement_with_layering_with_replacer(self):
"""Verify that replacement works alongside layering. This scenario
involves a parent, a child that replaces its parent, and yet another
child that layers with the replacement document.
"""
self.documents = list(yaml.safe_load_all("""
---
schema: deckhand/LayeringPolicy/v1
metadata:
schema: metadata/Control/v1
name: layering-policy
storagePolicy: cleartext
data:
layerOrder:
- global
- site
---
schema: aic/Versions/v1
metadata:
schema: metadata/Document/v1
name: a
storagePolicy: cleartext
labels:
selector: foo
layeringDefinition:
abstract: False
layer: global
data:
conf:
foo: default
---
schema: aic/Versions/v1
metadata:
schema: metadata/Document/v1
name: a
labels:
selector: baz
replacement: true
storagePolicy: cleartext
layeringDefinition:
abstract: False
layer: site
parentSelector:
selector: foo
actions:
- method: merge
path: .
data:
conf:
bar: override
---
schema: aic/Versions/v1
metadata:
schema: metadata/Document/v1
name: b
storagePolicy: cleartext
labels:
selector: qux
layeringDefinition:
abstract: False
layer: site
parentSelector:
selector: foo
actions:
- method: merge
path: .
data:
conf:
baz: another
---
schema: armada/Chart/v1
metadata:
schema: metadata/Document/v1
name: c
storagePolicy: cleartext
layeringDefinition:
abstract: False
layer: global
substitutions:
- src:
schema: aic/Versions/v1
name: a
path: .conf
dest:
path: .application.conf
data:
application:
conf: {}
...
"""))
site_expected = [
{"conf": {"foo": "default", "bar": "override"}},
{"conf": {"foo": "default", "bar": "override", "baz": "another"}},
]
global_expected = [
{"application": {"conf": {"foo": "default", "bar": "override"}}}
]
self._test_layering(self.documents, site_expected=site_expected,
global_expected=global_expected)
# Try different permutations of document orders for good measure.
for documents in list(itertools.permutations(self.documents))[:10]:
self._test_layering(
documents, site_expected=site_expected,
global_expected=global_expected)
def test_replacement_document_receives_substitution(self):
"""Verifies that the parent-replacement receives substitution data
prior to the child-replacement layering with it, which in turn is
done prior to any other document attempting to substitute from or
layer with the child-replacement (which replaces its parent).
"""
test_path = os.path.join(
os.getcwd(), 'deckhand', 'tests', 'functional', 'gabbits',
'resources', 'replacement.yaml')
with open(test_path) as f:
self.documents = list(yaml.safe_load_all(f))
site_expected = [
"CERTIFICATE DATA\n",
"KEY DATA\n",
{
'chart': {
'details': {'data': 'bar'},
'values': {
'tls': {
'certificate': 'CERTIFICATE DATA\n',
'key': 'KEY DATA\n'
}
}
}
}
]
self._test_layering(self.documents, site_expected=site_expected,
region_expected=None)
# Try different permutations of document orders for good measure.
for documents in list(itertools.permutations(self.documents))[:10]:
self._test_layering(
documents, site_expected=site_expected,
region_expected=None)
def test_multi_layer_replacement(self):
"""Validate the following scenario:
* Global document called nova-global
* Region document called nova (layers with nova-global)
* Site document (replaces region document)
"""
site_expected = [
{
"values": {
"pod": {
"replicas": {
"api_metadata": 16,
"placement": 2,
"osapi": 16,
"conductor": 16,
"consoleauth": 2,
"scheduler": 2,
"novncproxy": 2,
"server": 16
}
}
}
}
]
global_expected = [
{
"values": {
"pod": {
"replicas": {
"server": 16
}
}
}
}
]
self._test_layering(REPLACEMENT_3_TIER_SAMPLE,
site_expected=site_expected,
region_expected=None,
global_expected=global_expected)
def test_multi_layer_replacement_with_intermediate_replacement(self):
"""Validate the following scenario:
* Global document called nova-replace
* Region document called nova-replace (layers with nova-replace and
replaces it)
* Site document (layers with region document)
"""
replacement_sample = list(REPLACEMENT_3_TIER_SAMPLE)
replacement_sample[1]['metadata']['name'] = 'nova-replace'
replacement_sample[2]['metadata']['name'] = 'nova-replace'
replacement_sample[2]['metadata']['replacement'] = True
replacement_sample[3]['metadata']['replacement'] = False
site_expected = [
{
"values": {
"pod": {
"replicas": {
"api_metadata": 16,
"placement": 2,
"osapi": 16,
"conductor": 16,
"consoleauth": 2,
"scheduler": 2,
"novncproxy": 2,
"server": 16
}
}
}
}
]
region_expected = [
{
"values": {
"pod": {
"replicas": {
"server": 16
}
}
}
}
]
self._test_layering(replacement_sample,
site_expected=site_expected,
region_expected=region_expected,
global_expected=None)