1 # Copyright (c) 2014 OpenStack Foundation, all rights reserved.
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain 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,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
17 from oslo_utils import uuidutils
18 from sqlalchemy.orm import query
20 from neutron import context
21 from neutron.db import db_base_plugin_v2
22 from neutron.db import l3_db
23 from neutron.db import models_v2
24 from neutron.extensions import portbindings
25 from neutron.plugins.ml2 import db as ml2_db
26 from neutron.plugins.ml2 import driver_api as api
27 from neutron.plugins.ml2 import models
28 from neutron.tests.unit import testlib_api
31 class Ml2DBTestCase(testlib_api.SqlTestCase):
34 super(Ml2DBTestCase, self).setUp()
35 self.ctx = context.get_admin_context()
37 def _setup_neutron_network(self, network_id):
38 with self.ctx.session.begin(subtransactions=True):
39 self.ctx.session.add(models_v2.Network(id=network_id))
41 def _setup_neutron_port(self, network_id, port_id):
42 mac_address = db_base_plugin_v2.NeutronDbPluginV2._generate_mac()
43 with self.ctx.session.begin(subtransactions=True):
44 port = models_v2.Port(id=port_id,
45 network_id=network_id,
46 mac_address=mac_address,
51 self.ctx.session.add(port)
54 def _setup_neutron_portbinding(self, port_id, vif_type, host):
55 with self.ctx.session.begin(subtransactions=True):
56 self.ctx.session.add(models.PortBinding(port_id=port_id,
60 def _create_segments(self, segments, is_seg_dynamic=False,
61 network_id='foo-network-id'):
62 self._setup_neutron_network(network_id)
63 for segment in segments:
64 ml2_db.add_network_segment(
65 self.ctx.session, network_id, segment,
66 is_dynamic=is_seg_dynamic)
68 net_segments = ml2_db.get_network_segments(
69 self.ctx.session, network_id,
70 filter_dynamic=is_seg_dynamic)
72 for segment_index, segment in enumerate(segments):
73 self.assertEqual(segment, net_segments[segment_index])
77 def test_network_segments_for_provider_network(self):
78 segment = {api.NETWORK_TYPE: 'vlan',
79 api.PHYSICAL_NETWORK: 'physnet1',
80 api.SEGMENTATION_ID: 1}
81 self._create_segments([segment])
83 def test_network_segments_is_dynamic_true(self):
84 segment = {api.NETWORK_TYPE: 'vlan',
85 api.PHYSICAL_NETWORK: 'physnet1',
86 api.SEGMENTATION_ID: 1}
87 self._create_segments([segment], is_seg_dynamic=True)
89 def test_network_segments_for_multiprovider_network(self):
90 segments = [{api.NETWORK_TYPE: 'vlan',
91 api.PHYSICAL_NETWORK: 'physnet1',
92 api.SEGMENTATION_ID: 1},
93 {api.NETWORK_TYPE: 'vlan',
94 api.PHYSICAL_NETWORK: 'physnet1',
95 api.SEGMENTATION_ID: 2}]
96 self._create_segments(segments)
98 def test_get_networks_segments(self):
99 segments1 = [{api.NETWORK_TYPE: 'vlan',
100 api.PHYSICAL_NETWORK: 'physnet1',
101 api.SEGMENTATION_ID: 1},
102 {api.NETWORK_TYPE: 'vlan',
103 api.PHYSICAL_NETWORK: 'physnet1',
104 api.SEGMENTATION_ID: 2}]
105 segments2 = [{api.NETWORK_TYPE: 'vlan',
106 api.PHYSICAL_NETWORK: 'physnet1',
107 api.SEGMENTATION_ID: 3},
108 {api.NETWORK_TYPE: 'vlan',
109 api.PHYSICAL_NETWORK: 'physnet1',
110 api.SEGMENTATION_ID: 4}]
111 net1segs = self._create_segments(segments1, network_id='net1')
112 net2segs = self._create_segments(segments2, network_id='net2')
113 segs = ml2_db.get_networks_segments(self.ctx.session, ['net1', 'net2'])
114 self.assertEqual(net1segs, segs['net1'])
115 self.assertEqual(net2segs, segs['net2'])
117 def test_get_networks_segments_no_segments(self):
118 self._create_segments([], network_id='net1')
119 self._create_segments([], network_id='net2')
120 segs = ml2_db.get_networks_segments(self.ctx.session, ['net1', 'net2'])
121 self.assertEqual([], segs['net1'])
122 self.assertEqual([], segs['net2'])
124 def test_get_segment_by_id(self):
125 segment = {api.NETWORK_TYPE: 'vlan',
126 api.PHYSICAL_NETWORK: 'physnet1',
127 api.SEGMENTATION_ID: 1}
129 net_segment = self._create_segments([segment])[0]
130 segment_uuid = net_segment[api.ID]
132 net_segment = ml2_db.get_segment_by_id(self.ctx.session, segment_uuid)
133 self.assertEqual(segment, net_segment)
135 def test_get_segment_by_id_result_not_found(self):
136 segment_uuid = uuidutils.generate_uuid()
137 net_segment = ml2_db.get_segment_by_id(self.ctx.session, segment_uuid)
138 self.assertIsNone(net_segment)
140 def test_delete_network_segment(self):
141 segment = {api.NETWORK_TYPE: 'vlan',
142 api.PHYSICAL_NETWORK: 'physnet1',
143 api.SEGMENTATION_ID: 1}
145 net_segment = self._create_segments([segment])[0]
146 segment_uuid = net_segment[api.ID]
148 ml2_db.delete_network_segment(self.ctx.session, segment_uuid)
149 # Get segment and verify its empty
150 net_segment = ml2_db.get_segment_by_id(self.ctx.session, segment_uuid)
151 self.assertIsNone(net_segment)
153 def test_add_port_binding(self):
154 network_id = 'foo-network-id'
155 port_id = 'foo-port-id'
156 self._setup_neutron_network(network_id)
157 self._setup_neutron_port(network_id, port_id)
159 port = ml2_db.add_port_binding(self.ctx.session, port_id)
160 self.assertEqual(port_id, port.port_id)
161 self.assertEqual(portbindings.VIF_TYPE_UNBOUND, port.vif_type)
163 def test_get_port_binding_host(self):
164 network_id = 'foo-network-id'
165 port_id = 'foo-port-id'
167 vif_type = portbindings.VIF_TYPE_UNBOUND
168 self._setup_neutron_network(network_id)
169 self._setup_neutron_port(network_id, port_id)
170 self._setup_neutron_portbinding(port_id, vif_type, host)
172 port_host = ml2_db.get_port_binding_host(self.ctx.session, port_id)
173 self.assertEqual(host, port_host)
175 def test_get_port_binding_host_multiple_results_found(self):
176 network_id = 'foo-network-id'
177 port_id = 'foo-port-id'
178 port_id_one = 'foo-port-id-one'
179 port_id_two = 'foo-port-id-two'
181 vif_type = portbindings.VIF_TYPE_UNBOUND
182 self._setup_neutron_network(network_id)
183 self._setup_neutron_port(network_id, port_id_one)
184 self._setup_neutron_portbinding(port_id_one, vif_type, host)
185 self._setup_neutron_port(network_id, port_id_two)
186 self._setup_neutron_portbinding(port_id_two, vif_type, host)
188 port_host = ml2_db.get_port_binding_host(self.ctx.session, port_id)
189 self.assertIsNone(port_host)
191 def test_get_port_binding_host_result_not_found(self):
192 port_id = uuidutils.generate_uuid()
194 port_host = ml2_db.get_port_binding_host(self.ctx.session, port_id)
195 self.assertIsNone(port_host)
197 def test_get_port(self):
198 network_id = 'foo-network-id'
199 port_id = 'foo-port-id'
200 self._setup_neutron_network(network_id)
201 self._setup_neutron_port(network_id, port_id)
203 port = ml2_db.get_port(self.ctx.session, port_id)
204 self.assertEqual(port_id, port.id)
206 def test_get_port_multiple_results_found(self):
207 network_id = 'foo-network-id'
208 port_id = 'foo-port-id'
209 port_id_one = 'foo-port-id-one'
210 port_id_two = 'foo-port-id-two'
211 self._setup_neutron_network(network_id)
212 self._setup_neutron_port(network_id, port_id_one)
213 self._setup_neutron_port(network_id, port_id_two)
215 port = ml2_db.get_port(self.ctx.session, port_id)
216 self.assertIsNone(port)
218 def test_get_port_result_not_found(self):
219 port_id = uuidutils.generate_uuid()
220 port = ml2_db.get_port(self.ctx.session, port_id)
221 self.assertIsNone(port)
223 def test_get_port_from_device_mac(self):
224 network_id = 'foo-network-id'
225 port_id = 'foo-port-id'
226 self._setup_neutron_network(network_id)
227 port = self._setup_neutron_port(network_id, port_id)
229 observed_port = ml2_db.get_port_from_device_mac(self.ctx,
231 self.assertEqual(port_id, observed_port.id)
233 def test_get_locked_port_and_binding(self):
234 network_id = 'foo-network-id'
235 port_id = 'foo-port-id'
237 vif_type = portbindings.VIF_TYPE_UNBOUND
238 self._setup_neutron_network(network_id)
239 self._setup_neutron_port(network_id, port_id)
240 self._setup_neutron_portbinding(port_id, vif_type, host)
242 port, binding = ml2_db.get_locked_port_and_binding(self.ctx.session,
244 self.assertEqual(port_id, port.id)
245 self.assertEqual(port_id, binding.port_id)
247 def test_get_locked_port_and_binding_result_not_found(self):
248 port_id = uuidutils.generate_uuid()
250 port, binding = ml2_db.get_locked_port_and_binding(self.ctx.session,
252 self.assertIsNone(port)
253 self.assertIsNone(binding)
256 class Ml2DvrDBTestCase(testlib_api.SqlTestCase):
259 super(Ml2DvrDBTestCase, self).setUp()
260 self.ctx = context.get_admin_context()
262 def _setup_neutron_network(self, network_id, port_ids):
263 with self.ctx.session.begin(subtransactions=True):
264 self.ctx.session.add(models_v2.Network(id=network_id))
266 for port_id in port_ids:
267 mac_address = (db_base_plugin_v2.NeutronDbPluginV2.
269 port = models_v2.Port(id=port_id,
270 network_id=network_id,
271 mac_address=mac_address,
276 self.ctx.session.add(port)
280 def _setup_neutron_router(self):
281 with self.ctx.session.begin(subtransactions=True):
282 router = l3_db.Router()
283 self.ctx.session.add(router)
286 def _setup_dvr_binding(self, network_id, port_id, router_id, host_id):
287 with self.ctx.session.begin(subtransactions=True):
288 record = models.DVRPortBinding(
292 vif_type=portbindings.VIF_TYPE_UNBOUND,
293 vnic_type=portbindings.VNIC_NORMAL,
295 self.ctx.session.add(record)
298 def test_ensure_dvr_port_binding_deals_with_db_duplicate(self):
299 network_id = 'foo_network_id'
300 port_id = 'foo_port_id'
301 router_id = 'foo_router_id'
302 host_id = 'foo_host_id'
303 self._setup_neutron_network(network_id, [port_id])
304 self._setup_dvr_binding(network_id, port_id, router_id, host_id)
305 with mock.patch.object(query.Query, 'first') as query_first:
306 query_first.return_value = []
307 with mock.patch.object(ml2_db.LOG, 'debug') as log_trace:
308 binding = ml2_db.ensure_dvr_port_binding(
309 self.ctx.session, port_id, host_id, router_id)
310 self.assertTrue(query_first.called)
311 self.assertTrue(log_trace.called)
312 self.assertEqual(port_id, binding.port_id)
314 def test_ensure_dvr_port_binding(self):
315 network_id = 'foo_network_id'
316 port_id = 'foo_port_id'
317 self._setup_neutron_network(network_id, [port_id])
318 router = self._setup_neutron_router()
319 ml2_db.ensure_dvr_port_binding(
320 self.ctx.session, port_id, 'foo_host', router.id)
321 expected = (self.ctx.session.query(models.DVRPortBinding).
322 filter_by(port_id=port_id).one())
323 self.assertEqual(expected.port_id, port_id)
325 def test_ensure_dvr_port_binding_multiple_bindings(self):
326 network_id = 'foo_network_id'
327 port_id = 'foo_port_id'
328 self._setup_neutron_network(network_id, [port_id])
329 router = self._setup_neutron_router()
330 ml2_db.ensure_dvr_port_binding(
331 self.ctx.session, port_id, 'foo_host_1', router.id)
332 ml2_db.ensure_dvr_port_binding(
333 self.ctx.session, port_id, 'foo_host_2', router.id)
334 bindings = (self.ctx.session.query(models.DVRPortBinding).
335 filter_by(port_id=port_id).all())
336 self.assertEqual(2, len(bindings))
338 def test_delete_dvr_port_binding(self):
339 network_id = 'foo_network_id'
340 port_id = 'foo_port_id'
341 self._setup_neutron_network(network_id, [port_id])
342 router = self._setup_neutron_router()
343 binding = self._setup_dvr_binding(
344 network_id, port_id, router.id, 'foo_host_id')
345 ml2_db.delete_dvr_port_binding(
346 self.ctx.session, port_id, 'foo_host_id')
347 count = (self.ctx.session.query(models.DVRPortBinding).
348 filter_by(port_id=binding.port_id).count())
349 self.assertFalse(count)
351 def test_delete_dvr_port_binding_not_found(self):
352 ml2_db.delete_dvr_port_binding(
353 self.ctx.session, 'foo_port_id', 'foo_host')
355 def test_delete_dvr_port_binding_if_stale(self):
356 network_id = 'foo_network_id'
357 port_id = 'foo_port_id'
358 self._setup_neutron_network(network_id, [port_id])
359 binding = self._setup_dvr_binding(
360 network_id, port_id, None, 'foo_host_id')
362 ml2_db.delete_dvr_port_binding_if_stale(self.ctx.session, binding)
363 count = (self.ctx.session.query(models.DVRPortBinding).
364 filter_by(port_id=binding.port_id).count())
365 self.assertFalse(count)
367 def test_get_dvr_port_binding_by_host_not_found(self):
368 port = ml2_db.get_dvr_port_binding_by_host(
369 self.ctx.session, 'foo_port_id', 'foo_host_id')
370 self.assertIsNone(port)
372 def test_get_dvr_port_bindings_not_found(self):
373 port = ml2_db.get_dvr_port_bindings(self.ctx.session, 'foo_port_id')
374 self.assertFalse(len(port))
376 def test_get_dvr_port_bindings(self):
377 network_id = 'foo_network_id'
378 port_id_1 = 'foo_port_id_1'
379 port_id_2 = 'foo_port_id_2'
380 self._setup_neutron_network(network_id, [port_id_1, port_id_2])
381 router = self._setup_neutron_router()
382 self._setup_dvr_binding(
383 network_id, port_id_1, router.id, 'foo_host_id_1')
384 self._setup_dvr_binding(
385 network_id, port_id_1, router.id, 'foo_host_id_2')
386 ports = ml2_db.get_dvr_port_bindings(self.ctx.session, 'foo_port_id')
387 self.assertEqual(2, len(ports))