Merge "Replace voluptuous with JSONSchema to validate migration action"

This commit is contained in:
Jenkins 2017-06-15 06:21:05 +00:00 committed by Gerrit Code Review
commit 986ba9872f
3 changed files with 49 additions and 53 deletions

View File

@ -6,6 +6,7 @@ apscheduler # MIT License
enum34;python_version=='2.7' or python_version=='2.6' or python_version=='3.3' # BSD enum34;python_version=='2.7' or python_version=='2.6' or python_version=='3.3' # BSD
jsonpatch>=1.1 # BSD jsonpatch>=1.1 # BSD
keystoneauth1>=2.21.0 # Apache-2.0 keystoneauth1>=2.21.0 # Apache-2.0
jsonschema!=2.5.0,<3.0.0,>=2.0.0 # MIT
keystonemiddleware>=4.12.0 # Apache-2.0 keystonemiddleware>=4.12.0 # Apache-2.0
lxml!=3.7.0,>=2.3 # BSD lxml!=3.7.0,>=2.3 # BSD
oslo.concurrency>=3.8.0 # Apache-2.0 oslo.concurrency>=3.8.0 # Apache-2.0

View File

@ -17,15 +17,13 @@
# limitations under the License. # limitations under the License.
# #
from oslo_log import log
import six
import voluptuous
import jsonschema
from oslo_log import log
from watcher._i18n import _ from watcher._i18n import _
from watcher.applier.actions import base from watcher.applier.actions import base
from watcher.common import exception from watcher.common import exception
from watcher.common import nova_helper from watcher.common import nova_helper
from watcher.common import utils
LOG = log.getLogger(__name__) LOG = log.getLogger(__name__)
@ -62,28 +60,42 @@ class Migrate(base.BaseAction):
DESTINATION_NODE = 'destination_node' DESTINATION_NODE = 'destination_node'
SOURCE_NODE = 'source_node' SOURCE_NODE = 'source_node'
def check_resource_id(self, value):
if (value is not None and
len(value) > 0 and not
utils.is_uuid_like(value)):
raise voluptuous.Invalid(_("The parameter "
"resource_id is invalid."))
@property @property
def schema(self): def schema(self):
return voluptuous.Schema({ return {
voluptuous.Required(self.RESOURCE_ID): self.check_resource_id, 'type': 'object',
voluptuous.Required( 'properties': {
self.MIGRATION_TYPE, default=self.LIVE_MIGRATION): 'destination_node': {
voluptuous.Any( 'type': 'string',
*[self.LIVE_MIGRATION, self.COLD_MIGRATION]), "minLength": 1
voluptuous.Required(self.DESTINATION_NODE): },
voluptuous.All(voluptuous.Any(*six.string_types), 'migration_type': {
voluptuous.Length(min=1)), 'type': 'string',
voluptuous.Required(self.SOURCE_NODE): "enum": ["live", "cold"]
voluptuous.All(voluptuous.Any(*six.string_types), },
voluptuous.Length(min=1)), 'resource_id': {
}) 'type': 'string',
"minlength": 1,
"pattern": ("^([a-fA-F0-9]){8}-([a-fA-F0-9]){4}-"
"([a-fA-F0-9]){4}-([a-fA-F0-9]){4}-"
"([a-fA-F0-9]){12}$")
},
'source_node': {
'type': 'string',
"minLength": 1
}
},
'required': ['destination_node', 'migration_type',
'resource_id', 'source_node'],
'additionalProperties': False,
}
def validate_parameters(self):
try:
jsonschema.validate(self.input_parameters, self.schema)
return True
except jsonschema.ValidationError as e:
raise e
@property @property
def instance_uuid(self): def instance_uuid(self):
@ -137,7 +149,6 @@ class Migrate(base.BaseAction):
LOG.critical("Unexpected error occurred. Migration failed for " LOG.critical("Unexpected error occurred. Migration failed for "
"instance %s. Leaving instance on previous " "instance %s. Leaving instance on previous "
"host.", self.instance_uuid) "host.", self.instance_uuid)
return result return result
def migrate(self, destination): def migrate(self, destination):

View File

