1
# Copyright (c) 2015 Openstack Foundation
3
# Licensed under the Apache License, Version 2.0 (the "License"); you may
4
# not use this file except in compliance with the License. You may obtain
5
# a copy of the License at
7
# http://www.apache.org/licenses/LICENSE-2.0
9
# Unless required by applicable law or agreed to in writing, software
10
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12
# License for the specific language governing permissions and limitations
17
from neutron.agent.l3 import router_info
18
from neutron.agent.linux import ip_lib
19
from neutron.common import constants as l3_constants
20
from neutron.common import exceptions as n_exc
21
from neutron.openstack.common import uuidutils
22
from neutron.tests import base
24
_uuid = uuidutils.generate_uuid
27
class BasicRouterTestCaseFramework(base.BaseTestCase):
28
def _create_router(self, router=None, **kwargs):
30
router = mock.MagicMock()
31
self.agent_conf = mock.Mock()
32
# NOTE The use_namespaces config will soon be deprecated
33
self.agent_conf.use_namespaces = True
34
self.router_id = _uuid()
35
return router_info.RouterInfo(self.router_id,
38
mock.sentinel.interface_driver,
42
class TestBasicRouterOperations(BasicRouterTestCaseFramework):
44
def test_get_floating_ips(self):
45
router = mock.MagicMock()
46
router.get.return_value = [mock.sentinel.floating_ip]
47
ri = self._create_router(router)
49
fips = ri.get_floating_ips()
51
self.assertEqual([mock.sentinel.floating_ip], fips)
53
def test_process_floating_ip_nat_rules(self):
54
ri = self._create_router()
55
fips = [{'fixed_ip_address': mock.sentinel.ip,
56
'floating_ip_address': mock.sentinel.fip}]
57
ri.get_floating_ips = mock.Mock(return_value=fips)
58
ri.iptables_manager = mock.MagicMock()
59
ipv4_nat = ri.iptables_manager.ipv4['nat']
60
ri.floating_forward_rules = mock.Mock(
61
return_value=[(mock.sentinel.chain, mock.sentinel.rule)])
63
ri.process_floating_ip_nat_rules()
65
# Be sure that the rules are cleared first and apply is called last
66
self.assertEqual(mock.call.clear_rules_by_tag('floating_ip'),
67
ipv4_nat.mock_calls[0])
68
self.assertEqual(mock.call.apply(), ri.iptables_manager.mock_calls[-1])
70
# Be sure that add_rule is called somewhere in the middle
71
ipv4_nat.add_rule.assert_called_once_with(mock.sentinel.chain,
75
def test_process_floating_ip_nat_rules_removed(self):
76
ri = self._create_router()
77
ri.get_floating_ips = mock.Mock(return_value=[])
78
ri.iptables_manager = mock.MagicMock()
79
ipv4_nat = ri.iptables_manager.ipv4['nat']
81
ri.process_floating_ip_nat_rules()
83
# Be sure that the rules are cleared first and apply is called last
84
self.assertEqual(mock.call.clear_rules_by_tag('floating_ip'),
85
ipv4_nat.mock_calls[0])
86
self.assertEqual(mock.call.apply(), ri.iptables_manager.mock_calls[-1])
88
# Be sure that add_rule is called somewhere in the middle
89
self.assertFalse(ipv4_nat.add_rule.called)
91
def _test_add_fip_addr_to_device_error(self, device):
92
ri = self._create_router()
95
result = ri._add_fip_addr_to_device(
96
{'id': mock.sentinel.id, 'floating_ip_address': ip}, device)
98
device.addr.add.assert_called_with(ip + '/32')
101
def test__add_fip_addr_to_device(self):
102
result = self._test_add_fip_addr_to_device_error(mock.Mock())
103
self.assertTrue(result)
105
def test__add_fip_addr_to_device_error(self):
107
device.addr.add.side_effect = RuntimeError
108
result = self._test_add_fip_addr_to_device_error(device)
109
self.assertFalse(result)
111
def test_process_snat_dnat_for_fip(self):
112
ri = self._create_router()
113
ri.process_floating_ip_nat_rules = mock.Mock(side_effect=Exception)
115
self.assertRaises(n_exc.FloatingIpSetupException,
116
ri.process_snat_dnat_for_fip)
118
ri.process_floating_ip_nat_rules.assert_called_once_with()
120
def test_put_fips_in_error_state(self):
121
ri = self._create_router()
122
ri.router = mock.Mock()
123
ri.router.get.return_value = [{'id': mock.sentinel.id1},
124
{'id': mock.sentinel.id2}]
126
statuses = ri.put_fips_in_error_state()
128
expected = [{mock.sentinel.id1: l3_constants.FLOATINGIP_STATUS_ERROR,
129
mock.sentinel.id2: l3_constants.FLOATINGIP_STATUS_ERROR}]
130
self.assertNotEqual(expected, statuses)
132
def test_configure_fip_addresses(self):
133
ri = self._create_router()
134
ri.process_floating_ip_addresses = mock.Mock(
135
side_effect=Exception)
137
self.assertRaises(n_exc.FloatingIpSetupException,
138
ri.configure_fip_addresses,
139
mock.sentinel.interface_name)
141
ri.process_floating_ip_addresses.assert_called_once_with(
142
mock.sentinel.interface_name)
144
def test_get_router_cidrs_returns_cidrs(self):
145
ri = self._create_router()
146
addresses = ['15.1.2.2/24', '15.1.2.3/32']
147
device = mock.MagicMock()
148
device.addr.list.return_value = [{'cidr': addresses[0]},
149
{'cidr': addresses[1]}]
150
self.assertEqual(set(addresses), ri.get_router_cidrs(device))
153
@mock.patch.object(ip_lib, 'IPDevice')
154
class TestFloatingIpWithMockDevice(BasicRouterTestCaseFramework):
156
def test_process_floating_ip_addresses_remap(self, IPDevice):
159
'id': fip_id, 'port_id': _uuid(),
160
'floating_ip_address': '15.1.2.3',
161
'fixed_ip_address': '192.168.0.2'
164
IPDevice.return_value = device = mock.Mock()
165
device.addr.list.return_value = [{'cidr': '15.1.2.3/32'}]
166
ri = self._create_router()
167
ri.get_floating_ips = mock.Mock(return_value=[fip])
169
fip_statuses = ri.process_floating_ip_addresses(
170
mock.sentinel.interface_name)
171
self.assertEqual({fip_id: l3_constants.FLOATINGIP_STATUS_ACTIVE},
174
self.assertFalse(device.addr.add.called)
175
self.assertFalse(device.addr.delete.called)
177
def test_process_router_with_disabled_floating_ip(self, IPDevice):
180
'id': fip_id, 'port_id': _uuid(),
181
'floating_ip_address': '15.1.2.3',
182
'fixed_ip_address': '192.168.0.2'
185
ri = self._create_router()
186
ri.floating_ips = [fip]
187
ri.get_floating_ips = mock.Mock(return_value=[])
189
fip_statuses = ri.process_floating_ip_addresses(
190
mock.sentinel.interface_name)
192
self.assertIsNone(fip_statuses.get(fip_id))
194
def test_process_router_floating_ip_with_device_add_error(self, IPDevice):
195
IPDevice.return_value = device = mock.Mock(side_effect=RuntimeError)
196
device.addr.list.return_value = []
199
'id': fip_id, 'port_id': _uuid(),
200
'floating_ip_address': '15.1.2.3',
201
'fixed_ip_address': '192.168.0.2'
203
ri = self._create_router()
204
ri.add_floating_ip = mock.Mock(
205
return_value=l3_constants.FLOATINGIP_STATUS_ERROR)
206
ri.get_floating_ips = mock.Mock(return_value=[fip])
208
fip_statuses = ri.process_floating_ip_addresses(
209
mock.sentinel.interface_name)
211
self.assertEqual({fip_id: l3_constants.FLOATINGIP_STATUS_ERROR},
214
# TODO(mrsmith): refactor for DVR cases
215
def test_process_floating_ip_addresses_remove(self, IPDevice):
216
IPDevice.return_value = device = mock.Mock()
217
device.addr.list.return_value = [{'cidr': '15.1.2.3/32'}]
219
ri = self._create_router()
220
ri.remove_floating_ip = mock.Mock()
221
ri.router.get = mock.Mock(return_value=[])
223
fip_statuses = ri.process_floating_ip_addresses(
224
mock.sentinel.interface_name)
225
self.assertEqual({}, fip_statuses)
226
ri.remove_floating_ip.assert_called_once_with(device, '15.1.2.3/32')