summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2017-06-15 06:21:05 +0000
committerGerrit Code Review <review@openstack.org>2017-06-15 06:21:05 +0000
commit986ba9872fd5bdc23960b253c16f8e732553fe04 (patch)
tree5b310ae4b2a01cf1b7859a7eac7a6958f40ad25a
parent44a5a1573c3fe0fb1a215f64e2b1110dee237efb (diff)
parent1451d9c13438357f38ac91a46615dea69c6c15a1 (diff)
Merge "Replace voluptuous with JSONSchema to validate migration action"
-rw-r--r--requirements.txt1
-rw-r--r--watcher/applier/actions/migration.py61
-rw-r--r--watcher/tests/applier/actions/test_migration.py40
3 files changed, 49 insertions, 53 deletions
diff --git a/requirements.txt b/requirements.txt
index 3e0d42c..0bad2cc 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -6,6 +6,7 @@ apscheduler # MIT License
6enum34;python_version=='2.7' or python_version=='2.6' or python_version=='3.3' # BSD 6enum34;python_version=='2.7' or python_version=='2.6' or python_version=='3.3' # BSD
7jsonpatch>=1.1 # BSD 7jsonpatch>=1.1 # BSD
8keystoneauth1>=2.21.0 # Apache-2.0 8keystoneauth1>=2.21.0 # Apache-2.0
9jsonschema!=2.5.0,<3.0.0,>=2.0.0 # MIT
9keystonemiddleware>=4.12.0 # Apache-2.0 10keystonemiddleware>=4.12.0 # Apache-2.0
10lxml!=3.7.0,>=2.3 # BSD 11lxml!=3.7.0,>=2.3 # BSD
11oslo.concurrency>=3.8.0 # Apache-2.0 12oslo.concurrency>=3.8.0 # Apache-2.0
diff --git a/watcher/applier/actions/migration.py b/watcher/applier/actions/migration.py
index 94ec0af..36d467d 100644
--- a/watcher/applier/actions/migration.py
+++ b/watcher/applier/actions/migration.py
@@ -17,15 +17,13 @@
17# limitations under the License. 17# limitations under the License.
18# 18#
19 19
20from oslo_log import log
21import six
22import voluptuous
23 20
21import jsonschema
22from oslo_log import log
24from watcher._i18n import _ 23from watcher._i18n import _
25from watcher.applier.actions import base 24from watcher.applier.actions import base
26from watcher.common import exception 25from watcher.common import exception
27from watcher.common import nova_helper 26from watcher.common import nova_helper
28from watcher.common import utils
29 27
30LOG = log.getLogger(__name__) 28LOG = log.getLogger(__name__)
31 29
@@ -62,28 +60,42 @@ class Migrate(base.BaseAction):
62 DESTINATION_NODE = 'destination_node' 60 DESTINATION_NODE = 'destination_node'
63 SOURCE_NODE = 'source_node' 61 SOURCE_NODE = 'source_node'
64 62
65 def check_resource_id(self, value):
66 if (value is not None and
67 len(value) > 0 and not
68 utils.is_uuid_like(value)):
69 raise voluptuous.Invalid(_("The parameter "
70 "resource_id is invalid."))
71
72 @property 63 @property
73 def schema(self): 64 def schema(self):
74 return voluptuous.Schema({ 65 return {
75 voluptuous.Required(self.RESOURCE_ID): self.check_resource_id, 66 'type': 'object',
76 voluptuous.Required( 67 'properties': {
77 self.MIGRATION_TYPE, default=self.LIVE_MIGRATION): 68 'destination_node': {
78 voluptuous.Any( 69 'type': 'string',
79 *[self.LIVE_MIGRATION, self.COLD_MIGRATION]), 70 "minLength": 1
80 voluptuous.Required(self.DESTINATION_NODE): 71 },
81 voluptuous.All(voluptuous.Any(*six.string_types), 72 'migration_type': {
82 voluptuous.Length(min=1)), 73 'type': 'string',
83 voluptuous.Required(self.SOURCE_NODE): 74 "enum": ["live", "cold"]
84 voluptuous.All(voluptuous.Any(*six.string_types), 75 },
85 voluptuous.Length(min=1)), 76 'resource_id': {
86 }) 77 'type': 'string',
78 "minlength": 1,
79 "pattern": ("^([a-fA-F0-9]){8}-([a-fA-F0-9]){4}-"
80 "([a-fA-F0-9]){4}-([a-fA-F0-9]){4}-"
81 "([a-fA-F0-9]){12}$")
82 },
83 'source_node': {
84 'type': 'string',
85 "minLength": 1
86 }
87 },
88 'required': ['destination_node', 'migration_type',
89 'resource_id', 'source_node'],
90 'additionalProperties': False,
91 }
92
93 def validate_parameters(self):
94 try:
95 jsonschema.validate(self.input_parameters, self.schema)
96 return True
97 except jsonschema.ValidationError as e:
98 raise e
87 99
88 @property 100 @property
89 def instance_uuid(self): 101 def instance_uuid(self):
@@ -137,7 +149,6 @@ class Migrate(base.BaseAction):
137 LOG.critical("Unexpected error occurred. Migration failed for " 149 LOG.critical("Unexpected error occurred. Migration failed for "
138 "instance %s. Leaving instance on previous " 150 "instance %s. Leaving instance on previous "
139 "host.", self.instance_uuid) 151 "host.", self.instance_uuid)
140
141 return result 152 return result
142 153
143 def migrate(self, destination): 154 def migrate(self, destination):
diff --git a/watcher/tests/applier/actions/test_migration.py b/watcher/tests/applier/actions/test_migration.py
index b91ae86..8dda577 100644
--- a/watcher/tests/applier/actions/test_migration.py
+++ b/watcher/tests/applier/actions/test_migration.py
@@ -15,8 +15,9 @@
15 15
16from __future__ import unicode_literals 16from __future__ import unicode_literals
17 17
18
19import jsonschema
18import mock 20import mock
19import voluptuous
20 21
21from watcher.applier.actions import base as baction 22from watcher.applier.actions import base as baction
22from watcher.applier.actions import migration 23from watcher.applier.actions import migration
@@ -93,13 +94,8 @@ class TestMigration(base.TestCase):
93 'source_node': None, 94 'source_node': None,
94 'destination_node': None} 95 'destination_node': None}
95 self.action.input_parameters = parameters 96 self.action.input_parameters = parameters
96 exc = self.assertRaises( 97 self.assertRaises(jsonschema.ValidationError,
97 voluptuous.MultipleInvalid, self.action.validate_parameters) 98 self.action.validate_parameters)
98 self.assertEqual(
99 sorted([(['migration_type'], voluptuous.ScalarInvalid),
100 (['source_node'], voluptuous.TypeInvalid),
101 (['destination_node'], voluptuous.TypeInvalid)]),
102 sorted([(e.path, type(e)) for e in exc.errors]))
103 99
104 def test_parameters_exception_migration_type(self): 100 def test_parameters_exception_migration_type(self):
105 parameters = {baction.BaseAction.RESOURCE_ID: 101 parameters = {baction.BaseAction.RESOURCE_ID:
@@ -108,11 +104,8 @@ class TestMigration(base.TestCase):
108 'source_node': 'compute-2', 104 'source_node': 'compute-2',
109 'destination_node': 'compute-3'} 105 'destination_node': 'compute-3'}
110 self.action.input_parameters = parameters 106 self.action.input_parameters = parameters
111 exc = self.assertRaises( 107 self.assertRaises(jsonschema.ValidationError,
112 voluptuous.Invalid, self.action.validate_parameters) 108 self.action.validate_parameters)
113 self.assertEqual(
114 [(['migration_type'], voluptuous.ScalarInvalid)],
115 [(e.path, type(e)) for e in exc.errors])
116 109
117 def test_parameters_exception_source_node(self): 110 def test_parameters_exception_source_node(self):
118 parameters = {baction.BaseAction.RESOURCE_ID: 111 parameters = {baction.BaseAction.RESOURCE_ID:
@@ -121,11 +114,8 @@ class TestMigration(base.TestCase):
121 'source_node': None, 114 'source_node': None,
122 'destination_node': 'compute-3'} 115 'destination_node': 'compute-3'}
123 self.action.input_parameters = parameters 116 self.action.input_parameters = parameters
124 exc = self.assertRaises( 117 self.assertRaises(jsonschema.ValidationError,
125 voluptuous.MultipleInvalid, self.action.validate_parameters) 118 self.action.validate_parameters)
126 self.assertEqual(
127 [(['source_node'], voluptuous.TypeInvalid)],
128 [(e.path, type(e)) for e in exc.errors])
129 119
130 def test_parameters_exception_destination_node(self): 120 def test_parameters_exception_destination_node(self):
131 parameters = {baction.BaseAction.RESOURCE_ID: 121 parameters = {baction.BaseAction.RESOURCE_ID:
@@ -134,11 +124,8 @@ class TestMigration(base.TestCase):
134 'source_node': 'compute-1', 124 'source_node': 'compute-1',
135 'destination_node': None} 125 'destination_node': None}
136 self.action.input_parameters = parameters 126 self.action.input_parameters = parameters
137 exc = self.assertRaises( 127 self.assertRaises(jsonschema.ValidationError,
138 voluptuous.MultipleInvalid, self.action.validate_parameters) 128 self.action.validate_parameters)
139 self.assertEqual(
140 [(['destination_node'], voluptuous.TypeInvalid)],
141 [(e.path, type(e)) for e in exc.errors])
142 129
143 def test_parameters_exception_resource_id(self): 130 def test_parameters_exception_resource_id(self):
144 parameters = {baction.BaseAction.RESOURCE_ID: "EFEF", 131 parameters = {baction.BaseAction.RESOURCE_ID: "EFEF",
@@ -146,11 +133,8 @@ class TestMigration(base.TestCase):
146 'source_node': 'compute-2', 133 'source_node': 'compute-2',
147 'destination_node': 'compute-3'} 134 'destination_node': 'compute-3'}
148 self.action.input_parameters = parameters 135 self.action.input_parameters = parameters
149 exc = self.assertRaises( 136 self.assertRaises(jsonschema.ValidationError,
150 voluptuous.MultipleInvalid, self.action.validate_parameters) 137 self.action.validate_parameters)
151 self.assertEqual(
152 [(['resource_id'], voluptuous.Invalid)],
153 [(e.path, type(e)) for e in exc.errors])
154 138
155 def test_migration_pre_condition(self): 139 def test_migration_pre_condition(self):
156 try: 140 try: