Validation of TOSCA version
The TOSCA version is validated such that it follows the Maven version syntax. Added unittest cases for validating TOSCA version. Modified the log messages such that they support i18n standards Implemented tosca version property type in toscalib and added testcases. Closes-Bug: #1450854 Closes-Bug: #1482359 Change-Id: I2c3adecd7291b7bd3b7e9cc2e651e51a4c205fc5
This commit is contained in:
@@ -293,3 +293,52 @@ class ToscaTemplateInputValidationTest(TestCase):
|
||||
input_params = {'storage_size': '-2 MB'}
|
||||
expectedmsg = _('"-2 MB" is not a valid scalar-unit')
|
||||
self._translate_input_test(tpl_snippet, input_params, expectedmsg)
|
||||
|
||||
def test_invalid_input_type_version(self):
|
||||
tpl_snippet = '''
|
||||
inputs:
|
||||
version:
|
||||
type: version
|
||||
'''
|
||||
|
||||
input_params = {'version': '0.a'}
|
||||
expectedmessage = _('Value of TOSCA version property '
|
||||
'"0.a" is invalid.')
|
||||
self._translate_input_test(tpl_snippet, input_params,
|
||||
expectedmessage)
|
||||
|
||||
input_params = {'version': '0.0.0.abc'}
|
||||
expectedmessage = _('Value of TOSCA version property '
|
||||
'"0.0.0.abc" is invalid.')
|
||||
self._translate_input_test(tpl_snippet, input_params,
|
||||
expectedmessage)
|
||||
|
||||
def test_valid_input_type_version(self):
|
||||
tpl_snippet = '''
|
||||
inputs:
|
||||
version:
|
||||
type: version
|
||||
default: 12
|
||||
'''
|
||||
|
||||
expectedmessage = _('both equal.')
|
||||
input_params = {'version': '18'}
|
||||
expected_hot_params = [{'version':
|
||||
OrderedDict([('type', 'string'),
|
||||
('default', '18.0')])}]
|
||||
self._translate_input_test(tpl_snippet, input_params, expectedmessage,
|
||||
expected_hot_params)
|
||||
|
||||
input_params = {'version': '18.0'}
|
||||
expected_hot_params = [{'version':
|
||||
OrderedDict([('type', 'string'),
|
||||
('default', '18.0')])}]
|
||||
self._translate_input_test(tpl_snippet, input_params, expectedmessage,
|
||||
expected_hot_params)
|
||||
|
||||
input_params = {'version': '18.0.1'}
|
||||
expected_hot_params = [{'version':
|
||||
OrderedDict([('type', 'string'),
|
||||
('default', '18.0.1')])}]
|
||||
self._translate_input_test(tpl_snippet, input_params, expectedmessage,
|
||||
expected_hot_params)
|
||||
|
||||
@@ -11,8 +11,11 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import logging
|
||||
from translator.common.utils import MemoryUnit
|
||||
from translator.hot.syntax.hot_resource import HotResource
|
||||
from translator.toscalib.utils.validateutils import TOSCAVersionProperty
|
||||
log = logging.getLogger('tosca')
|
||||
|
||||
# A design issue to be resolved is how to translate the generic TOSCA server
|
||||
# properties to OpenStack flavors and images. At the Atlanta design summit,
|
||||
@@ -76,9 +79,6 @@ class ToscaCompute(HotResource):
|
||||
pass
|
||||
|
||||
def handle_properties(self):
|
||||
self.properties.update(self.translate_compute_flavor_and_image(
|
||||
self.nodetemplate.get_capability('host'),
|
||||
self.nodetemplate.get_capability('os')))
|
||||
self.properties = self.translate_compute_flavor_and_image(
|
||||
self.nodetemplate.get_capability('host'),
|
||||
self.nodetemplate.get_capability('os'))
|
||||
@@ -156,6 +156,7 @@ class ToscaCompute(HotResource):
|
||||
'distribution',
|
||||
distribution)
|
||||
version = properties.get('version')
|
||||
version = TOSCAVersionProperty(version).get_version()
|
||||
match_version = self._match_images(match_distribution, IMAGES,
|
||||
'version', version)
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ from translator.hot.syntax.hot_parameter import HotParameter
|
||||
from translator.toscalib.dataentity import DataEntity
|
||||
from translator.toscalib.elements.scalarunit import ScalarUnit_Size
|
||||
from translator.toscalib.utils.gettextutils import _
|
||||
from translator.toscalib.utils.validateutils import TOSCAVersionProperty
|
||||
|
||||
|
||||
INPUT_CONSTRAINTS = (CONSTRAINTS, DESCRIPTION, LENGTH, RANGE,
|
||||
@@ -49,6 +50,7 @@ TOSCA_TO_HOT_INPUT_TYPES = {'string': 'string',
|
||||
'boolean': 'boolean',
|
||||
'timestamp': 'string',
|
||||
'scalar-unit.size': 'number',
|
||||
'version': 'string',
|
||||
'null': 'string',
|
||||
'PortDef': 'number'}
|
||||
|
||||
@@ -100,6 +102,8 @@ class TranslateInputs(object):
|
||||
"to %(hot_default)s GB.")
|
||||
% {'input_value': input_value,
|
||||
'hot_default': hot_default})
|
||||
if input.type == 'version':
|
||||
hot_default = TOSCAVersionProperty(hot_default).get_version()
|
||||
|
||||
hot_constraints = []
|
||||
if input.constraints:
|
||||
|
||||
@@ -94,3 +94,7 @@ class InvalidPropertyValueError(TOSCAException):
|
||||
class InvalidTemplateVersion(TOSCAException):
|
||||
msg_fmt = _('The template version "%(what)s" is invalid. '
|
||||
'The valid versions are: "%(valid_versions)s"')
|
||||
|
||||
|
||||
class InvalidTOSCAVersionPropertyException(TOSCAException):
|
||||
msg_fmt = _('Value of TOSCA version property "%(what)s" is invalid.')
|
||||
|
||||
@@ -131,6 +131,8 @@ class DataEntity(object):
|
||||
return ScalarUnit_Frequency(value).validate_scalar_unit()
|
||||
elif type == Schema.SCALAR_UNIT_TIME:
|
||||
return ScalarUnit_Time(value).validate_scalar_unit()
|
||||
elif type == Schema.VERSION:
|
||||
return validateutils.TOSCAVersionProperty(value).get_version()
|
||||
elif type == Schema.MAP:
|
||||
validateutils.validate_map(value)
|
||||
if entry_schema:
|
||||
|
||||
@@ -542,7 +542,7 @@ tosca.capabilities.OperatingSystem:
|
||||
debian, fedora, rhel and ubuntu.
|
||||
version:
|
||||
required: false
|
||||
type: string
|
||||
type: version
|
||||
description: >
|
||||
The host Operating System version.
|
||||
|
||||
|
||||
@@ -35,12 +35,12 @@ class Schema(collections.Mapping):
|
||||
INTEGER, STRING, BOOLEAN, FLOAT,
|
||||
NUMBER, TIMESTAMP, LIST, MAP,
|
||||
SCALAR_UNIT_SIZE, SCALAR_UNIT_FREQUENCY, SCALAR_UNIT_TIME,
|
||||
PORTDEF
|
||||
PORTDEF, VERSION
|
||||
) = (
|
||||
'integer', 'string', 'boolean', 'float',
|
||||
'number', 'timestamp', 'list', 'map',
|
||||
'scalar-unit.size', 'scalar-unit.frequency', 'scalar-unit.time',
|
||||
'PortDef'
|
||||
'PortDef', 'version'
|
||||
)
|
||||
|
||||
SCALAR_UNIT_SIZE_DEFAULT = 'B'
|
||||
|
||||
139
translator/toscalib/tests/test_validate_tosca_version.py
Normal file
139
translator/toscalib/tests/test_validate_tosca_version.py
Normal file
@@ -0,0 +1,139 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from translator.toscalib.common.exception import (
|
||||
InvalidTOSCAVersionPropertyException)
|
||||
from translator.toscalib.tests.base import TestCase
|
||||
from translator.toscalib.utils.validateutils import TOSCAVersionProperty
|
||||
|
||||
|
||||
class TOSCAVersionPropertyTest(TestCase):
|
||||
|
||||
def test_tosca_version_property(self):
|
||||
version = '18.0.3.beta-1'
|
||||
expected_output = '18.0.3.beta-1'
|
||||
output = TOSCAVersionProperty(version).get_version()
|
||||
self.assertEqual(output, expected_output)
|
||||
|
||||
version = 18
|
||||
expected_output = '18.0'
|
||||
output = TOSCAVersionProperty(version).get_version()
|
||||
self.assertEqual(output, expected_output)
|
||||
|
||||
version = 18.0
|
||||
expected_output = '18.0'
|
||||
output = TOSCAVersionProperty(version).get_version()
|
||||
self.assertEqual(output, expected_output)
|
||||
|
||||
version = '18.0.3'
|
||||
expected_output = '18.0.3'
|
||||
output = TOSCAVersionProperty(version).get_version()
|
||||
self.assertEqual(output, expected_output)
|
||||
|
||||
version = 0
|
||||
expected_output = None
|
||||
output = TOSCAVersionProperty(version).get_version()
|
||||
self.assertEqual(output, expected_output)
|
||||
|
||||
version = 00
|
||||
expected_output = None
|
||||
output = TOSCAVersionProperty(version).get_version()
|
||||
self.assertEqual(output, expected_output)
|
||||
|
||||
version = 0.0
|
||||
expected_output = None
|
||||
output = TOSCAVersionProperty(version).get_version()
|
||||
self.assertEqual(output, expected_output)
|
||||
|
||||
version = 00.00
|
||||
expected_output = None
|
||||
output = TOSCAVersionProperty(version).get_version()
|
||||
self.assertEqual(output, expected_output)
|
||||
|
||||
version = '0.0.0'
|
||||
expected_output = None
|
||||
output = TOSCAVersionProperty(version).get_version()
|
||||
self.assertEqual(output, expected_output)
|
||||
|
||||
def test_tosca_version_property_invalid_major_version(self):
|
||||
|
||||
version = 'x'
|
||||
exp_msg = ('Value of TOSCA version property "x" is invalid.')
|
||||
try:
|
||||
TOSCAVersionProperty(version).get_version()
|
||||
except InvalidTOSCAVersionPropertyException as err:
|
||||
self.assertEqual(exp_msg, err.__str__())
|
||||
|
||||
def test_tosca_version_property_invalid_minor_version(self):
|
||||
|
||||
version = '18.x'
|
||||
exp_msg = ('Value of TOSCA version property "18.x" is invalid.')
|
||||
try:
|
||||
TOSCAVersionProperty(version).get_version()
|
||||
except InvalidTOSCAVersionPropertyException as err:
|
||||
self.assertEqual(exp_msg, err.__str__())
|
||||
|
||||
version = '18.x.y'
|
||||
exp_msg = ('Value of TOSCA version property "18.x.y" is invalid.')
|
||||
try:
|
||||
TOSCAVersionProperty(version).get_version()
|
||||
except InvalidTOSCAVersionPropertyException as err:
|
||||
self.assertEqual(exp_msg, err.__str__())
|
||||
|
||||
version = '18-2'
|
||||
exp_msg = ('Value of TOSCA version property "18-2" is invalid.')
|
||||
try:
|
||||
TOSCAVersionProperty(version).get_version()
|
||||
except InvalidTOSCAVersionPropertyException as err:
|
||||
self.assertEqual(exp_msg, err.__str__())
|
||||
|
||||
def test_tosca_version_property_invalid_fix_version(self):
|
||||
|
||||
version = '18.0.a'
|
||||
exp_msg = ('Value of TOSCA version property "18.0.a" is invalid.')
|
||||
try:
|
||||
TOSCAVersionProperty(version).get_version()
|
||||
except InvalidTOSCAVersionPropertyException as err:
|
||||
self.assertEqual(exp_msg, err.__str__())
|
||||
|
||||
def test_tosca_version_property_invalid_qualifier(self):
|
||||
|
||||
version = '18.0.1-xyz'
|
||||
exp_msg = ('Value of TOSCA version property "18.0.1-xyz" is invalid.')
|
||||
try:
|
||||
TOSCAVersionProperty(version).get_version()
|
||||
except InvalidTOSCAVersionPropertyException as err:
|
||||
self.assertEqual(exp_msg, err.__str__())
|
||||
|
||||
version = '0.0.0.abc'
|
||||
exp_msg = ('Value of TOSCA version property "0.0.0.abc" is invalid.')
|
||||
try:
|
||||
TOSCAVersionProperty(version).get_version()
|
||||
except InvalidTOSCAVersionPropertyException as err:
|
||||
self.assertEqual(exp_msg, err.__str__())
|
||||
|
||||
def test_tosca_version_property_invalid_build_version(self):
|
||||
|
||||
version = '18.0.1.abc-x'
|
||||
exp_msg = ('Value of TOSCA version property '
|
||||
'"18.0.1.abc-x" is invalid.')
|
||||
try:
|
||||
TOSCAVersionProperty(version).get_version()
|
||||
except InvalidTOSCAVersionPropertyException as err:
|
||||
self.assertEqual(exp_msg, err.__str__())
|
||||
|
||||
version = '0.0.0.abc-x'
|
||||
exp_msg = ('Value of TOSCA version property "0.0.0.abc-x" is invalid.')
|
||||
try:
|
||||
TOSCAVersionProperty(version).get_version()
|
||||
except InvalidTOSCAVersionPropertyException as err:
|
||||
self.assertEqual(exp_msg, err.__str__())
|
||||
@@ -12,10 +12,15 @@
|
||||
|
||||
import collections
|
||||
import dateutil.parser
|
||||
import logging
|
||||
import numbers
|
||||
import re
|
||||
import six
|
||||
|
||||
from translator.toscalib.common.exception import (
|
||||
InvalidTOSCAVersionPropertyException)
|
||||
from translator.toscalib.utils.gettextutils import _
|
||||
log = logging.getLogger('tosca')
|
||||
|
||||
|
||||
def str_to_num(value):
|
||||
@@ -78,3 +83,72 @@ def validate_boolean(value):
|
||||
|
||||
def validate_timestamp(value):
|
||||
return dateutil.parser.parse(value)
|
||||
|
||||
|
||||
class TOSCAVersionProperty(object):
|
||||
|
||||
VERSION_RE = re.compile('^(?P<major_version>([0-9][0-9]*))'
|
||||
'(\.(?P<minor_version>([0-9][0-9]*)))?'
|
||||
'(\.(?P<fix_version>([0-9][0-9]*)))?'
|
||||
'(\.(?P<qualifier>([0-9A-Za-z]+)))?'
|
||||
'(\-(?P<build_version>[0-9])*)?$')
|
||||
|
||||
def __init__(self, version):
|
||||
self.version = str(version)
|
||||
match = self.VERSION_RE.match(self.version)
|
||||
if not match:
|
||||
raise InvalidTOSCAVersionPropertyException(what=(self.version))
|
||||
ver = match.groupdict()
|
||||
if self.version in ['0', '0.0', '0.0.0']:
|
||||
log.warning(_('Version assumed as not provided'))
|
||||
self.version = None
|
||||
self.minor_version = ver['minor_version']
|
||||
self.major_version = ver['major_version']
|
||||
self.fix_version = ver['fix_version']
|
||||
self.qualifier = self._validate_qualifier(ver['qualifier'])
|
||||
self.build_version = self._validate_build(ver['build_version'])
|
||||
self._validate_major_version(self.major_version)
|
||||
|
||||
def _validate_major_version(self, value):
|
||||
"""Validate major version
|
||||
|
||||
Checks if only major version is provided and assumes
|
||||
minor version as 0.
|
||||
Eg: If version = 18, then it returns version = '18.0'
|
||||
"""
|
||||
|
||||
if self.minor_version is None and self.build_version is None and \
|
||||
value != '0':
|
||||
log.warning(_('Minor version assumed "0"'))
|
||||
self.version = '.'.join([value, '0'])
|
||||
return value
|
||||
|
||||
def _validate_qualifier(self, value):
|
||||
"""Validate qualifier
|
||||
|
||||
TOSCA version is invalid if a qualifier is present without the
|
||||
fix version or with all of major, minor and fix version 0s.
|
||||
|
||||
For example, the following versions are invalid
|
||||
18.0.abc
|
||||
0.0.0.abc
|
||||
"""
|
||||
if (self.fix_version is None and value) or \
|
||||
(self.minor_version == self.major_version ==
|
||||
self.fix_version == '0' and value):
|
||||
raise InvalidTOSCAVersionPropertyException(what=(self.version))
|
||||
return value
|
||||
|
||||
def _validate_build(self, value):
|
||||
"""Validate build version
|
||||
|
||||
TOSCA version is invalid if build version is present without the
|
||||
qualifier.
|
||||
Eg: version = 18.0.0-1 is invalid.
|
||||
"""
|
||||
if not self.qualifier and value:
|
||||
raise InvalidTOSCAVersionPropertyException(what=(self.version))
|
||||
return value
|
||||
|
||||
def get_version(self):
|
||||
return self.version
|
||||
|
||||
Reference in New Issue
Block a user