[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:
Bryan Strassner 2018-04-16 13:46:31 -05:00
parent 47cd7a25f4
commit 6e32acbae1
16 changed files with 425 additions and 54 deletions

View File

@ -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:

View 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

View 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'])

View 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

View File

@ -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

View 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')

View 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: []

View 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: []

View 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: []

View 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: []

View 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

View 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

View 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-nodes
critical: false
depends_on: []
selectors: []

View 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: []

View File

View 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.