~niedbalski/ubuntu/vivid/neutron/fixes-1447803

« back to all changes in this revision

Viewing changes to neutron/tests/unit/db/test_l3_ha_db.py

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2014-10-03 18:45:23 UTC
  • mfrom: (1.1.15)
  • Revision ID: package-import@ubuntu.com-20141003184523-4mt6dy1q3j8n30c9
Tags: 1:2014.2~rc1-0ubuntu1
* New upstream release candidate:
  - d/p/*: Refreshed.
  - d/control: Add python-requests-mock to BD's.
  - d/control: Align versioned requirements with upstream.
* Transition linuxbridge and openvswitch plugin users to modular
  layer 2 plugin (LP: #1323729):
  - d/control: Mark removed plugin packages as transitional, depend
    on neutron-plugin-ml2, mark oldlibs/extra.
  - d/neutron-plugin-{linuxbridge,openvswitch}.install: Drop.
  - d/control: Depend on neutron-plugin-ml2 for linuxbridge
    agent package.
  - d/neutron-plugin-linuxbridge-agent.upstart: Use ml2 plugin
    configuration files.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2014 eNovance SAS <licensing@enovance.com>
 
2
#
 
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
 
6
#
 
7
#      http://www.apache.org/licenses/LICENSE-2.0
 
8
#
 
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
 
13
# under the License.
 
14
 
 
15
import mock
 
16
from oslo.config import cfg
 
17
 
 
18
from neutron.common import constants
 
19
from neutron import context
 
20
from neutron.db import agents_db
 
21
from neutron.db import common_db_mixin
 
22
from neutron.db import l3_hamode_db
 
23
from neutron.extensions import l3_ext_ha_mode
 
24
from neutron import manager
 
25
from neutron.openstack.common import uuidutils
 
26
from neutron.tests.unit import testlib_api
 
27
from neutron.tests.unit import testlib_plugin
 
28
 
 
29
_uuid = uuidutils.generate_uuid
 
30
 
 
31
 
 
32
class FakeL3Plugin(common_db_mixin.CommonDbMixin,
 
33
                   l3_hamode_db.L3_HA_NAT_db_mixin):
 
34
    pass
 
35
 
 
36
 
 
37
class FakeL3PluginWithAgents(FakeL3Plugin,
 
38
                             agents_db.AgentDbMixin):
 
39
    pass
 
40
 
 
41
 
 
42
class L3HATestFramework(testlib_api.SqlTestCase,
 
43
                        testlib_plugin.PluginSetupHelper):
 
44
    def setUp(self):
 
45
        super(L3HATestFramework, self).setUp()
 
46
 
 
47
        self.admin_ctx = context.get_admin_context()
 
48
        self.setup_coreplugin('neutron.plugins.ml2.plugin.Ml2Plugin')
 
49
        self.core_plugin = manager.NeutronManager.get_plugin()
 
50
        mock.patch.object(l3_hamode_db.L3_HA_NAT_db_mixin, 'get_l3_agents',
 
51
                          create=True, return_value=[1, 2]).start()
 
52
        notif_p = mock.patch.object(l3_hamode_db.L3_HA_NAT_db_mixin,
 
53
                                    '_notify_ha_interfaces_updated')
 
54
        self.notif_m = notif_p.start()
 
55
        cfg.CONF.set_override('allow_overlapping_ips', True)
 
56
 
 
57
    def _create_router(self, ha=True, tenant_id='tenant1', distributed=None):
 
58
        router = {'name': 'router1', 'admin_state_up': True}
 
59
        if ha is not None:
 
60
            router['ha'] = ha
 
61
        if distributed is not None:
 
62
            router['distributed'] = distributed
 
63
        return self.plugin._create_router_db(self.admin_ctx, router, tenant_id)
 
64
 
 
65
    def _update_router(self, router_id, ha=True, distributed=None):
 
66
        data = {'ha': ha} if ha is not None else {}
 
67
        if distributed is not None:
 
68
            data['distributed'] = distributed
 
69
        return self.plugin._update_router_db(self.admin_ctx, router_id,
 
70
                                             data, None)
 
71
 
 
72
 
 
73
class L3HAGetSyncDataTestCase(L3HATestFramework):
 
74
 
 
75
    def setUp(self):
 
76
        super(L3HAGetSyncDataTestCase, self).setUp()
 
77
        self.plugin = FakeL3PluginWithAgents()
 
78
        self._register_agents()
 
79
 
 
80
    def _register_agents(self):
 
81
        agent_status = {
 
82
            'agent_type': constants.AGENT_TYPE_L3,
 
83
            'binary': 'neutron-l3-agent',
 
84
            'host': 'l3host',
 
85
            'topic': 'N/A'
 
86
        }
 
87
        self.plugin.create_or_update_agent(self.admin_ctx, agent_status)
 
88
        agent_status['host'] = 'l3host_2'
 
89
        self.plugin.create_or_update_agent(self.admin_ctx, agent_status)
 
90
        self.agent1, self.agent2 = self.plugin.get_agents(self.admin_ctx)
 
91
 
 
92
    def _bind_router(self, router_id):
 
93
        with self.admin_ctx.session.begin(subtransactions=True):
 
94
            bindings = self.plugin.get_ha_router_port_bindings(self.admin_ctx,
 
95
                                                               [router_id])
 
96
 
 
97
            for agent_id, binding in zip(
 
98
                    [self.agent1['id'], self.agent2['id']], bindings):
 
99
                binding.l3_agent_id = agent_id
 
100
 
 
101
    def test_l3_agent_routers_query_interface(self):
 
102
        router = self._create_router()
 
103
        self._bind_router(router.id)
 
104
        routers = self.plugin.get_ha_sync_data_for_host(self.admin_ctx,
 
105
                                                        self.agent1['host'])
 
106
        self.assertEqual(1, len(routers))
 
107
        router = routers[0]
 
108
 
 
109
        self.assertIsNotNone(router.get('ha'))
 
110
 
 
111
        interface = router.get(constants.HA_INTERFACE_KEY)
 
112
        self.assertIsNotNone(interface)
 
113
 
 
114
        self.assertEqual(constants.DEVICE_OWNER_ROUTER_HA_INTF,
 
115
                         interface['device_owner'])
 
116
        self.assertEqual(cfg.CONF.l3_ha_net_cidr, interface['subnet']['cidr'])
 
117
 
 
118
    def test_update_state(self):
 
119
        router = self._create_router()
 
120
        self._bind_router(router.id)
 
121
        routers = self.plugin.get_ha_sync_data_for_host(self.admin_ctx,
 
122
                                                        self.agent1['host'])
 
123
        state = routers[0].get(constants.HA_ROUTER_STATE_KEY)
 
124
        self.assertEqual('standby', state)
 
125
 
 
126
        self.plugin.update_router_state(self.admin_ctx, router.id, 'active',
 
127
                                        self.agent1['host'])
 
128
 
 
129
        routers = self.plugin.get_ha_sync_data_for_host(self.admin_ctx,
 
130
                                                        self.agent1['host'])
 
131
 
 
132
        state = routers[0].get(constants.HA_ROUTER_STATE_KEY)
 
133
        self.assertEqual('active', state)
 
134
 
 
135
 
 
136
class L3HATestCase(L3HATestFramework):
 
137
 
 
138
    def setUp(self):
 
139
        super(L3HATestCase, self).setUp()
 
140
        self.plugin = FakeL3Plugin()
 
141
 
 
142
    def test_verify_configuration_succeed(self):
 
143
        # Default configuration should pass
 
144
        self.plugin._verify_configuration()
 
145
 
 
146
    def test_verify_configuration_l3_ha_net_cidr_is_not_a_cidr(self):
 
147
        cfg.CONF.set_override('l3_ha_net_cidr', 'not a cidr')
 
148
        self.assertRaises(
 
149
            l3_ext_ha_mode.HANetworkCIDRNotValid,
 
150
            self.plugin._verify_configuration)
 
151
 
 
152
    def test_verify_configuration_l3_ha_net_cidr_is_not_a_subnet(self):
 
153
        cfg.CONF.set_override('l3_ha_net_cidr', '10.0.0.1/8')
 
154
        self.assertRaises(
 
155
            l3_ext_ha_mode.HANetworkCIDRNotValid,
 
156
            self.plugin._verify_configuration)
 
157
 
 
158
    def test_verify_conifguration_min_l3_agents_per_router_below_minimum(self):
 
159
        cfg.CONF.set_override('min_l3_agents_per_router', 0)
 
160
        self.assertRaises(
 
161
            l3_ext_ha_mode.HAMinimumAgentsNumberNotValid,
 
162
            self.plugin._verify_configuration)
 
163
 
 
164
    def test_ha_router_create(self):
 
165
        router = self._create_router()
 
166
        self.assertTrue(router.extra_attributes['ha'])
 
167
 
 
168
    def test_ha_router_create_with_distributed(self):
 
169
        self.assertRaises(l3_ext_ha_mode.DistributedHARouterNotSupported,
 
170
                          self._create_router,
 
171
                          distributed=True)
 
172
 
 
173
    def test_no_ha_router_create(self):
 
174
        router = self._create_router(ha=False)
 
175
        self.assertFalse(router.extra_attributes['ha'])
 
176
 
 
177
    def test_router_create_with_ha_conf_enabled(self):
 
178
        cfg.CONF.set_override('l3_ha', True)
 
179
 
 
180
        router = self._create_router(ha=None)
 
181
        self.assertTrue(router.extra_attributes['ha'])
 
182
 
 
183
    def test_migration_from_ha(self):
 
184
        router = self._create_router()
 
185
        self.assertTrue(router.extra_attributes['ha'])
 
186
 
 
187
        router = self._update_router(router.id, ha=False)
 
188
        self.assertFalse(router.extra_attributes['ha'])
 
189
        self.assertIsNone(router.extra_attributes['ha_vr_id'])
 
190
 
 
191
    def test_migration_to_ha(self):
 
192
        router = self._create_router(ha=False)
 
193
        self.assertFalse(router.extra_attributes['ha'])
 
194
 
 
195
        router = self._update_router(router.id, ha=True)
 
196
        self.assertTrue(router.extra_attributes['ha'])
 
197
        self.assertIsNotNone(router.extra_attributes['ha_vr_id'])
 
198
 
 
199
    def test_migrate_ha_router_to_distributed(self):
 
200
        router = self._create_router()
 
201
        self.assertTrue(router.extra_attributes['ha'])
 
202
 
 
203
        self.assertRaises(l3_ext_ha_mode.DistributedHARouterNotSupported,
 
204
                          self._update_router,
 
205
                          router.id,
 
206
                          distributed=True)
 
207
 
 
208
    def test_unique_ha_network_per_tenant(self):
 
209
        tenant1 = _uuid()
 
210
        tenant2 = _uuid()
 
211
        self._create_router(tenant_id=tenant1)
 
212
        self._create_router(tenant_id=tenant2)
 
213
        ha_network1 = self.plugin.get_ha_network(self.admin_ctx, tenant1)
 
214
        ha_network2 = self.plugin.get_ha_network(self.admin_ctx, tenant2)
 
215
        self.assertNotEqual(
 
216
            ha_network1['network_id'], ha_network2['network_id'])
 
217
 
 
218
    def _deployed_router_change_ha_flag(self, to_ha):
 
219
        self._create_router(ha=not to_ha)
 
220
        routers = self.plugin.get_ha_sync_data_for_host(self.admin_ctx)
 
221
        router = routers[0]
 
222
        interface = router.get(constants.HA_INTERFACE_KEY)
 
223
        if to_ha:
 
224
            self.assertIsNone(interface)
 
225
        else:
 
226
            self.assertIsNotNone(interface)
 
227
 
 
228
        self._update_router(router['id'], to_ha)
 
229
        routers = self.plugin.get_ha_sync_data_for_host(self.admin_ctx)
 
230
        router = routers[0]
 
231
        interface = router.get(constants.HA_INTERFACE_KEY)
 
232
        if to_ha:
 
233
            self.assertIsNotNone(interface)
 
234
        else:
 
235
            self.assertIsNone(interface)
 
236
 
 
237
    def test_deployed_router_can_have_ha_enabled(self):
 
238
        self._deployed_router_change_ha_flag(to_ha=True)
 
239
 
 
240
    def test_deployed_router_can_have_ha_disabled(self):
 
241
        self._deployed_router_change_ha_flag(to_ha=False)
 
242
 
 
243
    def test_create_ha_router_notifies_agent(self):
 
244
        self._create_router()
 
245
        self.assertTrue(self.notif_m.called)
 
246
 
 
247
    def test_update_router_to_ha_notifies_agent(self):
 
248
        router = self._create_router(ha=False)
 
249
        self.notif_m.reset_mock()
 
250
        self._update_router(router.id, ha=True)
 
251
        self.assertTrue(self.notif_m.called)
 
252
 
 
253
    def test_unique_vr_id_between_routers(self):
 
254
        self._create_router()
 
255
        self._create_router()
 
256
        routers = self.plugin.get_ha_sync_data_for_host(self.admin_ctx)
 
257
        self.assertEqual(2, len(routers))
 
258
        self.assertNotEqual(routers[0]['ha_vr_id'], routers[1]['ha_vr_id'])
 
259
 
 
260
    @mock.patch('neutron.db.l3_hamode_db.VR_ID_RANGE', new=set(range(1, 1)))
 
261
    def test_vr_id_depleted(self):
 
262
        self.assertRaises(l3_ext_ha_mode.NoVRIDAvailable, self._create_router)
 
263
 
 
264
    @mock.patch('neutron.db.l3_hamode_db.VR_ID_RANGE', new=set(range(1, 2)))
 
265
    def test_vr_id_unique_range_per_tenant(self):
 
266
        self._create_router()
 
267
        self._create_router(tenant_id=_uuid())
 
268
        routers = self.plugin.get_ha_sync_data_for_host(self.admin_ctx)
 
269
        self.assertEqual(2, len(routers))
 
270
        self.assertEqual(routers[0]['ha_vr_id'], routers[1]['ha_vr_id'])
 
271
 
 
272
    @mock.patch('neutron.db.l3_hamode_db.MAX_ALLOCATION_TRIES', new=2)
 
273
    def test_vr_id_allocation_contraint_conflict(self):
 
274
        router = self._create_router()
 
275
        network = self.plugin.get_ha_network(self.admin_ctx, router.tenant_id)
 
276
 
 
277
        with mock.patch.object(self.plugin, '_get_allocated_vr_id',
 
278
                               return_value=set()) as alloc:
 
279
            self.assertRaises(l3_ext_ha_mode.MaxVRIDAllocationTriesReached,
 
280
                              self.plugin._allocate_vr_id, self.admin_ctx,
 
281
                              network.network_id, router.id)
 
282
            self.assertEqual(2, len(alloc.mock_calls))
 
283
 
 
284
    def test_vr_id_allocation_delete_router(self):
 
285
        router = self._create_router()
 
286
        network = self.plugin.get_ha_network(self.admin_ctx, router.tenant_id)
 
287
 
 
288
        allocs_before = self.plugin._get_allocated_vr_id(self.admin_ctx,
 
289
                                                         network.network_id)
 
290
        router = self._create_router()
 
291
        allocs_current = self.plugin._get_allocated_vr_id(self.admin_ctx,
 
292
                                                          network.network_id)
 
293
        self.assertNotEqual(allocs_before, allocs_current)
 
294
 
 
295
        self.plugin.delete_router(self.admin_ctx, router.id)
 
296
        allocs_after = self.plugin._get_allocated_vr_id(self.admin_ctx,
 
297
                                                        network.network_id)
 
298
        self.assertEqual(allocs_before, allocs_after)
 
299
 
 
300
    def test_vr_id_allocation_router_migration(self):
 
301
        router = self._create_router()
 
302
        network = self.plugin.get_ha_network(self.admin_ctx, router.tenant_id)
 
303
 
 
304
        allocs_before = self.plugin._get_allocated_vr_id(self.admin_ctx,
 
305
                                                         network.network_id)
 
306
        router = self._create_router()
 
307
        self._update_router(router.id, ha=False)
 
308
        allocs_after = self.plugin._get_allocated_vr_id(self.admin_ctx,
 
309
                                                        network.network_id)
 
310
        self.assertEqual(allocs_before, allocs_after)
 
311
 
 
312
    def test_one_ha_router_one_not(self):
 
313
        self._create_router(ha=False)
 
314
        self._create_router()
 
315
        routers = self.plugin.get_ha_sync_data_for_host(self.admin_ctx)
 
316
 
 
317
        ha0 = routers[0]['ha']
 
318
        ha1 = routers[1]['ha']
 
319
 
 
320
        self.assertNotEqual(ha0, ha1)
 
321
 
 
322
    def test_add_ha_port_binding_failure_rolls_back_port(self):
 
323
        router = self._create_router()
 
324
        device_filter = {'device_id': [router.id]}
 
325
        ports_before = self.core_plugin.get_ports(
 
326
            self.admin_ctx, filters=device_filter)
 
327
        network = self.plugin.get_ha_network(self.admin_ctx, router.tenant_id)
 
328
 
 
329
        with mock.patch.object(self.plugin, '_create_ha_port_binding',
 
330
                               side_effect=ValueError):
 
331
            self.assertRaises(ValueError, self.plugin.add_ha_port,
 
332
                              self.admin_ctx, router.id, network.network_id,
 
333
                              router.tenant_id)
 
334
 
 
335
        ports_after = self.core_plugin.get_ports(
 
336
            self.admin_ctx, filters=device_filter)
 
337
 
 
338
        self.assertEqual(ports_before, ports_after)
 
339
 
 
340
    def test_create_ha_network_binding_failure_rolls_back_network(self):
 
341
        networks_before = self.core_plugin.get_networks(self.admin_ctx)
 
342
 
 
343
        with mock.patch.object(self.plugin,
 
344
                               '_create_ha_network_tenant_binding',
 
345
                               side_effect=ValueError):
 
346
            self.assertRaises(ValueError, self.plugin._create_ha_network,
 
347
                              self.admin_ctx, _uuid())
 
348
 
 
349
        networks_after = self.core_plugin.get_networks(self.admin_ctx)
 
350
        self.assertEqual(networks_before, networks_after)
 
351
 
 
352
    def test_create_ha_network_subnet_failure_rolls_back_network(self):
 
353
        networks_before = self.core_plugin.get_networks(self.admin_ctx)
 
354
 
 
355
        with mock.patch.object(self.plugin, '_create_ha_subnet',
 
356
                               side_effect=ValueError):
 
357
            self.assertRaises(ValueError, self.plugin._create_ha_network,
 
358
                              self.admin_ctx, _uuid())
 
359
 
 
360
        networks_after = self.core_plugin.get_networks(self.admin_ctx)
 
361
        self.assertEqual(networks_before, networks_after)
 
362
 
 
363
    def test_create_ha_interfaces_binding_failure_rolls_back_ports(self):
 
364
        router = self._create_router()
 
365
        network = self.plugin.get_ha_network(self.admin_ctx, router.tenant_id)
 
366
        device_filter = {'device_id': [router.id]}
 
367
        ports_before = self.core_plugin.get_ports(
 
368
            self.admin_ctx, filters=device_filter)
 
369
 
 
370
        with mock.patch.object(self.plugin, '_create_ha_port_binding',
 
371
                               side_effect=ValueError):
 
372
            self.assertRaises(ValueError, self.plugin._create_ha_interfaces,
 
373
                              self.admin_ctx, router, network)
 
374
 
 
375
        ports_after = self.core_plugin.get_ports(
 
376
            self.admin_ctx, filters=device_filter)
 
377
        self.assertEqual(ports_before, ports_after)
 
378
 
 
379
    def test_create_router_db_ha_attribute_failure_rolls_back_router(self):
 
380
        routers_before = self.plugin.get_routers(self.admin_ctx)
 
381
 
 
382
        for method in ('_set_vr_id',
 
383
                       '_create_ha_interfaces',
 
384
                       '_notify_ha_interfaces_updated'):
 
385
            with mock.patch.object(self.plugin, method,
 
386
                                   side_effect=ValueError):
 
387
                self.assertRaises(ValueError, self._create_router)
 
388
 
 
389
        routers_after = self.plugin.get_routers(self.admin_ctx)
 
390
        self.assertEqual(routers_before, routers_after)