Merge "Use jsonschema to validate efficacy indicators"

This commit is contained in:
Zuul 2018-07-26 12:06:57 +00:00 committed by Gerrit Code Review
commit 595cd1d435
5 changed files with 75 additions and 43 deletions

View File

@ -126,7 +126,7 @@ class BaseAction(loadable.Loadable):
:returns: A schema declaring the input parameters this action should be
provided along with their respective constraints
:rtype: :py:class:`voluptuous.Schema` instance
:rtype: :py:class:`jsonschema.Schema` instance
"""
raise NotImplementedError()

View File

@ -24,10 +24,10 @@ calculating its :ref:`global efficacy <efficacy_definition>`.
"""
import abc
import jsonschema
from oslo_serialization import jsonutils
import six
import voluptuous
@six.add_metaclass(abc.ABCMeta)
@ -65,17 +65,21 @@ class EfficacySpecification(object):
@property
def schema(self):
"""Combined schema from the schema of the indicators"""
schema = voluptuous.Schema({}, required=True)
schema = {
"type": "object",
"properties": {},
"required": []
}
for indicator in self.indicators_specs:
key_constraint = (voluptuous.Required
if indicator.required else voluptuous.Optional)
schema = schema.extend(
{key_constraint(indicator.name): indicator.schema.schema})
schema["properties"][indicator.name] = indicator.schema
schema["required"].append(indicator.name)
return schema
def validate_efficacy_indicators(self, indicators_map):
return self.schema(indicators_map)
if indicators_map:
jsonschema.validate(indicators_map, self.schema)
else:
True
def get_indicators_specs_dicts(self):
return [indicator.to_dict()

View File

@ -15,10 +15,13 @@
# limitations under the License.
import abc
import jsonschema
from jsonschema import SchemaError
from jsonschema import ValidationError
import six
from oslo_log import log
import voluptuous
from oslo_serialization import jsonutils
from watcher._i18n import _
from watcher.common import exception
@ -37,10 +40,9 @@ class IndicatorSpecification(object):
@abc.abstractproperty
def schema(self):
"""Schema used to validate the indicator value
"""JsonSchema used to validate the indicator value
:return: A Voplutuous Schema
:rtype: :py:class:`.voluptuous.Schema` instance
:return: A Schema
"""
raise NotImplementedError()
@ -54,7 +56,10 @@ class IndicatorSpecification(object):
value = None
try:
value = getattr(solution, indicator.name)
indicator.schema(value)
jsonschema.validate(value, cls.schema)
except (SchemaError, ValidationError) as exc:
LOG.exception(exc)
raise exc
except Exception as exc:
LOG.exception(exc)
raise exception.InvalidIndicatorValue(
@ -65,7 +70,7 @@ class IndicatorSpecification(object):
"name": self.name,
"description": self.description,
"unit": self.unit,
"schema": str(self.schema.schema) if self.schema else None,
"schema": jsonutils.dumps(self.schema) if self.schema else None,
}
def __str__(self):
@ -82,8 +87,10 @@ class ComputeNodesCount(IndicatorSpecification):
@property
def schema(self):
return voluptuous.Schema(
voluptuous.Range(min=0), required=True)
return {
"type": "integer",
"minimum": 0
}
class ReleasedComputeNodesCount(IndicatorSpecification):
@ -96,8 +103,10 @@ class ReleasedComputeNodesCount(IndicatorSpecification):
@property
def schema(self):
return voluptuous.Schema(
voluptuous.Range(min=0), required=True)
return {
"type": "integer",
"minimum": 0
}
class InstanceMigrationsCount(IndicatorSpecification):
@ -110,8 +119,10 @@ class InstanceMigrationsCount(IndicatorSpecification):
@property
def schema(self):
return voluptuous.Schema(
voluptuous.Range(min=0), required=True)
return {
"type": "integer",
"minimum": 0
}
class LiveInstanceMigrateCount(IndicatorSpecification):
@ -124,8 +135,10 @@ class LiveInstanceMigrateCount(IndicatorSpecification):
@property
def schema(self):
return voluptuous.Schema(
voluptuous.Range(min=0), required=True)
return {
"type": "integer",
"minimum": 0
}
class PlannedLiveInstanceMigrateCount(IndicatorSpecification):
@ -138,8 +151,10 @@ class PlannedLiveInstanceMigrateCount(IndicatorSpecification):
@property
def schema(self):
return voluptuous.Schema(
voluptuous.Range(min=0), required=True)
return {
"type": "integer",
"minimum": 0
}
class ColdInstanceMigrateCount(IndicatorSpecification):
@ -152,8 +167,10 @@ class ColdInstanceMigrateCount(IndicatorSpecification):
@property
def schema(self):
return voluptuous.Schema(
voluptuous.Range(min=0), required=True)
return {
"type": "integer",
"minimum": 0
}
class PlannedColdInstanceMigrateCount(IndicatorSpecification):
@ -166,8 +183,10 @@ class PlannedColdInstanceMigrateCount(IndicatorSpecification):
@property
def schema(self):
return voluptuous.Schema(
voluptuous.Range(min=0), required=True)
return {
"type": "integer",
"minimum": 0
}
class VolumeMigrateCount(IndicatorSpecification):
@ -180,8 +199,10 @@ class VolumeMigrateCount(IndicatorSpecification):
@property
def schema(self):
return voluptuous.Schema(
voluptuous.Range(min=0), required=True)
return {
"type": "integer",
"minimum": 0
}
class PlannedVolumeMigrateCount(IndicatorSpecification):
@ -195,8 +216,10 @@ class PlannedVolumeMigrateCount(IndicatorSpecification):
@property
def schema(self):
return voluptuous.Schema(
voluptuous.Range(min=0), required=True)
return {
"type": "integer",
"minimum": 0
}
class VolumeUpdateCount(IndicatorSpecification):
@ -210,8 +233,10 @@ class VolumeUpdateCount(IndicatorSpecification):
@property
def schema(self):
return voluptuous.Schema(
voluptuous.Range(min=0), required=True)
return {
"type": "integer",
"minimum": 0
}
class PlannedVolumeUpdateCount(IndicatorSpecification):
@ -225,5 +250,7 @@ class PlannedVolumeUpdateCount(IndicatorSpecification):
@property
def schema(self):
return voluptuous.Schema(
voluptuous.Range(min=0), required=True)
return {
"type": "integer",
"minimum": 0
}

View File

@ -14,8 +14,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import voluptuous
from watcher.decision_engine.goal import base as base_goal
from watcher.decision_engine.goal.efficacy import base as efficacy_base
from watcher.decision_engine.goal.efficacy import indicators
@ -55,8 +53,10 @@ class DummyIndicator(indicators.IndicatorSpecification):
@property
def schema(self):
return voluptuous.Schema(
voluptuous.Range(min=0, max=100), required=True)
return {
"type": "integer",
"minimum": 0
}
class DummySpec1(efficacy_base.EfficacySpecification):

View File

@ -16,6 +16,8 @@
import mock
from oslo_serialization import jsonutils
from watcher.common import context
from watcher.common import utils
from watcher.decision_engine.loading import default
@ -451,8 +453,7 @@ class TestSyncer(base.DbTestCase):
dummy_1_spec = [
{'description': 'Dummy indicator', 'name': 'dummy',
'schema': 'Range(min=0, max=100, min_included=True, '
'max_included=True, msg=None)',
'schema': jsonutils.dumps({'minimum': 0, 'type': 'integer'}),
'unit': '%'}]
dummy_2_spec = []
self.assertEqual(