Adding dsl version validation
* service version validation added. It will be executed before deployment and as part of validate command for service definitions. * dsl_version field now is required field * initial dsl_version = "0.1.0" added * doc describing dsl versioning added Depends-On: I0abe9781300c794d690b0822fc2a857db3ca8ea5 Depends-On: Ib755efe784a1c4bc04fb49827baa268513dd27e1 Depends-On: I62520035507ca7c5ac97a0e34062fa9eac26e2f6 Depends-On: I9afb7143dc876b839297c5bf5c03b156e0daa8c2 Depends-On: I5a05d2538a3315ce2e652219a6cd5aead9c7d617 Depends-On: I4a0c00b40b2af4f213daf7e43419dd46951fc4bc Depends-On: Id988118f78fcdfe0599abe27959590f56f3617d3 Depends-On: I965814b147179435ef2cf94abc362df866495f8f Depends-On: Ic9e4e79e848ab944e5910b57cc5cd524f1f97ae0 Depends-On: Ic8d9c334ac57a13066db38562423523bd23b671f Depends-On: I581b587d36e03d60c5fb04e7dbf0c184c992b526 Depends-On: I4d4b9f363138b85198222ac2e770930ce7bd6ab5 Depends-On: I1728ee34eef02668cb54b1f54291a66d609dd6c4 Depends-On: I4d4b9f363138b85198222ac2e770930ce7bd6ab5 Change-Id: I220d99e76220c124d782c97de51112869c727148
This commit is contained in:
parent
194cf8664b
commit
2ffb9d57d0
|
@ -234,3 +234,35 @@ Application definition language
|
|||
|
||||
Please refer to :doc:`dsl` for detailed description of CCP DSL syntax.
|
||||
|
||||
DSL versioning
|
||||
==============
|
||||
|
||||
Some changes in CCP framework are backward compatible and some of them are not.
|
||||
To prevent situations when service definitions are being processed by
|
||||
incompatible version of CCP framework, DSL versioning has been implemented.
|
||||
|
||||
DSL versioning is based on Semantic Versioning model. Version has a format
|
||||
``MAJOR.MINOR.PATCH`` and is being defined in ``dsl_version`` field of
|
||||
:file:`fuel-ccp/__init__.py` module. Each service definition contains
|
||||
``dsl_version`` field with the version of DSL it was implemented/updated for.
|
||||
|
||||
During the validation phase of :command:`ccp deploy` those versions will be
|
||||
compared according to the following rules:
|
||||
|
||||
#. if DSL version of ``fuel-ccp`` is less than service's DSL version -
|
||||
they are incompatible - error will be printed, deployment will be
|
||||
aborted;
|
||||
#. if ``MAJOR`` parts of these versions are different - they are incompatible
|
||||
- error will be printed, deployment will be aborted;
|
||||
#. otherwise they are compatible and deployment can be continued.
|
||||
|
||||
For ``dsl_version`` in ``fuel-ccp`` repository you should increment:
|
||||
|
||||
#. MAJOR version when you make incompatible changes in DSL;
|
||||
#. MINOR version when you make backward-compatible changes in DSL;
|
||||
#. PATCH version when you make fixes that do not change DSL, but affect
|
||||
processing flow.
|
||||
|
||||
If you made a change in service definition that is not supposed to work with
|
||||
the current ```dsl_version```, you should bump it to the minimal appropriate
|
||||
number.
|
||||
|
|
|
@ -17,3 +17,4 @@ import pbr.version
|
|||
|
||||
version_info = pbr.version.VersionInfo("fuel_ccp")
|
||||
__version__ = version_info.version_string()
|
||||
dsl_version = "0.1.0"
|
||||
|
|
|
@ -84,6 +84,8 @@ class Deploy(BaseCommand):
|
|||
|
||||
validation_service.validate_service_definitions(
|
||||
components_map, components)
|
||||
validation_service.validate_service_versions(
|
||||
components_map, components)
|
||||
deploy.deploy_components(components_map, components)
|
||||
|
||||
|
||||
|
@ -257,9 +259,11 @@ class CCPApp(app.App):
|
|||
'%(asctime)s %(levelname)-8s %(name)-15s %(message)s'
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
ccp_version = "%s, dsl version %s" % (fuel_ccp.__version__,
|
||||
fuel_ccp.dsl_version)
|
||||
super(CCPApp, self).__init__(
|
||||
description='Containerized Control Plane tool',
|
||||
version=fuel_ccp.__version__,
|
||||
version=ccp_version,
|
||||
command_manager=commandmanager.CommandManager('ccp.cli'),
|
||||
deferred_help=True,
|
||||
**kwargs
|
||||
|
|
|
@ -131,6 +131,8 @@ class TestDeploy(TestParser):
|
|||
self.useFixture(fixtures.MockPatch(
|
||||
'fuel_ccp.common.utils.get_deploy_components_info',
|
||||
return_value={}))
|
||||
self.useFixture(fixtures.MockPatch(
|
||||
'fuel_ccp.validation.service.validate_service_versions'))
|
||||
self.argv += self.add_argv
|
||||
self._run_app()
|
||||
if self.components is None:
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
import fixtures
|
||||
import mock
|
||||
import testscenarios
|
||||
|
||||
from fuel_ccp.tests import base
|
||||
from fuel_ccp.validation import base as base_validation
|
||||
from fuel_ccp.validation import deploy as deploy_validation
|
||||
from fuel_ccp.validation import service as service_validation
|
||||
|
||||
|
||||
COMPONENTS_MAP = {
|
||||
|
@ -80,3 +83,36 @@ class TestDeployValidation(base.TestCase):
|
|||
'deployment: service2',
|
||||
deploy_validation.validate_requested_components,
|
||||
{'service1'}, COMPONENTS_MAP)
|
||||
|
||||
|
||||
class TestServiceValidation(testscenarios.WithScenarios, base.TestCase):
|
||||
scenarios = (
|
||||
('incompatible', {'version': '0.3.0', 'raises': RuntimeError}),
|
||||
('incompatible_major', {'version': '1.0.0', 'raises': RuntimeError}),
|
||||
('compatible', {'version': '0.1.0'}),
|
||||
('larget_but_compatible', {'version': '0.1.0'})
|
||||
)
|
||||
raises = None
|
||||
|
||||
def setUp(self):
|
||||
super(TestServiceValidation, self).setUp()
|
||||
self.useFixture(fixtures.MockPatch("fuel_ccp.dsl_version",
|
||||
"0.2.0"))
|
||||
|
||||
def test_validation(self):
|
||||
components_map = {
|
||||
"test": {
|
||||
"service_content": {
|
||||
"dsl_version": self.version
|
||||
}
|
||||
}
|
||||
}
|
||||
if self.raises:
|
||||
self.assertRaises(
|
||||
self.raises, service_validation.validate_service_versions,
|
||||
components_map, ['test']
|
||||
)
|
||||
else:
|
||||
service_validation.validate_service_versions(
|
||||
components_map, ['test']
|
||||
)
|
||||
|
|
|
@ -13,6 +13,8 @@ def validate(components, types):
|
|||
component_map = utils.get_deploy_components_info()
|
||||
service_validation.validate_service_definitions(component_map,
|
||||
components)
|
||||
service_validation.validate_service_versions(component_map,
|
||||
components)
|
||||
elif validation_type == "dockerfiles":
|
||||
dockerfiles.validate()
|
||||
else:
|
||||
|
|
|
@ -2,6 +2,7 @@ import copy
|
|||
from distutils import version
|
||||
import logging
|
||||
|
||||
import fuel_ccp
|
||||
from fuel_ccp.validation import base as validation_base
|
||||
import jsonschema
|
||||
|
||||
|
@ -166,7 +167,7 @@ PROBE_SCHEMA = {
|
|||
SERVICE_SCHEMA = {
|
||||
"type": "object",
|
||||
"additionalProperties": False,
|
||||
"required": ["service"],
|
||||
"required": ["dsl_version", "service"],
|
||||
|
||||
"properties": {
|
||||
"dsl_version": {
|
||||
|
@ -292,7 +293,7 @@ SERVICE_SCHEMA = {
|
|||
}
|
||||
|
||||
|
||||
def validate_service_definitions(components_map, components):
|
||||
def validate_service_definitions(components_map, components=None):
|
||||
if not components:
|
||||
components = components_map.keys()
|
||||
else:
|
||||
|
@ -316,7 +317,34 @@ def validate_service_definitions(components_map, components):
|
|||
"not passed.".format(len(not_passed_components), len(components))
|
||||
)
|
||||
else:
|
||||
LOG.info(
|
||||
"Validation of service definitions for %s components passed "
|
||||
"successfully!", len(components)
|
||||
)
|
||||
LOG.info("Service definitions validation passed successfully")
|
||||
|
||||
|
||||
def validate_service_versions(components_map, components=None):
|
||||
if not components:
|
||||
components = components_map.keys()
|
||||
incompatible_services = []
|
||||
parser_version = version.StrictVersion(fuel_ccp.dsl_version)
|
||||
for component in components:
|
||||
service_version = version.StrictVersion(
|
||||
components_map[component]['service_content']['dsl_version'])
|
||||
if service_version > parser_version:
|
||||
LOG.error('%s: Service version validation failed: service version '
|
||||
'(%s) greater than parser version (%s)',
|
||||
component, str(service_version), str(parser_version))
|
||||
incompatible_services.append(component)
|
||||
continue
|
||||
|
||||
service_major_version = service_version.version[0]
|
||||
parser_major_version = parser_version.version[0]
|
||||
if service_major_version != parser_major_version:
|
||||
LOG.error("%s: Service version validation failed: major versions "
|
||||
"of service (%s) and parser (%s) are not equal",
|
||||
component, str(service_version), str(parser_version))
|
||||
incompatible_services.append(component)
|
||||
|
||||
if incompatible_services:
|
||||
raise RuntimeError('The following services have incompatible versions:'
|
||||
' %s' % ', '.join(incompatible_services))
|
||||
else:
|
||||
LOG.info('Service versions validation passed successfully')
|
||||
|
|
Loading…
Reference in New Issue