Merge "Validate discovery url when create a bay"
This commit is contained in:
commit
4d1d73b90e
@ -154,6 +154,19 @@ class GetDiscoveryUrlFailed(MagnumException):
|
||||
message = _("Failed to get discovery url from '%(discovery_endpoint)s'.")
|
||||
|
||||
|
||||
class InvalidBayDiscoveryURL(Invalid):
|
||||
message = _("Invalid discovery URL '%(discovery_url)s'.")
|
||||
|
||||
|
||||
class InvalidClusterSize(Invalid):
|
||||
message = _("Expected cluster size %(expect_size)d but get cluster "
|
||||
"size %(size)d from '%(discovery_url)s'.")
|
||||
|
||||
|
||||
class GetClusterSizeFailed(MagnumException):
|
||||
message = _("Failed to get the size of cluster from '%(discovery_url)s'.")
|
||||
|
||||
|
||||
class InvalidIdentity(Invalid):
|
||||
message = _("Expected an uuid or int but received %(identity)s.")
|
||||
|
||||
|
@ -12,11 +12,13 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
import abc
|
||||
import ast
|
||||
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
from pkg_resources import iter_entry_points
|
||||
import requests
|
||||
from requests import exceptions as req_exceptions
|
||||
import six
|
||||
|
||||
from magnum.common import clients
|
||||
@ -394,8 +396,48 @@ class BaseTemplateDefinition(TemplateDefinition):
|
||||
extra_params=extra_params,
|
||||
**kwargs)
|
||||
|
||||
def validate_discovery_url(self, discovery_url, expect_size):
|
||||
url = str(discovery_url)
|
||||
if url[len(url)-1] == '/':
|
||||
url += '_config/size'
|
||||
else:
|
||||
url += '/_config/size'
|
||||
|
||||
try:
|
||||
result = requests.get(url).text
|
||||
except req_exceptions.RequestException as err:
|
||||
LOG.error(six.text_type(err))
|
||||
raise exception.GetClusterSizeFailed(
|
||||
discovery_url=discovery_url)
|
||||
|
||||
try:
|
||||
result = ast.literal_eval(result)
|
||||
except (ValueError, SyntaxError):
|
||||
raise exception.InvalidBayDiscoveryURL(
|
||||
discovery_url=discovery_url)
|
||||
|
||||
node_value = result.get('node', None)
|
||||
if node_value is None:
|
||||
raise exception.InvalidBayDiscoveryURL(
|
||||
discovery_url=discovery_url)
|
||||
|
||||
value = node_value.get('value', None)
|
||||
if value is None:
|
||||
raise exception.InvalidBayDiscoveryURL(
|
||||
discovery_url=discovery_url)
|
||||
elif int(value) != expect_size:
|
||||
raise exception.InvalidClusterSize(
|
||||
expect_size=expect_size,
|
||||
size=int(value),
|
||||
discovery_url=discovery_url)
|
||||
|
||||
def get_discovery_url(self, bay):
|
||||
if hasattr(bay, 'discovery_url') and bay.discovery_url:
|
||||
if getattr(bay, 'master_count', None) is not None:
|
||||
self.validate_discovery_url(bay.discovery_url,
|
||||
bay.master_count)
|
||||
else:
|
||||
self.validate_discovery_url(bay.discovery_url, 1)
|
||||
discovery_url = bay.discovery_url
|
||||
else:
|
||||
discovery_endpoint = (
|
||||
@ -403,7 +445,7 @@ class BaseTemplateDefinition(TemplateDefinition):
|
||||
{'size': bay.master_count})
|
||||
try:
|
||||
discovery_url = requests.get(discovery_endpoint).text
|
||||
except Exception as err:
|
||||
except req_exceptions.RequestException as err:
|
||||
LOG.error(six.text_type(err))
|
||||
raise exception.GetDiscoveryUrlFailed(
|
||||
discovery_endpoint=discovery_endpoint)
|
||||
|
@ -81,16 +81,19 @@ class TestBayConductorWithK8s(base.TestCase):
|
||||
self.mock_osc.keystone.return_value = self.mock_keystone
|
||||
self.mock_osc_class.return_value = self.mock_osc
|
||||
|
||||
@patch('requests.get')
|
||||
@patch('magnum.objects.BayModel.get_by_uuid')
|
||||
def test_extract_template_definition(
|
||||
self,
|
||||
mock_objects_baymodel_get_by_uuid):
|
||||
mock_objects_baymodel_get_by_uuid,
|
||||
mock_get):
|
||||
self._test_extract_template_definition(
|
||||
mock_objects_baymodel_get_by_uuid)
|
||||
mock_objects_baymodel_get_by_uuid, mock_get)
|
||||
|
||||
def _test_extract_template_definition(
|
||||
self,
|
||||
mock_objects_baymodel_get_by_uuid,
|
||||
mock_get,
|
||||
missing_attr=None):
|
||||
if missing_attr in self.baymodel_dict:
|
||||
self.baymodel_dict[missing_attr] = None
|
||||
@ -98,6 +101,11 @@ class TestBayConductorWithK8s(base.TestCase):
|
||||
self.bay_dict[missing_attr] = None
|
||||
baymodel = objects.BayModel(self.context, **self.baymodel_dict)
|
||||
mock_objects_baymodel_get_by_uuid.return_value = baymodel
|
||||
expected_result = str('{"action":"get","node":{"key":"test","value":'
|
||||
'"1","modifiedIndex":10,"createdIndex":10}}')
|
||||
mock_resp = mock.MagicMock()
|
||||
mock_resp.text = expected_result
|
||||
mock_get.return_value = mock_resp
|
||||
bay = objects.Bay(self.context, **self.bay_dict)
|
||||
|
||||
(template_path,
|
||||
@ -170,13 +178,20 @@ class TestBayConductorWithK8s(base.TestCase):
|
||||
self.assertEqual(expected, definition)
|
||||
self.assertEqual([], env_files)
|
||||
|
||||
@patch('requests.get')
|
||||
@patch('magnum.objects.BayModel.get_by_uuid')
|
||||
def test_extract_template_definition_with_registry(
|
||||
self,
|
||||
mock_objects_baymodel_get_by_uuid):
|
||||
mock_objects_baymodel_get_by_uuid,
|
||||
mock_get):
|
||||
self.baymodel_dict['registry_enabled'] = True
|
||||
baymodel = objects.BayModel(self.context, **self.baymodel_dict)
|
||||
mock_objects_baymodel_get_by_uuid.return_value = baymodel
|
||||
expected_result = str('{"action":"get","node":{"key":"test","value":'
|
||||
'"1","modifiedIndex":10,"createdIndex":10}}')
|
||||
mock_resp = mock.MagicMock()
|
||||
mock_resp.text = expected_result
|
||||
mock_get.return_value = mock_resp
|
||||
bay = objects.Bay(self.context, **self.bay_dict)
|
||||
|
||||
cfg.CONF.set_override('swift_region',
|
||||
@ -229,13 +244,20 @@ class TestBayConductorWithK8s(base.TestCase):
|
||||
self.assertEqual(expected, definition)
|
||||
self.assertEqual([], env_files)
|
||||
|
||||
@patch('requests.get')
|
||||
@patch('magnum.objects.BayModel.get_by_uuid')
|
||||
def test_extract_template_definition_coreos_with_disovery(
|
||||
self,
|
||||
mock_objects_baymodel_get_by_uuid):
|
||||
mock_objects_baymodel_get_by_uuid,
|
||||
mock_get):
|
||||
self.baymodel_dict['cluster_distro'] = 'coreos'
|
||||
baymodel = objects.BayModel(self.context, **self.baymodel_dict)
|
||||
mock_objects_baymodel_get_by_uuid.return_value = baymodel
|
||||
expected_result = str('{"action":"get","node":{"key":"test","value":'
|
||||
'"1","modifiedIndex":10,"createdIndex":10}}')
|
||||
mock_resp = mock.MagicMock()
|
||||
mock_resp.text = expected_result
|
||||
mock_get.return_value = mock_resp
|
||||
bay = objects.Bay(self.context, **self.bay_dict)
|
||||
|
||||
(template_path,
|
||||
@ -328,76 +350,103 @@ class TestBayConductorWithK8s(base.TestCase):
|
||||
self.assertEqual(expected, definition)
|
||||
self.assertEqual([], env_files)
|
||||
|
||||
@patch('requests.get')
|
||||
@patch('magnum.objects.BayModel.get_by_uuid')
|
||||
def test_extract_template_definition_without_dns(
|
||||
self,
|
||||
mock_objects_baymodel_get_by_uuid):
|
||||
mock_objects_baymodel_get_by_uuid,
|
||||
mock_get):
|
||||
self._test_extract_template_definition(
|
||||
mock_objects_baymodel_get_by_uuid,
|
||||
mock_get,
|
||||
missing_attr='dns_nameserver')
|
||||
|
||||
@patch('requests.get')
|
||||
@patch('magnum.objects.BayModel.get_by_uuid')
|
||||
def test_extract_template_definition_without_server_image(
|
||||
self,
|
||||
mock_objects_baymodel_get_by_uuid):
|
||||
mock_objects_baymodel_get_by_uuid,
|
||||
mock_get):
|
||||
self._test_extract_template_definition(
|
||||
mock_objects_baymodel_get_by_uuid,
|
||||
mock_get,
|
||||
missing_attr='image_id')
|
||||
|
||||
@patch('requests.get')
|
||||
@patch('magnum.objects.BayModel.get_by_uuid')
|
||||
def test_extract_template_definition_without_minion_flavor(
|
||||
self,
|
||||
mock_objects_baymodel_get_by_uuid):
|
||||
mock_objects_baymodel_get_by_uuid,
|
||||
mock_get):
|
||||
self._test_extract_template_definition(
|
||||
mock_objects_baymodel_get_by_uuid,
|
||||
mock_get,
|
||||
missing_attr='flavor_id')
|
||||
|
||||
@patch('requests.get')
|
||||
@patch('magnum.objects.BayModel.get_by_uuid')
|
||||
def test_extract_template_definition_without_docker_volume_size(
|
||||
self,
|
||||
mock_objects_baymodel_get_by_uuid):
|
||||
mock_objects_baymodel_get_by_uuid,
|
||||
mock_get):
|
||||
self._test_extract_template_definition(
|
||||
mock_objects_baymodel_get_by_uuid,
|
||||
mock_get,
|
||||
missing_attr='docker_volume_size')
|
||||
|
||||
@patch('requests.get')
|
||||
@patch('magnum.objects.BayModel.get_by_uuid')
|
||||
def test_extract_template_definition_without_docker_storage_driver(
|
||||
self,
|
||||
mock_objects_baymodel_get_by_uuid):
|
||||
mock_objects_baymodel_get_by_uuid,
|
||||
mock_get):
|
||||
self._test_extract_template_definition(
|
||||
mock_objects_baymodel_get_by_uuid,
|
||||
mock_get,
|
||||
missing_attr='docker_storage_driver')
|
||||
|
||||
@patch('requests.get')
|
||||
@patch('magnum.objects.BayModel.get_by_uuid')
|
||||
def test_extract_template_definition_without_master_flavor(
|
||||
self,
|
||||
mock_objects_baymodel_get_by_uuid):
|
||||
mock_objects_baymodel_get_by_uuid,
|
||||
mock_get):
|
||||
self._test_extract_template_definition(
|
||||
mock_objects_baymodel_get_by_uuid,
|
||||
mock_get,
|
||||
missing_attr='master_flavor_id')
|
||||
|
||||
@patch('requests.get')
|
||||
@patch('magnum.objects.BayModel.get_by_uuid')
|
||||
def test_extract_template_definition_without_apiserver_port(
|
||||
self,
|
||||
mock_objects_baymodel_get_by_uuid):
|
||||
mock_objects_baymodel_get_by_uuid,
|
||||
mock_get):
|
||||
self._test_extract_template_definition(
|
||||
mock_objects_baymodel_get_by_uuid,
|
||||
mock_get,
|
||||
missing_attr='apiserver_port')
|
||||
|
||||
@patch('requests.get')
|
||||
@patch('magnum.objects.BayModel.get_by_uuid')
|
||||
def test_extract_template_definition_without_node_count(
|
||||
self,
|
||||
mock_objects_baymodel_get_by_uuid):
|
||||
mock_objects_baymodel_get_by_uuid,
|
||||
mock_get):
|
||||
self._test_extract_template_definition(
|
||||
mock_objects_baymodel_get_by_uuid,
|
||||
mock_get,
|
||||
missing_attr='node_count')
|
||||
|
||||
@patch('requests.get')
|
||||
@patch('magnum.objects.BayModel.get_by_uuid')
|
||||
def test_extract_template_definition_without_master_count(
|
||||
self,
|
||||
mock_objects_baymodel_get_by_uuid):
|
||||
mock_objects_baymodel_get_by_uuid,
|
||||
mock_get):
|
||||
self._test_extract_template_definition(
|
||||
mock_objects_baymodel_get_by_uuid,
|
||||
mock_get,
|
||||
missing_attr='master_count')
|
||||
|
||||
@patch('requests.get')
|
||||
|
@ -75,12 +75,19 @@ class TestBayConductorWithSwarm(base.TestCase):
|
||||
self.mock_osc_class.return_value = self.mock_osc
|
||||
self.context.auth_url = 'http://192.168.10.10:5000/v3'
|
||||
|
||||
@patch('requests.get')
|
||||
@patch('magnum.objects.BayModel.get_by_uuid')
|
||||
def test_extract_template_definition_all_values(
|
||||
self,
|
||||
mock_objects_baymodel_get_by_uuid):
|
||||
mock_objects_baymodel_get_by_uuid,
|
||||
mock_get):
|
||||
baymodel = objects.BayModel(self.context, **self.baymodel_dict)
|
||||
mock_objects_baymodel_get_by_uuid.return_value = baymodel
|
||||
expected_result = str('{"action":"get","node":{"key":"test","value":'
|
||||
'"1","modifiedIndex":10,"createdIndex":10}}')
|
||||
mock_resp = mock.MagicMock()
|
||||
mock_resp.text = expected_result
|
||||
mock_get.return_value = mock_resp
|
||||
bay = objects.Bay(self.context, **self.bay_dict)
|
||||
|
||||
(template_path,
|
||||
@ -121,13 +128,20 @@ class TestBayConductorWithSwarm(base.TestCase):
|
||||
self.assertEqual(expected, definition)
|
||||
self.assertEqual([], env_files)
|
||||
|
||||
@patch('requests.get')
|
||||
@patch('magnum.objects.BayModel.get_by_uuid')
|
||||
def test_extract_template_definition_with_registry(
|
||||
self,
|
||||
mock_objects_baymodel_get_by_uuid):
|
||||
mock_objects_baymodel_get_by_uuid,
|
||||
mock_get):
|
||||
self.baymodel_dict['registry_enabled'] = True
|
||||
baymodel = objects.BayModel(self.context, **self.baymodel_dict)
|
||||
mock_objects_baymodel_get_by_uuid.return_value = baymodel
|
||||
expected_result = str('{"action":"get","node":{"key":"test","value":'
|
||||
'"1","modifiedIndex":10,"createdIndex":10}}')
|
||||
mock_resp = mock.MagicMock()
|
||||
mock_resp.text = expected_result
|
||||
mock_get.return_value = mock_resp
|
||||
bay = objects.Bay(self.context, **self.bay_dict)
|
||||
|
||||
cfg.CONF.set_override('swift_region',
|
||||
@ -174,10 +188,12 @@ class TestBayConductorWithSwarm(base.TestCase):
|
||||
self.assertEqual(expected, definition)
|
||||
self.assertEqual([], env_files)
|
||||
|
||||
@patch('requests.get')
|
||||
@patch('magnum.objects.BayModel.get_by_uuid')
|
||||
def test_extract_template_definition_only_required(
|
||||
self,
|
||||
mock_objects_baymodel_get_by_uuid):
|
||||
mock_objects_baymodel_get_by_uuid,
|
||||
mock_get):
|
||||
|
||||
not_required = ['image_id', 'flavor_id', 'dns_nameserver',
|
||||
'docker_volume_size', 'fixed_network', 'http_proxy',
|
||||
@ -189,6 +205,11 @@ class TestBayConductorWithSwarm(base.TestCase):
|
||||
|
||||
baymodel = objects.BayModel(self.context, **self.baymodel_dict)
|
||||
mock_objects_baymodel_get_by_uuid.return_value = baymodel
|
||||
expected_result = str('{"action":"get","node":{"key":"test","value":'
|
||||
'"1","modifiedIndex":10,"createdIndex":10}}')
|
||||
mock_resp = mock.MagicMock()
|
||||
mock_resp.text = expected_result
|
||||
mock_get.return_value = mock_resp
|
||||
bay = objects.Bay(self.context, **self.bay_dict)
|
||||
|
||||
(template_path,
|
||||
|
@ -14,6 +14,7 @@
|
||||
|
||||
import mock
|
||||
from oslo_config import cfg
|
||||
from requests import exceptions as req_exceptions
|
||||
|
||||
from magnum.common import exception
|
||||
from magnum.conductor import template_definition as tdef
|
||||
@ -270,6 +271,50 @@ class AtomicK8sTemplateDefinitionTestCase(base.TestCase):
|
||||
mock_get_params.assert_called_once_with(mock_context, mock_baymodel,
|
||||
mock_bay, **expected_kwargs)
|
||||
|
||||
@mock.patch('requests.get')
|
||||
def test_k8s_validate_discovery_url(self, mock_get):
|
||||
expected_result = str('{"action":"get","node":{"key":"test","value":'
|
||||
'"1","modifiedIndex":10,"createdIndex":10}}')
|
||||
mock_resp = mock.MagicMock()
|
||||
mock_resp.text = expected_result
|
||||
mock_get.return_value = mock_resp
|
||||
|
||||
k8s_def = tdef.AtomicK8sTemplateDefinition()
|
||||
k8s_def.validate_discovery_url('http://etcd/test', 1)
|
||||
|
||||
@mock.patch('requests.get')
|
||||
def test_k8s_validate_discovery_url_fail(self, mock_get):
|
||||
mock_get.side_effect = req_exceptions.RequestException()
|
||||
|
||||
k8s_def = tdef.AtomicK8sTemplateDefinition()
|
||||
self.assertRaises(exception.GetClusterSizeFailed,
|
||||
k8s_def.validate_discovery_url,
|
||||
'http://etcd/test', 1)
|
||||
|
||||
@mock.patch('requests.get')
|
||||
def test_k8s_validate_discovery_url_invalid(self, mock_get):
|
||||
mock_resp = mock.MagicMock()
|
||||
mock_resp.text = str('{"action":"get"}')
|
||||
mock_get.return_value = mock_resp
|
||||
|
||||
k8s_def = tdef.AtomicK8sTemplateDefinition()
|
||||
self.assertRaises(exception.InvalidBayDiscoveryURL,
|
||||
k8s_def.validate_discovery_url,
|
||||
'http://etcd/test', 1)
|
||||
|
||||
@mock.patch('requests.get')
|
||||
def test_k8s_validate_discovery_url_unexpect_size(self, mock_get):
|
||||
expected_result = str('{"action":"get","node":{"key":"test","value":'
|
||||
'"1","modifiedIndex":10,"createdIndex":10}}')
|
||||
mock_resp = mock.MagicMock()
|
||||
mock_resp.text = expected_result
|
||||
mock_get.return_value = mock_resp
|
||||
|
||||
k8s_def = tdef.AtomicK8sTemplateDefinition()
|
||||
self.assertRaises(exception.InvalidClusterSize,
|
||||
k8s_def.validate_discovery_url,
|
||||
'http://etcd/test', 5)
|
||||
|
||||
@mock.patch('requests.get')
|
||||
def test_k8s_get_discovery_url(self, mock_get):
|
||||
cfg.CONF.set_override('etcd_discovery_service_endpoint_format',
|
||||
@ -295,7 +340,7 @@ class AtomicK8sTemplateDefinitionTestCase(base.TestCase):
|
||||
cfg.CONF.set_override('etcd_discovery_service_endpoint_format',
|
||||
'http://etcd/test?size=%(size)d',
|
||||
group='bay')
|
||||
mock_get.side_effect = Exception()
|
||||
mock_get.side_effect = req_exceptions.RequestException()
|
||||
mock_bay = mock.MagicMock()
|
||||
mock_bay.master_count = 10
|
||||
mock_bay.discovery_url = None
|
||||
@ -481,6 +526,50 @@ class AtomicSwarmTemplateDefinitionTestCase(base.TestCase):
|
||||
mock_get_params.assert_called_once_with(mock_context, mock_baymodel,
|
||||
mock_bay, **expected_kwargs)
|
||||
|
||||
@mock.patch('requests.get')
|
||||
def test_swarm_validate_discovery_url(self, mock_get):
|
||||
expected_result = str('{"action":"get","node":{"key":"test","value":'
|
||||
'"1","modifiedIndex":10,"createdIndex":10}}')
|
||||
mock_resp = mock.MagicMock()
|
||||
mock_resp.text = expected_result
|
||||
mock_get.return_value = mock_resp
|
||||
|
||||
k8s_def = tdef.AtomicK8sTemplateDefinition()
|
||||
k8s_def.validate_discovery_url('http://etcd/test', 1)
|
||||
|
||||
@mock.patch('requests.get')
|
||||
def test_swarm_validate_discovery_url_fail(self, mock_get):
|
||||
mock_get.side_effect = req_exceptions.RequestException()
|
||||
|
||||
k8s_def = tdef.AtomicK8sTemplateDefinition()
|
||||
self.assertRaises(exception.GetClusterSizeFailed,
|
||||
k8s_def.validate_discovery_url,
|
||||
'http://etcd/test', 1)
|
||||
|
||||
@mock.patch('requests.get')
|
||||
def test_swarm_validate_discovery_url_invalid(self, mock_get):
|
||||
mock_resp = mock.MagicMock()
|
||||
mock_resp.text = str('{"action":"get"}')
|
||||
mock_get.return_value = mock_resp
|
||||
|
||||
k8s_def = tdef.AtomicK8sTemplateDefinition()
|
||||
self.assertRaises(exception.InvalidBayDiscoveryURL,
|
||||
k8s_def.validate_discovery_url,
|
||||
'http://etcd/test', 1)
|
||||
|
||||
@mock.patch('requests.get')
|
||||
def test_swarm_validate_discovery_url_unexpect_size(self, mock_get):
|
||||
expected_result = str('{"action":"get","node":{"key":"test","value":'
|
||||
'"1","modifiedIndex":10,"createdIndex":10}}')
|
||||
mock_resp = mock.MagicMock()
|
||||
mock_resp.text = expected_result
|
||||
mock_get.return_value = mock_resp
|
||||
|
||||
k8s_def = tdef.AtomicK8sTemplateDefinition()
|
||||
self.assertRaises(exception.InvalidClusterSize,
|
||||
k8s_def.validate_discovery_url,
|
||||
'http://etcd/test', 5)
|
||||
|
||||
@mock.patch('requests.get')
|
||||
def test_swarm_get_discovery_url(self, mock_get):
|
||||
cfg.CONF.set_override('etcd_discovery_service_endpoint_format',
|
||||
|
Loading…
Reference in New Issue
Block a user