329 lines
15 KiB
Python
329 lines
15 KiB
Python
# 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 ddt import data
|
|
from ddt import ddt
|
|
import mock
|
|
from neutronclient.common import exceptions
|
|
from oslo_serialization import jsonutils
|
|
from oslo_utils import uuidutils
|
|
|
|
from kuryr.lib import utils as lib_utils
|
|
from kuryr_libnetwork import constants as const
|
|
from kuryr_libnetwork.tests.unit import base
|
|
from kuryr_libnetwork import utils
|
|
|
|
|
|
class TestKuryrNetworkCreateFailures(base.TestKuryrFailures):
|
|
"""Unittests for the failures for creating networks.
|
|
|
|
This test covers error responses listed in the spec:
|
|
http://developer.openstack.org/api-ref-networking-v2-ext.html#createProviderNetwork # noqa
|
|
"""
|
|
def _invoke_create_request(self, network_request):
|
|
response = self.app.post('/NetworkDriver.CreateNetwork',
|
|
content_type='application/json',
|
|
data=jsonutils.dumps(network_request))
|
|
return response
|
|
|
|
@mock.patch('kuryr_libnetwork.controllers.app.neutron.create_network')
|
|
@mock.patch(
|
|
'kuryr_libnetwork.controllers.app.driver.get_default_network_id',
|
|
return_value=None)
|
|
@mock.patch('kuryr_libnetwork.controllers.app.neutron.list_subnetpools')
|
|
def test_create_network_unauthorized(self, mock_list_subnetpools,
|
|
mock_get_default_network, mock_create_network):
|
|
docker_network_id = lib_utils.get_hash()
|
|
network_request = {
|
|
'NetworkID': docker_network_id,
|
|
'IPv4Data': [{
|
|
'AddressSpace': 'foo',
|
|
'Pool': '192.168.42.0/24',
|
|
'Gateway': '192.168.42.1/24',
|
|
'AuxAddresses': {}
|
|
}],
|
|
'IPv6Data': [{
|
|
'AddressSpace': 'bar',
|
|
'Pool': 'fe80::/64',
|
|
'Gateway': 'fe80::f816:3eff:fe20:57c3/64',
|
|
'AuxAddresses': {}
|
|
}],
|
|
'Options': {}
|
|
}
|
|
|
|
fake_kuryr_v4_subnetpool_id = uuidutils.generate_uuid()
|
|
fake_v4_pool_name = lib_utils.get_neutron_subnetpool_name(
|
|
network_request['IPv4Data'][0]['Pool'])
|
|
kuryr_v4_subnetpools = self._get_fake_v4_subnetpools(
|
|
fake_kuryr_v4_subnetpool_id, name=fake_v4_pool_name)
|
|
|
|
fake_kuryr_v6_subnetpool_id = uuidutils.generate_uuid()
|
|
fake_v6_pool_name = lib_utils.get_neutron_subnetpool_name(
|
|
network_request['IPv6Data'][0]['Pool'])
|
|
kuryr_v6_subnetpools = self._get_fake_v6_subnetpools(
|
|
fake_kuryr_v6_subnetpool_id, name=fake_v6_pool_name)
|
|
fake_v4_pool_attrs = {'name': fake_v4_pool_name}
|
|
fake_v6_pool_attrs = {'name': fake_v6_pool_name}
|
|
mock_list_subnetpools.side_effect = [
|
|
{'subnetpools': kuryr_v4_subnetpools['subnetpools']},
|
|
{'subnetpools': kuryr_v6_subnetpools['subnetpools']}
|
|
]
|
|
|
|
fake_request = {
|
|
"network": {
|
|
"name": utils.make_net_name(docker_network_id),
|
|
"admin_state_up": True
|
|
}
|
|
}
|
|
mock_create_network.side_effect = exceptions.Unauthorized
|
|
response = self._invoke_create_request(network_request)
|
|
self.assertEqual(401, response.status_code)
|
|
decoded_json = jsonutils.loads(response.data)
|
|
mock_list_subnetpools.assert_any_call(**fake_v4_pool_attrs)
|
|
mock_list_subnetpools.assert_any_call(**fake_v6_pool_attrs)
|
|
mock_create_network.assert_called_with(fake_request)
|
|
self.assertIn('Err', decoded_json)
|
|
self.assertEqual(
|
|
{'Err': exceptions.Unauthorized.message}, decoded_json)
|
|
|
|
@mock.patch(
|
|
'kuryr_libnetwork.controllers.app.driver.get_default_network_id')
|
|
@mock.patch('kuryr_libnetwork.controllers.app.neutron.list_subnetpools')
|
|
def test_create_network_get_default_network_id_unauthorized(self,
|
|
mock_list_subnetpools, mock_get_default_network_id):
|
|
docker_network_id = lib_utils.get_hash()
|
|
network_request = {
|
|
'NetworkID': docker_network_id,
|
|
'IPv4Data': [{
|
|
'AddressSpace': 'foo',
|
|
'Pool': '192.168.42.0/24',
|
|
'Gateway': '192.168.42.1/24',
|
|
'AuxAddresses': {}
|
|
}],
|
|
'IPv6Data': [{
|
|
'AddressSpace': 'bar',
|
|
'Pool': 'fe80::/64',
|
|
'Gateway': 'fe80::f816:3eff:fe20:57c3/64',
|
|
'AuxAddresses': {}
|
|
}],
|
|
'Options': {}
|
|
}
|
|
|
|
fake_kuryr_v4_subnetpool_id = uuidutils.generate_uuid()
|
|
fake_v4_pool_name = lib_utils.get_neutron_subnetpool_name(
|
|
network_request['IPv4Data'][0]['Pool'])
|
|
kuryr_v4_subnetpools = self._get_fake_v4_subnetpools(
|
|
fake_kuryr_v4_subnetpool_id, name=fake_v4_pool_name)
|
|
|
|
fake_kuryr_v6_subnetpool_id = uuidutils.generate_uuid()
|
|
fake_v6_pool_name = lib_utils.get_neutron_subnetpool_name(
|
|
network_request['IPv6Data'][0]['Pool'])
|
|
kuryr_v6_subnetpools = self._get_fake_v6_subnetpools(
|
|
fake_kuryr_v6_subnetpool_id, name=fake_v6_pool_name)
|
|
fake_v4_pool_attrs = {'name': fake_v4_pool_name}
|
|
fake_v6_pool_attrs = {'name': fake_v6_pool_name}
|
|
mock_list_subnetpools.side_effect = [
|
|
{'subnetpools': kuryr_v4_subnetpools['subnetpools']},
|
|
{'subnetpools': kuryr_v6_subnetpools['subnetpools']}
|
|
]
|
|
|
|
mock_get_default_network_id.side_effect = exceptions.Unauthorized
|
|
response = self._invoke_create_request(network_request)
|
|
self.assertEqual(401, response.status_code)
|
|
decoded_json = jsonutils.loads(response.data)
|
|
mock_list_subnetpools.assert_any_call(**fake_v4_pool_attrs)
|
|
mock_list_subnetpools.assert_any_call(**fake_v6_pool_attrs)
|
|
mock_get_default_network_id.assert_called()
|
|
self.assertIn('Err', decoded_json)
|
|
self.assertEqual(
|
|
{'Err': exceptions.Unauthorized.message}, decoded_json)
|
|
|
|
def test_create_network_bad_request(self):
|
|
invalid_docker_network_id = 'id-should-be-hexdigits'
|
|
network_request = {
|
|
'NetworkID': invalid_docker_network_id,
|
|
'IPv4Data': [{
|
|
'AddressSpace': 'foo',
|
|
'Pool': '192.168.42.0/24',
|
|
'Gateway': '192.168.42.1/24',
|
|
'AuxAddresses': {}
|
|
}],
|
|
'IPv6Data': [{
|
|
'AddressSpace': 'bar',
|
|
'Pool': 'fe80::/64',
|
|
'Gateway': 'fe80::f816:3eff:fe20:57c3/64',
|
|
'AuxAddresses': {}
|
|
}],
|
|
'Options': {}
|
|
}
|
|
|
|
response = self._invoke_create_request(network_request)
|
|
self.assertEqual(400, response.status_code)
|
|
decoded_json = jsonutils.loads(response.data)
|
|
self.assertIn('Err', decoded_json)
|
|
# TODO(tfukushima): Add the better error message validation.
|
|
self.assertIn(invalid_docker_network_id, decoded_json['Err'])
|
|
self.assertIn('NetworkID', decoded_json['Err'])
|
|
|
|
|
|
@ddt
|
|
class TestKuryrNetworkDeleteFailures(base.TestKuryrFailures):
|
|
"""Unittests for the failures for deleting networks.
|
|
|
|
This test covers error responses listed in the spec:
|
|
http://developer.openstack.org/api-ref-networking-v2-ext.html#deleteProviderNetwork # noqa
|
|
"""
|
|
def _invoke_delete_request(self, network_name):
|
|
data = {'NetworkID': network_name}
|
|
response = self.app.post('/NetworkDriver.DeleteNetwork',
|
|
content_type='application/json',
|
|
data=jsonutils.dumps(data))
|
|
return response
|
|
|
|
@mock.patch('kuryr_libnetwork.controllers.app.neutron.delete_network')
|
|
@mock.patch('kuryr_libnetwork.controllers.app.neutron.delete_subnet')
|
|
@mock.patch('kuryr_libnetwork.controllers.app.neutron.list_subnetpools')
|
|
@mock.patch('kuryr_libnetwork.controllers.app.neutron.list_subnets')
|
|
@mock.patch('kuryr_libnetwork.controllers.app.neutron.list_networks')
|
|
@data(exceptions.Unauthorized, exceptions.NotFound, exceptions.Conflict)
|
|
def test_delete_network_failures(self, GivenException,
|
|
mock_list_networks, mock_list_subnets,
|
|
mock_list_subnetpools, mock_delete_subnet,
|
|
mock_delete_network):
|
|
fake_subnetpools_response = {"subnetpools": []}
|
|
docker_network_id = lib_utils.get_hash()
|
|
docker_endpoint_id = lib_utils.get_hash()
|
|
fake_neutron_network_id = "4e8e5957-649f-477b-9e5b-f1f75b21c03c"
|
|
t = utils.make_net_tags(docker_network_id)
|
|
te = t + ',' + utils.existing_net_tag(docker_network_id)
|
|
subnet_v4_id = "9436e561-47bf-436a-b1f1-fe23a926e031"
|
|
subnet_v6_id = "64dd4a98-3d7a-4bfd-acf4-91137a8d2f51"
|
|
|
|
def mock_network(*args, **kwargs):
|
|
if kwargs['tags'] == te:
|
|
return self._get_fake_list_network(
|
|
fake_neutron_network_id,
|
|
check_existing=True)
|
|
elif kwargs['tags'] == t:
|
|
if GivenException == exceptions.NotFound:
|
|
return self._get_fake_list_network(
|
|
fake_neutron_network_id,
|
|
check_existing=True)
|
|
return self._get_fake_list_network(
|
|
fake_neutron_network_id)
|
|
|
|
fake_v4_subnet = self._get_fake_v4_subnet(
|
|
docker_network_id, docker_endpoint_id, subnet_v4_id)
|
|
fake_v6_subnet = self._get_fake_v6_subnet(
|
|
docker_network_id, docker_endpoint_id, subnet_v6_id)
|
|
fake_subnets_response = {
|
|
"subnets": [
|
|
fake_v4_subnet['subnet'],
|
|
fake_v6_subnet['subnet']
|
|
]
|
|
}
|
|
mock_list_networks.side_effect = mock_network
|
|
mock_list_subnets.return_value = fake_subnets_response
|
|
mock_list_subnetpools.return_value = fake_subnetpools_response
|
|
mock_delete_subnet.return_value = None
|
|
mock_delete_network.side_effect = GivenException
|
|
|
|
response = self._invoke_delete_request(docker_network_id)
|
|
decoded_json = jsonutils.loads(response.data)
|
|
if GivenException == exceptions.NotFound:
|
|
self.assertEqual(GivenException.status_code, 404)
|
|
self.assertEqual(const.SCHEMA['SUCCESS'], decoded_json)
|
|
else:
|
|
self.assertEqual(GivenException.status_code, response.status_code)
|
|
fake_v4_pool_attrs = {'name': 'kuryr'}
|
|
fake_v6_pool_attrs = {'name': 'kuryr6'}
|
|
mock_list_subnetpools.assert_any_call(**fake_v6_pool_attrs)
|
|
mock_list_subnetpools.assert_any_call(**fake_v4_pool_attrs)
|
|
mock_delete_subnet.assert_any_call(subnet_v4_id)
|
|
mock_delete_subnet.assert_any_call(subnet_v6_id)
|
|
mock_delete_network.assert_called_with(fake_neutron_network_id)
|
|
mock_list_subnets.assert_called_with(
|
|
network_id=fake_neutron_network_id)
|
|
self.assertIn('Err', decoded_json)
|
|
self.assertEqual({'Err': GivenException.message}, decoded_json)
|
|
mock_list_networks.assert_any_call(tags=t)
|
|
mock_list_networks.assert_any_call(tags=te)
|
|
|
|
def test_delete_network_bad_request(self):
|
|
invalid_docker_network_id = 'invalid-network-id'
|
|
|
|
response = self._invoke_delete_request(invalid_docker_network_id)
|
|
|
|
self.assertEqual(400, response.status_code)
|
|
decoded_json = jsonutils.loads(response.data)
|
|
self.assertIn('Err', decoded_json)
|
|
self.assertIn(invalid_docker_network_id, decoded_json['Err'])
|
|
self.assertIn('NetworkID', decoded_json['Err'])
|
|
|
|
@mock.patch('kuryr_libnetwork.controllers.app.neutron.delete_subnet')
|
|
@mock.patch('kuryr_libnetwork.controllers.app.neutron.list_subnetpools')
|
|
@mock.patch('kuryr_libnetwork.controllers.app.neutron.list_subnets')
|
|
@mock.patch('kuryr_libnetwork.controllers.app.neutron.list_networks')
|
|
@data(exceptions.Unauthorized, exceptions.NotFound, exceptions.Conflict)
|
|
def test_delete_network_with_subnet_deletion_failures(self,
|
|
GivenException, mock_list_networks, mock_list_subnets,
|
|
mock_list_subnetpools, mock_delete_subnet):
|
|
|
|
fake_subnetpools_response = {"subnetpools": []}
|
|
docker_network_id = lib_utils.get_hash()
|
|
docker_endpoint_id = lib_utils.get_hash()
|
|
fake_neutron_network_id = "4e8e5957-649f-477b-9e5b-f1f75b21c03c"
|
|
t = utils.make_net_tags(docker_network_id)
|
|
te = t + ',' + utils.existing_net_tag(docker_network_id)
|
|
subnet_v4_id = "9436e561-47bf-436a-b1f1-fe23a926e031"
|
|
subnet_v6_id = "64dd4a98-3d7a-4bfd-acf4-91137a8d2f51"
|
|
|
|
def mock_network(*args, **kwargs):
|
|
if kwargs['tags'] == te:
|
|
return self._get_fake_list_network(
|
|
fake_neutron_network_id,
|
|
check_existing=True)
|
|
elif kwargs['tags'] == t:
|
|
return self._get_fake_list_network(
|
|
fake_neutron_network_id)
|
|
|
|
fake_v4_subnet = self._get_fake_v4_subnet(
|
|
docker_network_id, docker_endpoint_id, subnet_v4_id)
|
|
fake_v6_subnet = self._get_fake_v6_subnet(
|
|
docker_network_id, docker_endpoint_id, subnet_v6_id)
|
|
fake_subnets_response = {
|
|
"subnets": [
|
|
fake_v4_subnet['subnet'],
|
|
fake_v6_subnet['subnet']
|
|
]
|
|
}
|
|
mock_list_networks.side_effect = mock_network
|
|
mock_list_subnets.return_value = fake_subnets_response
|
|
mock_list_subnetpools.return_value = fake_subnetpools_response
|
|
mock_delete_subnet.side_effect = GivenException
|
|
response = self._invoke_delete_request(docker_network_id)
|
|
|
|
self.assertEqual(GivenException.status_code, response.status_code)
|
|
mock_list_networks.assert_any_call(tags=t)
|
|
mock_list_networks.assert_any_call(tags=te)
|
|
mock_list_subnets.assert_called_with(
|
|
network_id=fake_neutron_network_id)
|
|
fake_v4_pool_attrs = {'name': 'kuryr'}
|
|
fake_v6_pool_attrs = {'name': 'kuryr6'}
|
|
mock_list_subnetpools.assert_any_call(**fake_v6_pool_attrs)
|
|
mock_list_subnetpools.assert_any_call(**fake_v4_pool_attrs)
|
|
mock_delete_subnet.assert_called_with(subnet_v4_id)
|
|
|
|
decoded_json = jsonutils.loads(response.data)
|
|
self.assertIn('Err', decoded_json)
|
|
self.assertEqual({'Err': GivenException.message}, decoded_json)
|