Move the convert_requirements method to the utils namespace
The convert_requirements method is used by host_plugin and instance_plugin. But this method is implemented as an instance method of host_plugin. The instance_plugin can't use this method without an instance of host_plugin. This patch moves the convert_requirements method to the utils namespace. All plugins which query the db data can use this method. Partially implements: blueprint new-instance-reservation Change-Id: Ib365a794b45a1a1bf0c1b0a8a750171d44d25b8a
This commit is contained in:
parent
a20b29b179
commit
50e730f060
@ -15,10 +15,8 @@
|
||||
# under the License.
|
||||
|
||||
import datetime
|
||||
import json
|
||||
|
||||
from oslo_config import cfg
|
||||
import six
|
||||
|
||||
from blazar.db import api as db_api
|
||||
from blazar.db import exceptions as db_ex
|
||||
@ -27,6 +25,7 @@ from blazar.manager import exceptions as manager_ex
|
||||
from blazar.plugins import base
|
||||
from blazar.plugins import oshosts as plugin
|
||||
from blazar.utils.openstack import nova
|
||||
from blazar.utils import plugins as plugins_utils
|
||||
from blazar.utils import trusts
|
||||
|
||||
plugin_opts = [
|
||||
@ -348,10 +347,10 @@ class PhysicalHostPlugin(base.BasePlugin, nova.NovaClientWrapper):
|
||||
filter_array = []
|
||||
# TODO(frossigneux) support "or" operator
|
||||
if hypervisor_properties:
|
||||
filter_array = self._convert_requirements(
|
||||
filter_array = plugins_utils.convert_requirements(
|
||||
hypervisor_properties)
|
||||
if resource_properties:
|
||||
filter_array += self._convert_requirements(
|
||||
filter_array += plugins_utils.convert_requirements(
|
||||
resource_properties)
|
||||
for host in db_api.host_get_all_by_queries(filter_array):
|
||||
if not db_api.host_allocation_get_all_by_values(
|
||||
@ -373,53 +372,3 @@ class PhysicalHostPlugin(base.BasePlugin, nova.NovaClientWrapper):
|
||||
return all_host_ids[:int(max_host)]
|
||||
else:
|
||||
return []
|
||||
|
||||
def _convert_requirements(self, requirements):
|
||||
"""Convert the requirements to an array of strings
|
||||
|
||||
Convert the requirements to an array of strings.
|
||||
["key op value", "key op value", ...]
|
||||
"""
|
||||
# TODO(frossigneux) Support the "or" operator
|
||||
# Convert text to json
|
||||
if isinstance(requirements, six.string_types):
|
||||
try:
|
||||
requirements = json.loads(requirements)
|
||||
except ValueError:
|
||||
raise manager_ex.MalformedRequirements(rqrms=requirements)
|
||||
|
||||
# Requirement list looks like ['<', '$ram', '1024']
|
||||
if self._requirements_with_three_elements(requirements):
|
||||
result = []
|
||||
if requirements[0] == '=':
|
||||
requirements[0] = '=='
|
||||
string = (requirements[1][1:] + " " + requirements[0] + " " +
|
||||
requirements[2])
|
||||
result.append(string)
|
||||
return result
|
||||
# Remove the 'and' element at the head of the requirement list
|
||||
elif self._requirements_with_and_keyword(requirements):
|
||||
return [self._convert_requirements(x)[0]
|
||||
for x in requirements[1:]]
|
||||
# Empty requirement list0
|
||||
elif isinstance(requirements, list) and not requirements:
|
||||
return requirements
|
||||
else:
|
||||
raise manager_ex.MalformedRequirements(rqrms=requirements)
|
||||
|
||||
def _requirements_with_three_elements(self, requirements):
|
||||
"""Return true if requirement list looks like ['<', '$ram', '1024']."""
|
||||
return (isinstance(requirements, list) and
|
||||
len(requirements) == 3 and
|
||||
isinstance(requirements[0], six.string_types) and
|
||||
isinstance(requirements[1], six.string_types) and
|
||||
isinstance(requirements[2], six.string_types) and
|
||||
requirements[0] in ['==', '=', '!=', '>=', '<=', '>', '<'] and
|
||||
len(requirements[1]) > 1 and requirements[1][0] == '$' and
|
||||
len(requirements[2]) > 0)
|
||||
|
||||
def _requirements_with_and_keyword(self, requirements):
|
||||
return (len(requirements) > 1 and
|
||||
isinstance(requirements[0], six.string_types) and
|
||||
requirements[0] == 'and' and
|
||||
all(self._convert_requirements(x) for x in requirements[1:]))
|
||||
|
@ -771,54 +771,3 @@ class PhysicalHostPluginTestCase(tests.TestCase):
|
||||
datetime.datetime(2013, 12, 19, 20, 00),
|
||||
datetime.datetime(2013, 12, 19, 21, 00))
|
||||
self.assertEqual([], result)
|
||||
|
||||
def test_convert_requirements_empty(self):
|
||||
request = '[]'
|
||||
result = self.fake_phys_plugin._convert_requirements(request)
|
||||
self.assertEqual([], result)
|
||||
|
||||
def test_convert_requirements_small(self):
|
||||
request = '["=", "$memory", "4096"]'
|
||||
result = self.fake_phys_plugin._convert_requirements(request)
|
||||
self.assertEqual(['memory == 4096'], result)
|
||||
|
||||
def test_convert_requirements_with_incorrect_syntax_1(self):
|
||||
self.assertRaises(
|
||||
manager_exceptions.MalformedRequirements,
|
||||
self.fake_phys_plugin._convert_requirements,
|
||||
'["a", "$memory", "4096"]')
|
||||
|
||||
def test_convert_requirements_with_incorrect_syntax_2(self):
|
||||
self.assertRaises(
|
||||
manager_exceptions.MalformedRequirements,
|
||||
self.fake_phys_plugin._convert_requirements,
|
||||
'["=", "memory", "4096"]')
|
||||
|
||||
def test_convert_requirements_with_incorrect_syntax_3(self):
|
||||
self.assertRaises(
|
||||
manager_exceptions.MalformedRequirements,
|
||||
self.fake_phys_plugin._convert_requirements,
|
||||
'["=", "$memory", 4096]')
|
||||
|
||||
def test_convert_requirements_complex(self):
|
||||
request = '["and", [">", "$memory", "4096"], [">", "$disk", "40"]]'
|
||||
result = self.fake_phys_plugin._convert_requirements(request)
|
||||
self.assertEqual(['memory > 4096', 'disk > 40'], result)
|
||||
|
||||
def test_convert_requirements_complex_with_incorrect_syntax_1(self):
|
||||
self.assertRaises(
|
||||
manager_exceptions.MalformedRequirements,
|
||||
self.fake_phys_plugin._convert_requirements,
|
||||
'["and", [">", "memory", "4096"], [">", "$disk", "40"]]')
|
||||
|
||||
def test_convert_requirements_complex_with_incorrect_syntax_2(self):
|
||||
self.assertRaises(
|
||||
manager_exceptions.MalformedRequirements,
|
||||
self.fake_phys_plugin._convert_requirements,
|
||||
'["fail", [">", "$memory", "4096"], [">", "$disk", "40"]]')
|
||||
|
||||
def test_convert_requirements_complex_with_not_json_value(self):
|
||||
self.assertRaises(
|
||||
manager_exceptions.MalformedRequirements,
|
||||
self.fake_phys_plugin._convert_requirements,
|
||||
'something')
|
||||
|
72
blazar/tests/utils/test_plugins.py
Normal file
72
blazar/tests/utils/test_plugins.py
Normal file
@ -0,0 +1,72 @@
|
||||
# Copyright (c) 2017 NTT.
|
||||
#
|
||||
# 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 blazar.manager import exceptions as manager_exceptions
|
||||
from blazar import tests
|
||||
from blazar.utils import plugins as plugins_utils
|
||||
|
||||
|
||||
class TestPluginsUtils(tests.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestPluginsUtils, self).setUp()
|
||||
|
||||
def test_convert_requirements_empty(self):
|
||||
request = '[]'
|
||||
result = plugins_utils.convert_requirements(request)
|
||||
self.assertEqual([], result)
|
||||
|
||||
def test_convert_requirements_small(self):
|
||||
request = '["=", "$memory", "4096"]'
|
||||
result = plugins_utils.convert_requirements(request)
|
||||
self.assertEqual(['memory == 4096'], result)
|
||||
|
||||
def test_convert_requirements_with_incorrect_syntax_1(self):
|
||||
self.assertRaises(
|
||||
manager_exceptions.MalformedRequirements,
|
||||
plugins_utils.convert_requirements, '["a", "$memory", "4096"]')
|
||||
|
||||
def test_convert_requirements_with_incorrect_syntax_2(self):
|
||||
self.assertRaises(
|
||||
manager_exceptions.MalformedRequirements,
|
||||
plugins_utils.convert_requirements, '["=", "memory", "4096"]')
|
||||
|
||||
def test_convert_requirements_with_incorrect_syntax_3(self):
|
||||
self.assertRaises(
|
||||
manager_exceptions.MalformedRequirements,
|
||||
plugins_utils.convert_requirements, '["=", "$memory", 4096]')
|
||||
|
||||
def test_convert_requirements_complex(self):
|
||||
request = '["and", [">", "$memory", "4096"], [">", "$disk", "40"]]'
|
||||
result = plugins_utils.convert_requirements(request)
|
||||
self.assertEqual(['memory > 4096', 'disk > 40'], result)
|
||||
|
||||
def test_convert_requirements_complex_with_incorrect_syntax_1(self):
|
||||
self.assertRaises(
|
||||
manager_exceptions.MalformedRequirements,
|
||||
plugins_utils.convert_requirements,
|
||||
'["and", [">", "memory", "4096"], [">", "$disk", "40"]]')
|
||||
|
||||
def test_convert_requirements_complex_with_incorrect_syntax_2(self):
|
||||
self.assertRaises(
|
||||
manager_exceptions.MalformedRequirements,
|
||||
plugins_utils.convert_requirements,
|
||||
'["fail", [">", "$memory", "4096"], [">", "$disk", "40"]]')
|
||||
|
||||
def test_convert_requirements_complex_with_not_json_value(self):
|
||||
self.assertRaises(
|
||||
manager_exceptions.MalformedRequirements,
|
||||
plugins_utils.convert_requirements, 'something')
|
73
blazar/utils/plugins.py
Normal file
73
blazar/utils/plugins.py
Normal file
@ -0,0 +1,73 @@
|
||||
# Copyright (c) 2017 NTT.
|
||||
#
|
||||
# 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.
|
||||
|
||||
import json
|
||||
|
||||
import six
|
||||
|
||||
from blazar.manager import exceptions as manager_ex
|
||||
|
||||
|
||||
def convert_requirements(requirements):
|
||||
"""Convert the requirements to an array of strings
|
||||
|
||||
Convert the requirements to an array of strings.
|
||||
["key op value", "key op value", ...]
|
||||
"""
|
||||
# TODO(frossigneux) Support the "or" operator
|
||||
# Convert text to json
|
||||
if isinstance(requirements, six.string_types):
|
||||
try:
|
||||
requirements = json.loads(requirements)
|
||||
except ValueError:
|
||||
raise manager_ex.MalformedRequirements(rqrms=requirements)
|
||||
|
||||
# Requirement list looks like ['<', '$ram', '1024']
|
||||
if _requirements_with_three_elements(requirements):
|
||||
result = []
|
||||
if requirements[0] == '=':
|
||||
requirements[0] = '=='
|
||||
string = (requirements[1][1:] + " " + requirements[0] + " " +
|
||||
requirements[2])
|
||||
result.append(string)
|
||||
return result
|
||||
# Remove the 'and' element at the head of the requirement list
|
||||
elif _requirements_with_and_keyword(requirements):
|
||||
return [convert_requirements(x)[0] for x in requirements[1:]]
|
||||
|
||||
# Empty requirement list0
|
||||
elif isinstance(requirements, list) and not requirements:
|
||||
return requirements
|
||||
else:
|
||||
raise manager_ex.MalformedRequirements(rqrms=requirements)
|
||||
|
||||
|
||||
def _requirements_with_three_elements(requirements):
|
||||
"""Return true if requirement list looks like ['<', '$ram', '1024']."""
|
||||
return (isinstance(requirements, list) and
|
||||
len(requirements) == 3 and
|
||||
isinstance(requirements[0], six.string_types) and
|
||||
isinstance(requirements[1], six.string_types) and
|
||||
isinstance(requirements[2], six.string_types) and
|
||||
requirements[0] in ['==', '=', '!=', '>=', '<=', '>', '<'] and
|
||||
len(requirements[1]) > 1 and requirements[1][0] == '$' and
|
||||
len(requirements[2]) > 0)
|
||||
|
||||
|
||||
def _requirements_with_and_keyword(requirements):
|
||||
return (len(requirements) > 1 and
|
||||
isinstance(requirements[0], six.string_types) and
|
||||
requirements[0] == 'and' and
|
||||
all(convert_requirements(x) for x in requirements[1:]))
|
Loading…
x
Reference in New Issue
Block a user