Update default_schema with our updated schema definition

This commit updates the default_schema based on recent changes
to the document definition that Deckhand is supposed to validate.
This commit is contained in:
Felipe Monteiro 2017-07-12 16:52:02 +01:00
parent 81a87c5444
commit ac557f70f4
4 changed files with 80 additions and 56 deletions

View File

@ -15,19 +15,29 @@
substitution_schema = { substitution_schema = {
'type': 'object', 'type': 'object',
'properties': { 'properties': {
'dest': {'type': 'string'}, 'dest': {
'type': 'object',
'properties': {
'path': {'type': 'string'},
'replacePattern': {'type': 'string'}
},
'additionalProperties': False,
# 'replacePattern' is not required.
'required': ['path']
},
'src': { 'src': {
'type': 'object', 'type': 'object',
'properties': { 'properties': {
'apiVersion': { 'apiVersion': {
'type': 'string', 'type': 'string',
'choices': ['deckhand/v1'] 'pattern': '^([A-Za-z]+\/v[0-9]{1})$'
}, },
'kind': {'type': 'string'}, 'kind': {'type': 'string'},
'name': {'type': 'string'} 'name': {'type': 'string'},
'path': {'type': 'string'}
}, },
'additionalProperties': False, 'additionalProperties': False,
'required': ['apiVersion', 'kind', 'name'] 'required': ['apiVersion', 'kind', 'name', 'path']
} }
}, },
'additionalProperties': False, 'additionalProperties': False,
@ -37,31 +47,58 @@ substitution_schema = {
schema = { schema = {
'type': 'object', 'type': 'object',
'properties': { 'properties': {
'apiVersion': { 'schemaVersion': {
'type': 'string', 'type': 'string',
'pattern': '^([A-Za-z]+\/v[0-9]{1})$' 'pattern': '^([A-Za-z]+\/v[0-9]{1})$'
}, },
'kind': { 'kind': {'type': 'string'},
'type': 'string',
'pattern': '^([A-Za-z]+)$'
},
'metadata': { 'metadata': {
'type': 'object', 'type': 'object',
'properties': { 'properties': {
'metadataVersion': {
'type': 'string',
'pattern': '^([A-Za-z]+\/v[0-9]{1})$'
},
'name': {'type': 'string'}, 'name': {'type': 'string'},
'storage': {'type': 'string'}, 'labels': {
'type': 'object',
'properties': {
'component': {'type': 'string'},
'hostname': {'type': 'string'}
},
'additionalProperties': False,
'required': ['component', 'hostname']
},
'layerDefinition': {
'type': 'object',
'properties': {
'layer': {'enum': ['global', 'region', 'local']},
'abstract': {'type': 'boolean'},
'childSelector': {
'type': 'object',
'properties': {
'label': {'type': 'string'}
},
'additionalProperties': False,
'required': ['label']
}
},
'additionalProperties': False,
'required': ['layer', 'abstract', 'childSelector']
},
'substitutions': { 'substitutions': {
'type': 'array', 'type': 'array',
'items': substitution_schema 'items': substitution_schema
} }
}, },
'additionalProperties': False, 'additionalProperties': False,
'required': ['name', 'storage', 'substitutions'] 'required': ['metadataVersion', 'name', 'labels',
'layerDefinition', 'substitutions']
}, },
'data': { 'data': {
'type': 'object' 'type': 'object'
} }
}, },
'additionalProperties': False, 'additionalProperties': False,
'required': ['apiVersion', 'kind', 'metadata', 'data'] 'required': ['schemaVersion', 'kind', 'metadata', 'data']
} }

View File

@ -61,33 +61,7 @@ class SecretSubstitution(object):
if v['version'] == self.schema_version][0].schema if v['version'] == self.schema_version][0].schema
def validate_data(self): def validate_data(self):
"""Pre-validate that the YAML file is correctly formatted. """Pre-validate that the YAML file is correctly formatted."""
The YAML file must adhere to the following bare minimum format:
.. code-block:: yaml
---
apiVersion: service/v1
kind: ConsumerOfCertificateData
metadata:
substitutions:
- dest: .tls_endpoint.certificate
src:
apiVersion: deckhand/v1
kind: Certificate
name: some-certificate-asdf-1234
# Forward-reference to specific section under "data" below.
- dest: .tls_endpoint.certificateKey
src:
apiVersion: deckhand/v1
kind: CertificateKey
name: some-certificate-key-asdf-1234
data:
tls_endpoint:
certificate: null # Data to be substituted.
certificateKey: null # Data to be substituted.
"""
self._validate_with_schema() self._validate_with_schema()
# Validate that each "dest" field exists in the YAML data. # Validate that each "dest" field exists in the YAML data.
@ -96,7 +70,7 @@ class SecretSubstitution(object):
sub_data = self.data['data'] sub_data = self.data['data']
for dest in destinations: for dest in destinations:
result, missing_attr = self._multi_getattr(dest, sub_data) result, missing_attr = self._multi_getattr(dest['path'], sub_data)
if not result: if not result:
raise errors.InvalidFormat( raise errors.InvalidFormat(
'The attribute "%s" included in the "dest" field "%s" is ' 'The attribute "%s" included in the "dest" field "%s" is '
@ -109,7 +83,7 @@ class SecretSubstitution(object):
# Validate that a schema with "apiVersion" version number exists, then # Validate that a schema with "apiVersion" version number exists, then
# use that schema to validate the YAML data. # use that schema to validate the YAML data.
try: try:
schema_version = self.data['apiVersion'].split('/')[-1] schema_version = self.data['schemaVersion'].split('/')[-1]
data_schema_version = self.SchemaVersion(schema_version) data_schema_version = self.SchemaVersion(schema_version)
except (AttributeError, IndexError, KeyError) as e: except (AttributeError, IndexError, KeyError) as e:
raise errors.InvalidFormat( raise errors.InvalidFormat(

View File

@ -85,8 +85,8 @@ class TestSecretSubtitution(testtools.TestCase):
invalid_data = [ invalid_data = [
(self._corrupt_data('data'), 'data'), (self._corrupt_data('data'), 'data'),
(self._corrupt_data('metadata'), 'metadata'), (self._corrupt_data('metadata'), 'metadata'),
(self._corrupt_data('metadata.metadataVersion'), 'metadataVersion'),
(self._corrupt_data('metadata.name'), 'name'), (self._corrupt_data('metadata.name'), 'name'),
(self._corrupt_data('metadata.storage'), 'storage'),
(self._corrupt_data('metadata.substitutions'), 'substitutions'), (self._corrupt_data('metadata.substitutions'), 'substitutions'),
(self._corrupt_data('metadata.substitutions.0.dest'), 'dest'), (self._corrupt_data('metadata.substitutions.0.dest'), 'dest'),
(self._corrupt_data('metadata.substitutions.0.src'), 'src') (self._corrupt_data('metadata.substitutions.0.src'), 'src')
@ -103,11 +103,12 @@ class TestSecretSubtitution(testtools.TestCase):
invalid_data = [] invalid_data = []
data = copy.deepcopy(self.data) data = copy.deepcopy(self.data)
data['metadata']['substitutions'][0]['dest'] = 'foo' data['metadata']['substitutions'][0]['dest'] = {'path': 'foo'}
invalid_data.append(self._format_data(data)) invalid_data.append(self._format_data(data))
data = copy.deepcopy(self.data) data = copy.deepcopy(self.data)
data['metadata']['substitutions'][0]['dest'] = 'tls_endpoint.bar' data['metadata']['substitutions'][0]['dest'] = {
'path': 'tls_endpoint.bar'}
invalid_data.append(self._format_data(data)) invalid_data.append(self._format_data(data))
def _test(invalid_entry, field, dest): def _test(invalid_entry, field, dest):
@ -117,6 +118,6 @@ class TestSecretSubtitution(testtools.TestCase):
secret_substitution.SecretSubstitution(invalid_entry) secret_substitution.SecretSubstitution(invalid_entry)
# Verify that invalid body dest reference is invalid. # Verify that invalid body dest reference is invalid.
_test(invalid_data[0], "foo", "foo") _test(invalid_data[0], "foo", {'path': 'foo'})
# Verify that nested invalid body dest reference is invalid. # Verify that nested invalid body dest reference is invalid.
_test(invalid_data[1], "bar", "tls_endpoint.bar") _test(invalid_data[1], "bar", {'path': 'tls_endpoint.bar'})

View File

@ -1,23 +1,35 @@
# Sample YAML file for testing forward replacement. # Sample YAML file for testing forward replacement.
--- ---
apiVersion: service/v1 schemaVersion: promenade/v1
kind: ConsumerOfCertificateData kind: SomeConfigType
metadata: metadata:
name: asdf-1234 metadataVersion: deckhand/v1
storage: cleartext name: a-unique-config-name-12345
labels:
component: apiserver
hostname: server0
layerDefinition:
layer: global
abstract: True
childSelector:
label: value
substitutions: substitutions:
- dest: .tls_endpoint.certificate - dest:
path: .tls_endpoint.certificate
replacePattern: 'test.pattern'
src: src:
apiVersion: deckhand/v1 apiVersion: deckhand/v1
kind: Certificate kind: Certificate
name: some-certificate-asdf-1234 name: some-certificate-asdf-1234
- dest: .tls_endpoint.certificateKey path: .cert
- dest:
path: .tls_endpoint.key
src: src:
apiVersion: deckhand/v1 apiVersion: deckhand/v1
kind: CertificateKey kind: CertificateKey
name: some-certificate-key-asdf-1234 name: some-certificate-asdf-1234
path: .key
data: data:
tls_endpoint: tls_endpoint:
uri: http://localhost:443 certificate: '.cert'
certificate: null key: deckhand/v1:some-certificate-asdf-1234
certificateKey: null