@ -15,8 +15,9 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import jsonschema
import mock import mock
import voluptuous
from watcher.applier.actions import base as baction from watcher.applier.actions import base as baction
from watcher.applier.actions import migration from watcher.applier.actions import migration
@ -93,13 +94,8 @@ class TestMigration(base.TestCase):
'source_node': None, 'source_node': None,
'destination_node': None} 'destination_node': None}
self.action.input_parameters = parameters self.action.input_parameters = parameters
exc = self.assertRaises( self.assertRaises(jsonschema.ValidationError,
voluptuous.MultipleInvalid, self.action.validate_parameters) self.action.validate_parameters)
self.assertEqual(
sorted([(['migration_type'], voluptuous.ScalarInvalid),
(['source_node'], voluptuous.TypeInvalid),
(['destination_node'], voluptuous.TypeInvalid)]),
sorted([(e.path, type(e)) for e in exc.errors]))
def test_parameters_exception_migration_type(self): def test_parameters_exception_migration_type(self):
parameters = {baction.BaseAction.RESOURCE_ID: parameters = {baction.BaseAction.RESOURCE_ID:
@ -108,11 +104,8 @@ class TestMigration(base.TestCase):
'source_node': 'compute-2', 'source_node': 'compute-2',
'destination_node': 'compute-3'} 'destination_node': 'compute-3'}
self.action.input_parameters = parameters self.action.input_parameters = parameters
exc = self.assertRaises( self.assertRaises(jsonschema.ValidationError,
voluptuous.Invalid, self.action.validate_parameters) self.action.validate_parameters)
self.assertEqual(
[(['migration_type'], voluptuous.ScalarInvalid)],
[(e.path, type(e)) for e in exc.errors])
def test_parameters_exception_source_node(self): def test_parameters_exception_source_node(self):
parameters = {baction.BaseAction.RESOURCE_ID: parameters = {baction.BaseAction.RESOURCE_ID:
@ -121,11 +114,8 @@ class TestMigration(base.TestCase):
'source_node': None, 'source_node': None,
'destination_node': 'compute-3'} 'destination_node': 'compute-3'}
self.action.input_parameters = parameters self.action.input_parameters = parameters
exc = self.assertRaises( self.assertRaises(jsonschema.ValidationError,
voluptuous.MultipleInvalid, self.action.validate_parameters) self.action.validate_parameters)
self.assertEqual(
[(['source_node'], voluptuous.TypeInvalid)],
[(e.path, type(e)) for e in exc.errors])
def test_parameters_exception_destination_node(self): def test_parameters_exception_destination_node(self):
parameters = {baction.BaseAction.RESOURCE_ID: parameters = {baction.BaseAction.RESOURCE_ID:
@ -134,11 +124,8 @@ class TestMigration(base.TestCase):
'source_node': 'compute-1', 'source_node': 'compute-1',
'destination_node': None} 'destination_node': None}
self.action.input_parameters = parameters self.action.input_parameters = parameters
exc = self.assertRaises( self.assertRaises(jsonschema.ValidationError,
voluptuous.MultipleInvalid, self.action.validate_parameters) self.action.validate_parameters)
self.assertEqual(
[(['destination_node'], voluptuous.TypeInvalid)],
[(e.path, type(e)) for e in exc.errors])
def test_parameters_exception_resource_id(self): def test_parameters_exception_resource_id(self):
parameters = {baction.BaseAction.RESOURCE_ID: "EFEF", parameters = {baction.BaseAction.RESOURCE_ID: "EFEF",
@ -146,11 +133,8 @@ class TestMigration(base.TestCase):
'source_node': 'compute-2', 'source_node': 'compute-2',
'destination_node': 'compute-3'} 'destination_node': 'compute-3'}
self.action.input_parameters = parameters self.action.input_parameters = parameters
exc = self.assertRaises( self.assertRaises(jsonschema.ValidationError,
voluptuous.MultipleInvalid, self.action.validate_parameters) self.action.validate_parameters)
self.assertEqual(
[(['resource_id'], voluptuous.Invalid)],
[(e.path, type(e)) for e in exc.errors])
def test_migration_pre_condition(self): def test_migration_pre_condition(self):
try: try: