313 lines
11 KiB
Python
313 lines
11 KiB
Python
# Copyright (c) 2018 Red Hat, Inc.
|
|
# All Rights Reserved.
|
|
#
|
|
# 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 mock
|
|
|
|
from kuryr_kubernetes import constants
|
|
from kuryr_kubernetes.controller.drivers import namespace_subnet as subnet_drv
|
|
from kuryr_kubernetes import exceptions as k_exc
|
|
from kuryr_kubernetes.tests import base as test_base
|
|
from kuryr_kubernetes.tests.unit import kuryr_fixtures as k_fix
|
|
|
|
from neutronclient.common import exceptions as n_exc
|
|
|
|
|
|
def get_pod_obj():
|
|
return {
|
|
'status': {
|
|
'qosClass': 'BestEffort',
|
|
'hostIP': '192.168.1.2',
|
|
},
|
|
'kind': 'Pod',
|
|
'spec': {
|
|
'schedulerName': 'default-scheduler',
|
|
'containers': [{
|
|
'name': 'busybox',
|
|
'image': 'busybox',
|
|
'resources': {}
|
|
}],
|
|
'nodeName': 'kuryr-devstack'
|
|
},
|
|
'metadata': {
|
|
'name': 'busybox-sleep1',
|
|
'namespace': 'default',
|
|
'resourceVersion': '53808',
|
|
'selfLink': '/api/v1/namespaces/default/pods/busybox-sleep1',
|
|
'uid': '452176db-4a85-11e7-80bd-fa163e29dbbb',
|
|
'annotations': {
|
|
'openstack.org/kuryr-vif': {}
|
|
}
|
|
}}
|
|
|
|
|
|
def get_namespace_obj():
|
|
return {
|
|
'metadata': {
|
|
'annotations': {
|
|
constants.K8S_ANNOTATION_NET_CRD: 'net_crd_url_sample'
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
class TestNamespacePodSubnetDriver(test_base.TestCase):
|
|
|
|
@mock.patch('kuryr_kubernetes.controller.drivers'
|
|
'.default_subnet._get_subnet')
|
|
def test_get_subnets(self, m_get_subnet):
|
|
project_id = mock.sentinel.project_id
|
|
pod = get_pod_obj()
|
|
pod_namespace = pod['metadata']['namespace']
|
|
subnet_id = mock.sentinel.subnet_id
|
|
subnet = mock.sentinel.subnet
|
|
|
|
cls = subnet_drv.NamespacePodSubnetDriver
|
|
m_driver = mock.MagicMock(spec=cls)
|
|
|
|
m_driver._get_namespace_subnet.return_value = subnet_id
|
|
m_get_subnet.return_value = subnet
|
|
|
|
subnets = cls.get_subnets(m_driver, pod, project_id)
|
|
|
|
self.assertEqual({subnet_id: subnet}, subnets)
|
|
m_driver._get_namespace_subnet.assert_called_once_with(pod_namespace)
|
|
m_get_subnet.assert_called_once_with(subnet_id)
|
|
|
|
@mock.patch('kuryr_kubernetes.controller.drivers'
|
|
'.default_subnet._get_subnet')
|
|
def test_get_subnets_namespace_not_ready(self, m_get_subnet):
|
|
project_id = mock.sentinel.project_id
|
|
pod = get_pod_obj()
|
|
pod_namespace = pod['metadata']['namespace']
|
|
|
|
cls = subnet_drv.NamespacePodSubnetDriver
|
|
m_driver = mock.MagicMock(spec=cls)
|
|
|
|
m_driver._get_namespace_subnet.side_effect = k_exc.ResourceNotReady(
|
|
pod_namespace)
|
|
|
|
self.assertRaises(k_exc.ResourceNotReady, cls.get_subnets, m_driver,
|
|
pod, project_id)
|
|
|
|
m_driver._get_namespace_subnet.assert_called_once_with(pod_namespace)
|
|
m_get_subnet.assert_not_called()
|
|
|
|
def test__get_namespace_subnets(self):
|
|
cls = subnet_drv.NamespacePodSubnetDriver
|
|
m_driver = mock.MagicMock(spec=cls)
|
|
|
|
namespace = mock.sentinel.namespace
|
|
subnet_id = mock.sentinel.subnet_id
|
|
ns = get_namespace_obj()
|
|
crd = {
|
|
'spec': {
|
|
'subnetId': subnet_id
|
|
}
|
|
}
|
|
|
|
kubernetes = self.useFixture(k_fix.MockK8sClient()).client
|
|
kubernetes.get.side_effect = [ns, crd]
|
|
|
|
subnet_id_resp = cls._get_namespace_subnet(m_driver, namespace)
|
|
kubernetes.get.assert_called()
|
|
self.assertEqual(subnet_id, subnet_id_resp)
|
|
|
|
def test__get_namespace_subnets_get_namespace_exception(self):
|
|
cls = subnet_drv.NamespacePodSubnetDriver
|
|
m_driver = mock.MagicMock(spec=cls)
|
|
|
|
namespace = mock.sentinel.namespace
|
|
|
|
kubernetes = self.useFixture(k_fix.MockK8sClient()).client
|
|
kubernetes.get.side_effect = k_exc.K8sClientException
|
|
|
|
self.assertRaises(k_exc.ResourceNotReady, cls._get_namespace_subnet,
|
|
m_driver, namespace)
|
|
kubernetes.get.assert_called_once()
|
|
|
|
def test__get_namespace_subnets_missing_annotation(self):
|
|
cls = subnet_drv.NamespacePodSubnetDriver
|
|
m_driver = mock.MagicMock(spec=cls)
|
|
|
|
namespace = mock.sentinel.namespace
|
|
subnet_id = mock.sentinel.subnet_id
|
|
ns = get_namespace_obj()
|
|
del ns['metadata']['annotations'][constants.K8S_ANNOTATION_NET_CRD]
|
|
crd = {
|
|
'spec': {
|
|
'subnetId': subnet_id
|
|
}
|
|
}
|
|
|
|
kubernetes = self.useFixture(k_fix.MockK8sClient()).client
|
|
kubernetes.get.side_effect = [ns, crd]
|
|
|
|
self.assertRaises(k_exc.ResourceNotReady, cls._get_namespace_subnet,
|
|
m_driver, namespace)
|
|
kubernetes.get.assert_called_once()
|
|
|
|
def test__get_namespace_subnets_get_crd_exception(self):
|
|
cls = subnet_drv.NamespacePodSubnetDriver
|
|
m_driver = mock.MagicMock(spec=cls)
|
|
|
|
namespace = mock.sentinel.namespace
|
|
ns = get_namespace_obj()
|
|
|
|
kubernetes = self.useFixture(k_fix.MockK8sClient()).client
|
|
kubernetes.get.side_effect = [ns, k_exc.K8sClientException]
|
|
|
|
self.assertRaises(k_exc.K8sClientException, cls._get_namespace_subnet,
|
|
m_driver, namespace)
|
|
kubernetes.get.assert_called()
|
|
|
|
def test_create_namespace_network(self):
|
|
cls = subnet_drv.NamespacePodSubnetDriver
|
|
m_driver = mock.MagicMock(spec=cls)
|
|
|
|
namespace = 'test'
|
|
|
|
neutron = self.useFixture(k_fix.MockNeutronClient()).client
|
|
net = {'id': mock.sentinel.net}
|
|
neutron.create_network.return_value = {'network': net}
|
|
subnet = {'id': mock.sentinel.subnet}
|
|
neutron.create_subnet.return_value = {'subnet': subnet}
|
|
net_crd = mock.sentinel.net_crd
|
|
m_driver._add_kuryrnet_crd.return_value = net_crd
|
|
|
|
net_crd_resp = cls.create_namespace_network(m_driver, namespace)
|
|
|
|
self.assertEqual(net_crd_resp, net_crd)
|
|
neutron.create_network.assert_called_once()
|
|
neutron.create_subnet.assert_called_once()
|
|
neutron.add_interface_router.assert_called_once()
|
|
m_driver._add_kuryrnet_crd.assert_called_once()
|
|
|
|
def test_create_namespace_network_net_exception(self):
|
|
cls = subnet_drv.NamespacePodSubnetDriver
|
|
m_driver = mock.MagicMock(spec=cls)
|
|
|
|
namespace = 'test'
|
|
|
|
neutron = self.useFixture(k_fix.MockNeutronClient()).client
|
|
neutron.create_network.side_effect = n_exc.NeutronClientException
|
|
|
|
self.assertRaises(n_exc.NeutronClientException,
|
|
cls.create_namespace_network, m_driver, namespace)
|
|
|
|
neutron.create_network.assert_called_once()
|
|
neutron.create_subnet.assert_not_called()
|
|
neutron.add_interface_router.assert_not_called()
|
|
m_driver._add_kuryrnet_crd.assert_not_called()
|
|
|
|
def test_create_namespace_network_subnet_exception(self):
|
|
cls = subnet_drv.NamespacePodSubnetDriver
|
|
m_driver = mock.MagicMock(spec=cls)
|
|
|
|
namespace = 'test'
|
|
|
|
neutron = self.useFixture(k_fix.MockNeutronClient()).client
|
|
net = {'id': mock.sentinel.net}
|
|
neutron.create_network.return_value = {'network': net}
|
|
neutron.create_subnet.side_effect = n_exc.NeutronClientException
|
|
|
|
self.assertRaises(n_exc.NeutronClientException,
|
|
cls.create_namespace_network, m_driver, namespace)
|
|
|
|
neutron.create_network.assert_called_once()
|
|
neutron.create_subnet.assert_called_once()
|
|
neutron.add_interface_router.assert_not_called()
|
|
m_driver._add_kuryrnet_crd.assert_not_called()
|
|
|
|
def test_create_namespace_network_router_exception(self):
|
|
pass
|
|
cls = subnet_drv.NamespacePodSubnetDriver
|
|
m_driver = mock.MagicMock(spec=cls)
|
|
|
|
namespace = 'test'
|
|
|
|
neutron = self.useFixture(k_fix.MockNeutronClient()).client
|
|
net = {'id': mock.sentinel.net}
|
|
neutron.create_network.return_value = {'network': net}
|
|
subnet = {'id': mock.sentinel.subnet}
|
|
neutron.create_subnet.return_value = {'subnet': subnet}
|
|
neutron.add_interface_router.side_effect = (
|
|
n_exc.NeutronClientException)
|
|
|
|
self.assertRaises(n_exc.NeutronClientException,
|
|
cls.create_namespace_network, m_driver, namespace)
|
|
|
|
neutron.create_network.assert_called_once()
|
|
neutron.create_subnet.assert_called_once()
|
|
neutron.add_interface_router.assert_called_once()
|
|
m_driver._add_kuryrnet_crd.assert_not_called()
|
|
|
|
def test_create_namespace_network_crd_exception(self):
|
|
cls = subnet_drv.NamespacePodSubnetDriver
|
|
m_driver = mock.MagicMock(spec=cls)
|
|
|
|
namespace = 'test'
|
|
|
|
neutron = self.useFixture(k_fix.MockNeutronClient()).client
|
|
net = {'id': mock.sentinel.net}
|
|
neutron.create_network.return_value = {'network': net}
|
|
subnet = {'id': mock.sentinel.subnet}
|
|
neutron.create_subnet.return_value = {'subnet': subnet}
|
|
m_driver._add_kuryrnet_crd.side_effect = k_exc.K8sClientException
|
|
|
|
self.assertRaises(k_exc.K8sClientException,
|
|
cls.create_namespace_network, m_driver, namespace)
|
|
|
|
neutron.create_network.assert_called_once()
|
|
neutron.create_subnet.assert_called_once()
|
|
neutron.add_interface_router.assert_called_once()
|
|
m_driver._add_kuryrnet_crd.assert_called_once()
|
|
m_driver.rollback_network_resources.assert_called_once()
|
|
|
|
def test_rollback_network_resources(self):
|
|
cls = subnet_drv.NamespacePodSubnetDriver
|
|
m_driver = mock.MagicMock(spec=cls)
|
|
|
|
router_id = mock.sentinel.router_id
|
|
net_id = mock.sentinel.net_id
|
|
subnet_id = mock.sentinel.subnet_id
|
|
namespace = mock.sentinel.namespace
|
|
|
|
neutron = self.useFixture(k_fix.MockNeutronClient()).client
|
|
|
|
cls.rollback_network_resources(m_driver, router_id, net_id,
|
|
subnet_id, namespace)
|
|
neutron.remove_interface_router.assert_called_with(
|
|
router_id, {'subnet_id': subnet_id})
|
|
neutron.delete_network.assert_called_with(net_id)
|
|
|
|
def test_rollback_network_resources_router_exception(self):
|
|
cls = subnet_drv.NamespacePodSubnetDriver
|
|
m_driver = mock.MagicMock(spec=cls)
|
|
|
|
router_id = mock.sentinel.router_id
|
|
net_id = mock.sentinel.net_id
|
|
subnet_id = mock.sentinel.subnet_id
|
|
namespace = mock.sentinel.namespace
|
|
|
|
neutron = self.useFixture(k_fix.MockNeutronClient()).client
|
|
neutron.remove_interface_router.side_effect = (
|
|
n_exc.NeutronClientException)
|
|
|
|
cls.rollback_network_resources(m_driver, router_id, net_id,
|
|
subnet_id, namespace)
|
|
neutron.remove_interface_router.assert_called_with(
|
|
router_id, {'subnet_id': subnet_id})
|
|
neutron.delete_network.assert_not_called()
|