[402036] add DeploymentStrategy schema
In support of a larger effort to introduce a DeploymentStrategy document for Shipyard to use to drive baremetal node deployment, this change adds a schema and tests for that schema. Change-Id: I94c41f0ee8c8cf9c3762c5c1af575798fb1dccb4
This commit is contained in:
parent
47cd7a25f4
commit
6e32acbae1
shipyard_airflow/schemas
tests/unit
schemas
yaml_samples
deploymentStrategy_bad_values_1.yamldeploymentStrategy_bad_values_2.yamldeploymentStrategy_bad_values_3.yamldeploymentStrategy_bad_values_4.yamldeploymentStrategy_bad_values_5.yamldeploymentStrategy_full_valid.yamldeploymentStrategy_min_with_content.yamldeploymentStrategy_minimal.yamlempty.yamltotal_garbage.yaml
@ -1,4 +1,3 @@
|
||||
|
||||
---
|
||||
schema: 'deckhand/DataSchema/v1'
|
||||
metadata:
|
||||
@ -16,8 +15,6 @@ data:
|
||||
properties:
|
||||
deployment_strategy:
|
||||
type: 'string'
|
||||
enum:
|
||||
- 'all-at-once'
|
||||
deploy_interval:
|
||||
type: 'integer'
|
||||
deploy_timeout:
|
||||
|
74
shipyard_airflow/schemas/deploymentStrategy.yaml
Normal file
74
shipyard_airflow/schemas/deploymentStrategy.yaml
Normal file
@ -0,0 +1,74 @@
|
||||
---
|
||||
schema: 'deckhand/DataSchema/v1'
|
||||
metadata:
|
||||
schema: metadata/Control/v1
|
||||
name: shipyard/DeploymentStrategy/v1
|
||||
labels:
|
||||
application: shipyard
|
||||
data:
|
||||
$schema: 'http://json-schema.org/schema#'
|
||||
id: 'https://github.com/att-comdev/shipyard/deploymentStrategy.yaml'
|
||||
type: 'object'
|
||||
required:
|
||||
- groups
|
||||
properties:
|
||||
groups:
|
||||
type: 'array'
|
||||
minItems: 0
|
||||
items:
|
||||
type: 'object'
|
||||
required:
|
||||
- name
|
||||
- critical
|
||||
- depends_on
|
||||
- selectors
|
||||
properties:
|
||||
name:
|
||||
type: 'string'
|
||||
minLength: 1
|
||||
critical:
|
||||
type: 'boolean'
|
||||
depends_on:
|
||||
type: 'array'
|
||||
minItems: 0
|
||||
items:
|
||||
type: 'string'
|
||||
selectors:
|
||||
type: 'array'
|
||||
minItems: 0
|
||||
items:
|
||||
type: 'object'
|
||||
minProperties: 1
|
||||
properties:
|
||||
node_names:
|
||||
type: 'array'
|
||||
items:
|
||||
type: 'string'
|
||||
node_labels:
|
||||
type: 'array'
|
||||
items:
|
||||
type: 'string'
|
||||
node_tags:
|
||||
type: 'array'
|
||||
items:
|
||||
type: 'string'
|
||||
rack_names:
|
||||
type: 'array'
|
||||
items:
|
||||
type: 'string'
|
||||
additionalProperties: false
|
||||
success_criteria:
|
||||
type: 'object'
|
||||
minProperties: 1
|
||||
properties:
|
||||
percent_successful_nodes:
|
||||
type: 'integer'
|
||||
minimum: 0
|
||||
maximum: 100
|
||||
minimum_successful_nodes:
|
||||
type: 'integer'
|
||||
minimum: 0
|
||||
maximum_failed_nodes:
|
||||
type: 'integer'
|
||||
minimum: 0
|
||||
additionalProperties: false
|
51
tests/unit/schemas/base_schema_validation.py
Normal file
51
tests/unit/schemas/base_schema_validation.py
Normal file
@ -0,0 +1,51 @@
|
||||
# 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 logging
|
||||
import os
|
||||
import yaml
|
||||
|
||||
import jsonschema
|
||||
import pkg_resources
|
||||
import pytest
|
||||
|
||||
from jsonschema.exceptions import ValidationError
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class BaseSchemaValidationTest(object):
|
||||
def _test_validate(self, schema, expect_failure, input_files, input):
|
||||
"""validates input yaml against schema.
|
||||
:param schema: schema yaml file
|
||||
:param expect_failure: should the validation pass or fail.
|
||||
:param input_files: pytest fixture used to access the test input files
|
||||
:param input: test input yaml doc filename"""
|
||||
schema_dir = pkg_resources.resource_filename('shipyard_airflow',
|
||||
'schemas')
|
||||
schema_filename = os.path.join(schema_dir, schema)
|
||||
schema_file = open(schema_filename, 'r')
|
||||
schema = yaml.safe_load(schema_file)
|
||||
|
||||
input_file = input_files.join(input)
|
||||
instance_file = open(str(input_file), 'r')
|
||||
instance = yaml.safe_load(instance_file)
|
||||
|
||||
LOG.info('Input: %s, Schema: %s', input_file, schema_filename)
|
||||
|
||||
if expect_failure:
|
||||
# TypeError is raised when he input document is not well formed.
|
||||
with pytest.raises((ValidationError, TypeError)):
|
||||
jsonschema.validate(instance['data'], schema['data'])
|
||||
else:
|
||||
jsonschema.validate(instance['data'], schema['data'])
|
31
tests/unit/schemas/conftest.py
Normal file
31
tests/unit/schemas/conftest.py
Normal file
@ -0,0 +1,31 @@
|
||||
# Copyright 2017 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 os
|
||||
|
||||
import pytest
|
||||
import shutil
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def input_files(tmpdir_factory, request):
|
||||
tmpdir = tmpdir_factory.mktemp('data')
|
||||
samples_dir = os.path.dirname(str(
|
||||
request.fspath)) + "/" + "../yaml_samples"
|
||||
samples = os.listdir(samples_dir)
|
||||
|
||||
for f in samples:
|
||||
src_file = samples_dir + "/" + f
|
||||
dst_file = str(tmpdir) + "/" + f
|
||||
shutil.copyfile(src_file, dst_file)
|
||||
return tmpdir
|
@ -11,44 +11,7 @@
|
||||
# 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 logging
|
||||
import os
|
||||
import yaml
|
||||
|
||||
import jsonschema
|
||||
import pkg_resources
|
||||
import pytest
|
||||
import shutil
|
||||
|
||||
from jsonschema.exceptions import ValidationError
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class BaseSchemaValidationTest(object):
|
||||
def _test_validate(self, schema, expect_failure, input_files, input):
|
||||
"""validates input yaml against schema.
|
||||
:param schema: schema yaml file
|
||||
:param expect_failure: should the validation pass or fail.
|
||||
:param input_files: pytest fixture used to access the test input files
|
||||
:param input: test input yaml doc filename"""
|
||||
schema_dir = pkg_resources.resource_filename('shipyard_airflow',
|
||||
'schemas')
|
||||
schema_filename = os.path.join(schema_dir, schema)
|
||||
schema_file = open(schema_filename, 'r')
|
||||
schema = yaml.safe_load(schema_file)
|
||||
|
||||
input_file = input_files.join(input)
|
||||
instance_file = open(str(input_file), 'r')
|
||||
instance = yaml.safe_load(instance_file)
|
||||
|
||||
LOG.info('Input: %s, Schema: %s', input_file, schema_filename)
|
||||
|
||||
if expect_failure:
|
||||
with pytest.raises(ValidationError):
|
||||
jsonschema.validate(instance['data'], schema['data'])
|
||||
else:
|
||||
jsonschema.validate(instance['data'], schema['data'])
|
||||
from .base_schema_validation import BaseSchemaValidationTest
|
||||
|
||||
|
||||
class TestValidation(BaseSchemaValidationTest):
|
||||
@ -63,16 +26,3 @@ class TestValidation(BaseSchemaValidationTest):
|
||||
def test_validate_deploy_config_minimal_valid(self, input_files):
|
||||
self._test_validate('deploymentConfiguration.yaml', False, input_files,
|
||||
'deploymentConfiguration_minimal_valid.yaml')
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def input_files(self, tmpdir_factory, request):
|
||||
tmpdir = tmpdir_factory.mktemp('data')
|
||||
samples_dir = os.path.dirname(str(
|
||||
request.fspath)) + "/" + "../yaml_samples"
|
||||
samples = os.listdir(samples_dir)
|
||||
|
||||
for f in samples:
|
||||
src_file = samples_dir + "/" + f
|
||||
dst_file = str(tmpdir) + "/" + f
|
||||
shutil.copyfile(src_file, dst_file)
|
||||
return tmpdir
|
||||
|
38
tests/unit/schemas/test_deployment_strategy.py
Normal file
38
tests/unit/schemas/test_deployment_strategy.py
Normal file
@ -0,0 +1,38 @@
|
||||
# Copyright 2017 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.
|
||||
from .base_schema_validation import BaseSchemaValidationTest
|
||||
|
||||
|
||||
class TestValidation(BaseSchemaValidationTest):
|
||||
def test_validate_deploy_config_full_valid(self, input_files):
|
||||
self._test_validate('deploymentStrategy.yaml', False, input_files,
|
||||
'deploymentStrategy_full_valid.yaml')
|
||||
|
||||
self._test_validate('deploymentStrategy.yaml', False, input_files,
|
||||
'deploymentStrategy_minimal.yaml')
|
||||
|
||||
self._test_validate('deploymentStrategy.yaml', False, input_files,
|
||||
'deploymentStrategy_min_with_content.yaml')
|
||||
|
||||
for testnum in range(1, 5):
|
||||
self._test_validate(
|
||||
'deploymentStrategy.yaml', True, input_files,
|
||||
'deploymentStrategy_bad_values_{}.yaml'.format(testnum)
|
||||
)
|
||||
|
||||
self._test_validate('deploymentStrategy.yaml', True, input_files,
|
||||
'total_garbage.yaml')
|
||||
|
||||
self._test_validate('deploymentStrategy.yaml', True, input_files,
|
||||
'empty.yaml')
|
16
tests/unit/yaml_samples/deploymentStrategy_bad_values_1.yaml
Normal file
16
tests/unit/yaml_samples/deploymentStrategy_bad_values_1.yaml
Normal file
@ -0,0 +1,16 @@
|
||||
---
|
||||
schema: shipyard/DeploymentStrategy/v1
|
||||
metadata:
|
||||
schema: metadata/Document/v1
|
||||
name: deployment-strategy
|
||||
layeringDefinition:
|
||||
abstract: false
|
||||
layer: global
|
||||
storagePolicy: cleartext
|
||||
data:
|
||||
groups:
|
||||
# name is a min length of 1
|
||||
- name: ""
|
||||
critical: false
|
||||
depends_on: []
|
||||
selectors: []
|
16
tests/unit/yaml_samples/deploymentStrategy_bad_values_2.yaml
Normal file
16
tests/unit/yaml_samples/deploymentStrategy_bad_values_2.yaml
Normal file
@ -0,0 +1,16 @@
|
||||
---
|
||||
schema: shipyard/DeploymentStrategy/v1
|
||||
metadata:
|
||||
schema: metadata/Document/v1
|
||||
name: deployment-strategy
|
||||
layeringDefinition:
|
||||
abstract: false
|
||||
layer: global
|
||||
storagePolicy: cleartext
|
||||
data:
|
||||
groups:
|
||||
- name: a_group
|
||||
# critical is boolean
|
||||
critical: cheese sandwich
|
||||
depends_on: []
|
||||
selectors: []
|
15
tests/unit/yaml_samples/deploymentStrategy_bad_values_3.yaml
Normal file
15
tests/unit/yaml_samples/deploymentStrategy_bad_values_3.yaml
Normal file
@ -0,0 +1,15 @@
|
||||
---
|
||||
schema: shipyard/DeploymentStrategy/v1
|
||||
metadata:
|
||||
schema: metadata/Document/v1
|
||||
name: deployment-strategy
|
||||
layeringDefinition:
|
||||
abstract: false
|
||||
layer: global
|
||||
storagePolicy: cleartext
|
||||
data:
|
||||
groups:
|
||||
- name: some_group
|
||||
critical: true
|
||||
# depends_on missing
|
||||
selectors: []
|
18
tests/unit/yaml_samples/deploymentStrategy_bad_values_4.yaml
Normal file
18
tests/unit/yaml_samples/deploymentStrategy_bad_values_4.yaml
Normal file
@ -0,0 +1,18 @@
|
||||
---
|
||||
schema: shipyard/DeploymentStrategy/v1
|
||||
metadata:
|
||||
schema: metadata/Document/v1
|
||||
name: deployment-strategy
|
||||
layeringDefinition:
|
||||
abstract: false
|
||||
layer: global
|
||||
storagePolicy: cleartext
|
||||
data:
|
||||
groups:
|
||||
- name: my_name_is
|
||||
critical: false
|
||||
depends_on: []
|
||||
selectors:
|
||||
# node_names are strings
|
||||
- node_names: [false, true, false]
|
||||
node_labels: []
|
20
tests/unit/yaml_samples/deploymentStrategy_bad_values_5.yaml
Normal file
20
tests/unit/yaml_samples/deploymentStrategy_bad_values_5.yaml
Normal file
@ -0,0 +1,20 @@
|
||||
---
|
||||
schema: shipyard/DeploymentStrategy/v1
|
||||
metadata:
|
||||
schema: metadata/Document/v1
|
||||
name: deployment-strategy
|
||||
layeringDefinition:
|
||||
abstract: false
|
||||
layer: global
|
||||
storagePolicy: cleartext
|
||||
data:
|
||||
groups:
|
||||
- name: my_group
|
||||
critical: false
|
||||
depends_on: []
|
||||
selectors:
|
||||
- node_names: []
|
||||
node_labels: []
|
||||
success_criteria:
|
||||
# should be 100 or less
|
||||
percent_successful_nodes: 190
|
75
tests/unit/yaml_samples/deploymentStrategy_full_valid.yaml
Normal file
75
tests/unit/yaml_samples/deploymentStrategy_full_valid.yaml
Normal file
@ -0,0 +1,75 @@
|
||||
---
|
||||
schema: shipyard/DeploymentStrategy/v1
|
||||
metadata:
|
||||
schema: metadata/Document/v1
|
||||
name: deployment-strategy
|
||||
layeringDefinition:
|
||||
abstract: false
|
||||
layer: global
|
||||
storagePolicy: cleartext
|
||||
data:
|
||||
groups:
|
||||
- name: control-nodes
|
||||
critical: true
|
||||
depends_on:
|
||||
- ntp-node
|
||||
selectors:
|
||||
- node_names: []
|
||||
node_labels: []
|
||||
node_tags:
|
||||
- control
|
||||
rack_names:
|
||||
- rack03
|
||||
success_criteria:
|
||||
percent_successful_nodes: 90
|
||||
minimum_successful_nodes: 3
|
||||
maximum_failed_nodes: 1
|
||||
- name: compute-nodes-1
|
||||
critical: false
|
||||
depends_on:
|
||||
- control-nodes
|
||||
selectors:
|
||||
- node_names: []
|
||||
node_labels: []
|
||||
rack_names:
|
||||
- rack01
|
||||
node_tags:
|
||||
- compute
|
||||
success_criteria:
|
||||
percent_successful_nodes: 50
|
||||
- name: compute-nodes-2
|
||||
critical: false
|
||||
depends_on:
|
||||
- control-nodes
|
||||
selectors:
|
||||
- node_names: []
|
||||
node_labels: []
|
||||
rack_names:
|
||||
- rack02
|
||||
node_tags:
|
||||
- compute
|
||||
success_criteria:
|
||||
percent_successful_nodes: 50
|
||||
- name: monitoring-nodes
|
||||
critical: false
|
||||
depends_on: []
|
||||
selectors:
|
||||
- node_names: []
|
||||
node_labels: []
|
||||
node_tags:
|
||||
- monitoring
|
||||
rack_names:
|
||||
- rack03
|
||||
- rack02
|
||||
- rack01
|
||||
- name: ntp-node
|
||||
critical: true
|
||||
depends_on: []
|
||||
selectors:
|
||||
- node_names:
|
||||
- ntp01
|
||||
node_labels: []
|
||||
node_tags: []
|
||||
rack_names: []
|
||||
success_criteria:
|
||||
minimum_successful_nodes: 1
|
@ -0,0 +1,15 @@
|
||||
---
|
||||
schema: shipyard/DeploymentStrategy/v1
|
||||
metadata:
|
||||
schema: metadata/Document/v1
|
||||
name: deployment-strategy
|
||||
layeringDefinition:
|
||||
abstract: false
|
||||
layer: global
|
||||
storagePolicy: cleartext
|
||||
data:
|
||||
groups:
|
||||
- name: some-nodes
|
||||
critical: false
|
||||
depends_on: []
|
||||
selectors: []
|
11
tests/unit/yaml_samples/deploymentStrategy_minimal.yaml
Normal file
11
tests/unit/yaml_samples/deploymentStrategy_minimal.yaml
Normal file
@ -0,0 +1,11 @@
|
||||
---
|
||||
schema: shipyard/DeploymentStrategy/v1
|
||||
metadata:
|
||||
schema: metadata/Document/v1
|
||||
name: deployment-strategy
|
||||
layeringDefinition:
|
||||
abstract: false
|
||||
layer: global
|
||||
storagePolicy: cleartext
|
||||
data:
|
||||
groups: []
|
0
tests/unit/yaml_samples/empty.yaml
Normal file
0
tests/unit/yaml_samples/empty.yaml
Normal file
44
tests/unit/yaml_samples/total_garbage.yaml
Normal file
44
tests/unit/yaml_samples/total_garbage.yaml
Normal file
@ -0,0 +1,44 @@
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras euismod
|
||||
sed urna nec posuere. Phasellus vel arcu vestibulum, mattis ligula eu,
|
||||
pulvinar magna. Cras mollis velit quis maximus gravida. Morbi nec ligula
|
||||
neque. Cras vitae cursus tellus, ut ornare enim. Nulla vel suscipit
|
||||
arcu, in auctor ipsum. Ut a maximus magna. Integer massa risus,
|
||||
tristique sit amet urna sit amet, facilisis bibendum lectus. Vivamus
|
||||
vehicula urna in purus lacinia, sit amet tincidunt diam consequat.
|
||||
Quisque ut metus vitae mauris condimentum sollicitudin. Pellentesque
|
||||
urna nibh, mollis eu dui ac, molestie malesuada quam. Aliquam fringilla
|
||||
faucibus orci, a tincidunt dui sollicitudin ac. Nullam enim velit,
|
||||
imperdiet ut nulla quis, efficitur tincidunt eros. Curabitur nisi justo,
|
||||
tristique non ornare vitae, mollis eu tortor. In non congue libero.
|
||||
Mauris et tincidunt sem. Quisque sed congue diam, non ultrices turpis.
|
||||
Pellentesque lobortis quam justo, facilisis sollicitudin mi imperdiet
|
||||
sed. Ut nec leo placerat, gravida odio id, hendrerit erat. Praesent
|
||||
placerat diam mi, et blandit mi sollicitudin et. Proin ligula sapien,
|
||||
faucibus eget arcu vel, rhoncus vestibulum ipsum. Morbi tristique
|
||||
pharetra diam non faucibus. Nam scelerisque, leo ut tempus fermentum,
|
||||
dolor odio tempus nisl, et volutpat ante est id enim. Integer venenatis
|
||||
scelerisque augue, quis porta lorem dapibus non. Sed arcu purus, iaculis
|
||||
vitae sem sit amet, ultrices pretium leo. Nulla ultricies eleifend
|
||||
tempus. Aenean elementum ipsum id auctor faucibus. Cras quis ipsum
|
||||
vehicula, auctor velit et, dignissim sem. Duis sed nunc sagittis,
|
||||
interdum dui consequat, iaculis purus. Curabitur quam ex, pellentesque
|
||||
nec sapien ut, sodales lacinia enim. Etiam hendrerit sem eu turpis
|
||||
euismod, quis luctus tortor iaculis. Vivamus a rutrum orci. Class aptent
|
||||
taciti sociosqu ad litora torquent per conubia nostra, per inceptos
|
||||
himenaeos. Pellentesque habitant morbi tristique senectus et netus et
|
||||
malesuada fames ac turpis egestas. Aenean non neque ultrices, consequat
|
||||
erat vitae, porta lorem. Phasellus fringilla fringilla imperdiet.
|
||||
Quisque in nulla at elit sodales vestibulum ac eget mauris. Ut vel purus
|
||||
nec metus ultrices aliquet in sed leo. Mauris vel congue velit. Donec
|
||||
quam turpis, venenatis tristique sem nec, condimentum fringilla orci.
|
||||
Sed eu feugiat dui. Proin vulputate lacus id blandit tempor. Vivamus
|
||||
sollicitudin tincidunt ultrices. Aenean sit amet orci efficitur,
|
||||
condimentum mi vel, condimentum nisi. Cras pellentesque, felis vel
|
||||
maximus volutpat, turpis arcu dapibus metus, vitae fringilla massa lorem
|
||||
et elit. Interdum et malesuada fames ac ante ipsum primis in faucibus.
|
||||
Duis lorem velit, laoreet tincidunt fringilla at, vestibulum eget risus.
|
||||
Pellentesque ullamcorper venenatis lectus, a mattis lectus feugiat vel.
|
||||
Suspendisse potenti. Duis suscipit malesuada risus nec egestas. Vivamus
|
||||
maximus, neque quis egestas rhoncus, mauris purus fringilla nisl, ut
|
||||
fringilla odio nunc sit amet justo. Phasellus at dui quis magna
|
||||
elementum sagittis. Nullam sed luctus felis, ac tincidunt erat.
|
Loading…
x
Reference in New Issue
Block a user