Introduce v2 docs
This introduces v2 docs in order to allow users to opt in to breaking changes, while still supporting v1 docs for a time so folks can migrate. At some point v1 doc support will be removed. This initial version of v2 docs is experimental. Further breaking changes will be made before v2 docs are finalized. A v1-v2 migration guide is included in the documentation. This also refactors the internal data model to include the full document structure, such as `metadata` and `schema`, so that different behavior can be acheived for v1, v2, etc. Change-Id: Ia0d44ff4276ef4c27f78706ab02c88aa421a307f
This commit is contained in:
parent
9a43213198
commit
8a50591dbf
@ -133,12 +133,12 @@ class TestReleasesManifestController(api.BaseResource):
|
||||
armada_obj = Manifest(
|
||||
documents, target_manifest=target_manifest).get_manifest()
|
||||
|
||||
prefix = armada_obj.get(const.KEYWORD_ARMADA).get(const.KEYWORD_PREFIX)
|
||||
prefix = armada_obj[const.KEYWORD_DATA][const.KEYWORD_PREFIX]
|
||||
known_releases = [release[0] for release in tiller.list_charts()]
|
||||
|
||||
message = {'tests': {'passed': [], 'skipped': [], 'failed': []}}
|
||||
|
||||
for group in armada_obj.get(const.KEYWORD_ARMADA).get(
|
||||
for group in armada_obj.get(const.KEYWORD_DATA).get(
|
||||
const.KEYWORD_GROUPS):
|
||||
for ch in group.get(const.KEYWORD_CHARTS):
|
||||
chart = ch['chart']
|
||||
|
@ -126,13 +126,14 @@ class DeleteChartManifest(CliAction):
|
||||
documents = list(yaml.safe_load_all(f.read()))
|
||||
try:
|
||||
armada_obj = Manifest(documents).get_manifest()
|
||||
prefix = armada_obj.get(const.KEYWORD_ARMADA).get(
|
||||
prefix = armada_obj.get(const.KEYWORD_DATA).get(
|
||||
const.KEYWORD_PREFIX)
|
||||
|
||||
for group in armada_obj.get(const.KEYWORD_ARMADA).get(
|
||||
for group in armada_obj.get(const.KEYWORD_DATA).get(
|
||||
const.KEYWORD_GROUPS):
|
||||
for ch in group.get(const.KEYWORD_CHARTS):
|
||||
chart = ch.get('chart')
|
||||
for ch in group.get(const.KEYWORD_DATA).get(
|
||||
const.KEYWORD_CHARTS):
|
||||
chart = ch.get(const.KEYWORD_DATA)
|
||||
release_name = release_prefixer(
|
||||
prefix, chart.get('release'))
|
||||
if release_name in known_release_names:
|
||||
|
@ -147,10 +147,10 @@ class TestChartManifest(CliAction):
|
||||
armada_obj = Manifest(
|
||||
documents,
|
||||
target_manifest=self.target_manifest).get_manifest()
|
||||
prefix = armada_obj.get(const.KEYWORD_ARMADA).get(
|
||||
prefix = armada_obj.get(const.KEYWORD_DATA).get(
|
||||
const.KEYWORD_PREFIX)
|
||||
|
||||
for group in armada_obj.get(const.KEYWORD_ARMADA).get(
|
||||
for group in armada_obj.get(const.KEYWORD_DATA).get(
|
||||
const.KEYWORD_GROUPS):
|
||||
for ch in group.get(const.KEYWORD_CHARTS):
|
||||
chart = ch['chart']
|
||||
|
@ -88,7 +88,7 @@ class ChartDeployAwareLogger(logging.Logger):
|
||||
def _log(self, level, msg, *args, **kwargs):
|
||||
chart = get_current_chart()
|
||||
if chart:
|
||||
name = chart['chart_name']
|
||||
name = chart['metadata']['name']
|
||||
prefix = '[chart={}]: '.format(name)
|
||||
else:
|
||||
prefix = ''
|
||||
|
@ -12,11 +12,8 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# Documents
|
||||
DOCUMENT_CHART = 'armada/Chart/v1'
|
||||
DOCUMENT_GROUP = 'armada/ChartGroup/v1'
|
||||
DOCUMENT_MANIFEST = 'armada/Manifest/v1'
|
||||
KEYWORD_ARMADA = 'armada'
|
||||
# Keywords
|
||||
KEYWORD_DATA = 'data'
|
||||
KEYWORD_PREFIX = 'release_prefix'
|
||||
KEYWORD_GROUPS = 'chart_groups'
|
||||
KEYWORD_CHARTS = 'chart_group'
|
||||
|
@ -104,13 +104,14 @@ class Armada(object):
|
||||
raise tiller_exceptions.TillerServicesUnavailableException()
|
||||
|
||||
# Clone the chart sources
|
||||
manifest_data = self.manifest.get(const.KEYWORD_ARMADA, {})
|
||||
manifest_data = self.manifest.get(const.KEYWORD_DATA, {})
|
||||
for group in manifest_data.get(const.KEYWORD_GROUPS, []):
|
||||
for ch in group.get(const.KEYWORD_CHARTS, []):
|
||||
for ch in group.get(const.KEYWORD_DATA).get(
|
||||
const.KEYWORD_CHARTS, []):
|
||||
self.get_chart(ch)
|
||||
|
||||
def get_chart(self, ch):
|
||||
chart = ch.get('chart', {})
|
||||
chart = ch.get(const.KEYWORD_DATA)
|
||||
chart_source = chart.get('source', {})
|
||||
location = chart_source.get('location')
|
||||
ct_type = chart_source.get('type')
|
||||
@ -158,10 +159,10 @@ class Armada(object):
|
||||
self.chart_cache[source_key] = repo_dir
|
||||
chart['source_dir'] = (self.chart_cache.get(source_key), subpath)
|
||||
else:
|
||||
chart_name = chart.get('chart_name')
|
||||
raise source_exceptions.ChartSourceException(ct_type, chart_name)
|
||||
name = chart['metadata']['name']
|
||||
raise source_exceptions.ChartSourceException(ct_type, name)
|
||||
|
||||
for dep in ch.get('chart', {}).get('dependencies', []):
|
||||
for dep in ch.get(const.KEYWORD_DATA, {}).get('dependencies', []):
|
||||
self.get_chart(dep)
|
||||
|
||||
def sync(self):
|
||||
@ -185,11 +186,12 @@ class Armada(object):
|
||||
|
||||
known_releases = self.tiller.list_releases()
|
||||
|
||||
manifest_data = self.manifest.get(const.KEYWORD_ARMADA, {})
|
||||
manifest_data = self.manifest.get(const.KEYWORD_DATA, {})
|
||||
prefix = manifest_data.get(const.KEYWORD_PREFIX)
|
||||
|
||||
for chartgroup in manifest_data.get(const.KEYWORD_GROUPS, []):
|
||||
cg_name = chartgroup.get('name', '<missing name>')
|
||||
for cg in manifest_data.get(const.KEYWORD_GROUPS, []):
|
||||
chartgroup = cg.get(const.KEYWORD_DATA)
|
||||
cg_name = cg.get('metadata').get('name')
|
||||
cg_desc = chartgroup.get('description', '<missing description>')
|
||||
cg_sequenced = chartgroup.get('sequenced',
|
||||
False) or self.force_wait
|
||||
@ -198,11 +200,10 @@ class Armada(object):
|
||||
cg_desc, cg_sequenced,
|
||||
' (forced)' if self.force_wait else '')
|
||||
|
||||
# TODO(MarshM): Deprecate the `test_charts` key
|
||||
# TODO: Remove when v1 doc support is removed.
|
||||
cg_test_all_charts = chartgroup.get('test_charts')
|
||||
|
||||
cg_charts = chartgroup.get(const.KEYWORD_CHARTS, [])
|
||||
charts = map(lambda x: x.get('chart', {}), cg_charts)
|
||||
|
||||
def deploy_chart(chart):
|
||||
set_current_chart(chart)
|
||||
@ -217,7 +218,7 @@ class Armada(object):
|
||||
|
||||
# Returns whether or not there was a failure
|
||||
def handle_result(chart, get_result):
|
||||
name = chart['chart_name']
|
||||
name = chart['metadata']['name']
|
||||
try:
|
||||
result = get_result()
|
||||
except Exception:
|
||||
@ -229,7 +230,7 @@ class Armada(object):
|
||||
return False
|
||||
|
||||
if cg_sequenced:
|
||||
for chart in charts:
|
||||
for chart in cg_charts:
|
||||
if (handle_result(chart, lambda: deploy_chart(chart))):
|
||||
break
|
||||
else:
|
||||
@ -237,7 +238,7 @@ class Armada(object):
|
||||
max_workers=len(cg_charts)) as executor:
|
||||
future_to_chart = {
|
||||
executor.submit(deploy_chart, chart): chart
|
||||
for chart in charts
|
||||
for chart in cg_charts
|
||||
}
|
||||
|
||||
for future in as_completed(future_to_chart):
|
||||
@ -260,7 +261,7 @@ class Armada(object):
|
||||
if self.enable_chart_cleanup:
|
||||
self._chart_cleanup(
|
||||
prefix,
|
||||
self.manifest[const.KEYWORD_ARMADA][const.KEYWORD_GROUPS], msg)
|
||||
self.manifest[const.KEYWORD_DATA][const.KEYWORD_GROUPS], msg)
|
||||
|
||||
LOG.info('Done applying manifest.')
|
||||
return msg
|
||||
|
@ -41,7 +41,8 @@ class ChartDeploy(object):
|
||||
self.timeout = timeout
|
||||
self.tiller = tiller
|
||||
|
||||
def execute(self, chart, cg_test_all_charts, prefix, known_releases):
|
||||
def execute(self, ch, cg_test_all_charts, prefix, known_releases):
|
||||
chart = ch[const.KEYWORD_DATA]
|
||||
namespace = chart.get('namespace')
|
||||
release = chart.get('release')
|
||||
release_name = r.release_prefixer(prefix, release)
|
||||
@ -73,7 +74,7 @@ class ChartDeploy(object):
|
||||
# Begin Chart timeout deadline
|
||||
deadline = time.time() + chart_wait.get_timeout()
|
||||
|
||||
chartbuilder = ChartBuilder(chart)
|
||||
chartbuilder = ChartBuilder(ch)
|
||||
new_chart = chartbuilder.get_helm_chart()
|
||||
|
||||
# TODO(mark-burnett): It may be more robust to directly call
|
||||
|
@ -25,6 +25,7 @@ from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
|
||||
from armada.exceptions import chartbuilder_exceptions
|
||||
from armada import const
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
@ -49,6 +50,7 @@ class ChartBuilder(object):
|
||||
|
||||
# store chart schema
|
||||
self.chart = chart
|
||||
self.chart_data = chart[const.KEYWORD_DATA]
|
||||
|
||||
# extract, pull, whatever the chart from its source
|
||||
self.source_directory = self.get_source_path()
|
||||
@ -62,7 +64,7 @@ class ChartBuilder(object):
|
||||
Returns "<source directory>/<subpath>" taken from the "source_dir"
|
||||
property from the chart, or else "" if the property isn't a 2-tuple.
|
||||
'''
|
||||
source_dir = self.chart.get('source_dir')
|
||||
source_dir = self.chart_data.get('source_dir')
|
||||
return (os.path.join(*source_dir) if
|
||||
(source_dir and isinstance(source_dir, (list, tuple)) and
|
||||
len(source_dir) == 2) else "")
|
||||
@ -206,7 +208,7 @@ class ChartBuilder(object):
|
||||
Process all files in templates/ as a template to attach to the chart,
|
||||
building a :class:`hapi.chart.template_pb2.Template` object.
|
||||
'''
|
||||
chart_name = self.chart.get('chart_name')
|
||||
chart_name = self.chart['metadata']['name']
|
||||
templates = []
|
||||
if not os.path.exists(
|
||||
os.path.join(self.source_directory, 'templates')):
|
||||
@ -240,12 +242,11 @@ class ChartBuilder(object):
|
||||
return self._helm_chart
|
||||
|
||||
dependencies = []
|
||||
chart_dependencies = self.chart.get('dependencies', [])
|
||||
chart_name = self.chart.get('chart_name', None)
|
||||
chart_release = self.chart.get('release', None)
|
||||
for dep in chart_dependencies:
|
||||
dep_chart = dep.get('chart', {})
|
||||
dep_chart_name = dep_chart.get('chart_name', None)
|
||||
chart_dependencies = self.chart_data.get('dependencies', [])
|
||||
chart_name = self.chart['metadata']['name']
|
||||
chart_release = self.chart_data.get('release', None)
|
||||
for dep_chart in chart_dependencies:
|
||||
dep_chart_name = dep_chart['metadata']['name']
|
||||
LOG.info("Building dependency chart %s for release %s.",
|
||||
dep_chart_name, chart_release)
|
||||
try:
|
||||
|
@ -17,6 +17,7 @@ from oslo_log import log as logging
|
||||
|
||||
from armada import const
|
||||
from armada import exceptions
|
||||
from armada.handlers import schema
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
@ -62,10 +63,10 @@ class Manifest(object):
|
||||
self.manifest = manifests[0] if manifests else None
|
||||
|
||||
if not all([self.charts, self.groups, self.manifest]):
|
||||
expected_schemas = [const.DOCUMENT_CHART, const.DOCUMENT_GROUP]
|
||||
error = ('Documents must be a list of documents with at least one '
|
||||
'of each of the following schemas: %s and only one '
|
||||
'manifest' % expected_schemas)
|
||||
expected_schemas = [schema.TYPE_CHART, schema.TYPE_CHARTGROUP]
|
||||
error = ('Documents must include at least one of each of {} '
|
||||
'and only one {}').format(expected_schemas,
|
||||
schema.TYPE_MANIFEST)
|
||||
LOG.error(error)
|
||||
raise exceptions.ManifestException(details=error)
|
||||
|
||||
@ -87,11 +88,14 @@ class Manifest(object):
|
||||
groups = []
|
||||
manifests = []
|
||||
for document in self.documents:
|
||||
if document.get('schema') == const.DOCUMENT_CHART:
|
||||
schema_info = schema.get_schema_info(document.get('schema'))
|
||||
if not schema_info:
|
||||
continue
|
||||
if schema_info.type == schema.TYPE_CHART:
|
||||
charts.append(document)
|
||||
if document.get('schema') == const.DOCUMENT_GROUP:
|
||||
if schema_info.type == schema.TYPE_CHARTGROUP:
|
||||
groups.append(document)
|
||||
if document.get('schema') == const.DOCUMENT_MANIFEST:
|
||||
if schema_info.type == schema.TYPE_MANIFEST:
|
||||
manifest_name = document.get('metadata', {}).get('name')
|
||||
if target_manifest:
|
||||
if manifest_name == target_manifest:
|
||||
@ -113,8 +117,8 @@ class Manifest(object):
|
||||
if chart.get('metadata', {}).get('name') == name:
|
||||
return chart
|
||||
raise exceptions.BuildChartException(
|
||||
details='Could not build {} named "{}"'.format(
|
||||
const.DOCUMENT_CHART, name))
|
||||
details='Could not find {} named "{}"'.format(
|
||||
schema.TYPE_CHART, name))
|
||||
|
||||
def find_chart_group_document(self, name):
|
||||
"""Returns a chart group document with the specified name
|
||||
@ -129,8 +133,8 @@ class Manifest(object):
|
||||
if group.get('metadata', {}).get('name') == name:
|
||||
return group
|
||||
raise exceptions.BuildChartGroupException(
|
||||
details='Could not build {} named "{}"'.format(
|
||||
const.DOCUMENT_GROUP, name))
|
||||
details='Could not find {} named "{}"'.format(
|
||||
schema.TYPE_CHARTGROUP, name))
|
||||
|
||||
def build_chart_deps(self, chart):
|
||||
"""Recursively build chart dependencies for ``chart``.
|
||||
@ -143,20 +147,19 @@ class Manifest(object):
|
||||
under ``chart['data']['dependencies']`` could not be found.
|
||||
"""
|
||||
try:
|
||||
chart_dependencies = chart.get('data', {}).get('dependencies', [])
|
||||
chart_dependencies = chart.get(const.KEYWORD_DATA, {}).get(
|
||||
'dependencies', [])
|
||||
for iter, dep in enumerate(chart_dependencies):
|
||||
if isinstance(dep, dict):
|
||||
continue
|
||||
chart_dep = self.find_chart_document(dep)
|
||||
self.build_chart_deps(chart_dep)
|
||||
chart['data']['dependencies'][iter] = {
|
||||
'chart': chart_dep.get('data', {})
|
||||
}
|
||||
chart[const.KEYWORD_DATA]['dependencies'][iter] = chart_dep
|
||||
except Exception:
|
||||
raise exceptions.ChartDependencyException(
|
||||
details="Could not build dependencies for chart {} in {}".
|
||||
format(
|
||||
chart.get('metadata').get('name'), const.DOCUMENT_CHART))
|
||||
details='Could not build dependencies for {} named "{}"'.
|
||||
format(schema.TYPE_CHART,
|
||||
chart.get('metadata').get('name')))
|
||||
else:
|
||||
return chart
|
||||
|
||||
@ -173,19 +176,19 @@ class Manifest(object):
|
||||
try:
|
||||
chart = None
|
||||
for iter, chart in enumerate(
|
||||
chart_group.get('data', {}).get('chart_group', [])):
|
||||
chart_group.get(const.KEYWORD_DATA).get(
|
||||
const.KEYWORD_CHARTS, [])):
|
||||
if isinstance(chart, dict):
|
||||
continue
|
||||
chart_dep = self.find_chart_document(chart)
|
||||
self.build_chart_deps(chart_dep)
|
||||
chart_group['data']['chart_group'][iter] = {
|
||||
'chart': chart_dep.get('data', {})
|
||||
}
|
||||
chart_object = self.find_chart_document(chart)
|
||||
self.build_chart_deps(chart_object)
|
||||
chart_group[const.KEYWORD_DATA][const.KEYWORD_CHARTS][iter] = \
|
||||
chart_object
|
||||
except exceptions.ManifestException:
|
||||
cg_name = chart_group.get('metadata', {}).get('name')
|
||||
raise exceptions.BuildChartGroupException(
|
||||
details="Could not build chart group {} in {}".format(
|
||||
cg_name, const.DOCUMENT_GROUP))
|
||||
details='Could not build {} named "{}"'.format(
|
||||
schema.TYPE_CHARTGROUP, cg_name))
|
||||
|
||||
return chart_group
|
||||
|
||||
@ -196,20 +199,18 @@ class Manifest(object):
|
||||
:returns: The Armada manifest with the data of the chart groups.
|
||||
:rtype: dict
|
||||
:raises ManifestException: If a chart group's data listed
|
||||
under ``chart_group['data']`` could not be found.
|
||||
under ``chart_group[const.KEYWORD_DATA]`` could not be found.
|
||||
"""
|
||||
for iter, group in enumerate(
|
||||
self.manifest.get('data', {}).get('chart_groups', [])):
|
||||
self.manifest.get(const.KEYWORD_DATA, {}).get(
|
||||
const.KEYWORD_GROUPS, [])):
|
||||
if isinstance(group, dict):
|
||||
continue
|
||||
chart_grp = self.find_chart_group_document(group)
|
||||
self.build_chart_group(chart_grp)
|
||||
|
||||
# Add name to chart group
|
||||
ch_grp_data = chart_grp.get('data', {})
|
||||
ch_grp_data['name'] = chart_grp.get('metadata', {}).get('name')
|
||||
|
||||
self.manifest['data']['chart_groups'][iter] = ch_grp_data
|
||||
self.manifest[const.KEYWORD_DATA][const.KEYWORD_GROUPS][iter] = \
|
||||
chart_grp
|
||||
|
||||
return self.manifest
|
||||
|
||||
@ -221,4 +222,4 @@ class Manifest(object):
|
||||
"""
|
||||
self.build_armada_manifest()
|
||||
|
||||
return {'armada': self.manifest.get('data', {})}
|
||||
return self.manifest
|
||||
|
@ -16,9 +16,9 @@ import collections
|
||||
import json
|
||||
import yaml
|
||||
|
||||
from armada import const
|
||||
from armada.exceptions import override_exceptions
|
||||
from armada.exceptions import validate_exceptions
|
||||
from armada.handlers import schema
|
||||
from armada.utils import validate
|
||||
|
||||
|
||||
@ -65,17 +65,18 @@ class Override(object):
|
||||
|
||||
def find_document_type(self, alias):
|
||||
if alias == 'chart_group':
|
||||
return const.DOCUMENT_GROUP
|
||||
return schema.TYPE_CHARTGROUP
|
||||
if alias == 'chart':
|
||||
return const.DOCUMENT_CHART
|
||||
return schema.TYPE_CHART
|
||||
if alias == 'manifest':
|
||||
return const.DOCUMENT_MANIFEST
|
||||
return schema.TYPE_MANIFEST
|
||||
else:
|
||||
raise ValueError("Could not find {} document".format(alias))
|
||||
|
||||
def find_manifest_document(self, doc_path):
|
||||
for doc in self.documents:
|
||||
if doc.get('schema') == self.find_document_type(
|
||||
schema_info = schema.get_schema_info(doc.get('schema'))
|
||||
if schema_info.type == self.find_document_type(
|
||||
doc_path[0]) and doc.get('metadata',
|
||||
{}).get('name') == doc_path[1]:
|
||||
return doc
|
||||
@ -121,45 +122,29 @@ class Override(object):
|
||||
new_data = self.array_to_dict(data_path, new_value)
|
||||
self.update(document.get('data', {}), new_data)
|
||||
|
||||
def update_document(self, merging_values):
|
||||
def update_documents(self, merging_values):
|
||||
for doc in merging_values:
|
||||
if doc.get('schema') == const.DOCUMENT_CHART:
|
||||
self.update_chart_document(doc)
|
||||
if doc.get('schema') == const.DOCUMENT_GROUP:
|
||||
self.update_chart_group_document(doc)
|
||||
if doc.get('schema') == const.DOCUMENT_MANIFEST:
|
||||
self.update_armada_manifest(doc)
|
||||
self.update_document(doc)
|
||||
|
||||
def update_chart_document(self, ovr):
|
||||
for doc in self.documents:
|
||||
if doc.get('schema') == const.DOCUMENT_CHART and doc.get(
|
||||
'metadata', {}).get('name') == ovr.get('metadata',
|
||||
{}).get('name'):
|
||||
self.update(doc.get('data', {}), ovr.get('data', {}))
|
||||
return
|
||||
|
||||
def update_chart_group_document(self, ovr):
|
||||
for doc in self.documents:
|
||||
if doc.get('schema') == const.DOCUMENT_GROUP and doc.get(
|
||||
'metadata', {}).get('name') == ovr.get('metadata',
|
||||
{}).get('name'):
|
||||
self.update(doc.get('data', {}), ovr.get('data', {}))
|
||||
return
|
||||
|
||||
def update_armada_manifest(self, ovr):
|
||||
for doc in self.documents:
|
||||
if doc.get('schema') == const.DOCUMENT_MANIFEST and doc.get(
|
||||
'metadata', {}).get('name') == ovr.get('metadata',
|
||||
{}).get('name'):
|
||||
self.update(doc.get('data', {}), ovr.get('data', {}))
|
||||
return
|
||||
def update_document(self, ovr):
|
||||
ovr_schema_info = schema.get_schema_info(ovr.get('schema'))
|
||||
if ovr_schema_info:
|
||||
for doc in self.documents:
|
||||
schema_info = schema.get_schema_info(doc.get('schema'))
|
||||
if schema_info:
|
||||
if schema_info == ovr_schema_info:
|
||||
if doc['metadata']['name'] == ovr['metadata']['name']:
|
||||
data = doc.get('data', {})
|
||||
ovr_data = ovr.get('data', {})
|
||||
self.update(data, ovr_data)
|
||||
return
|
||||
|
||||
def update_manifests(self):
|
||||
|
||||
if self.values:
|
||||
for value in self.values:
|
||||
merging_values = self._load_yaml_file(value)
|
||||
self.update_document(merging_values)
|
||||
self.update_documents(merging_values)
|
||||
# Validate document with updated values
|
||||
self._document_checker(self.documents, self.values)
|
||||
|
||||
|
80
armada/handlers/schema.py
Normal file
80
armada/handlers/schema.py
Normal file
@ -0,0 +1,80 @@
|
||||
# Copyright 2019 The Armada Authors.
|
||||
#
|
||||
# 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 pkg_resources
|
||||
import re
|
||||
import yaml
|
||||
|
||||
# Types
|
||||
TYPE_CHART = 'Chart'
|
||||
TYPE_CHARTGROUP = 'ChartGroup'
|
||||
TYPE_MANIFEST = 'Manifest'
|
||||
|
||||
# Versions
|
||||
VERSION_FORMAT = r'^v(\d+)$'
|
||||
VERSION_MIN = 1
|
||||
VERSION_MAX = 2
|
||||
|
||||
# Creates a mapping between ``metadata.name``: ``data`` where the
|
||||
# ``metadata.name`` is the ``schema`` of a manifest and the ``data`` is the
|
||||
# JSON schema to be used to validate the manifest in question.
|
||||
_SCHEMAS = {}
|
||||
|
||||
|
||||
class SchemaInfo(object):
|
||||
|
||||
def __init__(self, type, version, data):
|
||||
self.type = type
|
||||
self.version = version
|
||||
self.data = data
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.type == other.type and self.version == other.version
|
||||
|
||||
|
||||
def get_schema_info(name):
|
||||
return _SCHEMAS.get(name)
|
||||
|
||||
|
||||
def _get_schema_info(name, data):
|
||||
parts = name.split('/')
|
||||
prefix, type, version_string = parts
|
||||
version_match = re.search(VERSION_FORMAT, version_string)
|
||||
version = int(version_match.group(1))
|
||||
return SchemaInfo(type, version, data)
|
||||
|
||||
|
||||
def _get_schema_dir():
|
||||
return pkg_resources.resource_filename('armada', 'schemas')
|
||||
|
||||
|
||||
def _load_schemas():
|
||||
"""Populates ``_SCHEMAS`` with the schemas defined in package
|
||||
``armada.schemas``.
|
||||
|
||||
"""
|
||||
schema_dir = _get_schema_dir()
|
||||
for schema_file in os.listdir(schema_dir):
|
||||
with open(os.path.join(schema_dir, schema_file)) as f:
|
||||
for schema in yaml.safe_load_all(f):
|
||||
name = schema['metadata']['name']
|
||||
if name in _SCHEMAS:
|
||||
raise RuntimeError(
|
||||
'Duplicate schema specified for: %s.' % name)
|
||||
_SCHEMAS[name] = _get_schema_info(name, schema['data'])
|
||||
|
||||
|
||||
# Fill the cache.
|
||||
_load_schemas()
|
@ -60,9 +60,7 @@ class Test(object):
|
||||
|
||||
self.timeout = const.DEFAULT_TEST_TIMEOUT
|
||||
|
||||
# NOTE(drewwalters96): Support the chart_group `test_charts` key until
|
||||
# its deprecation period ends. The `test.enabled`, `enable_all` flag,
|
||||
# and deprecated, boolean `test` key override this value if provided.
|
||||
# TODO: Remove when v1 doc support is removed.
|
||||
if cg_test_charts is not None:
|
||||
LOG.warn('Chart group key `test_charts` is deprecated and will be '
|
||||
'removed. Use `test.enabled` instead.')
|
||||
@ -70,7 +68,7 @@ class Test(object):
|
||||
else:
|
||||
self.test_enabled = True
|
||||
|
||||
# NOTE: Support old, boolean `test` key until deprecation period ends.
|
||||
# TODO: Remove when v1 doc support is removed.
|
||||
if (type(test_values) == bool):
|
||||
LOG.warn('Boolean value for chart `test` key is deprecated and '
|
||||
'will be removed. Use `test.enabled` instead.')
|
||||
|
@ -30,8 +30,10 @@ from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
|
||||
from armada import const
|
||||
from armada.conf import get_current_chart
|
||||
from armada.exceptions import tiller_exceptions as ex
|
||||
from armada.handlers.k8s import K8s
|
||||
from armada.handlers import schema
|
||||
from armada.utils import helm
|
||||
from armada.utils.release import label_selectors, get_release_status
|
||||
|
||||
@ -303,6 +305,7 @@ class Tiller(object):
|
||||
:param namespace: name of pod for actions
|
||||
'''
|
||||
|
||||
# TODO: Remove when v1 doc support is removed.
|
||||
try:
|
||||
for action in actions.get('update', []):
|
||||
name = action.get('name')
|
||||
@ -667,15 +670,20 @@ class Tiller(object):
|
||||
self.k8s.delete_job_action(jb_name, namespace, timeout=timeout)
|
||||
handled = True
|
||||
|
||||
if resource_type == 'cronjob' or resource_type == 'job':
|
||||
# TODO: Remove when v1 doc support is removed.
|
||||
chart = get_current_chart()
|
||||
schema_info = schema.get_schema_info(chart['schema'])
|
||||
job_implies_cronjob = schema_info.version < 2
|
||||
implied_cronjob = resource_type == 'job' and job_implies_cronjob
|
||||
|
||||
if resource_type == 'cronjob' or implied_cronjob:
|
||||
get_jobs = self.k8s.get_namespace_cron_job(
|
||||
namespace, label_selector=label_selector)
|
||||
for jb in get_jobs.items:
|
||||
jb_name = jb.metadata.name
|
||||
|
||||
if resource_type == 'job':
|
||||
# TODO: Eventually disallow this, allowing initially since
|
||||
# some existing clients were expecting this behavior.
|
||||
# TODO: Remove when v1 doc support is removed.
|
||||
if implied_cronjob:
|
||||
LOG.warn("Deleting cronjobs via `type: job` is "
|
||||
"deprecated, use `type: cronjob` instead")
|
||||
|
||||
@ -726,7 +734,7 @@ class Tiller(object):
|
||||
values,
|
||||
timeout=const.DEFAULT_TILLER_TIMEOUT):
|
||||
'''
|
||||
update statefullsets (daemon, stateful)
|
||||
update statefulsets (daemon, stateful)
|
||||
'''
|
||||
|
||||
if action_type == 'daemonset':
|
||||
|
@ -12,7 +12,7 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# JSON schema for validating Armada charts.
|
||||
# NOTE: Do not modify this schema, it is deprecated.
|
||||
---
|
||||
schema: deckhand/DataSchema/v1
|
||||
metadata:
|
||||
@ -60,7 +60,6 @@ data:
|
||||
additionalProperties: false
|
||||
test:
|
||||
anyOf:
|
||||
# TODO: Remove boolean support after deprecation period.
|
||||
- type: boolean
|
||||
- type: object
|
||||
properties:
|
||||
@ -75,7 +74,6 @@ data:
|
||||
type: boolean
|
||||
additionalProperties: false
|
||||
additionalProperties: false
|
||||
# TODO(MarshM): Deprecate this `timeout` in favor of `wait.timeout`
|
||||
timeout:
|
||||
type: integer
|
||||
wait:
|
||||
@ -153,8 +151,6 @@ data:
|
||||
$ref: '#/definitions/hook_action'
|
||||
create:
|
||||
$ref: '#/definitions/hook_action'
|
||||
# TODO(drewwalters96): Armada ignores post-update actions. Remove them
|
||||
# in future schemas.
|
||||
post:
|
||||
type: object
|
||||
additionalProperties: false
|
151
armada/schemas/armada-chart-schema-v2.yaml
Normal file
151
armada/schemas/armada-chart-schema-v2.yaml
Normal file
@ -0,0 +1,151 @@
|
||||
# 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.
|
||||
|
||||
# JSON schema for validating Armada charts.
|
||||
---
|
||||
schema: deckhand/DataSchema/v1
|
||||
metadata:
|
||||
name: armada/Chart/v2
|
||||
schema: metadata/Control/v1
|
||||
data:
|
||||
$schema: http://json-schema.org/schema#
|
||||
definitions:
|
||||
labels:
|
||||
type: object
|
||||
additionalProperties:
|
||||
type: string
|
||||
hook_action:
|
||||
type: array
|
||||
items:
|
||||
properties:
|
||||
type:
|
||||
type: string
|
||||
labels:
|
||||
$ref: '#/definitions/labels'
|
||||
required:
|
||||
- type
|
||||
additionalProperties: false
|
||||
type: object
|
||||
properties:
|
||||
release:
|
||||
type: string
|
||||
namespace:
|
||||
type: string
|
||||
values:
|
||||
type: object
|
||||
# TODO: Remove this, and just read dependencies out of `chart` dir as helm
|
||||
# CLI does.
|
||||
dependencies:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
protected:
|
||||
type: object
|
||||
properties:
|
||||
continue_processing:
|
||||
type: boolean
|
||||
additionalProperties: false
|
||||
test:
|
||||
type: object
|
||||
properties:
|
||||
enabled:
|
||||
type: boolean
|
||||
timeout:
|
||||
type: integer
|
||||
options:
|
||||
type: object
|
||||
properties:
|
||||
cleanup:
|
||||
type: boolean
|
||||
additionalProperties: false
|
||||
additionalProperties: false
|
||||
wait:
|
||||
type: object
|
||||
properties:
|
||||
timeout:
|
||||
type: integer
|
||||
resources:
|
||||
type: array
|
||||
items:
|
||||
properties:
|
||||
type:
|
||||
type: string
|
||||
labels:
|
||||
$ref: '#/definitions/labels'
|
||||
min_ready:
|
||||
anyOf:
|
||||
- type: integer
|
||||
- type: string
|
||||
required:
|
||||
- type
|
||||
additionalProperties: false
|
||||
labels:
|
||||
$ref: "#/definitions/labels"
|
||||
# Config for helm's native `--wait` param.
|
||||
native:
|
||||
type: object
|
||||
properties:
|
||||
enabled:
|
||||
type: boolean
|
||||
additionalProperties: false
|
||||
additionalProperties: false
|
||||
source:
|
||||
type: object
|
||||
properties:
|
||||
type:
|
||||
type: string
|
||||
location:
|
||||
type: string
|
||||
subpath:
|
||||
type: string
|
||||
reference:
|
||||
type: string
|
||||
proxy_server:
|
||||
type: string
|
||||
auth_method:
|
||||
type: string
|
||||
required:
|
||||
- location
|
||||
- type
|
||||
delete:
|
||||
type: object
|
||||
properties:
|
||||
timeout:
|
||||
type: integer
|
||||
upgrade:
|
||||
type: object
|
||||
properties:
|
||||
no_hooks:
|
||||
type: boolean
|
||||
pre:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
properties:
|
||||
delete:
|
||||
$ref: '#/definitions/hook_action'
|
||||
options:
|
||||
type: object
|
||||
properties:
|
||||
force:
|
||||
type: boolean
|
||||
recreate_pods:
|
||||
type: boolean
|
||||
additionalProperties: false
|
||||
additionalProperties: false
|
||||
required:
|
||||
- namespace
|
||||
- release
|
||||
- source
|
||||
additionalProperties: false
|
||||
...
|
@ -12,7 +12,7 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# JSON schema for validating Armada chart groups.
|
||||
# NOTE: Do not modify this schema, it is deprecated.
|
||||
---
|
||||
schema: deckhand/DataSchema/v1
|
||||
metadata:
|
38
armada/schemas/armada-chartgroup-schema-v2.yaml
Normal file
38
armada/schemas/armada-chartgroup-schema-v2.yaml
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.
|
||||
|
||||
# JSON schema for validating Armada chart groups.
|
||||
---
|
||||
schema: deckhand/DataSchema/v1
|
||||
metadata:
|
||||
name: armada/ChartGroup/v2
|
||||
schema: metadata/Control/v1
|
||||
data:
|
||||
$schema: http://json-schema.org/schema#
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
description:
|
||||
type: string
|
||||
sequenced:
|
||||
type: boolean
|
||||
chart_group:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
required:
|
||||
# TODO: Rename to `charts`?
|
||||
- chart_group
|
||||
additionalProperties: false
|
||||
...
|
34
armada/schemas/armada-manifest-schema-v1.yaml
Normal file
34
armada/schemas/armada-manifest-schema-v1.yaml
Normal file
@ -0,0 +1,34 @@
|
||||
# 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.
|
||||
|
||||
# NOTE: Do not modify this schema, it is deprecated.
|
||||
---
|
||||
schema: deckhand/DataSchema/v1
|
||||
metadata:
|
||||
name: armada/Manifest/v1
|
||||
schema: metadata/Control/v1
|
||||
data:
|
||||
$schema: http://json-schema.org/schema#
|
||||
properties:
|
||||
release_prefix:
|
||||
type: string
|
||||
chart_groups:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
required:
|
||||
- chart_groups
|
||||
- release_prefix
|
||||
additionalProperties: false
|
||||
...
|
@ -16,7 +16,7 @@
|
||||
---
|
||||
schema: deckhand/DataSchema/v1
|
||||
metadata:
|
||||
name: armada/Manifest/v1
|
||||
name: armada/Manifest/v2
|
||||
schema: metadata/Control/v1
|
||||
data:
|
||||
$schema: http://json-schema.org/schema#
|
@ -169,8 +169,7 @@ class TestReleasesManifestControllerNegativeTest(base.BaseControllerTest):
|
||||
self.assertIn({
|
||||
'message':
|
||||
('An error occurred while building chart group: '
|
||||
'Could not build chart group keystone-infra-services in '
|
||||
'armada/ChartGroup/v1.'),
|
||||
'Could not build ChartGroup named "keystone-infra-services".'),
|
||||
'error':
|
||||
True,
|
||||
'kind':
|
||||
|
@ -158,125 +158,153 @@ class ArmadaHandlerTestCase(base.ArmadaTestCase):
|
||||
armada_obj.pre_flight_ops()
|
||||
|
||||
expected_config = {
|
||||
'armada': {
|
||||
'release_prefix':
|
||||
'armada',
|
||||
'schema': 'armada/Manifest/v1',
|
||||
'metadata': {
|
||||
'schema': 'metadata/Document/v1',
|
||||
'name': 'example-manifest'
|
||||
},
|
||||
'data': {
|
||||
'release_prefix': 'armada',
|
||||
'chart_groups': [{
|
||||
'chart_group': [{
|
||||
'chart': {
|
||||
'dependencies': [],
|
||||
'chart_name': 'test_chart_1',
|
||||
'namespace': 'test',
|
||||
'release': 'test_chart_1',
|
||||
'source': {
|
||||
'location': ('git://github.com/dummy/armada'),
|
||||
'reference': 'master',
|
||||
'subpath': 'chart_1',
|
||||
'type': 'git'
|
||||
'schema': 'armada/ChartGroup/v1',
|
||||
'metadata': {
|
||||
'schema': 'metadata/Document/v1',
|
||||
'name': 'example-group'
|
||||
},
|
||||
'data': {
|
||||
'chart_group': [{
|
||||
'schema': 'armada/Chart/v1',
|
||||
'metadata': {
|
||||
'schema': 'metadata/Document/v1',
|
||||
'name': 'example-chart-1'
|
||||
},
|
||||
'source_dir': CHART_SOURCES[0],
|
||||
'values': {},
|
||||
'wait': {
|
||||
'timeout': 10,
|
||||
'native': {
|
||||
'enabled': False
|
||||
}
|
||||
},
|
||||
'test': {
|
||||
'enabled': True
|
||||
}
|
||||
}
|
||||
}, {
|
||||
'chart': {
|
||||
'dependencies': [],
|
||||
'chart_name': 'test_chart_2',
|
||||
'namespace': 'test',
|
||||
'protected': {
|
||||
'continue_processing': True
|
||||
},
|
||||
'release': 'test_chart_2',
|
||||
'source': {
|
||||
'location': '/tmp/dummy/armada',
|
||||
'subpath': 'chart_2',
|
||||
'type': 'local'
|
||||
},
|
||||
'source_dir': CHART_SOURCES[1],
|
||||
'values': {},
|
||||
'wait': {
|
||||
'timeout': 10
|
||||
},
|
||||
'upgrade': {
|
||||
'no_hooks': False,
|
||||
'options': {
|
||||
'force': True,
|
||||
'recreate_pods': True
|
||||
}
|
||||
},
|
||||
'test': {
|
||||
'enabled': True,
|
||||
'options': {
|
||||
'cleanup': True
|
||||
'data': {
|
||||
'dependencies': [],
|
||||
'chart_name': 'test_chart_1',
|
||||
'namespace': 'test',
|
||||
'release': 'test_chart_1',
|
||||
'source': {
|
||||
'location':
|
||||
'git://github.com/dummy/armada',
|
||||
'reference': 'master',
|
||||
'subpath': 'chart_1',
|
||||
'type': 'git'
|
||||
},
|
||||
'source_dir': CHART_SOURCES[0],
|
||||
'values': {},
|
||||
'wait': {
|
||||
'timeout': 10,
|
||||
'native': {
|
||||
'enabled': False
|
||||
}
|
||||
},
|
||||
'test': {
|
||||
'enabled': True
|
||||
}
|
||||
}
|
||||
}
|
||||
}, {
|
||||
'chart': {
|
||||
'dependencies': [],
|
||||
'chart_name': 'test_chart_3',
|
||||
'namespace': 'test',
|
||||
'protected': {
|
||||
'continue_processing': False
|
||||
}, {
|
||||
'schema': 'armada/Chart/v1',
|
||||
'metadata': {
|
||||
'schema': 'metadata/Document/v1',
|
||||
'name': 'example-chart-2'
|
||||
},
|
||||
'release': 'test_chart_3',
|
||||
'source': {
|
||||
'location': '/tmp/dummy/armada',
|
||||
'subpath': 'chart_3',
|
||||
'type': 'local'
|
||||
},
|
||||
'source_dir': CHART_SOURCES[2],
|
||||
'values': {},
|
||||
'wait': {
|
||||
'timeout': 10
|
||||
},
|
||||
'upgrade': {
|
||||
'no_hooks': False
|
||||
'data': {
|
||||
'dependencies': [],
|
||||
'chart_name': 'test_chart_2',
|
||||
'namespace': 'test',
|
||||
'protected': {
|
||||
'continue_processing': True
|
||||
},
|
||||
'release': 'test_chart_2',
|
||||
'source': {
|
||||
'location': '/tmp/dummy/armada',
|
||||
'subpath': 'chart_2',
|
||||
'type': 'local'
|
||||
},
|
||||
'source_dir': CHART_SOURCES[1],
|
||||
'values': {},
|
||||
'wait': {
|
||||
'timeout': 10
|
||||
},
|
||||
'upgrade': {
|
||||
'no_hooks': False,
|
||||
'options': {
|
||||
'force': True,
|
||||
'recreate_pods': True
|
||||
}
|
||||
},
|
||||
'test': {
|
||||
'enabled': True,
|
||||
'options': {
|
||||
'cleanup': True
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}, {
|
||||
'chart': {
|
||||
'dependencies': [],
|
||||
'chart_name': 'test_chart_4',
|
||||
'namespace': 'test',
|
||||
'release': 'test_chart_4',
|
||||
'source': {
|
||||
'location': '/tmp/dummy/armada',
|
||||
'subpath': 'chart_4',
|
||||
'type': 'local'
|
||||
}, {
|
||||
'schema': 'armada/Chart/v1',
|
||||
'metadata': {
|
||||
'schema': 'metadata/Document/v1',
|
||||
'name': 'example-chart-3'
|
||||
},
|
||||
'source_dir': CHART_SOURCES[3],
|
||||
'values': {},
|
||||
'wait': {
|
||||
'timeout': 10
|
||||
'data': {
|
||||
'dependencies': [],
|
||||
'chart_name': 'test_chart_3',
|
||||
'namespace': 'test',
|
||||
'protected': {
|
||||
'continue_processing': False
|
||||
},
|
||||
'release': 'test_chart_3',
|
||||
'source': {
|
||||
'location': '/tmp/dummy/armada',
|
||||
'subpath': 'chart_3',
|
||||
'type': 'local'
|
||||
},
|
||||
'source_dir': CHART_SOURCES[2],
|
||||
'values': {},
|
||||
'wait': {
|
||||
'timeout': 10
|
||||
},
|
||||
'upgrade': {
|
||||
'no_hooks': False
|
||||
}
|
||||
}
|
||||
}, {
|
||||
'schema': 'armada/Chart/v1',
|
||||
'metadata': {
|
||||
'schema': 'metadata/Document/v1',
|
||||
'name': 'example-chart-4'
|
||||
},
|
||||
'upgrade': {
|
||||
'no_hooks': False
|
||||
},
|
||||
'test': True
|
||||
}
|
||||
}],
|
||||
'description':
|
||||
'this is a test',
|
||||
'name':
|
||||
'example-group',
|
||||
'sequenced':
|
||||
True
|
||||
'data': {
|
||||
'dependencies': [],
|
||||
'chart_name': 'test_chart_4',
|
||||
'namespace': 'test',
|
||||
'release': 'test_chart_4',
|
||||
'source': {
|
||||
'location': '/tmp/dummy/armada',
|
||||
'subpath': 'chart_4',
|
||||
'type': 'local'
|
||||
},
|
||||
'source_dir': CHART_SOURCES[3],
|
||||
'values': {},
|
||||
'wait': {
|
||||
'timeout': 10
|
||||
},
|
||||
'upgrade': {
|
||||
'no_hooks': False
|
||||
},
|
||||
'test': True
|
||||
}
|
||||
}],
|
||||
'description': 'this is a test',
|
||||
'sequenced': True
|
||||
}
|
||||
}]
|
||||
}
|
||||
} # yapf: disable
|
||||
|
||||
self.assertTrue(hasattr(armada_obj, 'manifest'))
|
||||
self.assertIsInstance(armada_obj.manifest, dict)
|
||||
self.assertIn('armada', armada_obj.manifest)
|
||||
self.assertIn('data', armada_obj.manifest)
|
||||
self.assertEqual(expected_config, armada_obj.manifest)
|
||||
|
||||
@mock.patch.object(armada, 'source')
|
||||
@ -314,9 +342,11 @@ class ArmadaHandlerTestCase(base.ArmadaTestCase):
|
||||
|
||||
armada_obj.post_flight_ops()
|
||||
|
||||
for group in armada_obj.manifest['armada']['chart_groups']:
|
||||
for counter, chart in enumerate(group.get('chart_group')):
|
||||
if chart.get('chart').get('source').get('type') == 'git':
|
||||
for group in armada_obj.manifest['data']['chart_groups']:
|
||||
for counter, chart in enumerate(
|
||||
group.get(const.KEYWORD_DATA).get(const.KEYWORD_CHARTS)):
|
||||
if chart.get(
|
||||
const.KEYWORD_DATA).get('source').get('type') == 'git':
|
||||
mock_source.source_cleanup.assert_called_with(
|
||||
CHART_SOURCES[counter][0])
|
||||
|
||||
@ -348,7 +378,8 @@ class ArmadaHandlerTestCase(base.ArmadaTestCase):
|
||||
armada_obj = armada.Armada(yaml_documents, m_tiller)
|
||||
armada_obj.chart_deploy.get_diff = mock.Mock()
|
||||
|
||||
chart_group = armada_obj.manifest['armada']['chart_groups'][0]
|
||||
cg = armada_obj.manifest['data']['chart_groups'][0]
|
||||
chart_group = cg['data']
|
||||
charts = chart_group['chart_group']
|
||||
cg_test_all_charts = chart_group.get('test_charts')
|
||||
|
||||
@ -380,9 +411,9 @@ class ArmadaHandlerTestCase(base.ArmadaTestCase):
|
||||
expected_test_constructor_calls = []
|
||||
|
||||
for c in charts:
|
||||
chart = c['chart']
|
||||
chart = c['data']
|
||||
release = chart['release']
|
||||
prefix = armada_obj.manifest['armada']['release_prefix']
|
||||
prefix = armada_obj.manifest['data']['release_prefix']
|
||||
release_name = release_prefixer(prefix, release)
|
||||
# Simplified check because the actual code uses logical-or's
|
||||
# multiple conditions, so this is enough.
|
||||
@ -394,8 +425,8 @@ class ArmadaHandlerTestCase(base.ArmadaTestCase):
|
||||
mock.call(
|
||||
mock_chartbuilder().get_helm_chart(),
|
||||
"{}-{}".format(
|
||||
armada_obj.manifest['armada']
|
||||
['release_prefix'], chart['release']),
|
||||
armada_obj.manifest['data']['release_prefix'],
|
||||
chart['release']),
|
||||
chart['namespace'],
|
||||
values=yaml.safe_dump(chart['values']),
|
||||
wait=native_wait_enabled,
|
||||
@ -420,7 +451,7 @@ class ArmadaHandlerTestCase(base.ArmadaTestCase):
|
||||
mock.call(
|
||||
mock_chartbuilder().get_helm_chart(),
|
||||
"{}-{}".format(
|
||||
armada_obj.manifest['armada']
|
||||
armada_obj.manifest['data']
|
||||
['release_prefix'],
|
||||
chart['release']),
|
||||
chart['namespace'],
|
||||
@ -449,7 +480,7 @@ class ArmadaHandlerTestCase(base.ArmadaTestCase):
|
||||
mock.call(
|
||||
mock_chartbuilder().get_helm_chart(),
|
||||
"{}-{}".format(
|
||||
armada_obj.manifest['armada']
|
||||
armada_obj.manifest['data']
|
||||
['release_prefix'],
|
||||
chart['release']),
|
||||
chart['namespace'],
|
||||
@ -647,8 +678,8 @@ class ArmadaNegativeHandlerTestCase(base.ArmadaTestCase):
|
||||
def test_armada_get_manifest_exception(self, mock_source):
|
||||
"""Test armada handling with invalid manifest."""
|
||||
yaml_documents = list(yaml.safe_load_all(TEST_YAML))
|
||||
error_re = ('Documents must be a list of documents with at least one '
|
||||
'of each of the following schemas: .*')
|
||||
error_re = ('.*Documents must include at least one of each of .* and '
|
||||
'only one .*')
|
||||
self.assertRaisesRegexp(ManifestException, error_re, armada.Armada,
|
||||
yaml_documents[:1], mock.MagicMock())
|
||||
|
||||
|
@ -23,6 +23,7 @@ from hapi.chart.metadata_pb2 import Metadata
|
||||
import mock
|
||||
import testtools
|
||||
|
||||
from armada import const
|
||||
from armada.handlers.chartbuilder import ChartBuilder
|
||||
from armada.exceptions import chartbuilder_exceptions
|
||||
|
||||
@ -59,7 +60,9 @@ class BaseChartBuilderTestCase(testtools.TestCase):
|
||||
"""
|
||||
|
||||
chart_stream = """
|
||||
chart:
|
||||
metadata:
|
||||
name: test
|
||||
data:
|
||||
chart_name: mariadb
|
||||
release: mariadb
|
||||
namespace: openstack
|
||||
@ -87,7 +90,9 @@ class BaseChartBuilderTestCase(testtools.TestCase):
|
||||
"""
|
||||
|
||||
dependency_chart_stream = """
|
||||
chart:
|
||||
metadata:
|
||||
name: dep
|
||||
data:
|
||||
chart_name: keystone
|
||||
release: keystone
|
||||
namespace: undercloud
|
||||
@ -120,6 +125,16 @@ class BaseChartBuilderTestCase(testtools.TestCase):
|
||||
self.addCleanup(shutil.rmtree, subdir)
|
||||
return subdir
|
||||
|
||||
def _get_test_chart(self, chart_dir):
|
||||
return {
|
||||
'metadata': {
|
||||
'name': 'test'
|
||||
},
|
||||
const.KEYWORD_DATA: {
|
||||
'source_dir': (chart_dir.path, '')
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class ChartBuilderTestCase(BaseChartBuilderTestCase):
|
||||
|
||||
@ -131,8 +146,7 @@ class ChartBuilderTestCase(BaseChartBuilderTestCase):
|
||||
self._write_temporary_file_contents(chart_dir.path, 'Chart.yaml',
|
||||
self.chart_yaml)
|
||||
|
||||
test_chart = {'source_dir': (chart_dir.path, '')}
|
||||
chartbuilder = ChartBuilder(test_chart)
|
||||
chartbuilder = ChartBuilder(self._get_test_chart(chart_dir))
|
||||
|
||||
# Validate response type is :class:`hapi.chart.metadata_pb2.Metadata`
|
||||
resp = chartbuilder.get_metadata()
|
||||
@ -142,8 +156,7 @@ class ChartBuilderTestCase(BaseChartBuilderTestCase):
|
||||
chart_dir = self.useFixture(fixtures.TempDir())
|
||||
self.addCleanup(shutil.rmtree, chart_dir.path)
|
||||
|
||||
test_chart = {'source_dir': (chart_dir.path, '')}
|
||||
chartbuilder = ChartBuilder(test_chart)
|
||||
chartbuilder = ChartBuilder(self._get_test_chart(chart_dir))
|
||||
|
||||
self.assertRaises(chartbuilder_exceptions.MetadataLoadException,
|
||||
chartbuilder.get_metadata)
|
||||
@ -168,8 +181,7 @@ class ChartBuilderTestCase(BaseChartBuilderTestCase):
|
||||
for filename in ['template%d' % x for x in range(3)]:
|
||||
self._write_temporary_file_contents(templates_subdir, filename, "")
|
||||
|
||||
test_chart = {'source_dir': (chart_dir.path, '')}
|
||||
chartbuilder = ChartBuilder(test_chart)
|
||||
chartbuilder = ChartBuilder(self._get_test_chart(chart_dir))
|
||||
|
||||
expected_files = (
|
||||
'[type_url: "%s"\n, type_url: "%s"\n]' % ('./bar', './foo'))
|
||||
@ -185,8 +197,7 @@ class ChartBuilderTestCase(BaseChartBuilderTestCase):
|
||||
self._write_temporary_file_contents(
|
||||
chart_dir.path, filename, "DIRC^@^@^@^B^@^@^@×Z®<86>F.1")
|
||||
|
||||
test_chart = {'source_dir': (chart_dir.path, '')}
|
||||
chartbuilder = ChartBuilder(test_chart)
|
||||
chartbuilder = ChartBuilder(self._get_test_chart(chart_dir))
|
||||
chartbuilder.get_files()
|
||||
|
||||
def test_get_basic_helm_chart(self):
|
||||
@ -197,8 +208,8 @@ class ChartBuilderTestCase(BaseChartBuilderTestCase):
|
||||
self.addCleanup(shutil.rmtree, chart_dir.path)
|
||||
self._write_temporary_file_contents(chart_dir.path, 'Chart.yaml',
|
||||
self.chart_yaml)
|
||||
ch = yaml.safe_load(self.chart_stream)['chart']
|
||||
ch['source_dir'] = (chart_dir.path, '')
|
||||
ch = yaml.safe_load(self.chart_stream)
|
||||
ch['data']['source_dir'] = (chart_dir.path, '')
|
||||
|
||||
test_chart = ch
|
||||
chartbuilder = ChartBuilder(test_chart)
|
||||
@ -228,8 +239,8 @@ class ChartBuilderTestCase(BaseChartBuilderTestCase):
|
||||
self._write_temporary_file_contents(chart_dir.path, 'values.yaml',
|
||||
self.chart_value)
|
||||
|
||||
ch = yaml.safe_load(self.chart_stream)['chart']
|
||||
ch['source_dir'] = (chart_dir.path, '')
|
||||
ch = yaml.safe_load(self.chart_stream)
|
||||
ch['data']['source_dir'] = (chart_dir.path, '')
|
||||
|
||||
test_chart = ch
|
||||
chartbuilder = ChartBuilder(test_chart)
|
||||
@ -257,8 +268,8 @@ class ChartBuilderTestCase(BaseChartBuilderTestCase):
|
||||
'nested')
|
||||
self._write_temporary_file_contents(nested_dir, 'nested0', "random")
|
||||
|
||||
ch = yaml.safe_load(self.chart_stream)['chart']
|
||||
ch['source_dir'] = (chart_dir.path, '')
|
||||
ch = yaml.safe_load(self.chart_stream)
|
||||
ch['data']['source_dir'] = (chart_dir.path, '')
|
||||
|
||||
test_chart = ch
|
||||
chartbuilder = ChartBuilder(test_chart)
|
||||
@ -313,8 +324,8 @@ class ChartBuilderTestCase(BaseChartBuilderTestCase):
|
||||
# Files to **include** within charts/ subdirectory.
|
||||
self._write_temporary_file_contents(charts_subdir, '.prov', "xyzzy")
|
||||
|
||||
ch = yaml.safe_load(self.chart_stream)['chart']
|
||||
ch['source_dir'] = (chart_dir.path, '')
|
||||
ch = yaml.safe_load(self.chart_stream)
|
||||
ch['data']['source_dir'] = (chart_dir.path, '')
|
||||
|
||||
test_chart = ch
|
||||
chartbuilder = ChartBuilder(test_chart)
|
||||
@ -340,8 +351,8 @@ class ChartBuilderTestCase(BaseChartBuilderTestCase):
|
||||
self.addCleanup(shutil.rmtree, chart_dir.path)
|
||||
self._write_temporary_file_contents(chart_dir.path, 'Chart.yaml',
|
||||
self.chart_yaml)
|
||||
ch = yaml.safe_load(self.chart_stream)['chart']
|
||||
ch['source_dir'] = (chart_dir.path, '')
|
||||
ch = yaml.safe_load(self.chart_stream)
|
||||
ch['data']['source_dir'] = (chart_dir.path, '')
|
||||
|
||||
# Dependency chart directory and files.
|
||||
dep_chart_dir = self.useFixture(fixtures.TempDir())
|
||||
@ -349,11 +360,11 @@ class ChartBuilderTestCase(BaseChartBuilderTestCase):
|
||||
self._write_temporary_file_contents(dep_chart_dir.path, 'Chart.yaml',
|
||||
self.dependency_chart_yaml)
|
||||
dep_ch = yaml.safe_load(self.dependency_chart_stream)
|
||||
dep_ch['chart']['source_dir'] = (dep_chart_dir.path, '')
|
||||
dep_ch['data']['source_dir'] = (dep_chart_dir.path, '')
|
||||
|
||||
main_chart = ch
|
||||
dependency_chart = dep_ch
|
||||
main_chart['dependencies'] = [dependency_chart]
|
||||
main_chart['data']['dependencies'] = [dependency_chart]
|
||||
|
||||
chartbuilder = ChartBuilder(main_chart)
|
||||
helm_chart = chartbuilder.get_helm_chart()
|
||||
@ -409,8 +420,8 @@ class ChartBuilderTestCase(BaseChartBuilderTestCase):
|
||||
self.addCleanup(shutil.rmtree, chart_dir.path)
|
||||
self._write_temporary_file_contents(chart_dir.path, 'Chart.yaml',
|
||||
self.chart_yaml)
|
||||
ch = yaml.safe_load(self.chart_stream)['chart']
|
||||
ch['source_dir'] = (chart_dir.path, '')
|
||||
ch = yaml.safe_load(self.chart_stream)
|
||||
ch['data']['source_dir'] = (chart_dir.path, '')
|
||||
|
||||
test_chart = ch
|
||||
chartbuilder = ChartBuilder(test_chart)
|
||||
@ -424,10 +435,10 @@ class ChartBuilderTestCase(BaseChartBuilderTestCase):
|
||||
self._write_temporary_file_contents(dep_chart_dir.path, 'Chart.yaml',
|
||||
self.dependency_chart_yaml)
|
||||
dep_ch = yaml.safe_load(self.dependency_chart_stream)
|
||||
dep_ch['chart']['source_dir'] = (dep_chart_dir.path, '')
|
||||
dep_ch['data']['source_dir'] = (dep_chart_dir.path, '')
|
||||
|
||||
dependency_chart = dep_ch
|
||||
test_chart['dependencies'] = [dependency_chart]
|
||||
test_chart['data']['dependencies'] = [dependency_chart]
|
||||
chartbuilder = ChartBuilder(test_chart)
|
||||
|
||||
re = inspect.cleandoc("""
|
||||
@ -457,8 +468,7 @@ class ChartBuilderNegativeTestCase(BaseChartBuilderTestCase):
|
||||
self._write_temporary_file_contents(
|
||||
chart_dir.path, filename, "DIRC^@^@^@^B^@^@^@×Z®<86>F.1")
|
||||
|
||||
test_chart = {'source_dir': (chart_dir.path, '')}
|
||||
chartbuilder = ChartBuilder(test_chart)
|
||||
chartbuilder = ChartBuilder(self._get_test_chart(chart_dir))
|
||||
|
||||
# Confirm it failed for both encodings.
|
||||
error_re = (r'.*A str exception occurred while trying to read file:'
|
||||
@ -477,8 +487,7 @@ class ChartBuilderNegativeTestCase(BaseChartBuilderTestCase):
|
||||
self._write_temporary_file_contents(
|
||||
chart_dir.path, filename, "DIRC^@^@^@^B^@^@^@×Z®<86>F.1")
|
||||
|
||||
test_chart = {'source_dir': (chart_dir.path, '')}
|
||||
chartbuilder = ChartBuilder(test_chart)
|
||||
chartbuilder = ChartBuilder(self._get_test_chart(chart_dir))
|
||||
|
||||
side_effects = [self.exc_to_raise, "", ""]
|
||||
with mock.patch("builtins.open", mock.mock_open(read_data="")) \
|
||||
|
@ -18,9 +18,9 @@ import yaml
|
||||
|
||||
import testtools
|
||||
|
||||
from armada import const
|
||||
from armada import exceptions
|
||||
from armada.handlers import manifest
|
||||
from armada.handlers import schema
|
||||
from armada.utils import validate
|
||||
|
||||
|
||||
@ -111,7 +111,7 @@ class ManifestTestCase(testtools.TestCase):
|
||||
self.documents, target_manifest='armada-manifest')
|
||||
obtained_manifest = armada_manifest.get_manifest()
|
||||
self.assertIsInstance(obtained_manifest, dict)
|
||||
self.assertEqual(obtained_manifest['armada'],
|
||||
self.assertEqual(obtained_manifest['data'],
|
||||
armada_manifest.manifest['data'])
|
||||
|
||||
def test_find_documents(self):
|
||||
@ -194,19 +194,15 @@ class ManifestTestCase(testtools.TestCase):
|
||||
# the first chart group in the Armada manifest
|
||||
keystone_infra_services_chart_group = armada_manifest. \
|
||||
find_chart_group_document('keystone-infra-services')
|
||||
keystone_infra_services_chart_group_data = \
|
||||
keystone_infra_services_chart_group.get('data')
|
||||
|
||||
self.assertEqual(keystone_infra_services_chart_group_data,
|
||||
self.assertEqual(keystone_infra_services_chart_group,
|
||||
built_armada_manifest['data']['chart_groups'][0])
|
||||
|
||||
# the first chart group in the Armada manifest
|
||||
openstack_keystone_chart_group = armada_manifest. \
|
||||
find_chart_group_document('openstack-keystone')
|
||||
openstack_keystone_chart_group_data = \
|
||||
openstack_keystone_chart_group.get('data')
|
||||
|
||||
self.assertEqual(openstack_keystone_chart_group_data,
|
||||
self.assertEqual(openstack_keystone_chart_group,
|
||||
built_armada_manifest['data']['chart_groups'][1])
|
||||
|
||||
def test_verify_build_chart_group_deps(self):
|
||||
@ -218,7 +214,7 @@ class ManifestTestCase(testtools.TestCase):
|
||||
build_chart_group(chart_group)
|
||||
openstack_keystone_chart_group_deps_dep_added = \
|
||||
openstack_keystone_chart_group_deps[
|
||||
'data']['chart_group'][0]['chart']['dependencies']
|
||||
'data']['chart_group'][0]['data']['dependencies']
|
||||
|
||||
# keystone chart dependencies
|
||||
keystone_chart = armada_manifest.find_chart_document('keystone')
|
||||
@ -237,7 +233,7 @@ class ManifestTestCase(testtools.TestCase):
|
||||
build_chart_group(chart_group)
|
||||
keystone_infra_services_dep_added = \
|
||||
openstack_keystone_chart_group_deps[
|
||||
'data']['chart_group'][0]['chart']['dependencies']
|
||||
'data']['chart_group'][0]['data']['dependencies']
|
||||
|
||||
# building mariadb chart dependencies
|
||||
mariadb_chart = armada_manifest.find_chart_document('mariadb')
|
||||
@ -274,9 +270,7 @@ class ManifestTestCase(testtools.TestCase):
|
||||
|
||||
# helm-toolkit dependency, the basis for comparison of d
|
||||
# ependencies in other charts
|
||||
expected_helm_toolkit_dependency = {
|
||||
'chart': helm_toolkit_chart.get('data')
|
||||
}
|
||||
expected_helm_toolkit_dependency = helm_toolkit_chart
|
||||
|
||||
# keystone chart dependencies
|
||||
keystone_chart = armada_manifest.find_chart_document('keystone')
|
||||
@ -366,42 +360,39 @@ class ManifestNegativeTestCase(testtools.TestCase):
|
||||
documents,
|
||||
target_manifest='armada-manifest')
|
||||
|
||||
def _assert_missing_documents_raises(self, documents):
|
||||
error_re = ('.*Documents must include at least one of each of .* and '
|
||||
'only one .*')
|
||||
self.assertRaisesRegexp(exceptions.ManifestException, error_re,
|
||||
manifest.Manifest, documents)
|
||||
|
||||
def test_get_documents_missing_manifest(self):
|
||||
# Validates exceptions.ManifestException is thrown if no manifest is
|
||||
# found. Manifest is last document in sample YAML.
|
||||
error_re = ('Documents must be a list of documents with at least one '
|
||||
'of each of the following schemas: .*')
|
||||
self.assertRaisesRegexp(exceptions.ManifestException, error_re,
|
||||
manifest.Manifest, self.documents[:-1])
|
||||
self._assert_missing_documents_raises(self.documents[:-1])
|
||||
|
||||
def test_get_documents_missing_charts(self):
|
||||
# Validates exceptions.ManifestException is thrown if no chart is
|
||||
# found. Charts are first 5 documents in sample YAML.
|
||||
error_re = ('Documents must be a list of documents with at least one '
|
||||
'of each of the following schemas: .*')
|
||||
self.assertRaisesRegexp(exceptions.ManifestException, error_re,
|
||||
manifest.Manifest, self.documents[5:])
|
||||
self._assert_missing_documents_raises(self.documents[5:])
|
||||
|
||||
def test_get_documents_missing_chart_groups(self):
|
||||
# Validates exceptions.ManifestException is thrown if no chart is
|
||||
# found. ChartGroups are 5-6 documents in sample YAML.
|
||||
documents = self.documents[:4] + [self.documents[-1]]
|
||||
error_re = ('Documents must be a list of documents with at least one '
|
||||
'of each of the following schemas: .*')
|
||||
self.assertRaisesRegexp(exceptions.ManifestException, error_re,
|
||||
manifest.Manifest, documents)
|
||||
self._assert_missing_documents_raises(documents)
|
||||
|
||||
def test_find_chart_document_negative(self):
|
||||
armada_manifest = manifest.Manifest(self.documents)
|
||||
error_re = r'Could not build %s named "%s"' % (const.DOCUMENT_CHART,
|
||||
'invalid')
|
||||
error_re = r'.*Could not find %s named "%s"' % (schema.TYPE_CHART,
|
||||
'invalid')
|
||||
self.assertRaisesRegexp(exceptions.BuildChartException, error_re,
|
||||
armada_manifest.find_chart_document, 'invalid')
|
||||
|
||||
def test_find_group_document_negative(self):
|
||||
armada_manifest = manifest.Manifest(self.documents)
|
||||
error_re = r'Could not build %s named "%s"' % (const.DOCUMENT_GROUP,
|
||||
'invalid')
|
||||
error_re = r'.*Could not find %s named "%s"' % (schema.TYPE_CHARTGROUP,
|
||||
'invalid')
|
||||
self.assertRaisesRegexp(exceptions.BuildChartGroupException, error_re,
|
||||
armada_manifest.find_chart_group_document,
|
||||
'invalid')
|
||||
|
@ -20,8 +20,8 @@ import yaml
|
||||
import testtools
|
||||
|
||||
from armada.handlers.override import Override
|
||||
from armada.handlers import schema
|
||||
from armada.exceptions import override_exceptions
|
||||
from armada import const
|
||||
|
||||
|
||||
class OverrideTestCase(testtools.TestCase):
|
||||
@ -117,13 +117,13 @@ class OverrideTestCase(testtools.TestCase):
|
||||
documents = list(yaml.safe_load_all(f.read()))
|
||||
ovr = Override(documents)
|
||||
test_group = ovr.find_document_type('chart_group')
|
||||
self.assertEqual(test_group, const.DOCUMENT_GROUP)
|
||||
self.assertEqual(test_group, schema.TYPE_CHARTGROUP)
|
||||
|
||||
test_chart = ovr.find_document_type('chart')
|
||||
self.assertEqual(test_chart, const.DOCUMENT_CHART)
|
||||
self.assertEqual(test_chart, schema.TYPE_CHART)
|
||||
|
||||
test_manifest = ovr.find_document_type('manifest')
|
||||
self.assertEqual(test_manifest, const.DOCUMENT_MANIFEST)
|
||||
self.assertEqual(test_manifest, schema.TYPE_MANIFEST)
|
||||
|
||||
def test_update_chart_document_valid(self):
|
||||
with open(self.base_manifest) as f:
|
||||
@ -138,7 +138,7 @@ class OverrideTestCase(testtools.TestCase):
|
||||
|
||||
ovr = Override(documents)
|
||||
# update with document values with the modified ones
|
||||
ovr.update_chart_document(documents_modified[0])
|
||||
ovr.update_document(documents_modified[0])
|
||||
|
||||
# after the update, both documents are equal
|
||||
self.assertEqual(ovr.documents[0]['data']['chart_name'],
|
||||
@ -148,7 +148,7 @@ class OverrideTestCase(testtools.TestCase):
|
||||
# Case 2: Checking if dictionaries get updated
|
||||
documents_modified[0]['data']['values'] = {'foo': 'bar'}
|
||||
|
||||
ovr.update_chart_document(documents_modified[0])
|
||||
ovr.update_document(documents_modified[0])
|
||||
|
||||
# after the update, both documents are equal
|
||||
self.assertEqual(ovr.documents[0]['data']['values'],
|
||||
@ -158,7 +158,7 @@ class OverrideTestCase(testtools.TestCase):
|
||||
# Case 3: Checking if lists get updated
|
||||
documents_modified[0]['data']['dependencies'] = ['foo', 'bar']
|
||||
|
||||
ovr.update_chart_document(documents_modified[0])
|
||||
ovr.update_document(documents_modified[0])
|
||||
|
||||
# after the update, both documents are equal
|
||||
self.assertEqual(['foo', 'bar'],
|
||||
@ -179,7 +179,7 @@ class OverrideTestCase(testtools.TestCase):
|
||||
|
||||
ovr = Override(documents)
|
||||
# update with document values with the modified ones
|
||||
ovr.update_chart_document(documents_modified[0])
|
||||
ovr.update_document(documents_modified[0])
|
||||
|
||||
self.assertIn('chart_name', ovr.documents[0]['data'])
|
||||
self.assertNotEqual(ovr.documents[0], documents_modified[0])
|
||||
@ -195,7 +195,7 @@ class OverrideTestCase(testtools.TestCase):
|
||||
|
||||
ovr = Override(documents)
|
||||
# update with document values with the modified ones
|
||||
ovr.update_chart_group_document(documents_modified[1])
|
||||
ovr.update_document(documents_modified[1])
|
||||
|
||||
# after the update, both documents are equal
|
||||
self.assertEqual(ovr.documents[1]['data']['sequenced'],
|
||||
@ -214,7 +214,7 @@ class OverrideTestCase(testtools.TestCase):
|
||||
|
||||
ovr = Override(documents)
|
||||
# update with document values with the modified ones
|
||||
ovr.update_chart_group_document(documents_modified[1])
|
||||
ovr.update_document(documents_modified[1])
|
||||
|
||||
self.assertIn('sequenced', ovr.documents[1]['data'])
|
||||
self.assertNotEqual(ovr.documents[1], documents_modified[1])
|
||||
@ -230,7 +230,7 @@ class OverrideTestCase(testtools.TestCase):
|
||||
|
||||
ovr = Override(documents)
|
||||
# update with document values with the modified ones
|
||||
ovr.update_armada_manifest(documents_modified[2])
|
||||
ovr.update_document(documents_modified[2])
|
||||
|
||||
# after the update, both documents are equal
|
||||
self.assertEqual(ovr.documents[2]['data']['release_prefix'],
|
||||
@ -249,7 +249,7 @@ class OverrideTestCase(testtools.TestCase):
|
||||
|
||||
ovr = Override(documents)
|
||||
# update with document values from base_manifest
|
||||
ovr.update_armada_manifest(documents_modified[2])
|
||||
ovr.update_document(documents_modified[2])
|
||||
|
||||
self.assertIn('release_prefix', ovr.documents[2]['data'])
|
||||
self.assertNotEqual(ovr.documents[2], documents_modified[2])
|
||||
@ -265,7 +265,7 @@ class OverrideTestCase(testtools.TestCase):
|
||||
documents = list(yaml.safe_load_all(f.read()))
|
||||
doc_path = ['chart', 'blog-1']
|
||||
ovr = Override(documents)
|
||||
ovr.update_document(merging_values)
|
||||
ovr.update_documents(merging_values)
|
||||
ovr_doc = ovr.find_manifest_document(doc_path)
|
||||
expect_doc = list(yaml.load_all(e.read()))[0]
|
||||
|
||||
|
38
armada/tests/unit/utils/schema.py
Normal file
38
armada/tests/unit/utils/schema.py
Normal file
@ -0,0 +1,38 @@
|
||||
# Copyright 2019 The Armada Authors.
|
||||
#
|
||||
# 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 unittest
|
||||
|
||||
from armada.utils import schema
|
||||
|
||||
|
||||
class SchemaTestCase(unittest.TestCase):
|
||||
|
||||
def test_validate_load_schemas(self):
|
||||
expected_schemas = [
|
||||
'armada/Chart/v1', 'armada/ChartGroup/v1', 'armada/Manifest/v1'
|
||||
'armada/Chart/v2', 'armada/ChartGroup/v2', 'armada/Manifest/v2'
|
||||
]
|
||||
for expected_schema in expected_schemas:
|
||||
self.assertIn(expected_schema, schema._SCHEMAS)
|
||||
|
||||
def test_validate_load_duplicate_schemas_expect_runtime_error(self):
|
||||
"""Validate that calling ``_load_schemas`` results in a
|
||||
``RuntimeError`` being thrown, because the call is made during module
|
||||
import, and importing the schemas again in manually results in
|
||||
duplicates.
|
||||
"""
|
||||
with self.assertRaisesRegexp(RuntimeError,
|
||||
'Duplicate schema specified for: .*'):
|
||||
schema._load_schemas()
|
@ -111,13 +111,6 @@ class ValidateOwnExamplesTestCase(BaseValidateTest):
|
||||
|
||||
class ValidateTestCase(BaseValidateTest):
|
||||
|
||||
def test_validate_load_schemas(self):
|
||||
expected_schemas = [
|
||||
'armada/Chart/v1', 'armada/ChartGroup/v1', 'armada/Manifest/v1'
|
||||
]
|
||||
for expected_schema in expected_schemas:
|
||||
self.assertIn(expected_schema, validate.SCHEMAS)
|
||||
|
||||
def test_validate_armada_yaml_passes(self):
|
||||
template = '{}/resources/valid_armada_document.yaml'.format(
|
||||
self.basepath)
|
||||
@ -223,16 +216,6 @@ data:
|
||||
|
||||
class ValidateNegativeTestCase(BaseValidateTest):
|
||||
|
||||
def test_validate_load_duplicate_schemas_expect_runtime_error(self):
|
||||
"""Validate that calling ``validate._load_schemas`` results in a
|
||||
``RuntimeError`` being thrown, because the call is made during module
|
||||
import, and importing the schemas again in manually results in
|
||||
duplicates.
|
||||
"""
|
||||
with self.assertRaisesRegexp(RuntimeError,
|
||||
'Duplicate schema specified for: .*'):
|
||||
validate._load_schemas()
|
||||
|
||||
def test_validate_no_dictionary_expect_type_error(self):
|
||||
expected_error = 'The provided input "invalid" must be a dictionary.'
|
||||
self.assertRaisesRegexp(TypeError, expected_error,
|
||||
|
@ -13,44 +13,18 @@
|
||||
# limitations under the License.
|
||||
|
||||
import jsonschema
|
||||
import os
|
||||
import pkg_resources
|
||||
import requests
|
||||
import traceback
|
||||
import yaml
|
||||
|
||||
from oslo_log import log as logging
|
||||
|
||||
from armada.const import KEYWORD_GROUPS, KEYWORD_CHARTS, KEYWORD_RELEASE
|
||||
from armada import const
|
||||
from armada.handlers import schema as sch
|
||||
from armada.handlers.manifest import Manifest
|
||||
from armada.exceptions.manifest_exceptions import ManifestException
|
||||
from armada.utils.validation_message import ValidationMessage
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
# Creates a mapping between ``metadata.name``: ``data`` where the
|
||||
# ``metadata.name`` is the ``schema`` of a manifest and the ``data`` is the
|
||||
# JSON schema to be used to validate the manifest in question.
|
||||
SCHEMAS = {}
|
||||
|
||||
|
||||
def _get_schema_dir():
|
||||
return pkg_resources.resource_filename('armada', 'schemas')
|
||||
|
||||
|
||||
def _load_schemas():
|
||||
"""Populates ``SCHEMAS`` with the schemas defined in package
|
||||
``armada.schemas``.
|
||||
|
||||
"""
|
||||
schema_dir = _get_schema_dir()
|
||||
for schema_file in os.listdir(schema_dir):
|
||||
with open(os.path.join(schema_dir, schema_file)) as f:
|
||||
for schema in yaml.safe_load_all(f):
|
||||
name = schema['metadata']['name']
|
||||
if name in SCHEMAS:
|
||||
raise RuntimeError(
|
||||
'Duplicate schema specified for: %s.' % name)
|
||||
SCHEMAS[name] = schema['data']
|
||||
|
||||
|
||||
def _validate_armada_manifest(manifest):
|
||||
@ -71,7 +45,7 @@ def _validate_armada_manifest(manifest):
|
||||
details = []
|
||||
|
||||
try:
|
||||
armada_object = manifest.get_manifest().get('armada')
|
||||
manifest.get_manifest().get(const.KEYWORD_DATA)
|
||||
except ManifestException as me:
|
||||
vmsg = ValidationMessage(
|
||||
message=str(me), error=True, name='ARM001', level='Error')
|
||||
@ -80,27 +54,6 @@ def _validate_armada_manifest(manifest):
|
||||
details.append(vmsg.get_output())
|
||||
return False, details
|
||||
|
||||
groups = armada_object.get(KEYWORD_GROUPS)
|
||||
|
||||
if not isinstance(groups, list):
|
||||
message = '{} entry is of wrong type: {} (expected: {})'.format(
|
||||
KEYWORD_GROUPS, type(groups), 'list')
|
||||
vmsg = ValidationMessage(
|
||||
message=message, error=True, name='ARM101', level='Error')
|
||||
LOG.info('ValidationMessage: %s', vmsg.get_output_json())
|
||||
details.append(vmsg.get_output())
|
||||
|
||||
for group in groups:
|
||||
for chart in group.get(KEYWORD_CHARTS):
|
||||
chart_obj = chart.get('chart')
|
||||
if KEYWORD_RELEASE not in chart_obj:
|
||||
message = 'Could not find {} keyword in {}'.format(
|
||||
KEYWORD_RELEASE, chart_obj.get('release'))
|
||||
vmsg = ValidationMessage(
|
||||
message=message, error=True, name='ARM102', level='Error')
|
||||
LOG.info('ValidationMessage: %s', vmsg.get_output_json())
|
||||
details.append(vmsg.get_output())
|
||||
|
||||
if len([x for x in details if x.get('error', False)]) > 0:
|
||||
return False, details
|
||||
|
||||
@ -117,13 +70,16 @@ def validate_armada_manifests(documents):
|
||||
all_valid = True
|
||||
|
||||
for document in documents:
|
||||
if document.get('schema', '') == 'armada/Manifest/v1':
|
||||
target = document.get('metadata').get('name')
|
||||
# TODO(MarshM) explore: why does this pass 'documents'?
|
||||
manifest = Manifest(documents, target_manifest=target)
|
||||
is_valid, details = _validate_armada_manifest(manifest)
|
||||
all_valid = all_valid and is_valid
|
||||
messages.extend(details)
|
||||
doc_schema = document.get('schema')
|
||||
if doc_schema:
|
||||
schema_info = sch.get_schema_info(doc_schema)
|
||||
if schema_info and schema_info.type == sch.TYPE_MANIFEST:
|
||||
target = document.get('metadata').get('name')
|
||||
# TODO(MarshM) explore: why does this pass 'documents'?
|
||||
manifest = Manifest(documents, target_manifest=target)
|
||||
is_valid, details = _validate_armada_manifest(manifest)
|
||||
all_valid = all_valid and is_valid
|
||||
messages.extend(details)
|
||||
|
||||
return all_valid, messages
|
||||
|
||||
@ -151,9 +107,10 @@ def validate_armada_document(document):
|
||||
details = []
|
||||
LOG.debug('Validating document [%s] %s', schema, document_name)
|
||||
|
||||
if schema in SCHEMAS:
|
||||
schema_info = sch.get_schema_info(schema)
|
||||
if schema_info:
|
||||
try:
|
||||
validator = jsonschema.Draft4Validator(SCHEMAS[schema])
|
||||
validator = jsonschema.Draft4Validator(schema_info.data)
|
||||
for error in validator.iter_errors(document.get('data')):
|
||||
error_message = "Invalid document [%s] %s: %s." % \
|
||||
(schema, document_name, error.message)
|
||||
@ -222,7 +179,3 @@ def validate_manifest_url(value):
|
||||
return (requests.get(value).status_code == 200)
|
||||
except requests.exceptions.RequestException:
|
||||
return False
|
||||
|
||||
|
||||
# Fill the cache.
|
||||
_load_schemas()
|
||||
|
26
doc/source/operations/documents/index.rst
Normal file
26
doc/source/operations/documents/index.rst
Normal file
@ -0,0 +1,26 @@
|
||||
..
|
||||
Copyright 2019 AT&T Intellectual Property.
|
||||
All 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.
|
||||
|
||||
Document Authoring Guide
|
||||
========================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:caption: Contents:
|
||||
|
||||
v1/index
|
||||
v2/index
|
||||
migration-v1-v2
|
70
doc/source/operations/documents/migration-v1-v2.rst
Normal file
70
doc/source/operations/documents/migration-v1-v2.rst
Normal file
@ -0,0 +1,70 @@
|
||||
..
|
||||
Copyright 2019 AT&T Intellectual Property.
|
||||
All 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.
|
||||
|
||||
v1-v2 Migration
|
||||
===============
|
||||
|
||||
The following migrations must be done when moving from :ref:`v1 <document_authoring_v1>` to :ref:`v2 <document_authoring_v2>` docs.
|
||||
|
||||
Chart
|
||||
-----
|
||||
|
||||
+--------------------------------+------------------------------------------------------------+
|
||||
| change | migration |
|
||||
+================================+============================================================+
|
||||
| ``chart_name`` removed | Remove. It was redundant with ``metadata.name`` while at |
|
||||
| | the same time not guaranteeing uniqueness. Log messages now|
|
||||
| | reference ``metadata.name`` for improved grep-ability. |
|
||||
+--------------------------------+------------------------------------------------------------+
|
||||
| ``test`` as a boolean removed | :ref:`test <test_v2>` must now be an object. |
|
||||
+--------------------------------+------------------------------------------------------------+
|
||||
| ``timeout`` removed | Use ``wait.timeout`` instead. |
|
||||
+--------------------------------+------------------------------------------------------------+
|
||||
| ``install`` removed | Remove. Previously unused. |
|
||||
+--------------------------------+------------------------------------------------------------+
|
||||
| ``upgrade.post`` removed | Remove. |
|
||||
+--------------------------------+------------------------------------------------------------+
|
||||
| ``upgrade.pre.update`` removed | Remove. |
|
||||
+--------------------------------+------------------------------------------------------------+
|
||||
| ``upgrade.pre.create`` removed | Remove. |
|
||||
+--------------------------------+------------------------------------------------------------+
|
||||
| ``upgrade.pre.delete[*].name`` | Remove. |
|
||||
| removed | |
|
||||
+--------------------------------+------------------------------------------------------------+
|
||||
| ``upgrade.pre.delete[*]`` | If you have an item in ``upgrade.pre.delete`` and |
|
||||
| with ``type: job`` no longer | ``type: job`` and you also want to delete cronjobs, add |
|
||||
| deletes cronjobs | another item with ``type: cronjob`` and same labels. |
|
||||
+--------------------------------+------------------------------------------------------------+
|
||||
| ``dependencies``, | Remove as desired. |
|
||||
| ``upgrade.no_hooks``, | |
|
||||
| ``source.subpath`` | |
|
||||
| now optional | |
|
||||
+--------------------------------+------------------------------------------------------------+
|
||||
|
||||
ChartGroup
|
||||
----------
|
||||
|
||||
+--------------------------+-----------------------------------------------------------+
|
||||
| change | migration |
|
||||
+==========================+===========================================================+
|
||||
| ``test_charts`` removed | Use the Chart schema's :ref:`test.enabled <test_v2>` |
|
||||
| | instead. |
|
||||
+--------------------------+-----------------------------------------------------------+
|
||||
|
||||
Manifest
|
||||
--------
|
||||
|
||||
No changes.
|
@ -1,5 +1,23 @@
|
||||
Armada - Making Your First Armada Manifest
|
||||
==========================================
|
||||
..
|
||||
Copyright 2019 AT&T Intellectual Property.
|
||||
All 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.
|
||||
|
||||
.. _document_authoring_v1:
|
||||
|
||||
v1 Authoring
|
||||
============
|
||||
|
||||
armada/Manifest/v1
|
||||
------------------
|
||||
@ -191,9 +209,6 @@ Run helm tests on the chart after install/upgrade.
|
||||
deprecated and will be removed. The ``cleanup`` option below is set to true
|
||||
in this case for backward compatibility.
|
||||
|
||||
.. _test_options:
|
||||
|
||||
|
||||
Test Options
|
||||
^^^^^^^^^^^^
|
||||
|
25
doc/source/operations/documents/v1/index.rst
Normal file
25
doc/source/operations/documents/v1/index.rst
Normal file
@ -0,0 +1,25 @@
|
||||
..
|
||||
Copyright 2019 AT&T Intellectual Property.
|
||||
All 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.
|
||||
|
||||
v1
|
||||
==
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:caption: Contents:
|
||||
|
||||
document-authoring
|
||||
schemas
|
@ -14,15 +14,11 @@
|
||||
License for the specific language governing permissions and limitations
|
||||
under the License.
|
||||
|
||||
.. _armada-documents:
|
||||
v1 Schemas
|
||||
==========
|
||||
|
||||
Armada Documents
|
||||
================
|
||||
|
||||
Below are the schemas Armada uses to validate :ref:`Charts`,
|
||||
:ref:`Chart Groups`, and :ref:`Manifests`.
|
||||
|
||||
.. _Charts:
|
||||
Below are the schemas Armada uses to validate Charts, Chart Groups, and
|
||||
Manifests.
|
||||
|
||||
Charts
|
||||
------
|
||||
@ -32,16 +28,12 @@ comparable to a Helm chart. Charts consist of all the labels, dependencies,
|
||||
install and upgrade information, hooks and additional information needed to
|
||||
convey to Tiller.
|
||||
|
||||
.. _Chart Groups:
|
||||
|
||||
Chart Groups
|
||||
------------
|
||||
|
||||
A ``Chart Group`` consists of a list of charts. ``Chart Group`` documents are
|
||||
useful for managing a group of ``Chart`` documents together.
|
||||
|
||||
.. _Manifests:
|
||||
|
||||
Manifests
|
||||
---------
|
||||
|
||||
@ -76,7 +68,7 @@ Schemas
|
||||
``metadata.name`` are validated.
|
||||
|
||||
.. literalinclude::
|
||||
../../../armada/schemas/armada-chart-schema.yaml
|
||||
../../../../../armada/schemas/armada-chart-schema-v1.yaml
|
||||
:language: yaml
|
||||
:lines: 15-
|
||||
:caption: Schema for ``armada/Chart/v1`` documents.
|
||||
@ -90,7 +82,7 @@ Schemas
|
||||
``metadata.name`` are validated.
|
||||
|
||||
.. literalinclude::
|
||||
../../../armada/schemas/armada-chartgroup-schema.yaml
|
||||
../../../../../armada/schemas/armada-chartgroup-schema-v1.yaml
|
||||
:language: yaml
|
||||
:lines: 15-
|
||||
:caption: Schema for ``armada/ChartGroup/v1`` documents.
|
||||
@ -104,7 +96,7 @@ Schemas
|
||||
``metadata.name`` are validated.
|
||||
|
||||
.. literalinclude::
|
||||
../../../armada/schemas/armada-manifest-schema.yaml
|
||||
../../../../../armada/schemas/armada-manifest-schema-v1.yaml
|
||||
:language: yaml
|
||||
:lines: 15-
|
||||
:caption: Schema for ``armada/Manifest/v1`` documents.
|
||||
@ -112,8 +104,6 @@ Schemas
|
||||
This schema is used to sanity-check all ``Manifest`` documents that are passed
|
||||
to Armada.
|
||||
|
||||
.. _authoring-guidelines:
|
||||
|
||||
Authoring Guidelines
|
||||
--------------------
|
||||
|
469
doc/source/operations/documents/v2/document-authoring.rst
Normal file
469
doc/source/operations/documents/v2/document-authoring.rst
Normal file
@ -0,0 +1,469 @@
|
||||
..
|
||||
Copyright 2019 AT&T Intellectual Property.
|
||||
All 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.
|
||||
|
||||
.. _document_authoring_v2:
|
||||
|
||||
v2 Authoring
|
||||
============
|
||||
|
||||
.. DANGER::
|
||||
|
||||
EXPERIMENTAL: `v2` docs are still experimental and WILL have breaking changes
|
||||
before they are finalized.
|
||||
|
||||
armada/Manifest/v2
|
||||
------------------
|
||||
|
||||
+---------------------+--------+-------------------------+
|
||||
| keyword | type | action |
|
||||
+=====================+========+=========================+
|
||||
| ``release_prefix`` | string | appends to the |
|
||||
| | | front of all |
|
||||
| | | charts |
|
||||
| | | released |
|
||||
| | | by the |
|
||||
| | | manifest in |
|
||||
| | | order to |
|
||||
| | | manage releases |
|
||||
| | | throughout their |
|
||||
| | | lifecycle |
|
||||
+---------------------+--------+-------------------------+
|
||||
| ``chart_groups`` | array | A list of the |
|
||||
| | | ``metadata.name`` of |
|
||||
| | | each ``ChartGroup`` to |
|
||||
| | | deploy in order. |
|
||||
+---------------------+--------+-------------------------+
|
||||
|
||||
Manifest Example
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
::
|
||||
|
||||
---
|
||||
schema: armada/Manifest/v2
|
||||
metadata:
|
||||
schema: metadata/Document/v1
|
||||
name: simple-armada
|
||||
data:
|
||||
release_prefix: armada
|
||||
chart_groups:
|
||||
- chart_group
|
||||
|
||||
|
||||
armada/ChartGroup/v2
|
||||
--------------------
|
||||
|
||||
+-----------------+----------+------------------------------------------------------------------------+
|
||||
| keyword | type | action |
|
||||
+=================+==========+========================================================================+
|
||||
| description | string | description of chart set |
|
||||
+-----------------+----------+------------------------------------------------------------------------+
|
||||
| chart_group | array | A list of the ``metadata.name`` of each ``Chart`` to deploy. |
|
||||
+-----------------+----------+------------------------------------------------------------------------+
|
||||
| sequenced | bool | If ``true``, deploys each chart in sequence, else in parallel. |
|
||||
| | | Default ``false``. |
|
||||
+-----------------+----------+------------------------------------------------------------------------+
|
||||
|
||||
Chart Group Example
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
::
|
||||
|
||||
---
|
||||
schema: armada/ChartGroup/v2
|
||||
metadata:
|
||||
schema: metadata/Document/v1
|
||||
name: blog-group
|
||||
data:
|
||||
description: Deploys Simple Service
|
||||
chart_group:
|
||||
- chart1
|
||||
- chart2
|
||||
|
||||
armada/Chart/v2
|
||||
---------------
|
||||
|
||||
Chart
|
||||
^^^^^
|
||||
|
||||
+-----------------+----------+---------------------------------------------------------------------------------------+
|
||||
| keyword | type | action |
|
||||
+=================+==========+=======================================================================================+
|
||||
| release | string | name of the release (Armada will prepend with ``release-prefix`` during processing) |
|
||||
+-----------------+----------+---------------------------------------------------------------------------------------+
|
||||
| namespace | string | namespace of your chart |
|
||||
+-----------------+----------+---------------------------------------------------------------------------------------+
|
||||
| wait | object | See `Wait`_. |
|
||||
+-----------------+----------+---------------------------------------------------------------------------------------+
|
||||
| protected | object | do not delete FAILED releases when encountered from previous run (provide the |
|
||||
| | | 'continue_processing' bool to continue or halt execution (default: halt)) |
|
||||
+-----------------+----------+---------------------------------------------------------------------------------------+
|
||||
| test | object | See Test_. |
|
||||
+-----------------+----------+---------------------------------------------------------------------------------------+
|
||||
| upgrade | object | upgrade the chart managed by the armada yaml |
|
||||
+-----------------+----------+---------------------------------------------------------------------------------------+
|
||||
| delete | object | See Delete_. |
|
||||
+-----------------+----------+---------------------------------------------------------------------------------------+
|
||||
| values | object | (optional) override any default values in the charts |
|
||||
+-----------------+----------+---------------------------------------------------------------------------------------+
|
||||
| source | object | provide a path to a ``git repo``, ``local dir``, or ``tarball url`` chart |
|
||||
+-----------------+----------+---------------------------------------------------------------------------------------+
|
||||
| dependencies | object | (optional) reference any chart dependencies before install |
|
||||
+-----------------+----------+---------------------------------------------------------------------------------------+
|
||||
|
||||
Wait
|
||||
^^^^
|
||||
|
||||
+-------------+----------+--------------------------------------------------------------------+
|
||||
| keyword | type | action |
|
||||
+=============+==========+====================================================================+
|
||||
| timeout | int | time (in seconds) to wait for chart to deploy |
|
||||
+-------------+----------+--------------------------------------------------------------------+
|
||||
| resources | array | Array of `Wait Resource`_ to wait on, with ``labels`` added to each|
|
||||
| | | item. Defaults to pods and jobs (if any exist) matching ``labels``.|
|
||||
+-------------+----------+--------------------------------------------------------------------+
|
||||
| labels | object | Base mapping of labels to wait on. They are added to any labels in |
|
||||
| | | each item in the ``resources`` array. |
|
||||
+-------------+----------+--------------------------------------------------------------------+
|
||||
| native | boolean | See `Wait Native`_. |
|
||||
+-------------+----------+--------------------------------------------------------------------+
|
||||
|
||||
Wait Resource
|
||||
^^^^^^^^^^^^^
|
||||
+-------------+----------+--------------------------------------------------------------------+
|
||||
| keyword | type | action |
|
||||
+=============+==========+====================================================================+
|
||||
| type | string | k8s resource type, supports: controllers ('deployment', |
|
||||
| | | 'daemonset', 'statefulset'), 'pod', 'job' |
|
||||
+-------------+----------+--------------------------------------------------------------------+
|
||||
| labels | object | mapping of kubernetes resource labels |
|
||||
+-------------+----------+--------------------------------------------------------------------+
|
||||
| min\_ready | int | Only for controller ``type``s. Amount of pods in a controller |
|
||||
| | string | which must be ready. Can be integer or percent string e.g. ``80%``.|
|
||||
| | | Default ``100%``. |
|
||||
+-------------+----------+--------------------------------------------------------------------+
|
||||
|
||||
Wait Native
|
||||
^^^^^^^^^^^
|
||||
|
||||
Config for the native ``helm (install|upgrade) --wait`` flag.
|
||||
|
||||
+-------------+----------+--------------------------------------------------------------------+
|
||||
| keyword | type | action |
|
||||
+=============+==========+====================================================================+
|
||||
| enabled | boolean | defaults to true |
|
||||
+-------------+----------+--------------------------------------------------------------------+
|
||||
|
||||
.. _test_v2:
|
||||
|
||||
Test
|
||||
^^^^
|
||||
|
||||
Run helm tests on the chart after install/upgrade.
|
||||
|
||||
+-------------+----------+--------------------------------------------------------------------+
|
||||
| keyword | type | action |
|
||||
+=============+==========+====================================================================+
|
||||
| enabled | bool | whether to enable/disable helm tests for this chart (default True) |
|
||||
+-------------+----------+--------------------------------------------------------------------+
|
||||
| timeout | int | time (in sec) to wait for completion of Helm tests |
|
||||
+-------------+----------+--------------------------------------------------------------------+
|
||||
| options | object | See `Test Options`_. |
|
||||
+-------------+----------+--------------------------------------------------------------------+
|
||||
|
||||
.. note::
|
||||
|
||||
Armada will attempt to run helm tests by default. They may be disabled by
|
||||
setting the ``enabled`` key to ``False``.
|
||||
|
||||
Test Options
|
||||
^^^^^^^^^^^^
|
||||
|
||||
Test options to pass through directly to helm.
|
||||
|
||||
+-------------+----------+---------------------------------------------------------------+
|
||||
| keyword | type | action |
|
||||
+=============+==========+===============================================================+
|
||||
| cleanup | bool | cleanup test pods after test completion, defaults to false |
|
||||
+-------------+----------+---------------------------------------------------------------+
|
||||
|
||||
.. note::
|
||||
|
||||
If cleanup is ``true`` this prevents being able to debug a test in the event of failure.
|
||||
|
||||
Historically, the preferred way to achieve test cleanup has been to add a pre-upgrade delete
|
||||
action on the test pod.
|
||||
|
||||
This still works, however it is usually no longer necessary as Armada now automatically
|
||||
cleans up any test pods which match the ``wait.labels`` of the chart, immediately before
|
||||
running tests. Similar suggestions have been made for how ``helm test --cleanup`` itself
|
||||
ought to work (https://github.com/helm/helm/issues/3279).
|
||||
|
||||
Upgrade - Pre
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
+-------------+----------+---------------------------------------------------------------+
|
||||
| keyword | type | action |
|
||||
+=============+==========+===============================================================+
|
||||
| pre | object | actions performed prior to updating a release |
|
||||
+-------------+----------+---------------------------------------------------------------+
|
||||
|
||||
Upgrade - Actions
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
+-------------+----------+---------------------------------------------------------------+
|
||||
| keyword | type | action |
|
||||
+=============+==========+===============================================================+
|
||||
| delete | array | List of `Upgrade - Actions - Delete`_. |
|
||||
+-------------+----------+---------------------------------------------------------------+
|
||||
|
||||
Upgrade - Actions - Delete
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
+-------------+----------+---------------------------------------------------------------+
|
||||
| keyword | type | action |
|
||||
+=============+==========+===============================================================+
|
||||
| type | string | type of kubernetes resource to delete |
|
||||
| | | supported types are: 'pod', 'job', 'cronjob'. |
|
||||
+-------------+----------+---------------------------------------------------------------+
|
||||
| labels | object | k:v mapping of labels to select Kubernetes resources |
|
||||
+-------------+----------+---------------------------------------------------------------+
|
||||
|
||||
Chart Example
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
::
|
||||
|
||||
---
|
||||
schema: armada/Chart/v2
|
||||
metadata:
|
||||
schema: metadata/Document/v1
|
||||
name: blog-1
|
||||
data:
|
||||
release: blog-1
|
||||
namespace: default
|
||||
wait:
|
||||
timeout: 100
|
||||
protected:
|
||||
continue_processing: false
|
||||
test:
|
||||
enabled: true
|
||||
upgrade:
|
||||
pre:
|
||||
delete:
|
||||
- name: test-job
|
||||
type: job
|
||||
labels:
|
||||
foo: bar
|
||||
component: bar
|
||||
rak1: enabled
|
||||
source:
|
||||
type: git
|
||||
location: https://github.com/namespace/repo
|
||||
reference: master
|
||||
|
||||
Delete
|
||||
^^^^^^
|
||||
|
||||
+-------------+----------+-----------------------------------------------------------------------------------+
|
||||
| keyword | type | action |
|
||||
+=============+==========+===================================================================================+
|
||||
| timeout | integer | time (in seconds) to wait for chart to be deleted |
|
||||
+-------------+----------+-----------------------------------------------------------------------------------+
|
||||
|
||||
Source
|
||||
^^^^^^
|
||||
|
||||
+-------------+----------+-----------------------------------------------------------------------------------+
|
||||
| keyword | type | action |
|
||||
+=============+==========+===================================================================================+
|
||||
| type | string | source to build the chart: ``git``, ``local``, or ``tar`` |
|
||||
+-------------+----------+-----------------------------------------------------------------------------------+
|
||||
| location | string | ``url`` or ``path`` to the chart's parent directory |
|
||||
+-------------+----------+-----------------------------------------------------------------------------------+
|
||||
| subpath | string | (optional) relative path to target chart from parent (``.`` if not specified) |
|
||||
+-------------+----------+-----------------------------------------------------------------------------------+
|
||||
| reference | string | (optional) branch, commit, or reference in the repo (``master`` if not specified) |
|
||||
+-------------+----------+-----------------------------------------------------------------------------------+
|
||||
|
||||
Source Example
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
::
|
||||
|
||||
# type git
|
||||
---
|
||||
schema: armada/Chart/v2
|
||||
metadata:
|
||||
schema: metadata/Document/v1
|
||||
name: blog-1
|
||||
data:
|
||||
release: blog-1
|
||||
namespace: default
|
||||
wait:
|
||||
timeout: 100
|
||||
labels:
|
||||
component: blog
|
||||
source:
|
||||
type: git
|
||||
location: https://github.com/namespace/repo
|
||||
|
||||
# type local
|
||||
---
|
||||
schema: armada/Chart/v2
|
||||
metadata:
|
||||
schema: metadata/Document/v1
|
||||
name: blog-1
|
||||
data:
|
||||
release: blog-1
|
||||
namespace: default
|
||||
wait:
|
||||
timeout: 100
|
||||
source:
|
||||
type: local
|
||||
location: /path/to/charts
|
||||
subpath: chart
|
||||
reference: master
|
||||
|
||||
# type tar
|
||||
---
|
||||
schema: armada/Chart/v2
|
||||
metadata:
|
||||
schema: metadata/Document/v1
|
||||
name: blog-1
|
||||
data:
|
||||
release: blog-1
|
||||
namespace: default
|
||||
wait:
|
||||
timeout: 100
|
||||
source:
|
||||
type: tar
|
||||
location: https://localhost:8879/charts/chart-0.1.0.tgz
|
||||
subpath: mariadb
|
||||
|
||||
Simple Example
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
::
|
||||
|
||||
---
|
||||
schema: armada/Chart/v2
|
||||
metadata:
|
||||
schema: metadata/Document/v1
|
||||
name: blog-1
|
||||
data:
|
||||
release: blog-1
|
||||
namespace: default
|
||||
source:
|
||||
type: git
|
||||
location: https://github.com/namespace/repo
|
||||
subpath: blog-1
|
||||
reference: new-feat
|
||||
---
|
||||
schema: armada/ChartGroup/v2
|
||||
metadata:
|
||||
schema: metadata/Document/v1
|
||||
name: blog-group
|
||||
data:
|
||||
description: Deploys Simple Service
|
||||
chart_group:
|
||||
- blog-1
|
||||
---
|
||||
schema: armada/Manifest/v2
|
||||
metadata:
|
||||
schema: metadata/Document/v1
|
||||
name: simple-armada
|
||||
data:
|
||||
release_prefix: armada
|
||||
chart_groups:
|
||||
- blog-group
|
||||
|
||||
Multichart Example
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
::
|
||||
|
||||
---
|
||||
schema: armada/Chart/v2
|
||||
metadata:
|
||||
schema: metadata/Document/v1
|
||||
name: blog-1
|
||||
data:
|
||||
release: blog-1
|
||||
namespace: default
|
||||
source:
|
||||
type: git
|
||||
location: https://github.com/namespace/repo
|
||||
subpath: blog1
|
||||
reference: master
|
||||
---
|
||||
schema: armada/Chart/v2
|
||||
metadata:
|
||||
schema: metadata/Document/v1
|
||||
name: blog-2
|
||||
data:
|
||||
release: blog-2
|
||||
namespace: default
|
||||
source:
|
||||
type: tar
|
||||
location: https://github.com/namespace/repo/blog2.tgz
|
||||
subpath: blog2
|
||||
---
|
||||
schema: armada/Chart/v2
|
||||
metadata:
|
||||
schema: metadata/Document/v1
|
||||
name: blog-3
|
||||
data:
|
||||
release: blog-3
|
||||
namespace: default
|
||||
source:
|
||||
type: local
|
||||
location: /home/user/namespace/repo/blog3
|
||||
---
|
||||
schema: armada/ChartGroup/v2
|
||||
metadata:
|
||||
schema: metadata/Document/v1
|
||||
name: blog-group-1
|
||||
data:
|
||||
description: Deploys Simple Service
|
||||
chart_group:
|
||||
- blog-2
|
||||
---
|
||||
schema: armada/ChartGroup/v2
|
||||
metadata:
|
||||
schema: metadata/Document/v1
|
||||
name: blog-group-2
|
||||
data:
|
||||
description: Deploys Simple Service
|
||||
chart_group:
|
||||
- blog-1
|
||||
- blog-3
|
||||
---
|
||||
schema: armada/Manifest/v2
|
||||
metadata:
|
||||
schema: metadata/Document/v1
|
||||
name: simple-armada
|
||||
data:
|
||||
release_prefix: armada
|
||||
chart_groups:
|
||||
- blog-group-1
|
||||
- blog-group-2
|
||||
|
||||
References
|
||||
~~~~~~~~~~
|
||||
|
||||
For working examples please check the examples in our repo
|
||||
`here <https://github.com/openstack/airship-armada/tree/master/examples>`__
|
25
doc/source/operations/documents/v2/index.rst
Normal file
25
doc/source/operations/documents/v2/index.rst
Normal file
@ -0,0 +1,25 @@
|
||||
..
|
||||
Copyright 2019 AT&T Intellectual Property.
|
||||
All 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.
|
||||
|
||||
v2 (EXPERIMENTAL!)
|
||||
==================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:caption: Contents:
|
||||
|
||||
document-authoring
|
||||
schemas
|
114
doc/source/operations/documents/v2/schemas.rst
Normal file
114
doc/source/operations/documents/v2/schemas.rst
Normal file
@ -0,0 +1,114 @@
|
||||
..
|
||||
Copyright 2018 AT&T Intellectual Property.
|
||||
All 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.
|
||||
|
||||
v2 Schemas
|
||||
==========
|
||||
|
||||
Below are the schemas Armada uses to validate Charts, Chart Groups, and
|
||||
Manifests.
|
||||
|
||||
Charts
|
||||
------
|
||||
|
||||
Charts consist of the smallest building blocks in Armada. A ``Chart`` is
|
||||
comparable to a Helm chart. Charts consist of all the labels, dependencies,
|
||||
install and upgrade information, hooks and additional information needed to
|
||||
convey to Tiller.
|
||||
|
||||
Chart Groups
|
||||
------------
|
||||
|
||||
A ``Chart Group`` consists of a list of charts. ``Chart Group`` documents are
|
||||
useful for managing a group of ``Chart`` documents together.
|
||||
|
||||
Manifests
|
||||
---------
|
||||
|
||||
A ``Manifest`` is the largest building block in Armada. ``Manifest`` documents
|
||||
are responsible for managing collections of ``Chart Group`` documents.
|
||||
|
||||
Validation Schemas
|
||||
------------------
|
||||
|
||||
Introduction
|
||||
^^^^^^^^^^^^
|
||||
|
||||
All schemas below are `Deckhand DataSchema`_ documents, which are essentially
|
||||
JSON schemas, with additional metadata useful for Deckhand to perform
|
||||
`layering`_ and `substitution`_.
|
||||
|
||||
The validation schemas below are used by Armada to validate all ingested
|
||||
Charts, Chart Groups, and Manifests. Use the schemas below as models for
|
||||
authoring Armada documents.
|
||||
|
||||
.. _Deckhand DataSchema: https://airship-deckhand.readthedocs.io/en/latest/document-types.html?highlight=dataschema#dataschema
|
||||
.. _Helm charts: https://docs.helm.sh/developing_charts/
|
||||
.. _layering: https://airship-deckhand.readthedocs.io/en/latest/layering.html
|
||||
.. _substitution: https://airship-deckhand.readthedocs.io/en/latest/substitution.html
|
||||
|
||||
Schemas
|
||||
^^^^^^^
|
||||
|
||||
* ``Chart`` schema.
|
||||
|
||||
JSON schema against which all documents with ``armada/Chart/v2``
|
||||
``metadata.name`` are validated.
|
||||
|
||||
.. literalinclude::
|
||||
../../../../../armada/schemas/armada-chart-schema-v2.yaml
|
||||
:language: yaml
|
||||
:lines: 15-
|
||||
:caption: Schema for ``armada/Chart/v2`` documents.
|
||||
|
||||
This schema is used to sanity-check all ``Chart`` documents that are passed
|
||||
to Armada.
|
||||
|
||||
* ``Chart Group`` schema.
|
||||
|
||||
JSON schema against which all documents with ``armada/Chart/v2``
|
||||
``metadata.name`` are validated.
|
||||
|
||||
.. literalinclude::
|
||||
../../../../../armada/schemas/armada-chartgroup-schema-v2.yaml
|
||||
:language: yaml
|
||||
:lines: 15-
|
||||
:caption: Schema for ``armada/ChartGroup/v2`` documents.
|
||||
|
||||
This schema is used to sanity-check all ``Chart Group`` documents that are
|
||||
passed to Armada.
|
||||
|
||||
* ``Manifest`` schema.
|
||||
|
||||
JSON schema against which all documents with ``armada/Manifest/v2``
|
||||
``metadata.name`` are validated.
|
||||
|
||||
.. literalinclude::
|
||||
../../../../../armada/schemas/armada-manifest-schema-v2.yaml
|
||||
:language: yaml
|
||||
:lines: 15-
|
||||
:caption: Schema for ``armada/Manifest/v2`` documents.
|
||||
|
||||
This schema is used to sanity-check all ``Manifest`` documents that are passed
|
||||
to Armada.
|
||||
|
||||
Authoring Guidelines
|
||||
--------------------
|
||||
|
||||
All Armada documents must use the ``deckhand/DataSchema/v1`` schema.
|
||||
|
||||
.. todo::
|
||||
|
||||
Expand on this section.
|
@ -10,7 +10,9 @@ Kubernetes Cluster
|
||||
|
||||
`Tiller Service <https://github.com/kubernetes/helm>`_
|
||||
|
||||
`Armada.yaml <https://airship-armada.readthedocs.io/en/latest/operations/guide-build-armada-yaml.html>`_
|
||||
.. todo:: point this to v2 docs once they're stable
|
||||
|
||||
:ref:`Armada documents <document_authoring_v1>`
|
||||
|
||||
.. note::
|
||||
|
||||
|
@ -10,11 +10,10 @@ Operations Guide
|
||||
:maxdepth: 2
|
||||
:caption: Contents:
|
||||
|
||||
guide-build-armada-yaml
|
||||
documents/index
|
||||
guide-configure
|
||||
guide-troubleshooting
|
||||
guide-use-armada
|
||||
documents
|
||||
exceptions/index
|
||||
guide-helm-plugin
|
||||
sampleconf
|
||||
|
Loading…
x
Reference in New Issue
Block a user