b787c418e3
From recently merged document updates in [0] there is a desire to standardize the Airship project python codebase. This is the effort to do so for the Armada project. [0] https://review.opendev.org/#/c/671291/ Change-Id: I4fe916d6e330618ea3a1fccfa4bdfdfabb9ffcb2
310 lines
9.2 KiB
Python
310 lines
9.2 KiB
Python
# 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 testtools
|
|
import yaml
|
|
|
|
from armada.tests.unit import base
|
|
from armada.utils import validate
|
|
|
|
template_chart = """
|
|
schema: armada/Chart/v1
|
|
metadata:
|
|
schema: metadata/Document/v1
|
|
name: example-chart
|
|
data:
|
|
chart_name: keystone
|
|
release: keystone
|
|
namespace: undercloud
|
|
timeout: 100
|
|
install:
|
|
no_hooks: false
|
|
upgrade:
|
|
no_hooks: false
|
|
values: {}
|
|
source:
|
|
type: git
|
|
location: git://github.com/example/example
|
|
subpath: example-chart
|
|
reference: master
|
|
dependencies: []
|
|
"""
|
|
|
|
template_chart_group = """
|
|
schema: armada/ChartGroup/v1
|
|
metadata:
|
|
schema: metadata/Document/v1
|
|
name: example-manifest
|
|
data:
|
|
description: this is sample
|
|
chart_group:
|
|
- example-chart
|
|
"""
|
|
|
|
template_manifest = """
|
|
schema: armada/Manifest/v1
|
|
metadata:
|
|
schema: metadata/Document/v1
|
|
name: example-manifest
|
|
data:
|
|
release_prefix: example
|
|
chart_groups:
|
|
- example-chart
|
|
"""
|
|
|
|
|
|
class BaseValidateTest(base.ArmadaTestCase):
|
|
def setUp(self):
|
|
super(BaseValidateTest, self).setUp()
|
|
self.basepath = os.path.join(os.path.dirname(__file__), os.pardir)
|
|
|
|
def _build_error_message(self, document, name, message):
|
|
return "Invalid document [{}] {}: {}.".format(document, name, message)
|
|
|
|
|
|
class ValidateOwnExamplesTestCase(BaseValidateTest):
|
|
"""Validates that each of the relevant example documents under
|
|
``armada/examples`` passes internal Armada schema validation.
|
|
|
|
"""
|
|
|
|
def test_own_document_examples(self):
|
|
examples_path = os.path.join(os.getcwd(), 'examples')
|
|
example_files = [
|
|
os.path.join(examples_path, f) for f in os.listdir(examples_path)
|
|
if os.path.isfile(os.path.join(examples_path, f))
|
|
]
|
|
validated_manifests = []
|
|
|
|
for example_file in example_files:
|
|
with open(example_file) as f:
|
|
documents = yaml.safe_load_all(f.read())
|
|
|
|
# If the example file doesn't have a document with
|
|
# armada/Manifest/v1 then skip validating it as the example could
|
|
# merely be an override.
|
|
has_manifest = any(
|
|
x['schema'] == 'armada/Manifest/v1' for x in documents)
|
|
if not has_manifest:
|
|
continue
|
|
|
|
validated_manifests.append(example_file)
|
|
valid, _ = validate.validate_armada_documents(list(documents))
|
|
self.assertTrue(valid)
|
|
|
|
self.assertTrue(validated_manifests)
|
|
|
|
|
|
class ValidateTestCase(BaseValidateTest):
|
|
def test_validate_armada_yaml_passes(self):
|
|
template = '{}/resources/valid_armada_document.yaml'.format(
|
|
self.basepath)
|
|
|
|
with open(template) as f:
|
|
documents = yaml.safe_load_all(f.read())
|
|
valid, details = validate.validate_armada_documents(list(documents))
|
|
|
|
self.assertTrue(valid)
|
|
|
|
def test_validate_manifest_passes(self):
|
|
manifest = yaml.safe_load(template_manifest)
|
|
is_valid, error = validate.validate_armada_document(manifest)
|
|
|
|
self.assertTrue(is_valid)
|
|
|
|
def test_validate_chart_group_with_values(self):
|
|
test_chart_group = """
|
|
---
|
|
schema: armada/ChartGroup/v1
|
|
metadata:
|
|
name: kubernetes-proxy
|
|
schema: metadata/Document/v1
|
|
data:
|
|
description: Kubernetes proxy
|
|
name: kubernetes-proxy
|
|
sequenced: true
|
|
chart_group:
|
|
- proxy
|
|
---
|
|
schema: armada/Chart/v1
|
|
metadata:
|
|
name: proxy
|
|
schema: metadata/Document/v1
|
|
data:
|
|
chart_name: proxy
|
|
timeout: 600
|
|
release: kubernetes-proxy
|
|
source:
|
|
subpath: proxy
|
|
type: local
|
|
location: "/etc/genesis/armada/assets/charts"
|
|
namespace: kube-system
|
|
upgrade:
|
|
no_hooks: true
|
|
values:
|
|
images:
|
|
tags:
|
|
proxy: gcr.io/google_containers/hyperkube-amd64:v1.8.6
|
|
network:
|
|
kubernetes_netloc: 127.0.0.1:6553
|
|
dependencies:
|
|
- helm-toolkit
|
|
---
|
|
schema: armada/Chart/v1
|
|
metadata:
|
|
name: helm-toolkit
|
|
schema: metadata/Document/v1
|
|
data:
|
|
chart_name: helm-toolkit
|
|
wait:
|
|
timeout: 600
|
|
release: helm-toolkit
|
|
source:
|
|
reference: master
|
|
subpath: helm-toolkit
|
|
location: https://git.openstack.org/openstack/openstack-helm-infra
|
|
type: git
|
|
namespace: helm-toolkit
|
|
upgrade:
|
|
no_hooks: true
|
|
values: {}
|
|
dependencies: []
|
|
"""
|
|
|
|
chart_group = yaml.safe_load_all(test_chart_group)
|
|
is_valid, error = validate.validate_armada_documents(list(chart_group))
|
|
|
|
self.assertTrue(is_valid)
|
|
|
|
def test_validate_group_passes(self):
|
|
chart_group = yaml.safe_load(template_chart_group)
|
|
is_valid, error = validate.validate_armada_document(chart_group)
|
|
|
|
self.assertTrue(is_valid)
|
|
|
|
def test_validate_chart_passes(self):
|
|
chart = yaml.safe_load(template_chart)
|
|
is_valid, error = validate.validate_armada_document(chart)
|
|
|
|
self.assertTrue(is_valid)
|
|
|
|
@testtools.skipUnless(
|
|
base.is_connected(),
|
|
'validate_manifest_url requires network connectivity.')
|
|
def test_validate_manifest_url(self):
|
|
value = 'url'
|
|
self.assertFalse(validate.validate_manifest_url(value))
|
|
value = 'https://opendev.org/airship/armada/' \
|
|
'raw/branch/master/examples/simple.yaml'
|
|
self.assertTrue(validate.validate_manifest_url(value))
|
|
|
|
|
|
class ValidateNegativeTestCase(BaseValidateTest):
|
|
def test_validate_no_dictionary_expect_type_error(self):
|
|
expected_error = 'The provided input "invalid" must be a dictionary.'
|
|
self.assertRaisesRegexp(
|
|
TypeError, expected_error, validate.validate_armada_documents,
|
|
['invalid'])
|
|
|
|
def test_validate_invalid_chart_armada_manifest(self):
|
|
template = '{}/resources/valid_armada_document.yaml'.format(
|
|
self.basepath)
|
|
|
|
with open(template) as f:
|
|
documents = list(yaml.safe_load_all(f.read()))
|
|
|
|
mariadb_document = [
|
|
d for d in documents if d['metadata']['name'] == 'mariadb'
|
|
][0]
|
|
del mariadb_document['data']['release']
|
|
|
|
_, error_messages = validate.validate_armada_documents(documents)
|
|
expected_error = self._build_error_message(
|
|
'armada/Chart/v1', 'mariadb', "'release' is a required property")
|
|
|
|
self.assertEqual(1, len(error_messages))
|
|
self.assertEqual(expected_error, error_messages[0]['message'])
|
|
|
|
def test_validate_validate_group_without_required_chart_group(self):
|
|
template_manifest = """
|
|
schema: armada/ChartGroup/v1
|
|
metadata:
|
|
schema: metadata/Document/v1
|
|
name: example-manifest
|
|
data:
|
|
description: this is sample
|
|
"""
|
|
document = yaml.safe_load(template_manifest)
|
|
is_valid, error = validate.validate_armada_document(document)
|
|
|
|
expected_error = self._build_error_message(
|
|
'armada/ChartGroup/v1', 'example-manifest',
|
|
"'chart_group' is a required property")
|
|
|
|
self.assertFalse(is_valid)
|
|
self.assertEqual(error[0]['message'], expected_error)
|
|
|
|
def test_validate_manifest_without_required_release_prefix(self):
|
|
template_manifest = """
|
|
schema: armada/Manifest/v1
|
|
metadata:
|
|
schema: metadata/Document/v1
|
|
name: example-manifest
|
|
data:
|
|
chart_groups:
|
|
- example-group
|
|
"""
|
|
document = yaml.safe_load(template_manifest)
|
|
is_valid, error = validate.validate_armada_document(document)
|
|
expected_error = self._build_error_message(
|
|
'armada/Manifest/v1', 'example-manifest',
|
|
"'release_prefix' is a required property")
|
|
|
|
self.assertFalse(is_valid)
|
|
self.assertEqual(error[0]['message'], expected_error)
|
|
|
|
def test_validate_chart_without_required_release_property(self):
|
|
template_manifest = """
|
|
schema: armada/Chart/v1
|
|
metadata:
|
|
schema: metadata/Document/v1
|
|
name: example-chart
|
|
data:
|
|
chart_name: keystone
|
|
namespace: undercloud
|
|
timeout: 100
|
|
install:
|
|
no_hooks: false
|
|
upgrade:
|
|
no_hooks: false
|
|
values: {}
|
|
source:
|
|
type: git
|
|
location: git://github.com/example/example
|
|
subpath: example-chart
|
|
reference: master
|
|
dependencies:
|
|
- dep-chart
|
|
"""
|
|
document = yaml.safe_load(template_manifest)
|
|
is_valid, error = validate.validate_armada_document(document)
|
|
expected_error = self._build_error_message(
|
|
'armada/Chart/v1', 'example-chart',
|
|
"'release' is a required property")
|
|
|
|
self.assertFalse(is_valid)
|
|
self.assertEqual(error[0]['message'], expected_error)
|